{"version":3,"sources":["out-editor/vs/editor/fake","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/css.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/nls.ts","out-editor/vs/editor/vs/base/browser/dompurify/dompurify.js","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/fastDomNode.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/iframe.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/performance.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/hover/hoverDelegate2.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/list/list.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/list/splice.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/scrollbar/scrollbarState.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/tree/tree.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/window.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/browser.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/arrays.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/arraysFind.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/cache.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/collections.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/color.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/decorators.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/diff/diffChange.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/equals.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/errors.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/trustedTypes.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/assert.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/functional.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/hierarchicalKind.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/idGenerator.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/iterator.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/keyCodes.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/keybindings.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/lazy.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/hover/hoverDelegateFactory.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/buffer.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/comparers.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/lifecycle.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/linkedList.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/linkedText.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/map.ts","out-editor/vs/editor/vs/base/common/marked/marked.js","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/mime.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/dnd.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/naturalLanguage/korean.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/navigator.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/history.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/numbers.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/observableInternal/debugName.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/observableInternal/logging.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/observableInternal/autorun.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/observableInternal/base.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/observableInternal/derived.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/observableInternal/promise.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/range.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/list/rangeMap.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/stopwatch.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/event.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/event.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/cancellation.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/ime.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/observableInternal/utils.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/observable.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/scrollable.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/strings.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/filters.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/hash.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/diff/diff.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/search.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/severity.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/symbols.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/ternarySearchTree.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/tfIdf.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/types.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/codiconsUtil.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/codiconsLibrary.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/codicons.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/objects.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/themables.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/iconLabels.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/uint.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/uuid.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/dataTransfer.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/codicons/codiconStyles.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/mouseCursor/mouseCursor.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/config/domFontInfo.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/config/charWidthReader.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/config/migrateOptions.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/config/tabFocus.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/observableUtilities.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/stableEditorScroll.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/view/renderingContext.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/viewParts/lines/domReadingContext.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/viewParts/lines/rangeUtil.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/viewParts/minimap/minimapCharSheet.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/viewParts/minimap/minimapCharRenderer.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/viewParts/minimap/minimapPreBaked.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/viewParts/minimap/minimapCharRendererFactory.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/widget/diffEditor/delegatingEditorImpl.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/widget/multiDiffEditor/objectPool.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/config/diffEditor.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/config/editorZoom.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/core/characterClassifier.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/core/cursorColumns.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/core/eolCounter.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/core/indentation.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/core/offsetRange.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/core/position.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/view/viewUserInputEvents.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/core/range.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/controller/textAreaState.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/core/editOperation.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/commands/trimTrailingWhitespaceCommand.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/core/lineRange.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/core/rgba.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/core/selection.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/commands/replaceCommand.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/commands/surroundSelectionCommand.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/core/textLength.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/core/positionToOffset.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/core/textEdit.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/core/textModelDefaults.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/core/wordCharacterClassifier.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/core/wordHelper.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/cursor/cursorAtomicMoveOperations.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/cursor/cursorContext.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/diff/defaultLinesDiffComputer/algorithms/diffAlgorithm.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/diff/defaultLinesDiffComputer/algorithms/myersDiffAlgorithm.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/diff/defaultLinesDiffComputer/heuristicSequenceOptimizations.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/diff/defaultLinesDiffComputer/lineSequence.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/diff/defaultLinesDiffComputer/utils.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/diff/defaultLinesDiffComputer/algorithms/dynamicProgrammingDiffing.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/diff/defaultLinesDiffComputer/linesSliceCharSequence.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/diff/linesDiffComputer.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/diff/rangeMapping.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/diff/defaultLinesDiffComputer/computeMovedLines.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/diff/defaultLinesDiffComputer/defaultLinesDiffComputer.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/diff/legacyLinesDiffComputer.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/diff/linesDiffComputers.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/editorAction.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/editorCommon.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/editorBrowser.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/editorFeatures.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/editorTheme.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/encodedTokenAttributes.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/languages/defaultDocumentColorsComputer.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/languages/languageConfiguration.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/languages/linkComputer.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/languages/supports.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/cursorCommon.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/cursor/cursorColumnSelection.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/cursor/cursorMoveOperations.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/cursor/cursorDeleteOperations.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/cursor/cursorWordOperations.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/cursor/cursorMoveCommands.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/cursor/oneCursor.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/cursor/cursorCollection.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/languages/supports/characterPair.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/languages/supports/indentRules.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/languages/supports/inplaceReplaceSupport.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/languages/supports/languageBracketsConfiguration.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/languages/supports/onEnter.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/languages/supports/tokenization.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/model.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/length.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/beforeEditPositionMapper.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/combineTextEditInfos.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/nodeReader.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/smallImmutableSet.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/ast.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/concat23Trees.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/parser.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/tokenizer.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/brackets.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/model/bracketPairsTextModelPart/fixBrackets.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/model/fixedArray.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/model/indentationGuesser.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/model/intervalTree.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/model/pieceTreeTextBuffer/rbTreeBase.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/model/prefixSumComputer.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/model/mirrorTextModel.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/model/textModelPart.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/model/textModelSearch.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeBase.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/model/textModelText.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/model/utils.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/modelLineProjectionData.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/services/findSectionHeaders.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/services/treeViewsDnd.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/services/unicodeTextModelHighlighter.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/standalone/standaloneEnums.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/textModelBracketPairs.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/bracketPairsTree.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/textModelEvents.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/textModelGuides.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/model/guidesTextModelPart.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/tokenizationRegistry.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/tokens/contiguousMultilineTokens.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/tokens/contiguousMultilineTokensBuilder.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/tokens/lineTokens.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/tokens/contiguousTokensEditing.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/tokens/contiguousTokensStore.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/tokens/sparseMultilineTokens.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/tokens/sparseTokensStore.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/viewEventHandler.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/view/dynamicViewOverlay.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/view/viewPart.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/viewParts/blockDecorations/blockDecorations.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/viewParts/decorations/decorations.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/viewParts/glyphMargin/glyphMargin.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/viewParts/linesDecorations/linesDecorations.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/viewParts/margin/margin.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/viewParts/marginDecorations/marginDecorations.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/viewParts/rulers/rulers.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/viewParts/scrollDecoration/scrollDecoration.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/viewParts/viewZones/viewZones.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/viewEvents.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/viewLayout/lineDecorations.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/viewLayout/linePart.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/viewLayout/linesLayout.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/viewLayout/viewLinesViewportData.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/viewModel.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/viewModel/glyphLanesModel.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/viewModel/modelLineProjection.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/viewModel/monospaceLineBreaksComputer.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/viewModel/overviewZoneManager.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/viewParts/overviewRuler/overviewRuler.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/viewModel/viewContext.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/viewModelEventDispatcher.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/viewLayout/viewLayout.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/caretOperations/browser/moveCaretCommand.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/codeAction/common/types.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/colorPicker/browser/colorPickerModel.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/comment/browser/blockCommentCommand.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/comment/browser/lineCommentCommand.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/dnd/browser/dragAndDropCommand.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/find/browser/replaceAllCommand.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/find/browser/replacePattern.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/folding/browser/foldingRanges.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/folding/browser/foldingModel.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/folding/browser/hiddenRangeModel.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/folding/browser/indentRangeProvider.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/folding/browser/syntaxRangeProvider.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/format/browser/formattingEdit.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/hover/browser/contentHoverTypes.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/hover/browser/hoverAccessibleViews.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/hover/browser/hoverActionIds.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/hover/browser/hoverTypes.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/inPlaceReplace/browser/inPlaceReplaceCommand.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/indentation/common/indentUtils.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/inlineCompletions/browser/commandIds.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/inlineCompletions/browser/ghostText.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/inlineCompletions/browser/inlineCompletionsAccessibleView.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/inlineCompletions/browser/singleTextEdit.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/inlineCompletions/browser/utils.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/inlineEdit/browser/commandIds.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/linesOperations/browser/copyLinesCommand.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/linesOperations/browser/sortLinesCommand.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/semanticTokens/common/semanticTokensConfig.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/smartSelect/browser/bracketSelections.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/smartSelect/browser/wordSelections.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/snippet/browser/snippetParser.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/stickyScroll/browser/stickyScrollElement.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/suggest/browser/completionModel.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/suggest/browser/suggestCommitCharacters.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/suggest/browser/suggestOvertypingCapturer.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/suggest/browser/wordDistance.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/standalone/common/monarch/monarchCommon.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/standalone/common/monarch/monarchCompile.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/actions.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/widget/multiDiffEditor/utils.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/errorMessage.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/keybindingLabels.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/platform.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/canIUse.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/fonts.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/keyboardEvent.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/mouseEvent.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/async.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/scrollbar/scrollbarVisibilityController.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/tree/indexTreeModel.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/tree/objectTreeModel.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/tree/compressedObjectTreeModel.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/process.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/hotReload.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/path.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/extpath.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/fuzzyScorer.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/glob.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/labels.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/uri.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/marshalling.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/network.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/dom.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/formattedTextRenderer.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/globalPointerMoveMonitor.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/pixelRatio.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/touch.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/aria/aria.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/contextview/contextview.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/countBadge/countBadge.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/dropdown/dropdown.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/iconLabel/iconLabels.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/highlightedlabel/highlightedLabel.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/iconLabel/iconLabel.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/keybindingLabel/keybindingLabel.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/list/rowCache.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/progressbar/progressbar.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/sash/sash.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/resizable/resizable.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/selectBox/selectBoxNative.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/widget.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/scrollbar/scrollbarArrow.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/scrollbar/abstractScrollbar.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/scrollbar/horizontalScrollbar.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/scrollbar/verticalScrollbar.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/scrollbar/scrollableElement.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/hover/hoverWidget.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/list/listView.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/list/listWidget.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/list/listPaging.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/splitview/splitview.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/table/tableWidget.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/toggle/toggle.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/findinput/findInputToggles.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/resources.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/htmlContent.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/markdownRenderer.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/button/button.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/selectBox/selectBoxCustom.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/selectBox/selectBox.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/actionbar/actionViewItems.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/actionbar/actionbar.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/dropdown/dropdownActionViewItem.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/inputbox/inputBox.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/findinput/findInput.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/findinput/replaceInput.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/menu/menu.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/toolbar/toolbar.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/tree/abstractTree.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/tree/dataTree.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/tree/objectTree.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/ui/tree/asyncDataTree.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/common/worker/simpleWorker.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/browser/defaultWorkerFactory.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/base/parts/storage/common/storage.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/config/elementSizeObserver.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/viewParts/contentWidgets/contentWidgets.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/viewParts/overlayWidgets/overlayWidgets.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/widget/codeEditor/codeEditorContributions.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/widget/diffEditor/components/diffEditorSash.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/widget/diffEditor/utils.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/widget/diffEditor/utils/editorGutter.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/core/stringBuilder.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/view/domLineBreaksComputer.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/view/viewLayer.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/view/viewOverlays.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/core/textChange.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/languageSelector.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/languageFeatureRegistry.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/languages/supports/richEditBrackets.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/languages/supports/electricCharacter.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/model/bracketPairsTextModelPart/bracketPairsImpl.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBuffer.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBufferBuilder.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/services/semanticTokensDto.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/gotoSymbol/browser/link/clickLinkGesture.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/hover/browser/contentHoverComputer.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/hover/browser/hoverOperation.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/hover/browser/marginHoverComputer.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/hover/browser/resizableContentWidget.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/inlayHints/browser/inlayHints.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/inlineCompletions/browser/provideInlineCompletions.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/services/hoverService/updatableHoverWidget.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/widget/diffEditor/components/diffEditorViewZones/inlineDiffDeletedCodeMargin.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/widget/diffEditor/features/movedBlocksLinesFeature.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/widget/diffEditor/features/revertButtonsFeature.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/config/editorOptions.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/viewParts/viewCursors/viewCursor.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/config/fontInfo.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/config/fontMeasurements.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/viewModel/viewModelDecorations.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/languages.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/languages/nullTokenize.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/languages/textToHtmlTokenizer.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/model/textModelTokens.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/model/tokenizationTextModelPart.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/services/editorBaseApi.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/services/editorSimpleWorker.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/viewModel/minimapTokensColorTracker.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/model/editStack.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/standaloneStrings.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/viewLayout/viewLineRenderer.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/widget/diffEditor/components/diffEditorViewZones/renderLines.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/gotoSymbol/browser/referencesModel.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/accessibility/browser/accessibleViewRegistry.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/action/common/action.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/action/common/actionCommonCategories.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/contextkey/common/scanner.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/editor/common/editor.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/extensions/common/extensions.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/files/common/files.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/history/browser/historyWidgetKeybindingHint.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/instantiation/common/descriptors.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/instantiation/common/extensions.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/instantiation/common/graph.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/instantiation/common/instantiation.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/services/bulkEditService.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/services/codeEditorService.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/widget/diffEditor/features/hideUnchangedRegionsFeature.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/languages/language.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/services/editorWorker.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/services/languageFeatures.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/services/languageFeaturesService.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/services/markerDecorations.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/services/model.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/services/resolverService.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/services/semanticTokensStyling.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/services/textResourceConfiguration.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/services/treeViewsDndService.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/dropOrPasteInto/browser/edit.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/inlineCompletions/browser/ghostTextWidget.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/inlineEdit/browser/ghostTextWidget.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/standalone/common/standaloneTheme.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/accessibilitySignal/browser/accessibilitySignalService.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/clipboard/common/clipboardService.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/commands/common/commands.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/codelens/browser/codelens.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/links/browser/getLinks.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/semanticTokens/common/getSemanticTokens.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/configuration/common/configuration.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/standalone/common/monarch/monarchLexer.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/standalone/browser/colorizer.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/contextkey/common/contextkey.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/editorContextKeys.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/inlineCompletions/browser/inlineCompletionContextKeys.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/parameterHints/browser/provideSignatureHelp.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/parameterHints/browser/parameterHintsModel.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/suggest/browser/suggestAlternatives.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/suggest/browser/wordContextKey.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/accessibility/common/accessibility.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/config/editorConfiguration.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/widget/diffEditor/diffEditorOptions.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/contextkey/browser/contextKeyService.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/contextkey/common/contextkeys.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/contextview/browser/contextView.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/dialogs/common/dialogs.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/environment/common/environment.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/hover/browser/hover.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/instantiation/common/serviceCollection.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/instantiation/common/instantiationService.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/keybinding/common/baseResolvedKeybinding.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/keybinding/common/keybinding.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/hover/browser/contentHoverStatusBar.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/hover/browser/contentHoverWidget.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/keybinding/common/keybindingResolver.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/keybinding/common/abstractKeybindingService.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/keybinding/common/resolvedKeybindingItem.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/keybinding/common/usLayoutResolvedKeybinding.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/label/common/label.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/layout/browser/layoutService.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/standalone/browser/standaloneLayoutService.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/accessibility/browser/accessibilityService.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/contextview/browser/contextViewService.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/log/common/log.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/controller/textAreaInput.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/services/languageFeatureDebounce.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/documentSymbols/browser/outlineModel.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/diffEditorBreadcrumbs/browser/contribution.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/documentSymbols/browser/documentSymbols.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/clipboard/browser/clipboardService.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/log/common/logService.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/markers/common/markers.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/gotoError/browser/markerNavigationService.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/markers/common/markerService.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/notification/common/notification.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/dropOrPasteInto/browser/postEditWidget.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/observable/common/platformObservableUtils.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/opener/common/opener.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/services/openerService.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/opener/browser/link.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/progress/common/progress.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/quickinput/browser/pickerQuickAccess.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/quickinput/browser/quickInputBox.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/quickinput/browser/quickInputUtils.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/quickinput/common/quickInput.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/quickinput/browser/quickInput.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/registry/common/platform.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/dnd/browser/dnd.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/dnd.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/jsonschemas/common/jsonContributionRegistry.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/configuration/common/configurationRegistry.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/config/editorConfigurationSchema.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/languages/modesRegistry.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/widget/markdownRenderer/browser/markdownRenderer.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/services/hoverService/hoverWidget.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/languages/languageConfigurationRegistry.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/services/editorWorkerService.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/services/webWorker.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/languages/autoIndent.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/languages/enterAction.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/commands/shiftCommand.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/cursor/cursorTypeOperations.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/cursor/cursor.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/services/getIconClasses.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/services/languagesAssociations.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/services/languagesRegistry.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/services/languageService.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/colorPicker/browser/defaultDocumentColorProvider.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/colorPicker/browser/color.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/hover/browser/marginHoverWidget.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/indentation/common/indentation.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/inlineCompletions/browser/inlineCompletionsSource.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/linesOperations/browser/moveLinesCommand.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/suggest/browser/suggestWidgetDetails.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/configuration/common/configurationModels.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/configuration/common/configurations.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/keybinding/common/keybindingsRegistry.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/actions/common/actions.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/toggleTabFocusMode/browser/toggleTabFocusMode.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/history/browser/contextScopedHistoryWidget.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/suggest/browser/suggest.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/quickinput/browser/quickInputActions.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/quickinput/common/quickAccess.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/quickinput/browser/helpQuickAccess.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/standalone/browser/quickAccess/standaloneHelpQuickAccess.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/quickinput/browser/quickAccess.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/severityIcon/browser/severityIcon.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/storage/common/storage.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/codelens/browser/codeLensCache.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/suggest/browser/suggestMemory.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/actions/common/menuService.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/telemetry/common/telemetry.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/editorExtensions.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/coreCommands.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/services/markerDecorations.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/view/viewController.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/widget/diffEditor/diffProviderFactoryService.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/widget/diffEditor/diffEditorViewModel.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/anchorSelect/browser/anchorSelect.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/caretOperations/browser/caretOperations.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/caretOperations/browser/transpose.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/comment/browser/comment.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/cursorUndo/browser/cursorUndo.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/editorState/browser/keybindingCancellation.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/editorState/browser/editorState.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/codeAction/browser/codeAction.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/codeAction/browser/codeActionKeybindingResolver.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/codeAction/browser/codeActionModel.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/codeAction/browser/lightBulbWidget.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/fontZoom/browser/fontZoom.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/format/browser/format.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/format/browser/formatActions.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/gotoSymbol/browser/goToSymbol.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/gotoSymbol/browser/symbolNavigation.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/hover/browser/getHover.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/indentation/browser/indentation.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/lineSelection/browser/lineSelection.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/linesOperations/browser/linesOperations.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/longLinesHelper/browser/longLinesHelper.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/message/browser/messageController.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/readOnlyMessage/browser/contribution.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/smartSelect/browser/smartSelect.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/tokenization/browser/tokenization.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/unusualLineTerminators/browser/unusualLineTerminators.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/wordOperations/browser/wordOperations.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/wordPartOperations/browser/wordPartOperations.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/standalone/browser/iPadShowKeyboard/iPadShowKeyboard.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/standalone/browser/inspectTokens/inspectTokens.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/quickinput/browser/commandsQuickAccess.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/quickAccess/browser/commandsQuickAccess.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/standalone/browser/quickAccess/standaloneCommandsQuickAccess.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/theme/common/colorUtils.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/theme/common/colors/baseColors.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/theme/common/colors/miscColors.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/theme/common/colors/editorColors.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/theme/common/colors/inputColors.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/theme/common/colors/listColors.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/theme/common/colors/menuColors.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/theme/common/colors/minimapColors.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/theme/common/colors/chartsColors.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/theme/common/colors/quickpickColors.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/theme/common/colors/searchColors.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/theme/common/colorRegistry.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/editorDom.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/viewParts/minimap/minimap.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/widget/multiDiffEditor/colors.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/symbolIcons/browser/symbolIcons.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/codeAction/browser/codeActionMenu.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/theme/browser/defaultStyles.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/gotoSymbol/browser/peek/referencesTree.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/actionWidget/browser/actionList.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/actionWidget/browser/actionWidget.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/contextview/browser/contextMenuHandler.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/list/browser/listService.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/theme/common/iconRegistry.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/widget/diffEditor/components/accessibleDiffViewer.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/colorPicker/browser/colorPickerWidget.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/hover/browser/markdownHoverParticipant.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/parameterHints/browser/parameterHintsWidget.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/parameterHints/browser/parameterHints.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/unicodeHighlighter/browser/bannerController.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/theme/browser/iconsStyleSheet.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/theme/common/theme.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/viewParts/lines/viewLine.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/controller/mouseTarget.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/controller/mouseHandler.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/controller/pointerHandler.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/viewParts/lines/viewLines.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/theme/common/themeService.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/services/abstractCodeEditorService.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/services/hoverService/hoverService.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/viewParts/editorScrollbar/editorScrollbar.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/viewParts/selections/selections.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/widget/diffEditor/features/overviewRulerFeature.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/widget/diffEditor/components/diffEditorEditors.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/core/editorColorRegistry.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/viewParts/currentLineHighlight/currentLineHighlight.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/viewParts/indentGuides/indentGuides.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/viewParts/lineNumbers/lineNumbers.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/controller/textAreaHandler.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/viewParts/overviewRuler/decorationsOverviewRuler.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/viewParts/viewCursors/viewCursors.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/viewParts/whitespace/whitespace.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/view.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/model/bracketPairsTextModelPart/colorizedBracketPairsDecorationProvider.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/services/markerDecorationsService.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/services/semanticTokensProviderStyling.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/services/semanticTokensStylingService.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/quickAccess/browser/editorNavigationQuickAccess.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/quickAccess/browser/gotoLineQuickAccess.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/quickAccess/browser/gotoSymbolQuickAccess.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/rename/browser/renameWidget.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/rename/browser/rename.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/semanticTokens/browser/documentSemanticTokens.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/semanticTokens/browser/viewportSemanticTokens.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/suggest/browser/suggestWidgetRenderer.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/standalone/browser/quickAccess/standaloneGotoLineQuickAccess.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/standalone/browser/quickAccess/standaloneGotoSymbolQuickAccess.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/standalone/browser/standaloneCodeEditorService.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/standalone/common/themes.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/standalone/browser/standaloneThemeService.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/standalone/browser/toggleHighContrast/toggleHighContrast.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/actions/browser/menuEntryActionViewItem.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/suggest/browser/suggestWidgetStatus.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/actions/browser/toolbar.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/widget/diffEditor/features/gutterFeature.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/inlineCompletions/browser/inlineCompletionsHintsWidget.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/inlineEdit/browser/inlineEditHintsWidget.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/inlineEdit/browser/inlineEditController.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/inlineEdit/browser/commands.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/inlineEdit/browser/hoverParticipant.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/inlineEdit/browser/inlineEdit.contribution.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/contextview/browser/contextMenuService.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/quickinput/browser/quickInputTree.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/quickinput/browser/quickInputController.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/quickinput/browser/quickInputService.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/standalone/browser/quickInput/standaloneQuickInputService.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/undoRedo/common/undoRedo.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/model/textModel.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/widget/diffEditor/registrations.contribution.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/widget/diffEditor/components/diffEditorDecorations.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/widget/diffEditor/components/diffEditorViewZones/diffEditorViewZones.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/services/modelService.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/viewModel/viewModelLines.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/common/viewModel/viewModelImpl.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/widget/codeEditor/codeEditorWidget.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/widget/codeEditor/embeddedCodeEditorWidget.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/widget/diffEditor/diffEditorWidget.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/widget/diffEditor/commands.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/widget/diffEditor/diffEditor.contribution.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/widget/multiDiffEditor/diffEditorItemTemplate.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/widget/multiDiffEditor/multiDiffEditorWidgetImpl.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/browser/widget/multiDiffEditor/multiDiffEditorWidget.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/bracketMatching/browser/bracketMatching.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/codeAction/browser/codeActionController.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/codeAction/browser/codeActionCommands.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/codeAction/browser/codeActionContributions.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/codelens/browser/codelensWidget.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/codelens/browser/codelensController.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/colorPicker/browser/colorDetector.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/colorPicker/browser/colorHoverParticipant.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/colorPicker/browser/standaloneColorPickerWidget.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/colorPicker/browser/standaloneColorPickerActions.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/dnd/browser/dnd.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/find/browser/findDecorations.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/find/browser/findModel.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/find/browser/findOptionsWidget.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/find/browser/findState.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/find/browser/findWidget.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/find/browser/findController.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/folding/browser/foldingDecorations.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/folding/browser/folding.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/inPlaceReplace/browser/inPlaceReplace.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/inlineProgress/browser/inlineProgress.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/dropOrPasteInto/browser/dropIntoEditorController.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/linkedEditing/browser/linkedEditing.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/links/browser/links.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/sectionHeaders/browser/sectionHeaders.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/stickyScroll/browser/stickyScrollModelProvider.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/stickyScroll/browser/stickyScrollProvider.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/stickyScroll/browser/stickyScrollWidget.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/suggest/browser/suggestWidget.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/wordHighlighter/browser/highlightDecorations.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/multicursor/browser/multicursor.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/wordHighlighter/browser/wordHighlighter.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/zoneWidget/browser/zoneWidget.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/peekView/browser/peekView.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/gotoError/browser/gotoErrorWidget.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/gotoError/browser/gotoError.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/gotoSymbol/browser/peek/referencesWidget.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/gotoSymbol/browser/peek/referencesController.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/gotoSymbol/browser/goToCommands.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/gotoSymbol/browser/link/goToDefinitionAtPosition.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/hover/browser/markerHoverParticipant.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/inlayHints/browser/inlayHintsLocations.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/inlayHints/browser/inlayHintsController.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/inlayHints/browser/inlayHintsHover.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/hover/browser/contentHoverController.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/hover/browser/hoverController.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/colorPicker/browser/colorContributions.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/hover/browser/hoverActions.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/hover/browser/hoverContribution.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/inlayHints/browser/inlayHintsContribution.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/stickyScroll/browser/stickyScrollController.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/stickyScroll/browser/stickyScrollActions.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/stickyScroll/browser/stickyScrollContribution.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/standalone/browser/referenceSearch/standaloneReferenceSearch.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/undoRedo/common/undoRedoService.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/workspace/common/workspace.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/contextmenu/browser/contextmenu.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/dropOrPasteInto/browser/defaultProviders.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/dropOrPasteInto/browser/copyPasteController.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/clipboard/browser/clipboard.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/dropOrPasteInto/browser/copyPasteContribution.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/dropOrPasteInto/browser/dropIntoEditorContribution.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/snippet/browser/snippetVariables.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/snippet/browser/snippetSession.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/snippet/browser/snippetController2.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/inlineCompletions/browser/inlineCompletionsModel.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/suggest/browser/suggestModel.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/suggest/browser/suggestController.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/inlineCompletions/browser/suggestWidgetInlineCompletionProvider.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/inlineCompletions/browser/inlineCompletionsController.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/inlineCompletions/browser/commands.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/inlineCompletions/browser/hoverParticipant.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/inlineCompletions/browser/inlineCompletions.contribution.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/suggest/browser/suggestInlineCompletions.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/platform/workspace/common/workspaceTrust.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/contrib/unicodeHighlighter/browser/unicodeHighlighter.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/editor.all.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/standalone/browser/standaloneServices.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/standalone/browser/standaloneCodeEditor.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/standalone/browser/standaloneEditor.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/standalone/browser/standaloneLanguages.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/vscode/out-editor-src/vs/editor/editor.api.ts","out-editor/vs/editor/file:/mnt/vss/_work/1/s/dependencies/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\ninterface ICSSPluginConfig {\n\tdisabled?: boolean;\n}\n\n/**\n * Invoked by the loader at run-time\n *\n * @skipMangle\n */\nexport function load(name: string, req: AMDLoader.IRelativeRequire, load: AMDLoader.IPluginLoadCallback, config: AMDLoader.IConfigurationOptions): void {\n\tconfig = config || {};\n\tconst cssConfig = (config['vs/css'] || {});\n\n\tif (cssConfig.disabled) {\n\t\t// the plugin is asked to not create any style sheets\n\t\tload({});\n\t\treturn;\n\t}\n\n\tconst cssUrl = req.toUrl(name + '.css');\n\tloadCSS(name, cssUrl, () => {\n\t\tload({});\n\t}, (err: any) => {\n\t\tif (typeof load.error === 'function') {\n\t\t\tload.error('Could not find ' + cssUrl + '.');\n\t\t}\n\t});\n}\n\nfunction loadCSS(name: string, cssUrl: string, callback: () => void, errorback: (err: any) => void): void {\n\tif (linkTagExists(name, cssUrl)) {\n\t\tcallback();\n\t\treturn;\n\t}\n\tcreateLinkTag(name, cssUrl, callback, errorback);\n}\n\nfunction linkTagExists(name: string, cssUrl: string): boolean {\n\t// eslint-disable-next-line no-restricted-globals\n\tconst links = window.document.getElementsByTagName('link');\n\tfor (let i = 0, len = links.length; i < len; i++) {\n\t\tconst nameAttr = links[i].getAttribute('data-name');\n\t\tconst hrefAttr = links[i].getAttribute('href');\n\t\tif (nameAttr === name || hrefAttr === cssUrl) {\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\nfunction createLinkTag(name: string, cssUrl: string, callback: () => void, errorback: (err: any) => void): void {\n\tconst linkNode = document.createElement('link');\n\tlinkNode.setAttribute('rel', 'stylesheet');\n\tlinkNode.setAttribute('type', 'text/css');\n\tlinkNode.setAttribute('data-name', name);\n\n\tattachListeners(name, linkNode, callback, errorback);\n\tlinkNode.setAttribute('href', cssUrl);\n\n\t// eslint-disable-next-line no-restricted-globals\n\tconst head = window.document.head || window.document.getElementsByTagName('head')[0];\n\thead.appendChild(linkNode);\n}\n\nfunction attachListeners(name: string, linkNode: HTMLLinkElement, callback: () => void, errorback: (err: any) => void): void {\n\tconst unbind = () => {\n\t\tlinkNode.removeEventListener('load', loadEventListener);\n\t\tlinkNode.removeEventListener('error', errorEventListener);\n\t};\n\tconst loadEventListener = (e: any) => {\n\t\tunbind();\n\t\tcallback();\n\t};\n\tconst errorEventListener = (e: any) => {\n\t\tunbind();\n\t\terrorback(e);\n\t};\n\tlinkNode.addEventListener('load', loadEventListener);\n\tlinkNode.addEventListener('error', errorEventListener);\n}\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\nlet isPseudo = (typeof document !== 'undefined' && document.location && document.location.hash.indexOf('pseudo=true') >= 0);\nconst DEFAULT_TAG = 'i-default';\n\ninterface INLSPluginConfig {\n\tavailableLanguages?: INLSPluginConfigAvailableLanguages;\n\tloadBundle?: BundleLoader;\n\ttranslationServiceUrl?: string;\n}\n\nexport interface INLSPluginConfigAvailableLanguages {\n\t'*'?: string;\n\t[module: string]: string | undefined;\n}\n\ninterface BundleLoader {\n\t(bundle: string, locale: string | null, cb: (err: Error, messages: string[] | IBundledStrings) => void): void;\n}\n\ninterface IBundledStrings {\n\t[moduleId: string]: string[];\n}\n\nexport interface ILocalizeInfo {\n\tkey: string;\n\tcomment: string[];\n}\n\nexport interface ILocalizedString {\n\toriginal: string;\n\tvalue: string;\n}\n\ninterface ILocalizeFunc {\n\t(info: ILocalizeInfo, message: string, ...args: (string | number | boolean | undefined | null)[]): string;\n\t(key: string, message: string, ...args: (string | number | boolean | undefined | null)[]): string;\n}\n\ninterface IBoundLocalizeFunc {\n\t(idx: number, defaultValue: null): string;\n}\n\ninterface ILocalize2Func {\n\t(info: ILocalizeInfo, message: string, ...args: (string | number | boolean | undefined | null)[]): ILocalizedString;\n\t(key: string, message: string, ...args: (string | number | boolean | undefined | null)[]): ILocalizedString;\n}\n\ninterface IBoundLocalize2Func {\n\t(idx: number, defaultValue: string): ILocalizedString;\n}\n\ninterface IConsumerAPI {\n\tlocalize: ILocalizeFunc | IBoundLocalizeFunc;\n\tlocalize2: ILocalize2Func | IBoundLocalize2Func;\n\tgetConfiguredDefaultLocale(stringFromLocalizeCall: string): string | undefined;\n}\n\nfunction _format(message: string, args: (string | number | boolean | undefined | null)[]): string {\n\tlet result: string;\n\n\tif (args.length === 0) {\n\t\tresult = message;\n\t} else {\n\t\tresult = message.replace(/\\{(\\d+)\\}/g, (match, rest) => {\n\t\t\tconst index = rest[0];\n\t\t\tconst arg = args[index];\n\t\t\tlet result = match;\n\t\t\tif (typeof arg === 'string') {\n\t\t\t\tresult = arg;\n\t\t\t} else if (typeof arg === 'number' || typeof arg === 'boolean' || arg === void 0 || arg === null) {\n\t\t\t\tresult = String(arg);\n\t\t\t}\n\t\t\treturn result;\n\t\t});\n\t}\n\n\tif (isPseudo) {\n\t\t// FF3B and FF3D is the Unicode zenkaku representation for [ and ]\n\t\tresult = '\\uFF3B' + result.replace(/[aouei]/g, '$&$&') + '\\uFF3D';\n\t}\n\n\treturn result;\n}\n\nfunction findLanguageForModule(config: INLSPluginConfigAvailableLanguages, name: string) {\n\tlet result = config[name];\n\tif (result) {\n\t\treturn result;\n\t}\n\tresult = config['*'];\n\tif (result) {\n\t\treturn result;\n\t}\n\treturn null;\n}\n\nfunction endWithSlash(path: string): string {\n\tif (path.charAt(path.length - 1) === '/') {\n\t\treturn path;\n\t}\n\treturn path + '/';\n}\n\nasync function getMessagesFromTranslationsService(translationServiceUrl: string, language: string, name: string): Promise {\n\tconst url = endWithSlash(translationServiceUrl) + endWithSlash(language) + 'vscode/' + endWithSlash(name);\n\tconst res = await fetch(url);\n\tif (res.ok) {\n\t\tconst messages = await res.json() as string[] | IBundledStrings;\n\t\treturn messages;\n\t}\n\tthrow new Error(`${res.status} - ${res.statusText}`);\n}\n\nfunction createScopedLocalize(scope: string[]): IBoundLocalizeFunc {\n\treturn function (idx: number, defaultValue: null) {\n\t\tconst restArgs = Array.prototype.slice.call(arguments, 2);\n\t\treturn _format(scope[idx], restArgs);\n\t};\n}\n\nfunction createScopedLocalize2(scope: string[]): IBoundLocalize2Func {\n\treturn (idx: number, defaultValue: string, ...args) => ({\n\t\tvalue: _format(scope[idx], args),\n\t\toriginal: _format(defaultValue, args)\n\t});\n}\n\n/**\n * Marks a string to be localized. Returns the localized string.\n *\n * @param info The {@linkcode ILocalizeInfo} which describes the id and comments associated with the localized string.\n * @param message The string to localize\n * @param args The arguments to the string\n *\n * @note `message` can contain `{n}` notation where it is replaced by the nth value in `...args`\n * @example `localize({ key: 'sayHello', comment: ['Welcomes user'] }, 'hello {0}', name)`\n *\n * @returns string The localized string.\n */\nexport function localize(info: ILocalizeInfo, message: string, ...args: (string | number | boolean | undefined | null)[]): string;\n\n/**\n * Marks a string to be localized. Returns the localized string.\n *\n * @param key The key to use for localizing the string\n * @param message The string to localize\n * @param args The arguments to the string\n *\n * @note `message` can contain `{n}` notation where it is replaced by the nth value in `...args`\n * @example For example, `localize('sayHello', 'hello {0}', name)`\n *\n * @returns string The localized string.\n */\nexport function localize(key: string, message: string, ...args: (string | number | boolean | undefined | null)[]): string;\n\n/**\n * @skipMangle\n */\nexport function localize(data: ILocalizeInfo | string, message: string, ...args: (string | number | boolean | undefined | null)[]): string {\n\treturn _format(message, args);\n}\n\n/**\n * Marks a string to be localized. Returns an {@linkcode ILocalizedString}\n * which contains the localized string and the original string.\n *\n * @param info The {@linkcode ILocalizeInfo} which describes the id and comments associated with the localized string.\n * @param message The string to localize\n * @param args The arguments to the string\n *\n * @note `message` can contain `{n}` notation where it is replaced by the nth value in `...args`\n * @example `localize2({ key: 'sayHello', comment: ['Welcomes user'] }, 'hello {0}', name)`\n *\n * @returns ILocalizedString which contains the localized string and the original string.\n */\nexport function localize2(info: ILocalizeInfo, message: string, ...args: (string | number | boolean | undefined | null)[]): ILocalizedString;\n\n/**\n * Marks a string to be localized. Returns an {@linkcode ILocalizedString}\n * which contains the localized string and the original string.\n *\n * @param key The key to use for localizing the string\n * @param message The string to localize\n * @param args The arguments to the string\n *\n * @note `message` can contain `{n}` notation where it is replaced by the nth value in `...args`\n * @example `localize('sayHello', 'hello {0}', name)`\n *\n * @returns ILocalizedString which contains the localized string and the original string.\n */\nexport function localize2(key: string, message: string, ...args: (string | number | boolean | undefined | null)[]): ILocalizedString;\n\n/**\n * @skipMangle\n */\nexport function localize2(data: ILocalizeInfo | string, message: string, ...args: (string | number | boolean | undefined | null)[]): ILocalizedString {\n\tconst original = _format(message, args);\n\treturn {\n\t\tvalue: original,\n\t\toriginal\n\t};\n}\n\n/**\n *\n * @param stringFromLocalizeCall You must pass in a string that was returned from a `nls.localize()` call\n * in order to ensure the loader plugin has been initialized before this function is called.\n */\nexport function getConfiguredDefaultLocale(stringFromLocalizeCall: string): string | undefined;\n/**\n * @skipMangle\n */\nexport function getConfiguredDefaultLocale(_: string): string | undefined {\n\t// This returns undefined because this implementation isn't used and is overwritten by the loader\n\t// when loaded.\n\treturn undefined;\n}\n\n/**\n * @skipMangle\n */\nexport function setPseudoTranslation(value: boolean) {\n\tisPseudo = value;\n}\n\n/**\n * Invoked in a built product at run-time\n * @skipMangle\n */\nexport function create(key: string, data: IBundledStrings & IConsumerAPI): IConsumerAPI {\n\treturn {\n\t\tlocalize: createScopedLocalize(data[key]),\n\t\tlocalize2: createScopedLocalize2(data[key]),\n\t\tgetConfiguredDefaultLocale: data.getConfiguredDefaultLocale ?? ((_: string) => undefined)\n\t};\n}\n\n/**\n * Invoked by the loader at run-time\n * @skipMangle\n */\nexport function load(name: string, req: AMDLoader.IRelativeRequire, load: AMDLoader.IPluginLoadCallback, config: AMDLoader.IConfigurationOptions): void {\n\tconst pluginConfig: INLSPluginConfig = config['vs/nls'] ?? {};\n\tif (!name || name.length === 0) {\n\t\t// TODO: We need to give back the mangled names here\n\t\treturn load({\n\t\t\tlocalize: localize,\n\t\t\tlocalize2: localize2,\n\t\t\tgetConfiguredDefaultLocale: () => pluginConfig.availableLanguages?.['*']\n\t\t} as IConsumerAPI);\n\t}\n\tconst language = pluginConfig.availableLanguages ? findLanguageForModule(pluginConfig.availableLanguages, name) : null;\n\tconst useDefaultLanguage = language === null || language === DEFAULT_TAG;\n\tlet suffix = '.nls';\n\tif (!useDefaultLanguage) {\n\t\tsuffix = suffix + '.' + language;\n\t}\n\tconst messagesLoaded = (messages: string[] | IBundledStrings) => {\n\t\tif (Array.isArray(messages)) {\n\t\t\t(messages as any as IConsumerAPI).localize = createScopedLocalize(messages);\n\t\t\t(messages as any as IConsumerAPI).localize2 = createScopedLocalize2(messages);\n\t\t} else {\n\t\t\t(messages as any as IConsumerAPI).localize = createScopedLocalize(messages[name]);\n\t\t\t(messages as any as IConsumerAPI).localize2 = createScopedLocalize2(messages[name]);\n\t\t}\n\t\t(messages as any as IConsumerAPI).getConfiguredDefaultLocale = () => pluginConfig.availableLanguages?.['*'];\n\t\tload(messages);\n\t};\n\tif (typeof pluginConfig.loadBundle === 'function') {\n\t\t(pluginConfig.loadBundle as BundleLoader)(name, language, (err: Error, messages) => {\n\t\t\t// We have an error. Load the English default strings to not fail\n\t\t\tif (err) {\n\t\t\t\treq([name + '.nls'], messagesLoaded);\n\t\t\t} else {\n\t\t\t\tmessagesLoaded(messages);\n\t\t\t}\n\t\t});\n\t} else if (pluginConfig.translationServiceUrl && !useDefaultLanguage) {\n\t\t(async () => {\n\t\t\ttry {\n\t\t\t\tconst messages = await getMessagesFromTranslationsService(pluginConfig.translationServiceUrl!, language, name);\n\t\t\t\treturn messagesLoaded(messages);\n\t\t\t} catch (err) {\n\t\t\t\t// Language is already as generic as it gets, so require default messages\n\t\t\t\tif (!language.includes('-')) {\n\t\t\t\t\tconsole.error(err);\n\t\t\t\t\treturn req([name + '.nls'], messagesLoaded);\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\t// Since there is a dash, the language configured is a specific sub-language of the same generic language.\n\t\t\t\t\t// Since we were unable to load the specific language, try to load the generic language. Ex. we failed to find a\n\t\t\t\t\t// Swiss German (de-CH), so try to load the generic German (de) messages instead.\n\t\t\t\t\tconst genericLanguage = language.split('-')[0];\n\t\t\t\t\tconst messages = await getMessagesFromTranslationsService(pluginConfig.translationServiceUrl!, genericLanguage, name);\n\t\t\t\t\t// We got some messages, so we configure the configuration to use the generic language for this session.\n\t\t\t\t\tpluginConfig.availableLanguages ??= {};\n\t\t\t\t\tpluginConfig.availableLanguages['*'] = genericLanguage;\n\t\t\t\t\treturn messagesLoaded(messages);\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconsole.error(err);\n\t\t\t\t\treturn req([name + '.nls'], messagesLoaded);\n\t\t\t\t}\n\t\t\t}\n\t\t})();\n\t} else {\n\t\treq([name + suffix], messagesLoaded, (err: Error) => {\n\t\t\tif (suffix === '.nls') {\n\t\t\t\tconsole.error('Failed trying to load default language strings', err);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconsole.error(`Failed to load message bundle for language ${language}. Falling back to the default language:`, err);\n\t\t\treq([name + '.nls'], messagesLoaded);\n\t\t});\n\t}\n}\n","/*! @license DOMPurify 3.0.5 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.0.5/LICENSE */\n\nconst {\n\tentries,\n\tsetPrototypeOf,\n\tisFrozen,\n\tgetPrototypeOf,\n\tgetOwnPropertyDescriptor\n} = Object;\nlet {\n\tfreeze,\n\tseal,\n\tcreate\n} = Object; // eslint-disable-line import/no-mutable-exports\n\nlet {\n\tapply,\n\tconstruct\n} = typeof Reflect !== 'undefined' && Reflect;\n\nif (!apply) {\n\tapply = function apply(fun, thisValue, args) {\n\t\treturn fun.apply(thisValue, args);\n\t};\n}\n\nif (!freeze) {\n\tfreeze = function freeze(x) {\n\t\treturn x;\n\t};\n}\n\nif (!seal) {\n\tseal = function seal(x) {\n\t\treturn x;\n\t};\n}\n\nif (!construct) {\n\tconstruct = function construct(Func, args) {\n\t\treturn new Func(...args);\n\t};\n}\n\nconst arrayForEach = unapply(Array.prototype.forEach);\nconst arrayPop = unapply(Array.prototype.pop);\nconst arrayPush = unapply(Array.prototype.push);\nconst stringToLowerCase = unapply(String.prototype.toLowerCase);\nconst stringToString = unapply(String.prototype.toString);\nconst stringMatch = unapply(String.prototype.match);\nconst stringReplace = unapply(String.prototype.replace);\nconst stringIndexOf = unapply(String.prototype.indexOf);\nconst stringTrim = unapply(String.prototype.trim);\nconst regExpTest = unapply(RegExp.prototype.test);\nconst typeErrorCreate = unconstruct(TypeError);\nfunction unapply(func) {\n\treturn function (thisArg) {\n\t\tfor (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {\n\t\t\targs[_key - 1] = arguments[_key];\n\t\t}\n\n\t\treturn apply(func, thisArg, args);\n\t};\n}\nfunction unconstruct(func) {\n\treturn function () {\n\t\tfor (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {\n\t\t\targs[_key2] = arguments[_key2];\n\t\t}\n\n\t\treturn construct(func, args);\n\t};\n}\n/* Add properties to a lookup table */\n\nfunction addToSet(set, array, transformCaseFunc) {\n\tvar _transformCaseFunc;\n\n\ttransformCaseFunc = (_transformCaseFunc = transformCaseFunc) !== null && _transformCaseFunc !== void 0 ? _transformCaseFunc : stringToLowerCase;\n\n\tif (setPrototypeOf) {\n\t\t// Make 'in' and truthy checks like Boolean(set.constructor)\n\t\t// independent of any properties defined on Object.prototype.\n\t\t// Prevent prototype setters from intercepting set as a this value.\n\t\tsetPrototypeOf(set, null);\n\t}\n\n\tlet l = array.length;\n\n\twhile (l--) {\n\t\tlet element = array[l];\n\n\t\tif (typeof element === 'string') {\n\t\t\tconst lcElement = transformCaseFunc(element);\n\n\t\t\tif (lcElement !== element) {\n\t\t\t\t// Config presets (e.g. tags.js, attrs.js) are immutable.\n\t\t\t\tif (!isFrozen(array)) {\n\t\t\t\t\tarray[l] = lcElement;\n\t\t\t\t}\n\n\t\t\t\telement = lcElement;\n\t\t\t}\n\t\t}\n\n\t\tset[element] = true;\n\t}\n\n\treturn set;\n}\n/* Shallow clone an object */\n\nfunction clone(object) {\n\tconst newObject = create(null);\n\n\tfor (const [property, value] of entries(object)) {\n\t\tnewObject[property] = value;\n\t}\n\n\treturn newObject;\n}\n/* This method automatically checks if the prop is function\n * or getter and behaves accordingly. */\n\nfunction lookupGetter(object, prop) {\n\twhile (object !== null) {\n\t\tconst desc = getOwnPropertyDescriptor(object, prop);\n\n\t\tif (desc) {\n\t\t\tif (desc.get) {\n\t\t\t\treturn unapply(desc.get);\n\t\t\t}\n\n\t\t\tif (typeof desc.value === 'function') {\n\t\t\t\treturn unapply(desc.value);\n\t\t\t}\n\t\t}\n\n\t\tobject = getPrototypeOf(object);\n\t}\n\n\tfunction fallbackValue(element) {\n\t\tconsole.warn('fallback value for', element);\n\t\treturn null;\n\t}\n\n\treturn fallbackValue;\n}\n\nconst html$1 = freeze(['a', 'abbr', 'acronym', 'address', 'area', 'article', 'aside', 'audio', 'b', 'bdi', 'bdo', 'big', 'blink', 'blockquote', 'body', 'br', 'button', 'canvas', 'caption', 'center', 'cite', 'code', 'col', 'colgroup', 'content', 'data', 'datalist', 'dd', 'decorator', 'del', 'details', 'dfn', 'dialog', 'dir', 'div', 'dl', 'dt', 'element', 'em', 'fieldset', 'figcaption', 'figure', 'font', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'head', 'header', 'hgroup', 'hr', 'html', 'i', 'img', 'input', 'ins', 'kbd', 'label', 'legend', 'li', 'main', 'map', 'mark', 'marquee', 'menu', 'menuitem', 'meter', 'nav', 'nobr', 'ol', 'optgroup', 'option', 'output', 'p', 'picture', 'pre', 'progress', 'q', 'rp', 'rt', 'ruby', 's', 'samp', 'section', 'select', 'shadow', 'small', 'source', 'spacer', 'span', 'strike', 'strong', 'style', 'sub', 'summary', 'sup', 'table', 'tbody', 'td', 'template', 'textarea', 'tfoot', 'th', 'thead', 'time', 'tr', 'track', 'tt', 'u', 'ul', 'var', 'video', 'wbr']); // SVG\n\nconst svg$1 = freeze(['svg', 'a', 'altglyph', 'altglyphdef', 'altglyphitem', 'animatecolor', 'animatemotion', 'animatetransform', 'circle', 'clippath', 'defs', 'desc', 'ellipse', 'filter', 'font', 'g', 'glyph', 'glyphref', 'hkern', 'image', 'line', 'lineargradient', 'marker', 'mask', 'metadata', 'mpath', 'path', 'pattern', 'polygon', 'polyline', 'radialgradient', 'rect', 'stop', 'style', 'switch', 'symbol', 'text', 'textpath', 'title', 'tref', 'tspan', 'view', 'vkern']);\nconst svgFilters = freeze(['feBlend', 'feColorMatrix', 'feComponentTransfer', 'feComposite', 'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap', 'feDistantLight', 'feDropShadow', 'feFlood', 'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR', 'feGaussianBlur', 'feImage', 'feMerge', 'feMergeNode', 'feMorphology', 'feOffset', 'fePointLight', 'feSpecularLighting', 'feSpotLight', 'feTile', 'feTurbulence']); // List of SVG elements that are disallowed by default.\n// We still need to know them so that we can do namespace\n// checks properly in case one wants to add them to\n// allow-list.\n\nconst svgDisallowed = freeze(['animate', 'color-profile', 'cursor', 'discard', 'font-face', 'font-face-format', 'font-face-name', 'font-face-src', 'font-face-uri', 'foreignobject', 'hatch', 'hatchpath', 'mesh', 'meshgradient', 'meshpatch', 'meshrow', 'missing-glyph', 'script', 'set', 'solidcolor', 'unknown', 'use']);\nconst mathMl$1 = freeze(['math', 'menclose', 'merror', 'mfenced', 'mfrac', 'mglyph', 'mi', 'mlabeledtr', 'mmultiscripts', 'mn', 'mo', 'mover', 'mpadded', 'mphantom', 'mroot', 'mrow', 'ms', 'mspace', 'msqrt', 'mstyle', 'msub', 'msup', 'msubsup', 'mtable', 'mtd', 'mtext', 'mtr', 'munder', 'munderover', 'mprescripts']); // Similarly to SVG, we want to know all MathML elements,\n// even those that we disallow by default.\n\nconst mathMlDisallowed = freeze(['maction', 'maligngroup', 'malignmark', 'mlongdiv', 'mscarries', 'mscarry', 'msgroup', 'mstack', 'msline', 'msrow', 'semantics', 'annotation', 'annotation-xml', 'mprescripts', 'none']);\nconst text = freeze(['#text']);\n\nconst html = freeze(['accept', 'action', 'align', 'alt', 'autocapitalize', 'autocomplete', 'autopictureinpicture', 'autoplay', 'background', 'bgcolor', 'border', 'capture', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'controls', 'controlslist', 'coords', 'crossorigin', 'datetime', 'decoding', 'default', 'dir', 'disabled', 'disablepictureinpicture', 'disableremoteplayback', 'download', 'draggable', 'enctype', 'enterkeyhint', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', 'inputmode', 'integrity', 'ismap', 'kind', 'label', 'lang', 'list', 'loading', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'minlength', 'multiple', 'muted', 'name', 'nonce', 'noshade', 'novalidate', 'nowrap', 'open', 'optimum', 'pattern', 'placeholder', 'playsinline', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'rev', 'reversed', 'role', 'rows', 'rowspan', 'spellcheck', 'scope', 'selected', 'shape', 'size', 'sizes', 'span', 'srclang', 'start', 'src', 'srcset', 'step', 'style', 'summary', 'tabindex', 'title', 'translate', 'type', 'usemap', 'valign', 'value', 'width', 'xmlns', 'slot']);\nconst svg = freeze(['accent-height', 'accumulate', 'additive', 'alignment-baseline', 'ascent', 'attributename', 'attributetype', 'azimuth', 'basefrequency', 'baseline-shift', 'begin', 'bias', 'by', 'class', 'clip', 'clippathunits', 'clip-path', 'clip-rule', 'color', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'cx', 'cy', 'd', 'dx', 'dy', 'diffuseconstant', 'direction', 'display', 'divisor', 'dur', 'edgemode', 'elevation', 'end', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'filterunits', 'flood-color', 'flood-opacity', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'fx', 'fy', 'g1', 'g2', 'glyph-name', 'glyphref', 'gradientunits', 'gradienttransform', 'height', 'href', 'id', 'image-rendering', 'in', 'in2', 'k', 'k1', 'k2', 'k3', 'k4', 'kerning', 'keypoints', 'keysplines', 'keytimes', 'lang', 'lengthadjust', 'letter-spacing', 'kernelmatrix', 'kernelunitlength', 'lighting-color', 'local', 'marker-end', 'marker-mid', 'marker-start', 'markerheight', 'markerunits', 'markerwidth', 'maskcontentunits', 'maskunits', 'max', 'mask', 'media', 'method', 'mode', 'min', 'name', 'numoctaves', 'offset', 'operator', 'opacity', 'order', 'orient', 'orientation', 'origin', 'overflow', 'paint-order', 'path', 'pathlength', 'patterncontentunits', 'patterntransform', 'patternunits', 'points', 'preservealpha', 'preserveaspectratio', 'primitiveunits', 'r', 'rx', 'ry', 'radius', 'refx', 'refy', 'repeatcount', 'repeatdur', 'restart', 'result', 'rotate', 'scale', 'seed', 'shape-rendering', 'specularconstant', 'specularexponent', 'spreadmethod', 'startoffset', 'stddeviation', 'stitchtiles', 'stop-color', 'stop-opacity', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke', 'stroke-width', 'style', 'surfacescale', 'systemlanguage', 'tabindex', 'targetx', 'targety', 'transform', 'transform-origin', 'text-anchor', 'text-decoration', 'text-rendering', 'textlength', 'type', 'u1', 'u2', 'unicode', 'values', 'viewbox', 'visibility', 'version', 'vert-adv-y', 'vert-origin-x', 'vert-origin-y', 'width', 'word-spacing', 'wrap', 'writing-mode', 'xchannelselector', 'ychannelselector', 'x', 'x1', 'x2', 'xmlns', 'y', 'y1', 'y2', 'z', 'zoomandpan']);\nconst mathMl = freeze(['accent', 'accentunder', 'align', 'bevelled', 'close', 'columnsalign', 'columnlines', 'columnspan', 'denomalign', 'depth', 'dir', 'display', 'displaystyle', 'encoding', 'fence', 'frame', 'height', 'href', 'id', 'largeop', 'length', 'linethickness', 'lspace', 'lquote', 'mathbackground', 'mathcolor', 'mathsize', 'mathvariant', 'maxsize', 'minsize', 'movablelimits', 'notation', 'numalign', 'open', 'rowalign', 'rowlines', 'rowspacing', 'rowspan', 'rspace', 'rquote', 'scriptlevel', 'scriptminsize', 'scriptsizemultiplier', 'selection', 'separator', 'separators', 'stretchy', 'subscriptshift', 'supscriptshift', 'symmetric', 'voffset', 'width', 'xmlns']);\nconst xml = freeze(['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:xlink']);\n\nconst MUSTACHE_EXPR = seal(/\\{\\{[\\w\\W]*|[\\w\\W]*\\}\\}/gm); // Specify template detection regex for SAFE_FOR_TEMPLATES mode\n\nconst ERB_EXPR = seal(/<%[\\w\\W]*|[\\w\\W]*%>/gm);\nconst TMPLIT_EXPR = seal(/\\${[\\w\\W]*}/gm);\nconst DATA_ATTR = seal(/^data-[\\-\\w.\\u00B7-\\uFFFF]/); // eslint-disable-line no-useless-escape\n\nconst ARIA_ATTR = seal(/^aria-[\\-\\w]+$/); // eslint-disable-line no-useless-escape\n\nconst IS_ALLOWED_URI = seal(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.\\-]+(?:[^a-z+.\\-:]|$))/i // eslint-disable-line no-useless-escape\n);\nconst IS_SCRIPT_OR_DATA = seal(/^(?:\\w+script|data):/i);\nconst ATTR_WHITESPACE = seal(/[\\u0000-\\u0020\\u00A0\\u1680\\u180E\\u2000-\\u2029\\u205F\\u3000]/g // eslint-disable-line no-control-regex\n);\nconst DOCTYPE_NAME = seal(/^html$/i);\n\nvar EXPRESSIONS = /*#__PURE__*/Object.freeze({\n\t__proto__: null,\n\tMUSTACHE_EXPR: MUSTACHE_EXPR,\n\tERB_EXPR: ERB_EXPR,\n\tTMPLIT_EXPR: TMPLIT_EXPR,\n\tDATA_ATTR: DATA_ATTR,\n\tARIA_ATTR: ARIA_ATTR,\n\tIS_ALLOWED_URI: IS_ALLOWED_URI,\n\tIS_SCRIPT_OR_DATA: IS_SCRIPT_OR_DATA,\n\tATTR_WHITESPACE: ATTR_WHITESPACE,\n\tDOCTYPE_NAME: DOCTYPE_NAME\n});\n\nconst getGlobal = () => typeof window === 'undefined' ? null : window;\n/**\n * Creates a no-op policy for internal use only.\n * Don't export this function outside this module!\n * @param {?TrustedTypePolicyFactory} trustedTypes The policy factory.\n * @param {HTMLScriptElement} purifyHostElement The Script element used to load DOMPurify (to determine policy name suffix).\n * @return {?TrustedTypePolicy} The policy created (or null, if Trusted Types\n * are not supported or creating the policy failed).\n */\n\n\nconst _createTrustedTypesPolicy = function _createTrustedTypesPolicy(trustedTypes, purifyHostElement) {\n\tif (typeof trustedTypes !== 'object' || typeof trustedTypes.createPolicy !== 'function') {\n\t\treturn null;\n\t} // Allow the callers to control the unique policy name\n\t// by adding a data-tt-policy-suffix to the script element with the DOMPurify.\n\t// Policy creation with duplicate names throws in Trusted Types.\n\n\n\tlet suffix = null;\n\tconst ATTR_NAME = 'data-tt-policy-suffix';\n\n\tif (purifyHostElement && purifyHostElement.hasAttribute(ATTR_NAME)) {\n\t\tsuffix = purifyHostElement.getAttribute(ATTR_NAME);\n\t}\n\n\tconst policyName = 'dompurify' + (suffix ? '#' + suffix : '');\n\n\ttry {\n\t\treturn trustedTypes.createPolicy(policyName, {\n\t\t\tcreateHTML(html) {\n\t\t\t\treturn html;\n\t\t\t},\n\n\t\t\tcreateScriptURL(scriptUrl) {\n\t\t\t\treturn scriptUrl;\n\t\t\t}\n\n\t\t});\n\t} catch (_) {\n\t\t// Policy creation failed (most likely another DOMPurify script has\n\t\t// already run). Skip creating the policy, as this will only cause errors\n\t\t// if TT are enforced.\n\t\tconsole.warn('TrustedTypes policy ' + policyName + ' could not be created.');\n\t\treturn null;\n\t}\n};\n\nfunction createDOMPurify() {\n\tlet window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal();\n\n\tconst DOMPurify = root => createDOMPurify(root);\n\t/**\n\t * Version label, exposed for easier checks\n\t * if DOMPurify is up to date or not\n\t */\n\n\n\tDOMPurify.version = '3.0.5';\n\t/**\n\t * Array of elements that DOMPurify removed during sanitation.\n\t * Empty if nothing was removed.\n\t */\n\n\tDOMPurify.removed = [];\n\n\tif (!window || !window.document || window.document.nodeType !== 9) {\n\t\t// Not running in a browser, provide a factory function\n\t\t// so that you can pass your own Window\n\t\tDOMPurify.isSupported = false;\n\t\treturn DOMPurify;\n\t}\n\n\tconst originalDocument = window.document;\n\tconst currentScript = originalDocument.currentScript;\n\tlet {\n\t\tdocument\n\t} = window;\n\tconst {\n\t\tDocumentFragment,\n\t\tHTMLTemplateElement,\n\t\tNode,\n\t\tElement,\n\t\tNodeFilter,\n\t\tNamedNodeMap = window.NamedNodeMap || window.MozNamedAttrMap,\n\t\tHTMLFormElement,\n\t\tDOMParser,\n\t\ttrustedTypes\n\t} = window;\n\tconst ElementPrototype = Element.prototype;\n\tconst cloneNode = lookupGetter(ElementPrototype, 'cloneNode');\n\tconst getNextSibling = lookupGetter(ElementPrototype, 'nextSibling');\n\tconst getChildNodes = lookupGetter(ElementPrototype, 'childNodes');\n\tconst getParentNode = lookupGetter(ElementPrototype, 'parentNode'); // As per issue #47, the web-components registry is inherited by a\n\t// new document created via createHTMLDocument. As per the spec\n\t// (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries)\n\t// a new empty registry is used when creating a template contents owner\n\t// document, so we use that as our parent document to ensure nothing\n\t// is inherited.\n\n\tif (typeof HTMLTemplateElement === 'function') {\n\t\tconst template = document.createElement('template');\n\n\t\tif (template.content && template.content.ownerDocument) {\n\t\t\tdocument = template.content.ownerDocument;\n\t\t}\n\t}\n\n\tlet trustedTypesPolicy;\n\tlet emptyHTML = '';\n\tconst {\n\t\timplementation,\n\t\tcreateNodeIterator,\n\t\tcreateDocumentFragment,\n\t\tgetElementsByTagName\n\t} = document;\n\tconst {\n\t\timportNode\n\t} = originalDocument;\n\tlet hooks = {};\n\t/**\n\t * Expose whether this browser supports running the full DOMPurify.\n\t */\n\n\tDOMPurify.isSupported = typeof entries === 'function' && typeof getParentNode === 'function' && implementation && implementation.createHTMLDocument !== undefined;\n\tconst {\n\t\tMUSTACHE_EXPR,\n\t\tERB_EXPR,\n\t\tTMPLIT_EXPR,\n\t\tDATA_ATTR,\n\t\tARIA_ATTR,\n\t\tIS_SCRIPT_OR_DATA,\n\t\tATTR_WHITESPACE\n\t} = EXPRESSIONS;\n\tlet {\n\t\tIS_ALLOWED_URI: IS_ALLOWED_URI$1\n\t} = EXPRESSIONS;\n\t/**\n\t * We consider the elements and attributes below to be safe. Ideally\n\t * don't add any new ones but feel free to remove unwanted ones.\n\t */\n\n\t/* allowed element names */\n\n\tlet ALLOWED_TAGS = null;\n\tconst DEFAULT_ALLOWED_TAGS = addToSet({}, [...html$1, ...svg$1, ...svgFilters, ...mathMl$1, ...text]);\n\t/* Allowed attribute names */\n\n\tlet ALLOWED_ATTR = null;\n\tconst DEFAULT_ALLOWED_ATTR = addToSet({}, [...html, ...svg, ...mathMl, ...xml]);\n\t/*\n\t * Configure how DOMPUrify should handle custom elements and their attributes as well as customized built-in elements.\n\t * @property {RegExp|Function|null} tagNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any custom elements)\n\t * @property {RegExp|Function|null} attributeNameCheck one of [null, regexPattern, predicate]. Default: `null` (disallow any attributes not on the allow list)\n\t * @property {boolean} allowCustomizedBuiltInElements allow custom elements derived from built-ins if they pass CUSTOM_ELEMENT_HANDLING.tagNameCheck. Default: `false`.\n\t */\n\n\tlet CUSTOM_ELEMENT_HANDLING = Object.seal(Object.create(null, {\n\t\ttagNameCheck: {\n\t\t\twritable: true,\n\t\t\tconfigurable: false,\n\t\t\tenumerable: true,\n\t\t\tvalue: null\n\t\t},\n\t\tattributeNameCheck: {\n\t\t\twritable: true,\n\t\t\tconfigurable: false,\n\t\t\tenumerable: true,\n\t\t\tvalue: null\n\t\t},\n\t\tallowCustomizedBuiltInElements: {\n\t\t\twritable: true,\n\t\t\tconfigurable: false,\n\t\t\tenumerable: true,\n\t\t\tvalue: false\n\t\t}\n\t}));\n\t/* Explicitly forbidden tags (overrides ALLOWED_TAGS/ADD_TAGS) */\n\n\tlet FORBID_TAGS = null;\n\t/* Explicitly forbidden attributes (overrides ALLOWED_ATTR/ADD_ATTR) */\n\n\tlet FORBID_ATTR = null;\n\t/* Decide if ARIA attributes are okay */\n\n\tlet ALLOW_ARIA_ATTR = true;\n\t/* Decide if custom data attributes are okay */\n\n\tlet ALLOW_DATA_ATTR = true;\n\t/* Decide if unknown protocols are okay */\n\n\tlet ALLOW_UNKNOWN_PROTOCOLS = false;\n\t/* Decide if self-closing tags in attributes are allowed.\n\t * Usually removed due to a mXSS issue in jQuery 3.0 */\n\n\tlet ALLOW_SELF_CLOSE_IN_ATTR = true;\n\t/* Output should be safe for common template engines.\n\t * This means, DOMPurify removes data attributes, mustaches and ERB\n\t */\n\n\tlet SAFE_FOR_TEMPLATES = false;\n\t/* Decide if document with ... should be returned */\n\n\tlet WHOLE_DOCUMENT = false;\n\t/* Track whether config is already set on this instance of DOMPurify. */\n\n\tlet SET_CONFIG = false;\n\t/* Decide if all elements (e.g. style, script) must be children of\n\t * document.body. By default, browsers might move them to document.head */\n\n\tlet FORCE_BODY = false;\n\t/* Decide if a DOM `HTMLBodyElement` should be returned, instead of a html\n\t * string (or a TrustedHTML object if Trusted Types are supported).\n\t * If `WHOLE_DOCUMENT` is enabled a `HTMLHtmlElement` will be returned instead\n\t */\n\n\tlet RETURN_DOM = false;\n\t/* Decide if a DOM `DocumentFragment` should be returned, instead of a html\n\t * string (or a TrustedHTML object if Trusted Types are supported) */\n\n\tlet RETURN_DOM_FRAGMENT = false;\n\t/* Try to return a Trusted Type object instead of a string, return a string in\n\t * case Trusted Types are not supported */\n\n\tlet RETURN_TRUSTED_TYPE = false;\n\t/* Output should be free from DOM clobbering attacks?\n\t * This sanitizes markups named with colliding, clobberable built-in DOM APIs.\n\t */\n\n\tlet SANITIZE_DOM = true;\n\t/* Achieve full DOM Clobbering protection by isolating the namespace of named\n\t * properties and JS variables, mitigating attacks that abuse the HTML/DOM spec rules.\n\t *\n\t * HTML/DOM spec rules that enable DOM Clobbering:\n\t * - Named Access on Window (§7.3.3)\n\t * - DOM Tree Accessors (§3.1.5)\n\t * - Form Element Parent-Child Relations (§4.10.3)\n\t * - Iframe srcdoc / Nested WindowProxies (§4.8.5)\n\t * - HTMLCollection (§4.2.10.2)\n\t *\n\t * Namespace isolation is implemented by prefixing `id` and `name` attributes\n\t * with a constant string, i.e., `user-content-`\n\t */\n\n\tlet SANITIZE_NAMED_PROPS = false;\n\tconst SANITIZE_NAMED_PROPS_PREFIX = 'user-content-';\n\t/* Keep element content when removing element? */\n\n\tlet KEEP_CONTENT = true;\n\t/* If a `Node` is passed to sanitize(), then performs sanitization in-place instead\n\t * of importing it into a new Document and returning a sanitized copy */\n\n\tlet IN_PLACE = false;\n\t/* Allow usage of profiles like html, svg and mathMl */\n\n\tlet USE_PROFILES = {};\n\t/* Tags to ignore content of when KEEP_CONTENT is true */\n\n\tlet FORBID_CONTENTS = null;\n\tconst DEFAULT_FORBID_CONTENTS = addToSet({}, ['annotation-xml', 'audio', 'colgroup', 'desc', 'foreignobject', 'head', 'iframe', 'math', 'mi', 'mn', 'mo', 'ms', 'mtext', 'noembed', 'noframes', 'noscript', 'plaintext', 'script', 'style', 'svg', 'template', 'thead', 'title', 'video', 'xmp']);\n\t/* Tags that are safe for data: URIs */\n\n\tlet DATA_URI_TAGS = null;\n\tconst DEFAULT_DATA_URI_TAGS = addToSet({}, ['audio', 'video', 'img', 'source', 'image', 'track']);\n\t/* Attributes safe for values like \"javascript:\" */\n\n\tlet URI_SAFE_ATTRIBUTES = null;\n\tconst DEFAULT_URI_SAFE_ATTRIBUTES = addToSet({}, ['alt', 'class', 'for', 'id', 'label', 'name', 'pattern', 'placeholder', 'role', 'summary', 'title', 'value', 'style', 'xmlns']);\n\tconst MATHML_NAMESPACE = 'http://www.w3.org/1998/Math/MathML';\n\tconst SVG_NAMESPACE = 'http://www.w3.org/2000/svg';\n\tconst HTML_NAMESPACE = 'http://www.w3.org/1999/xhtml';\n\t/* Document namespace */\n\n\tlet NAMESPACE = HTML_NAMESPACE;\n\tlet IS_EMPTY_INPUT = false;\n\t/* Allowed XHTML+XML namespaces */\n\n\tlet ALLOWED_NAMESPACES = null;\n\tconst DEFAULT_ALLOWED_NAMESPACES = addToSet({}, [MATHML_NAMESPACE, SVG_NAMESPACE, HTML_NAMESPACE], stringToString);\n\t/* Parsing of strict XHTML documents */\n\n\tlet PARSER_MEDIA_TYPE;\n\tconst SUPPORTED_PARSER_MEDIA_TYPES = ['application/xhtml+xml', 'text/html'];\n\tconst DEFAULT_PARSER_MEDIA_TYPE = 'text/html';\n\tlet transformCaseFunc;\n\t/* Keep a reference to config to pass to hooks */\n\n\tlet CONFIG = null;\n\t/* Ideally, do not touch anything below this line */\n\n\t/* ______________________________________________ */\n\n\tconst formElement = document.createElement('form');\n\n\tconst isRegexOrFunction = function isRegexOrFunction(testValue) {\n\t\treturn testValue instanceof RegExp || testValue instanceof Function;\n\t};\n\t/**\n\t * _parseConfig\n\t *\n\t * @param {Object} cfg optional config literal\n\t */\n\t// eslint-disable-next-line complexity\n\n\n\tconst _parseConfig = function _parseConfig(cfg) {\n\t\tif (CONFIG && CONFIG === cfg) {\n\t\t\treturn;\n\t\t}\n\t\t/* Shield configuration object from tampering */\n\n\n\t\tif (!cfg || typeof cfg !== 'object') {\n\t\t\tcfg = {};\n\t\t}\n\t\t/* Shield configuration object from prototype pollution */\n\n\n\t\tcfg = clone(cfg);\n\t\tPARSER_MEDIA_TYPE = // eslint-disable-next-line unicorn/prefer-includes\n\t\t\tSUPPORTED_PARSER_MEDIA_TYPES.indexOf(cfg.PARSER_MEDIA_TYPE) === -1 ? PARSER_MEDIA_TYPE = DEFAULT_PARSER_MEDIA_TYPE : PARSER_MEDIA_TYPE = cfg.PARSER_MEDIA_TYPE; // HTML tags and attributes are not case-sensitive, converting to lowercase. Keeping XHTML as is.\n\n\t\ttransformCaseFunc = PARSER_MEDIA_TYPE === 'application/xhtml+xml' ? stringToString : stringToLowerCase;\n\t\t/* Set configuration parameters */\n\n\t\tALLOWED_TAGS = 'ALLOWED_TAGS' in cfg ? addToSet({}, cfg.ALLOWED_TAGS, transformCaseFunc) : DEFAULT_ALLOWED_TAGS;\n\t\tALLOWED_ATTR = 'ALLOWED_ATTR' in cfg ? addToSet({}, cfg.ALLOWED_ATTR, transformCaseFunc) : DEFAULT_ALLOWED_ATTR;\n\t\tALLOWED_NAMESPACES = 'ALLOWED_NAMESPACES' in cfg ? addToSet({}, cfg.ALLOWED_NAMESPACES, stringToString) : DEFAULT_ALLOWED_NAMESPACES;\n\t\tURI_SAFE_ATTRIBUTES = 'ADD_URI_SAFE_ATTR' in cfg ? addToSet(clone(DEFAULT_URI_SAFE_ATTRIBUTES), // eslint-disable-line indent\n\t\t\tcfg.ADD_URI_SAFE_ATTR, // eslint-disable-line indent\n\t\t\ttransformCaseFunc // eslint-disable-line indent\n\t\t) // eslint-disable-line indent\n\t\t\t: DEFAULT_URI_SAFE_ATTRIBUTES;\n\t\tDATA_URI_TAGS = 'ADD_DATA_URI_TAGS' in cfg ? addToSet(clone(DEFAULT_DATA_URI_TAGS), // eslint-disable-line indent\n\t\t\tcfg.ADD_DATA_URI_TAGS, // eslint-disable-line indent\n\t\t\ttransformCaseFunc // eslint-disable-line indent\n\t\t) // eslint-disable-line indent\n\t\t\t: DEFAULT_DATA_URI_TAGS;\n\t\tFORBID_CONTENTS = 'FORBID_CONTENTS' in cfg ? addToSet({}, cfg.FORBID_CONTENTS, transformCaseFunc) : DEFAULT_FORBID_CONTENTS;\n\t\tFORBID_TAGS = 'FORBID_TAGS' in cfg ? addToSet({}, cfg.FORBID_TAGS, transformCaseFunc) : {};\n\t\tFORBID_ATTR = 'FORBID_ATTR' in cfg ? addToSet({}, cfg.FORBID_ATTR, transformCaseFunc) : {};\n\t\tUSE_PROFILES = 'USE_PROFILES' in cfg ? cfg.USE_PROFILES : false;\n\t\tALLOW_ARIA_ATTR = cfg.ALLOW_ARIA_ATTR !== false; // Default true\n\n\t\tALLOW_DATA_ATTR = cfg.ALLOW_DATA_ATTR !== false; // Default true\n\n\t\tALLOW_UNKNOWN_PROTOCOLS = cfg.ALLOW_UNKNOWN_PROTOCOLS || false; // Default false\n\n\t\tALLOW_SELF_CLOSE_IN_ATTR = cfg.ALLOW_SELF_CLOSE_IN_ATTR !== false; // Default true\n\n\t\tSAFE_FOR_TEMPLATES = cfg.SAFE_FOR_TEMPLATES || false; // Default false\n\n\t\tWHOLE_DOCUMENT = cfg.WHOLE_DOCUMENT || false; // Default false\n\n\t\tRETURN_DOM = cfg.RETURN_DOM || false; // Default false\n\n\t\tRETURN_DOM_FRAGMENT = cfg.RETURN_DOM_FRAGMENT || false; // Default false\n\n\t\tRETURN_TRUSTED_TYPE = cfg.RETURN_TRUSTED_TYPE || false; // Default false\n\n\t\tFORCE_BODY = cfg.FORCE_BODY || false; // Default false\n\n\t\tSANITIZE_DOM = cfg.SANITIZE_DOM !== false; // Default true\n\n\t\tSANITIZE_NAMED_PROPS = cfg.SANITIZE_NAMED_PROPS || false; // Default false\n\n\t\tKEEP_CONTENT = cfg.KEEP_CONTENT !== false; // Default true\n\n\t\tIN_PLACE = cfg.IN_PLACE || false; // Default false\n\n\t\tIS_ALLOWED_URI$1 = cfg.ALLOWED_URI_REGEXP || IS_ALLOWED_URI;\n\t\tNAMESPACE = cfg.NAMESPACE || HTML_NAMESPACE;\n\t\tCUSTOM_ELEMENT_HANDLING = cfg.CUSTOM_ELEMENT_HANDLING || {};\n\n\t\tif (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck)) {\n\t\t\tCUSTOM_ELEMENT_HANDLING.tagNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.tagNameCheck;\n\t\t}\n\n\t\tif (cfg.CUSTOM_ELEMENT_HANDLING && isRegexOrFunction(cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)) {\n\t\t\tCUSTOM_ELEMENT_HANDLING.attributeNameCheck = cfg.CUSTOM_ELEMENT_HANDLING.attributeNameCheck;\n\t\t}\n\n\t\tif (cfg.CUSTOM_ELEMENT_HANDLING && typeof cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements === 'boolean') {\n\t\t\tCUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements = cfg.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements;\n\t\t}\n\n\t\tif (SAFE_FOR_TEMPLATES) {\n\t\t\tALLOW_DATA_ATTR = false;\n\t\t}\n\n\t\tif (RETURN_DOM_FRAGMENT) {\n\t\t\tRETURN_DOM = true;\n\t\t}\n\t\t/* Parse profile info */\n\n\n\t\tif (USE_PROFILES) {\n\t\t\tALLOWED_TAGS = addToSet({}, [...text]);\n\t\t\tALLOWED_ATTR = [];\n\n\t\t\tif (USE_PROFILES.html === true) {\n\t\t\t\taddToSet(ALLOWED_TAGS, html$1);\n\t\t\t\taddToSet(ALLOWED_ATTR, html);\n\t\t\t}\n\n\t\t\tif (USE_PROFILES.svg === true) {\n\t\t\t\taddToSet(ALLOWED_TAGS, svg$1);\n\t\t\t\taddToSet(ALLOWED_ATTR, svg);\n\t\t\t\taddToSet(ALLOWED_ATTR, xml);\n\t\t\t}\n\n\t\t\tif (USE_PROFILES.svgFilters === true) {\n\t\t\t\taddToSet(ALLOWED_TAGS, svgFilters);\n\t\t\t\taddToSet(ALLOWED_ATTR, svg);\n\t\t\t\taddToSet(ALLOWED_ATTR, xml);\n\t\t\t}\n\n\t\t\tif (USE_PROFILES.mathMl === true) {\n\t\t\t\taddToSet(ALLOWED_TAGS, mathMl$1);\n\t\t\t\taddToSet(ALLOWED_ATTR, mathMl);\n\t\t\t\taddToSet(ALLOWED_ATTR, xml);\n\t\t\t}\n\t\t}\n\t\t/* Merge configuration parameters */\n\n\n\t\tif (cfg.ADD_TAGS) {\n\t\t\tif (ALLOWED_TAGS === DEFAULT_ALLOWED_TAGS) {\n\t\t\t\tALLOWED_TAGS = clone(ALLOWED_TAGS);\n\t\t\t}\n\n\t\t\taddToSet(ALLOWED_TAGS, cfg.ADD_TAGS, transformCaseFunc);\n\t\t}\n\n\t\tif (cfg.ADD_ATTR) {\n\t\t\tif (ALLOWED_ATTR === DEFAULT_ALLOWED_ATTR) {\n\t\t\t\tALLOWED_ATTR = clone(ALLOWED_ATTR);\n\t\t\t}\n\n\t\t\taddToSet(ALLOWED_ATTR, cfg.ADD_ATTR, transformCaseFunc);\n\t\t}\n\n\t\tif (cfg.ADD_URI_SAFE_ATTR) {\n\t\t\taddToSet(URI_SAFE_ATTRIBUTES, cfg.ADD_URI_SAFE_ATTR, transformCaseFunc);\n\t\t}\n\n\t\tif (cfg.FORBID_CONTENTS) {\n\t\t\tif (FORBID_CONTENTS === DEFAULT_FORBID_CONTENTS) {\n\t\t\t\tFORBID_CONTENTS = clone(FORBID_CONTENTS);\n\t\t\t}\n\n\t\t\taddToSet(FORBID_CONTENTS, cfg.FORBID_CONTENTS, transformCaseFunc);\n\t\t}\n\t\t/* Add #text in case KEEP_CONTENT is set to true */\n\n\n\t\tif (KEEP_CONTENT) {\n\t\t\tALLOWED_TAGS['#text'] = true;\n\t\t}\n\t\t/* Add html, head and body to ALLOWED_TAGS in case WHOLE_DOCUMENT is true */\n\n\n\t\tif (WHOLE_DOCUMENT) {\n\t\t\taddToSet(ALLOWED_TAGS, ['html', 'head', 'body']);\n\t\t}\n\t\t/* Add tbody to ALLOWED_TAGS in case tables are permitted, see #286, #365 */\n\n\n\t\tif (ALLOWED_TAGS.table) {\n\t\t\taddToSet(ALLOWED_TAGS, ['tbody']);\n\t\t\tdelete FORBID_TAGS.tbody;\n\t\t}\n\n\t\tif (cfg.TRUSTED_TYPES_POLICY) {\n\t\t\tif (typeof cfg.TRUSTED_TYPES_POLICY.createHTML !== 'function') {\n\t\t\t\tthrow typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a \"createHTML\" hook.');\n\t\t\t}\n\n\t\t\tif (typeof cfg.TRUSTED_TYPES_POLICY.createScriptURL !== 'function') {\n\t\t\t\tthrow typeErrorCreate('TRUSTED_TYPES_POLICY configuration option must provide a \"createScriptURL\" hook.');\n\t\t\t} // Overwrite existing TrustedTypes policy.\n\n\n\t\t\ttrustedTypesPolicy = cfg.TRUSTED_TYPES_POLICY; // Sign local variables required by `sanitize`.\n\n\t\t\temptyHTML = trustedTypesPolicy.createHTML('');\n\t\t} else {\n\t\t\t// Uninitialized policy, attempt to initialize the internal dompurify policy.\n\t\t\tif (trustedTypesPolicy === undefined) {\n\t\t\t\ttrustedTypesPolicy = _createTrustedTypesPolicy(trustedTypes, currentScript);\n\t\t\t} // If creating the internal policy succeeded sign internal variables.\n\n\n\t\t\tif (trustedTypesPolicy !== null && typeof emptyHTML === 'string') {\n\t\t\t\temptyHTML = trustedTypesPolicy.createHTML('');\n\t\t\t}\n\t\t} // Prevent further manipulation of configuration.\n\t\t// Not available in IE8, Safari 5, etc.\n\n\n\t\tif (freeze) {\n\t\t\tfreeze(cfg);\n\t\t}\n\n\t\tCONFIG = cfg;\n\t};\n\n\tconst MATHML_TEXT_INTEGRATION_POINTS = addToSet({}, ['mi', 'mo', 'mn', 'ms', 'mtext']);\n\tconst HTML_INTEGRATION_POINTS = addToSet({}, ['foreignobject', 'desc', 'title', 'annotation-xml']); // Certain elements are allowed in both SVG and HTML\n\t// namespace. We need to specify them explicitly\n\t// so that they don't get erroneously deleted from\n\t// HTML namespace.\n\n\tconst COMMON_SVG_AND_HTML_ELEMENTS = addToSet({}, ['title', 'style', 'font', 'a', 'script']);\n\t/* Keep track of all possible SVG and MathML tags\n\t * so that we can perform the namespace checks\n\t * correctly. */\n\n\tconst ALL_SVG_TAGS = addToSet({}, svg$1);\n\taddToSet(ALL_SVG_TAGS, svgFilters);\n\taddToSet(ALL_SVG_TAGS, svgDisallowed);\n\tconst ALL_MATHML_TAGS = addToSet({}, mathMl$1);\n\taddToSet(ALL_MATHML_TAGS, mathMlDisallowed);\n\t/**\n\t *\n\t *\n\t * @param {Element} element a DOM element whose namespace is being checked\n\t * @returns {boolean} Return false if the element has a\n\t * namespace that a spec-compliant parser would never\n\t * return. Return true otherwise.\n\t */\n\n\tconst _checkValidNamespace = function _checkValidNamespace(element) {\n\t\tlet parent = getParentNode(element); // In JSDOM, if we're inside shadow DOM, then parentNode\n\t\t// can be null. We just simulate parent in this case.\n\n\t\tif (!parent || !parent.tagName) {\n\t\t\tparent = {\n\t\t\t\tnamespaceURI: NAMESPACE,\n\t\t\t\ttagName: 'template'\n\t\t\t};\n\t\t}\n\n\t\tconst tagName = stringToLowerCase(element.tagName);\n\t\tconst parentTagName = stringToLowerCase(parent.tagName);\n\n\t\tif (!ALLOWED_NAMESPACES[element.namespaceURI]) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (element.namespaceURI === SVG_NAMESPACE) {\n\t\t\t// The only way to switch from HTML namespace to SVG\n\t\t\t// is via . If it happens via any other tag, then\n\t\t\t// it should be killed.\n\t\t\tif (parent.namespaceURI === HTML_NAMESPACE) {\n\t\t\t\treturn tagName === 'svg';\n\t\t\t} // The only way to switch from MathML to SVG is via`\n\t\t\t// svg if parent is either or MathML\n\t\t\t// text integration points.\n\n\n\t\t\tif (parent.namespaceURI === MATHML_NAMESPACE) {\n\t\t\t\treturn tagName === 'svg' && (parentTagName === 'annotation-xml' || MATHML_TEXT_INTEGRATION_POINTS[parentTagName]);\n\t\t\t} // We only allow elements that are defined in SVG\n\t\t\t// spec. All others are disallowed in SVG namespace.\n\n\n\t\t\treturn Boolean(ALL_SVG_TAGS[tagName]);\n\t\t}\n\n\t\tif (element.namespaceURI === MATHML_NAMESPACE) {\n\t\t\t// The only way to switch from HTML namespace to MathML\n\t\t\t// is via . If it happens via any other tag, then\n\t\t\t// it should be killed.\n\t\t\tif (parent.namespaceURI === HTML_NAMESPACE) {\n\t\t\t\treturn tagName === 'math';\n\t\t\t} // The only way to switch from SVG to MathML is via\n\t\t\t// and HTML integration points\n\n\n\t\t\tif (parent.namespaceURI === SVG_NAMESPACE) {\n\t\t\t\treturn tagName === 'math' && HTML_INTEGRATION_POINTS[parentTagName];\n\t\t\t} // We only allow elements that are defined in MathML\n\t\t\t// spec. All others are disallowed in MathML namespace.\n\n\n\t\t\treturn Boolean(ALL_MATHML_TAGS[tagName]);\n\t\t}\n\n\t\tif (element.namespaceURI === HTML_NAMESPACE) {\n\t\t\t// The only way to switch from SVG to HTML is via\n\t\t\t// HTML integration points, and from MathML to HTML\n\t\t\t// is via MathML text integration points\n\t\t\tif (parent.namespaceURI === SVG_NAMESPACE && !HTML_INTEGRATION_POINTS[parentTagName]) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (parent.namespaceURI === MATHML_NAMESPACE && !MATHML_TEXT_INTEGRATION_POINTS[parentTagName]) {\n\t\t\t\treturn false;\n\t\t\t} // We disallow tags that are specific for MathML\n\t\t\t// or SVG and should never appear in HTML namespace\n\n\n\t\t\treturn !ALL_MATHML_TAGS[tagName] && (COMMON_SVG_AND_HTML_ELEMENTS[tagName] || !ALL_SVG_TAGS[tagName]);\n\t\t} // For XHTML and XML documents that support custom namespaces\n\n\n\t\tif (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && ALLOWED_NAMESPACES[element.namespaceURI]) {\n\t\t\treturn true;\n\t\t} // The code should never reach this place (this means\n\t\t// that the element somehow got namespace that is not\n\t\t// HTML, SVG, MathML or allowed via ALLOWED_NAMESPACES).\n\t\t// Return false just in case.\n\n\n\t\treturn false;\n\t};\n\t/**\n\t * _forceRemove\n\t *\n\t * @param {Node} node a DOM node\n\t */\n\n\n\tconst _forceRemove = function _forceRemove(node) {\n\t\tarrayPush(DOMPurify.removed, {\n\t\t\telement: node\n\t\t});\n\n\t\ttry {\n\t\t\t// eslint-disable-next-line unicorn/prefer-dom-node-remove\n\t\t\tnode.parentNode.removeChild(node);\n\t\t} catch (_) {\n\t\t\tnode.remove();\n\t\t}\n\t};\n\t/**\n\t * _removeAttribute\n\t *\n\t * @param {String} name an Attribute name\n\t * @param {Node} node a DOM node\n\t */\n\n\n\tconst _removeAttribute = function _removeAttribute(name, node) {\n\t\ttry {\n\t\t\tarrayPush(DOMPurify.removed, {\n\t\t\t\tattribute: node.getAttributeNode(name),\n\t\t\t\tfrom: node\n\t\t\t});\n\t\t} catch (_) {\n\t\t\tarrayPush(DOMPurify.removed, {\n\t\t\t\tattribute: null,\n\t\t\t\tfrom: node\n\t\t\t});\n\t\t}\n\n\t\tnode.removeAttribute(name); // We void attribute values for unremovable \"is\"\" attributes\n\n\t\tif (name === 'is' && !ALLOWED_ATTR[name]) {\n\t\t\tif (RETURN_DOM || RETURN_DOM_FRAGMENT) {\n\t\t\t\ttry {\n\t\t\t\t\t_forceRemove(node);\n\t\t\t\t} catch (_) { }\n\t\t\t} else {\n\t\t\t\ttry {\n\t\t\t\t\tnode.setAttribute(name, '');\n\t\t\t\t} catch (_) { }\n\t\t\t}\n\t\t}\n\t};\n\t/**\n\t * _initDocument\n\t *\n\t * @param {String} dirty a string of dirty markup\n\t * @return {Document} a DOM, filled with the dirty markup\n\t */\n\n\n\tconst _initDocument = function _initDocument(dirty) {\n\t\t/* Create a HTML document */\n\t\tlet doc;\n\t\tlet leadingWhitespace;\n\n\t\tif (FORCE_BODY) {\n\t\t\tdirty = '' + dirty;\n\t\t} else {\n\t\t\t/* If FORCE_BODY isn't used, leading whitespace needs to be preserved manually */\n\t\t\tconst matches = stringMatch(dirty, /^[\\r\\n\\t ]+/);\n\t\t\tleadingWhitespace = matches && matches[0];\n\t\t}\n\n\t\tif (PARSER_MEDIA_TYPE === 'application/xhtml+xml' && NAMESPACE === HTML_NAMESPACE) {\n\t\t\t// Root of XHTML doc must contain xmlns declaration (see https://www.w3.org/TR/xhtml1/normative.html#strict)\n\t\t\tdirty = '' + dirty + '';\n\t\t}\n\n\t\tconst dirtyPayload = trustedTypesPolicy ? trustedTypesPolicy.createHTML(dirty) : dirty;\n\t\t/*\n\t\t * Use the DOMParser API by default, fallback later if needs be\n\t\t * DOMParser not work for svg when has multiple root element.\n\t\t */\n\n\t\tif (NAMESPACE === HTML_NAMESPACE) {\n\t\t\ttry {\n\t\t\t\tdoc = new DOMParser().parseFromString(dirtyPayload, PARSER_MEDIA_TYPE);\n\t\t\t} catch (_) { }\n\t\t}\n\t\t/* Use createHTMLDocument in case DOMParser is not available */\n\n\n\t\tif (!doc || !doc.documentElement) {\n\t\t\tdoc = implementation.createDocument(NAMESPACE, 'template', null);\n\n\t\t\ttry {\n\t\t\t\tdoc.documentElement.innerHTML = IS_EMPTY_INPUT ? emptyHTML : dirtyPayload;\n\t\t\t} catch (_) {// Syntax error if dirtyPayload is invalid xml\n\t\t\t}\n\t\t}\n\n\t\tconst body = doc.body || doc.documentElement;\n\n\t\tif (dirty && leadingWhitespace) {\n\t\t\tbody.insertBefore(document.createTextNode(leadingWhitespace), body.childNodes[0] || null);\n\t\t}\n\t\t/* Work on whole document or just its body */\n\n\n\t\tif (NAMESPACE === HTML_NAMESPACE) {\n\t\t\treturn getElementsByTagName.call(doc, WHOLE_DOCUMENT ? 'html' : 'body')[0];\n\t\t}\n\n\t\treturn WHOLE_DOCUMENT ? doc.documentElement : body;\n\t};\n\t/**\n\t * _createIterator\n\t *\n\t * @param {Document} root document/fragment to create iterator for\n\t * @return {Iterator} iterator instance\n\t */\n\n\n\tconst _createIterator = function _createIterator(root) {\n\t\treturn createNodeIterator.call(root.ownerDocument || root, root, // eslint-disable-next-line no-bitwise\n\t\t\tNodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT, null, false);\n\t};\n\t/**\n\t * _isClobbered\n\t *\n\t * @param {Node} elm element to check for clobbering attacks\n\t * @return {Boolean} true if clobbered, false if safe\n\t */\n\n\n\tconst _isClobbered = function _isClobbered(elm) {\n\t\treturn elm instanceof HTMLFormElement && (typeof elm.nodeName !== 'string' || typeof elm.textContent !== 'string' || typeof elm.removeChild !== 'function' || !(elm.attributes instanceof NamedNodeMap) || typeof elm.removeAttribute !== 'function' || typeof elm.setAttribute !== 'function' || typeof elm.namespaceURI !== 'string' || typeof elm.insertBefore !== 'function' || typeof elm.hasChildNodes !== 'function');\n\t};\n\t/**\n\t * _isNode\n\t *\n\t * @param {Node} obj object to check whether it's a DOM node\n\t * @return {Boolean} true is object is a DOM node\n\t */\n\n\n\tconst _isNode = function _isNode(object) {\n\t\treturn typeof Node === 'object' ? object instanceof Node : object && typeof object === 'object' && typeof object.nodeType === 'number' && typeof object.nodeName === 'string';\n\t};\n\t/**\n\t * _executeHook\n\t * Execute user configurable hooks\n\t *\n\t * @param {String} entryPoint Name of the hook's entry point\n\t * @param {Node} currentNode node to work on with the hook\n\t * @param {Object} data additional hook parameters\n\t */\n\n\n\tconst _executeHook = function _executeHook(entryPoint, currentNode, data) {\n\t\tif (!hooks[entryPoint]) {\n\t\t\treturn;\n\t\t}\n\n\t\tarrayForEach(hooks[entryPoint], hook => {\n\t\t\thook.call(DOMPurify, currentNode, data, CONFIG);\n\t\t});\n\t};\n\t/**\n\t * _sanitizeElements\n\t *\n\t * @protect nodeName\n\t * @protect textContent\n\t * @protect removeChild\n\t *\n\t * @param {Node} currentNode to check for permission to exist\n\t * @return {Boolean} true if node was killed, false if left alive\n\t */\n\n\n\tconst _sanitizeElements = function _sanitizeElements(currentNode) {\n\t\tlet content;\n\t\t/* Execute a hook if present */\n\n\t\t_executeHook('beforeSanitizeElements', currentNode, null);\n\t\t/* Check if element is clobbered or can clobber */\n\n\n\t\tif (_isClobbered(currentNode)) {\n\t\t\t_forceRemove(currentNode);\n\n\t\t\treturn true;\n\t\t}\n\t\t/* Now let's check the element's type and name */\n\n\n\t\tconst tagName = transformCaseFunc(currentNode.nodeName);\n\t\t/* Execute a hook if present */\n\n\t\t_executeHook('uponSanitizeElement', currentNode, {\n\t\t\ttagName,\n\t\t\tallowedTags: ALLOWED_TAGS\n\t\t});\n\t\t/* Detect mXSS attempts abusing namespace confusion */\n\n\n\t\tif (currentNode.hasChildNodes() && !_isNode(currentNode.firstElementChild) && (!_isNode(currentNode.content) || !_isNode(currentNode.content.firstElementChild)) && regExpTest(/<[/\\w]/g, currentNode.innerHTML) && regExpTest(/<[/\\w]/g, currentNode.textContent)) {\n\t\t\t_forceRemove(currentNode);\n\n\t\t\treturn true;\n\t\t}\n\t\t/* Remove element if anything forbids its presence */\n\n\n\t\tif (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {\n\t\t\t/* Check if we have a custom element to handle */\n\t\t\tif (!FORBID_TAGS[tagName] && _basicCustomElementTest(tagName)) {\n\t\t\t\tif (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) return false;\n\t\t\t\tif (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(tagName)) return false;\n\t\t\t}\n\t\t\t/* Keep content except for bad-listed elements */\n\n\n\t\t\tif (KEEP_CONTENT && !FORBID_CONTENTS[tagName]) {\n\t\t\t\tconst parentNode = getParentNode(currentNode) || currentNode.parentNode;\n\t\t\t\tconst childNodes = getChildNodes(currentNode) || currentNode.childNodes;\n\n\t\t\t\tif (childNodes && parentNode) {\n\t\t\t\t\tconst childCount = childNodes.length;\n\n\t\t\t\t\tfor (let i = childCount - 1; i >= 0; --i) {\n\t\t\t\t\t\tparentNode.insertBefore(cloneNode(childNodes[i], true), getNextSibling(currentNode));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t_forceRemove(currentNode);\n\n\t\t\treturn true;\n\t\t}\n\t\t/* Check whether element has a valid namespace */\n\n\n\t\tif (currentNode instanceof Element && !_checkValidNamespace(currentNode)) {\n\t\t\t_forceRemove(currentNode);\n\n\t\t\treturn true;\n\t\t}\n\t\t/* Make sure that older browsers don't get fallback-tag mXSS */\n\n\n\t\tif ((tagName === 'noscript' || tagName === 'noembed' || tagName === 'noframes') && regExpTest(/<\\/no(script|embed|frames)/i, currentNode.innerHTML)) {\n\t\t\t_forceRemove(currentNode);\n\n\t\t\treturn true;\n\t\t}\n\t\t/* Sanitize element content to be template-safe */\n\n\n\t\tif (SAFE_FOR_TEMPLATES && currentNode.nodeType === 3) {\n\t\t\t/* Get the element's text content */\n\t\t\tcontent = currentNode.textContent;\n\t\t\tcontent = stringReplace(content, MUSTACHE_EXPR, ' ');\n\t\t\tcontent = stringReplace(content, ERB_EXPR, ' ');\n\t\t\tcontent = stringReplace(content, TMPLIT_EXPR, ' ');\n\n\t\t\tif (currentNode.textContent !== content) {\n\t\t\t\tarrayPush(DOMPurify.removed, {\n\t\t\t\t\telement: currentNode.cloneNode()\n\t\t\t\t});\n\t\t\t\tcurrentNode.textContent = content;\n\t\t\t}\n\t\t}\n\t\t/* Execute a hook if present */\n\n\n\t\t_executeHook('afterSanitizeElements', currentNode, null);\n\n\t\treturn false;\n\t};\n\t/**\n\t * _isValidAttribute\n\t *\n\t * @param {string} lcTag Lowercase tag name of containing element.\n\t * @param {string} lcName Lowercase attribute name.\n\t * @param {string} value Attribute value.\n\t * @return {Boolean} Returns true if `value` is valid, otherwise false.\n\t */\n\t// eslint-disable-next-line complexity\n\n\n\tconst _isValidAttribute = function _isValidAttribute(lcTag, lcName, value) {\n\t\t/* Make sure attribute cannot clobber */\n\t\tif (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement)) {\n\t\t\treturn false;\n\t\t}\n\t\t/* Allow valid data-* attributes: At least one character after \"-\"\n\t\t\t\t(https://html.spec.whatwg.org/multipage/dom.html#embedding-custom-non-visible-data-with-the-data-*-attributes)\n\t\t\t\tXML-compatible (https://html.spec.whatwg.org/multipage/infrastructure.html#xml-compatible and http://www.w3.org/TR/xml/#d0e804)\n\t\t\t\tWe don't need to check the value; it's always URI safe. */\n\n\n\t\tif (ALLOW_DATA_ATTR && !FORBID_ATTR[lcName] && regExpTest(DATA_ATTR, lcName)); else if (ALLOW_ARIA_ATTR && regExpTest(ARIA_ATTR, lcName)); else if (!ALLOWED_ATTR[lcName] || FORBID_ATTR[lcName]) {\n\t\t\tif ( // First condition does a very basic check if a) it's basically a valid custom element tagname AND\n\t\t\t\t// b) if the tagName passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck\n\t\t\t\t// and c) if the attribute name passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.attributeNameCheck\n\t\t\t\t_basicCustomElementTest(lcTag) && (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, lcTag) || CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(lcTag)) && (CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.attributeNameCheck, lcName) || CUSTOM_ELEMENT_HANDLING.attributeNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.attributeNameCheck(lcName)) || // Alternative, second condition checks if it's an `is`-attribute, AND\n\t\t\t\t// the value passes whatever the user has configured for CUSTOM_ELEMENT_HANDLING.tagNameCheck\n\t\t\t\tlcName === 'is' && CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements && (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, value) || CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof Function && CUSTOM_ELEMENT_HANDLING.tagNameCheck(value))); else {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t/* Check value is safe. First, is attr inert? If so, is safe */\n\n\t\t} else if (URI_SAFE_ATTRIBUTES[lcName]); else if (regExpTest(IS_ALLOWED_URI$1, stringReplace(value, ATTR_WHITESPACE, ''))); else if ((lcName === 'src' || lcName === 'xlink:href' || lcName === 'href') && lcTag !== 'script' && stringIndexOf(value, 'data:') === 0 && DATA_URI_TAGS[lcTag]); else if (ALLOW_UNKNOWN_PROTOCOLS && !regExpTest(IS_SCRIPT_OR_DATA, stringReplace(value, ATTR_WHITESPACE, ''))); else if (value) {\n\t\t\treturn false;\n\t\t} else;\n\n\t\treturn true;\n\t};\n\t/**\n\t * _basicCustomElementCheck\n\t * checks if at least one dash is included in tagName, and it's not the first char\n\t * for more sophisticated checking see https://github.com/sindresorhus/validate-element-name\n\t * @param {string} tagName name of the tag of the node to sanitize\n\t */\n\n\n\tconst _basicCustomElementTest = function _basicCustomElementTest(tagName) {\n\t\treturn tagName.indexOf('-') > 0;\n\t};\n\t/**\n\t * _sanitizeAttributes\n\t *\n\t * @protect attributes\n\t * @protect nodeName\n\t * @protect removeAttribute\n\t * @protect setAttribute\n\t *\n\t * @param {Node} currentNode to sanitize\n\t */\n\n\n\tconst _sanitizeAttributes = function _sanitizeAttributes(currentNode) {\n\t\tlet attr;\n\t\tlet value;\n\t\tlet lcName;\n\t\tlet l;\n\t\t/* Execute a hook if present */\n\n\t\t_executeHook('beforeSanitizeAttributes', currentNode, null);\n\n\t\tconst {\n\t\t\tattributes\n\t\t} = currentNode;\n\t\t/* Check if we have attributes; if not we might have a text node */\n\n\t\tif (!attributes) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst hookEvent = {\n\t\t\tattrName: '',\n\t\t\tattrValue: '',\n\t\t\tkeepAttr: true,\n\t\t\tallowedAttributes: ALLOWED_ATTR\n\t\t};\n\t\tl = attributes.length;\n\t\t/* Go backwards over all attributes; safely remove bad ones */\n\n\t\twhile (l--) {\n\t\t\tattr = attributes[l];\n\t\t\tconst {\n\t\t\t\tname,\n\t\t\t\tnamespaceURI\n\t\t\t} = attr;\n\t\t\tvalue = name === 'value' ? attr.value : stringTrim(attr.value);\n\t\t\tlcName = transformCaseFunc(name);\n\t\t\t/* Execute a hook if present */\n\n\t\t\thookEvent.attrName = lcName;\n\t\t\thookEvent.attrValue = value;\n\t\t\thookEvent.keepAttr = true;\n\t\t\thookEvent.forceKeepAttr = undefined; // Allows developers to see this is a property they can set\n\n\t\t\t_executeHook('uponSanitizeAttribute', currentNode, hookEvent);\n\n\t\t\tvalue = hookEvent.attrValue;\n\t\t\t/* Did the hooks approve of the attribute? */\n\n\t\t\tif (hookEvent.forceKeepAttr) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t/* Remove attribute */\n\n\n\t\t\t_removeAttribute(name, currentNode);\n\t\t\t/* Did the hooks approve of the attribute? */\n\n\n\t\t\tif (!hookEvent.keepAttr) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t/* Work around a security issue in jQuery 3.0 */\n\n\n\t\t\tif (!ALLOW_SELF_CLOSE_IN_ATTR && regExpTest(/\\/>/i, value)) {\n\t\t\t\t_removeAttribute(name, currentNode);\n\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t/* Sanitize attribute content to be template-safe */\n\n\n\t\t\tif (SAFE_FOR_TEMPLATES) {\n\t\t\t\tvalue = stringReplace(value, MUSTACHE_EXPR, ' ');\n\t\t\t\tvalue = stringReplace(value, ERB_EXPR, ' ');\n\t\t\t\tvalue = stringReplace(value, TMPLIT_EXPR, ' ');\n\t\t\t}\n\t\t\t/* Is `value` valid for this attribute? */\n\n\n\t\t\tconst lcTag = transformCaseFunc(currentNode.nodeName);\n\n\t\t\tif (!_isValidAttribute(lcTag, lcName, value)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t/* Full DOM Clobbering protection via namespace isolation,\n\t\t\t * Prefix id and name attributes with `user-content-`\n\t\t\t */\n\n\n\t\t\tif (SANITIZE_NAMED_PROPS && (lcName === 'id' || lcName === 'name')) {\n\t\t\t\t// Remove the attribute with this value\n\t\t\t\t_removeAttribute(name, currentNode); // Prefix the value and later re-create the attribute with the sanitized value\n\n\n\t\t\t\tvalue = SANITIZE_NAMED_PROPS_PREFIX + value;\n\t\t\t}\n\t\t\t/* Handle attributes that require Trusted Types */\n\n\n\t\t\tif (trustedTypesPolicy && typeof trustedTypes === 'object' && typeof trustedTypes.getAttributeType === 'function') {\n\t\t\t\tif (namespaceURI); else {\n\t\t\t\t\tswitch (trustedTypes.getAttributeType(lcTag, lcName)) {\n\t\t\t\t\t\tcase 'TrustedHTML':\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tvalue = trustedTypesPolicy.createHTML(value);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcase 'TrustedScriptURL':\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tvalue = trustedTypesPolicy.createScriptURL(value);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t/* Handle invalid data-* attribute set by try-catching it */\n\n\n\t\t\ttry {\n\t\t\t\tif (namespaceURI) {\n\t\t\t\t\tcurrentNode.setAttributeNS(namespaceURI, name, value);\n\t\t\t\t} else {\n\t\t\t\t\t/* Fallback to setAttribute() for browser-unrecognized namespaces e.g. \"x-schema\". */\n\t\t\t\t\tcurrentNode.setAttribute(name, value);\n\t\t\t\t}\n\n\t\t\t\tarrayPop(DOMPurify.removed);\n\t\t\t} catch (_) { }\n\t\t}\n\t\t/* Execute a hook if present */\n\n\n\t\t_executeHook('afterSanitizeAttributes', currentNode, null);\n\t};\n\t/**\n\t * _sanitizeShadowDOM\n\t *\n\t * @param {DocumentFragment} fragment to iterate over recursively\n\t */\n\n\n\tconst _sanitizeShadowDOM = function _sanitizeShadowDOM(fragment) {\n\t\tlet shadowNode;\n\n\t\tconst shadowIterator = _createIterator(fragment);\n\t\t/* Execute a hook if present */\n\n\n\t\t_executeHook('beforeSanitizeShadowDOM', fragment, null);\n\n\t\twhile (shadowNode = shadowIterator.nextNode()) {\n\t\t\t/* Execute a hook if present */\n\t\t\t_executeHook('uponSanitizeShadowNode', shadowNode, null);\n\t\t\t/* Sanitize tags and elements */\n\n\n\t\t\tif (_sanitizeElements(shadowNode)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t/* Deep shadow DOM detected */\n\n\n\t\t\tif (shadowNode.content instanceof DocumentFragment) {\n\t\t\t\t_sanitizeShadowDOM(shadowNode.content);\n\t\t\t}\n\t\t\t/* Check attributes, sanitize if necessary */\n\n\n\t\t\t_sanitizeAttributes(shadowNode);\n\t\t}\n\t\t/* Execute a hook if present */\n\n\n\t\t_executeHook('afterSanitizeShadowDOM', fragment, null);\n\t};\n\t/**\n\t * Sanitize\n\t * Public method providing core sanitation functionality\n\t *\n\t * @param {String|Node} dirty string or DOM node\n\t * @param {Object} configuration object\n\t */\n\t// eslint-disable-next-line complexity\n\n\n\tDOMPurify.sanitize = function (dirty) {\n\t\tlet cfg = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n\t\tlet body;\n\t\tlet importedNode;\n\t\tlet currentNode;\n\t\tlet returnNode;\n\t\t/* Make sure we have a string to sanitize.\n\t\t\tDO NOT return early, as this will return the wrong type if\n\t\t\tthe user has requested a DOM object rather than a string */\n\n\t\tIS_EMPTY_INPUT = !dirty;\n\n\t\tif (IS_EMPTY_INPUT) {\n\t\t\tdirty = '';\n\t\t}\n\t\t/* Stringify, in case dirty is an object */\n\n\n\t\tif (typeof dirty !== 'string' && !_isNode(dirty)) {\n\t\t\tif (typeof dirty.toString === 'function') {\n\t\t\t\tdirty = dirty.toString();\n\n\t\t\t\tif (typeof dirty !== 'string') {\n\t\t\t\t\tthrow typeErrorCreate('dirty is not a string, aborting');\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthrow typeErrorCreate('toString is not a function');\n\t\t\t}\n\t\t}\n\t\t/* Return dirty HTML if DOMPurify cannot run */\n\n\n\t\tif (!DOMPurify.isSupported) {\n\t\t\treturn dirty;\n\t\t}\n\t\t/* Assign config vars */\n\n\n\t\tif (!SET_CONFIG) {\n\t\t\t_parseConfig(cfg);\n\t\t}\n\t\t/* Clean up removed elements */\n\n\n\t\tDOMPurify.removed = [];\n\t\t/* Check if dirty is correctly typed for IN_PLACE */\n\n\t\tif (typeof dirty === 'string') {\n\t\t\tIN_PLACE = false;\n\t\t}\n\n\t\tif (IN_PLACE) {\n\t\t\t/* Do some early pre-sanitization to avoid unsafe root nodes */\n\t\t\tif (dirty.nodeName) {\n\t\t\t\tconst tagName = transformCaseFunc(dirty.nodeName);\n\n\t\t\t\tif (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {\n\t\t\t\t\tthrow typeErrorCreate('root node is forbidden and cannot be sanitized in-place');\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (dirty instanceof Node) {\n\t\t\t/* If dirty is a DOM element, append to an empty document to avoid\n\t\t\t\t elements being stripped by the parser */\n\t\t\tbody = _initDocument('');\n\t\t\timportedNode = body.ownerDocument.importNode(dirty, true);\n\n\t\t\tif (importedNode.nodeType === 1 && importedNode.nodeName === 'BODY') {\n\t\t\t\t/* Node is already a body, use as is */\n\t\t\t\tbody = importedNode;\n\t\t\t} else if (importedNode.nodeName === 'HTML') {\n\t\t\t\tbody = importedNode;\n\t\t\t} else {\n\t\t\t\t// eslint-disable-next-line unicorn/prefer-dom-node-append\n\t\t\t\tbody.appendChild(importedNode);\n\t\t\t}\n\t\t} else {\n\t\t\t/* Exit directly if we have nothing to do */\n\t\t\tif (!RETURN_DOM && !SAFE_FOR_TEMPLATES && !WHOLE_DOCUMENT && // eslint-disable-next-line unicorn/prefer-includes\n\t\t\t\tdirty.indexOf('<') === -1) {\n\t\t\t\treturn trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(dirty) : dirty;\n\t\t\t}\n\t\t\t/* Initialize the document to work on */\n\n\n\t\t\tbody = _initDocument(dirty);\n\t\t\t/* Check we have a DOM node from the data */\n\n\t\t\tif (!body) {\n\t\t\t\treturn RETURN_DOM ? null : RETURN_TRUSTED_TYPE ? emptyHTML : '';\n\t\t\t}\n\t\t}\n\t\t/* Remove first element node (ours) if FORCE_BODY is set */\n\n\n\t\tif (body && FORCE_BODY) {\n\t\t\t_forceRemove(body.firstChild);\n\t\t}\n\t\t/* Get node iterator */\n\n\n\t\tconst nodeIterator = _createIterator(IN_PLACE ? dirty : body);\n\t\t/* Now start iterating over the created document */\n\n\n\t\twhile (currentNode = nodeIterator.nextNode()) {\n\t\t\t/* Sanitize tags and elements */\n\t\t\tif (_sanitizeElements(currentNode)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t/* Shadow DOM detected, sanitize it */\n\n\n\t\t\tif (currentNode.content instanceof DocumentFragment) {\n\t\t\t\t_sanitizeShadowDOM(currentNode.content);\n\t\t\t}\n\t\t\t/* Check attributes, sanitize if necessary */\n\n\n\t\t\t_sanitizeAttributes(currentNode);\n\t\t}\n\t\t/* If we sanitized `dirty` in-place, return it. */\n\n\n\t\tif (IN_PLACE) {\n\t\t\treturn dirty;\n\t\t}\n\t\t/* Return sanitized string or DOM */\n\n\n\t\tif (RETURN_DOM) {\n\t\t\tif (RETURN_DOM_FRAGMENT) {\n\t\t\t\treturnNode = createDocumentFragment.call(body.ownerDocument);\n\n\t\t\t\twhile (body.firstChild) {\n\t\t\t\t\t// eslint-disable-next-line unicorn/prefer-dom-node-append\n\t\t\t\t\treturnNode.appendChild(body.firstChild);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturnNode = body;\n\t\t\t}\n\n\t\t\tif (ALLOWED_ATTR.shadowroot || ALLOWED_ATTR.shadowrootmode) {\n\t\t\t\t/*\n\t\t\t\t\tAdoptNode() is not used because internal state is not reset\n\t\t\t\t\t(e.g. the past names map of a HTMLFormElement), this is safe\n\t\t\t\t\tin theory but we would rather not risk another attack vector.\n\t\t\t\t\tThe state that is cloned by importNode() is explicitly defined\n\t\t\t\t\tby the specs.\n\t\t\t\t*/\n\t\t\t\treturnNode = importNode.call(originalDocument, returnNode, true);\n\t\t\t}\n\n\t\t\treturn returnNode;\n\t\t}\n\n\t\tlet serializedHTML = WHOLE_DOCUMENT ? body.outerHTML : body.innerHTML;\n\t\t/* Serialize doctype if allowed */\n\n\t\tif (WHOLE_DOCUMENT && ALLOWED_TAGS['!doctype'] && body.ownerDocument && body.ownerDocument.doctype && body.ownerDocument.doctype.name && regExpTest(DOCTYPE_NAME, body.ownerDocument.doctype.name)) {\n\t\t\tserializedHTML = '\\n' + serializedHTML;\n\t\t}\n\t\t/* Sanitize final string template-safe */\n\n\n\t\tif (SAFE_FOR_TEMPLATES) {\n\t\t\tserializedHTML = stringReplace(serializedHTML, MUSTACHE_EXPR, ' ');\n\t\t\tserializedHTML = stringReplace(serializedHTML, ERB_EXPR, ' ');\n\t\t\tserializedHTML = stringReplace(serializedHTML, TMPLIT_EXPR, ' ');\n\t\t}\n\n\t\treturn trustedTypesPolicy && RETURN_TRUSTED_TYPE ? trustedTypesPolicy.createHTML(serializedHTML) : serializedHTML;\n\t};\n\t/**\n\t * Public method to set the configuration once\n\t * setConfig\n\t *\n\t * @param {Object} cfg configuration object\n\t */\n\n\n\tDOMPurify.setConfig = function (cfg) {\n\t\t_parseConfig(cfg);\n\n\t\tSET_CONFIG = true;\n\t};\n\t/**\n\t * Public method to remove the configuration\n\t * clearConfig\n\t *\n\t */\n\n\n\tDOMPurify.clearConfig = function () {\n\t\tCONFIG = null;\n\t\tSET_CONFIG = false;\n\t};\n\t/**\n\t * Public method to check if an attribute value is valid.\n\t * Uses last set config, if any. Otherwise, uses config defaults.\n\t * isValidAttribute\n\t *\n\t * @param {string} tag Tag name of containing element.\n\t * @param {string} attr Attribute name.\n\t * @param {string} value Attribute value.\n\t * @return {Boolean} Returns true if `value` is valid. Otherwise, returns false.\n\t */\n\n\n\tDOMPurify.isValidAttribute = function (tag, attr, value) {\n\t\t/* Initialize shared config vars if necessary. */\n\t\tif (!CONFIG) {\n\t\t\t_parseConfig({});\n\t\t}\n\n\t\tconst lcTag = transformCaseFunc(tag);\n\t\tconst lcName = transformCaseFunc(attr);\n\t\treturn _isValidAttribute(lcTag, lcName, value);\n\t};\n\t/**\n\t * AddHook\n\t * Public method to add DOMPurify hooks\n\t *\n\t * @param {String} entryPoint entry point for the hook to add\n\t * @param {Function} hookFunction function to execute\n\t */\n\n\n\tDOMPurify.addHook = function (entryPoint, hookFunction) {\n\t\tif (typeof hookFunction !== 'function') {\n\t\t\treturn;\n\t\t}\n\n\t\thooks[entryPoint] = hooks[entryPoint] || [];\n\t\tarrayPush(hooks[entryPoint], hookFunction);\n\t};\n\t/**\n\t * RemoveHook\n\t * Public method to remove a DOMPurify hook at a given entryPoint\n\t * (pops it from the stack of hooks if more are present)\n\t *\n\t * @param {String} entryPoint entry point for the hook to remove\n\t * @return {Function} removed(popped) hook\n\t */\n\n\n\tDOMPurify.removeHook = function (entryPoint) {\n\t\tif (hooks[entryPoint]) {\n\t\t\treturn arrayPop(hooks[entryPoint]);\n\t\t}\n\t};\n\t/**\n\t * RemoveHooks\n\t * Public method to remove all DOMPurify hooks at a given entryPoint\n\t *\n\t * @param {String} entryPoint entry point for the hooks to remove\n\t */\n\n\n\tDOMPurify.removeHooks = function (entryPoint) {\n\t\tif (hooks[entryPoint]) {\n\t\t\thooks[entryPoint] = [];\n\t\t}\n\t};\n\t/**\n\t * RemoveAllHooks\n\t * Public method to remove all DOMPurify hooks\n\t *\n\t */\n\n\n\tDOMPurify.removeAllHooks = function () {\n\t\thooks = {};\n\t};\n\n\treturn DOMPurify;\n}\n\nvar purify = createDOMPurify();\n\n// ESM-comment-begin\ndefine(\"vs/base/browser/dompurify/dompurify\", function () { return purify; });\n// ESM-comment-end\n\n// ESM-uncomment-begin\n// export default purify;\n// export const version = purify.version;\n// export const isSupported = purify.isSupported;\n// export const sanitize = purify.sanitize;\n// export const setConfig = purify.setConfig;\n// export const clearConfig = purify.clearConfig;\n// export const isValidAttribute = purify.isValidAttribute;\n// export const addHook = purify.addHook;\n// export const removeHook = purify.removeHook;\n// export const removeHooks = purify.removeHooks;\n// export const removeAllHooks = purify.removeAllHooks;\n// ESM-uncomment-end\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\nexport class FastDomNode {\n\n\tprivate _maxWidth: string = '';\n\tprivate _width: string = '';\n\tprivate _height: string = '';\n\tprivate _top: string = '';\n\tprivate _left: string = '';\n\tprivate _bottom: string = '';\n\tprivate _right: string = '';\n\tprivate _paddingLeft: string = '';\n\tprivate _fontFamily: string = '';\n\tprivate _fontWeight: string = '';\n\tprivate _fontSize: string = '';\n\tprivate _fontStyle: string = '';\n\tprivate _fontFeatureSettings: string = '';\n\tprivate _fontVariationSettings: string = '';\n\tprivate _textDecoration: string = '';\n\tprivate _lineHeight: string = '';\n\tprivate _letterSpacing: string = '';\n\tprivate _className: string = '';\n\tprivate _display: string = '';\n\tprivate _position: string = '';\n\tprivate _visibility: string = '';\n\tprivate _color: string = '';\n\tprivate _backgroundColor: string = '';\n\tprivate _layerHint: boolean = false;\n\tprivate _contain: 'none' | 'strict' | 'content' | 'size' | 'layout' | 'style' | 'paint' = 'none';\n\tprivate _boxShadow: string = '';\n\n\tconstructor(\n\t\tpublic readonly domNode: T\n\t) { }\n\n\tpublic setMaxWidth(_maxWidth: number | string): void {\n\t\tconst maxWidth = numberAsPixels(_maxWidth);\n\t\tif (this._maxWidth === maxWidth) {\n\t\t\treturn;\n\t\t}\n\t\tthis._maxWidth = maxWidth;\n\t\tthis.domNode.style.maxWidth = this._maxWidth;\n\t}\n\n\tpublic setWidth(_width: number | string): void {\n\t\tconst width = numberAsPixels(_width);\n\t\tif (this._width === width) {\n\t\t\treturn;\n\t\t}\n\t\tthis._width = width;\n\t\tthis.domNode.style.width = this._width;\n\t}\n\n\tpublic setHeight(_height: number | string): void {\n\t\tconst height = numberAsPixels(_height);\n\t\tif (this._height === height) {\n\t\t\treturn;\n\t\t}\n\t\tthis._height = height;\n\t\tthis.domNode.style.height = this._height;\n\t}\n\n\tpublic setTop(_top: number | string): void {\n\t\tconst top = numberAsPixels(_top);\n\t\tif (this._top === top) {\n\t\t\treturn;\n\t\t}\n\t\tthis._top = top;\n\t\tthis.domNode.style.top = this._top;\n\t}\n\n\tpublic setLeft(_left: number | string): void {\n\t\tconst left = numberAsPixels(_left);\n\t\tif (this._left === left) {\n\t\t\treturn;\n\t\t}\n\t\tthis._left = left;\n\t\tthis.domNode.style.left = this._left;\n\t}\n\n\tpublic setBottom(_bottom: number | string): void {\n\t\tconst bottom = numberAsPixels(_bottom);\n\t\tif (this._bottom === bottom) {\n\t\t\treturn;\n\t\t}\n\t\tthis._bottom = bottom;\n\t\tthis.domNode.style.bottom = this._bottom;\n\t}\n\n\tpublic setRight(_right: number | string): void {\n\t\tconst right = numberAsPixels(_right);\n\t\tif (this._right === right) {\n\t\t\treturn;\n\t\t}\n\t\tthis._right = right;\n\t\tthis.domNode.style.right = this._right;\n\t}\n\n\tpublic setPaddingLeft(_paddingLeft: number | string): void {\n\t\tconst paddingLeft = numberAsPixels(_paddingLeft);\n\t\tif (this._paddingLeft === paddingLeft) {\n\t\t\treturn;\n\t\t}\n\t\tthis._paddingLeft = paddingLeft;\n\t\tthis.domNode.style.paddingLeft = this._paddingLeft;\n\t}\n\n\tpublic setFontFamily(fontFamily: string): void {\n\t\tif (this._fontFamily === fontFamily) {\n\t\t\treturn;\n\t\t}\n\t\tthis._fontFamily = fontFamily;\n\t\tthis.domNode.style.fontFamily = this._fontFamily;\n\t}\n\n\tpublic setFontWeight(fontWeight: string): void {\n\t\tif (this._fontWeight === fontWeight) {\n\t\t\treturn;\n\t\t}\n\t\tthis._fontWeight = fontWeight;\n\t\tthis.domNode.style.fontWeight = this._fontWeight;\n\t}\n\n\tpublic setFontSize(_fontSize: number | string): void {\n\t\tconst fontSize = numberAsPixels(_fontSize);\n\t\tif (this._fontSize === fontSize) {\n\t\t\treturn;\n\t\t}\n\t\tthis._fontSize = fontSize;\n\t\tthis.domNode.style.fontSize = this._fontSize;\n\t}\n\n\tpublic setFontStyle(fontStyle: string): void {\n\t\tif (this._fontStyle === fontStyle) {\n\t\t\treturn;\n\t\t}\n\t\tthis._fontStyle = fontStyle;\n\t\tthis.domNode.style.fontStyle = this._fontStyle;\n\t}\n\n\tpublic setFontFeatureSettings(fontFeatureSettings: string): void {\n\t\tif (this._fontFeatureSettings === fontFeatureSettings) {\n\t\t\treturn;\n\t\t}\n\t\tthis._fontFeatureSettings = fontFeatureSettings;\n\t\tthis.domNode.style.fontFeatureSettings = this._fontFeatureSettings;\n\t}\n\n\tpublic setFontVariationSettings(fontVariationSettings: string): void {\n\t\tif (this._fontVariationSettings === fontVariationSettings) {\n\t\t\treturn;\n\t\t}\n\t\tthis._fontVariationSettings = fontVariationSettings;\n\t\tthis.domNode.style.fontVariationSettings = this._fontVariationSettings;\n\t}\n\n\tpublic setTextDecoration(textDecoration: string): void {\n\t\tif (this._textDecoration === textDecoration) {\n\t\t\treturn;\n\t\t}\n\t\tthis._textDecoration = textDecoration;\n\t\tthis.domNode.style.textDecoration = this._textDecoration;\n\t}\n\n\tpublic setLineHeight(_lineHeight: number | string): void {\n\t\tconst lineHeight = numberAsPixels(_lineHeight);\n\t\tif (this._lineHeight === lineHeight) {\n\t\t\treturn;\n\t\t}\n\t\tthis._lineHeight = lineHeight;\n\t\tthis.domNode.style.lineHeight = this._lineHeight;\n\t}\n\n\tpublic setLetterSpacing(_letterSpacing: number | string): void {\n\t\tconst letterSpacing = numberAsPixels(_letterSpacing);\n\t\tif (this._letterSpacing === letterSpacing) {\n\t\t\treturn;\n\t\t}\n\t\tthis._letterSpacing = letterSpacing;\n\t\tthis.domNode.style.letterSpacing = this._letterSpacing;\n\t}\n\n\tpublic setClassName(className: string): void {\n\t\tif (this._className === className) {\n\t\t\treturn;\n\t\t}\n\t\tthis._className = className;\n\t\tthis.domNode.className = this._className;\n\t}\n\n\tpublic toggleClassName(className: string, shouldHaveIt?: boolean): void {\n\t\tthis.domNode.classList.toggle(className, shouldHaveIt);\n\t\tthis._className = this.domNode.className;\n\t}\n\n\tpublic setDisplay(display: string): void {\n\t\tif (this._display === display) {\n\t\t\treturn;\n\t\t}\n\t\tthis._display = display;\n\t\tthis.domNode.style.display = this._display;\n\t}\n\n\tpublic setPosition(position: string): void {\n\t\tif (this._position === position) {\n\t\t\treturn;\n\t\t}\n\t\tthis._position = position;\n\t\tthis.domNode.style.position = this._position;\n\t}\n\n\tpublic setVisibility(visibility: string): void {\n\t\tif (this._visibility === visibility) {\n\t\t\treturn;\n\t\t}\n\t\tthis._visibility = visibility;\n\t\tthis.domNode.style.visibility = this._visibility;\n\t}\n\n\tpublic setColor(color: string): void {\n\t\tif (this._color === color) {\n\t\t\treturn;\n\t\t}\n\t\tthis._color = color;\n\t\tthis.domNode.style.color = this._color;\n\t}\n\n\tpublic setBackgroundColor(backgroundColor: string): void {\n\t\tif (this._backgroundColor === backgroundColor) {\n\t\t\treturn;\n\t\t}\n\t\tthis._backgroundColor = backgroundColor;\n\t\tthis.domNode.style.backgroundColor = this._backgroundColor;\n\t}\n\n\tpublic setLayerHinting(layerHint: boolean): void {\n\t\tif (this._layerHint === layerHint) {\n\t\t\treturn;\n\t\t}\n\t\tthis._layerHint = layerHint;\n\t\tthis.domNode.style.transform = this._layerHint ? 'translate3d(0px, 0px, 0px)' : '';\n\t}\n\n\tpublic setBoxShadow(boxShadow: string): void {\n\t\tif (this._boxShadow === boxShadow) {\n\t\t\treturn;\n\t\t}\n\t\tthis._boxShadow = boxShadow;\n\t\tthis.domNode.style.boxShadow = boxShadow;\n\t}\n\n\tpublic setContain(contain: 'none' | 'strict' | 'content' | 'size' | 'layout' | 'style' | 'paint'): void {\n\t\tif (this._contain === contain) {\n\t\t\treturn;\n\t\t}\n\t\tthis._contain = contain;\n\t\t(this.domNode.style).contain = this._contain;\n\t}\n\n\tpublic setAttribute(name: string, value: string): void {\n\t\tthis.domNode.setAttribute(name, value);\n\t}\n\n\tpublic removeAttribute(name: string): void {\n\t\tthis.domNode.removeAttribute(name);\n\t}\n\n\tpublic appendChild(child: FastDomNode): void {\n\t\tthis.domNode.appendChild(child.domNode);\n\t}\n\n\tpublic removeChild(child: FastDomNode): void {\n\t\tthis.domNode.removeChild(child.domNode);\n\t}\n}\n\nfunction numberAsPixels(value: number | string): string {\n\treturn (typeof value === 'number' ? `${value}px` : value);\n}\n\nexport function createFastDomNode(domNode: T): FastDomNode {\n\treturn new FastDomNode(domNode);\n}\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 * Represents a window in a possible chain of iframes\n */\ninterface IWindowChainElement {\n\t/**\n\t * The window object for it\n\t */\n\treadonly window: WeakRef;\n\t/**\n\t * The iframe element inside the window.parent corresponding to window\n\t */\n\treadonly iframeElement: Element | null;\n}\n\nconst sameOriginWindowChainCache = new WeakMap();\n\nfunction getParentWindowIfSameOrigin(w: Window): Window | null {\n\tif (!w.parent || w.parent === w) {\n\t\treturn null;\n\t}\n\n\t// Cannot really tell if we have access to the parent window unless we try to access something in it\n\ttry {\n\t\tconst location = w.location;\n\t\tconst parentLocation = w.parent.location;\n\t\tif (location.origin !== 'null' && parentLocation.origin !== 'null' && location.origin !== parentLocation.origin) {\n\t\t\treturn null;\n\t\t}\n\t} catch (e) {\n\t\treturn null;\n\t}\n\n\treturn w.parent;\n}\n\nexport class IframeUtils {\n\n\t/**\n\t * Returns a chain of embedded windows with the same origin (which can be accessed programmatically).\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.\n\t */\n\tprivate static getSameOriginWindowChain(targetWindow: Window): IWindowChainElement[] {\n\t\tlet windowChainCache = sameOriginWindowChainCache.get(targetWindow);\n\t\tif (!windowChainCache) {\n\t\t\twindowChainCache = [];\n\t\t\tsameOriginWindowChainCache.set(targetWindow, windowChainCache);\n\t\t\tlet w: Window | null = targetWindow;\n\t\t\tlet parent: Window | null;\n\t\t\tdo {\n\t\t\t\tparent = getParentWindowIfSameOrigin(w);\n\t\t\t\tif (parent) {\n\t\t\t\t\twindowChainCache.push({\n\t\t\t\t\t\twindow: new WeakRef(w),\n\t\t\t\t\t\tiframeElement: w.frameElement || null\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\twindowChainCache.push({\n\t\t\t\t\t\twindow: new WeakRef(w),\n\t\t\t\t\t\tiframeElement: null\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tw = parent;\n\t\t\t} while (w);\n\t\t}\n\t\treturn windowChainCache.slice(0);\n\t}\n\n\t/**\n\t * Returns the position of `childWindow` relative to `ancestorWindow`\n\t */\n\tpublic static getPositionOfChildWindowRelativeToAncestorWindow(childWindow: Window, ancestorWindow: Window | null) {\n\n\t\tif (!ancestorWindow || childWindow === ancestorWindow) {\n\t\t\treturn {\n\t\t\t\ttop: 0,\n\t\t\t\tleft: 0\n\t\t\t};\n\t\t}\n\n\t\tlet top = 0, left = 0;\n\n\t\tconst windowChain = this.getSameOriginWindowChain(childWindow);\n\n\t\tfor (const windowChainEl of windowChain) {\n\t\t\tconst windowInChain = windowChainEl.window.deref();\n\t\t\ttop += windowInChain?.scrollY ?? 0;\n\t\t\tleft += windowInChain?.scrollX ?? 0;\n\n\t\t\tif (windowInChain === ancestorWindow) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (!windowChainEl.iframeElement) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tconst boundingRect = windowChainEl.iframeElement.getBoundingClientRect();\n\t\t\ttop += boundingRect.top;\n\t\t\tleft += boundingRect.left;\n\t\t}\n\n\t\treturn {\n\t\t\ttop: top,\n\t\t\tleft: left\n\t\t};\n\t}\n}\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\nexport namespace inputLatency {\n\n\t// Measurements are recorded as totals, the average is calculated when the final measurements\n\t// are created.\n\tinterface ICumulativeMeasurement {\n\t\ttotal: number;\n\t\tmin: number;\n\t\tmax: number;\n\t}\n\tconst totalKeydownTime: ICumulativeMeasurement = { total: 0, min: Number.MAX_VALUE, max: 0 };\n\tconst totalInputTime: ICumulativeMeasurement = { ...totalKeydownTime };\n\tconst totalRenderTime: ICumulativeMeasurement = { ...totalKeydownTime };\n\tconst totalInputLatencyTime: ICumulativeMeasurement = { ...totalKeydownTime };\n\tlet measurementsCount = 0;\n\n\n\n\t// The state of each event, this helps ensure the integrity of the measurement and that\n\t// something unexpected didn't happen that could skew the measurement.\n\tconst enum EventPhase {\n\t\tBefore = 0,\n\t\tInProgress = 1,\n\t\tFinished = 2\n\t}\n\tconst state = {\n\t\tkeydown: EventPhase.Before,\n\t\tinput: EventPhase.Before,\n\t\trender: EventPhase.Before,\n\t};\n\n\t/**\n\t * Record the start of the keydown event.\n\t */\n\texport function onKeyDown() {\n\t\t/** Direct Check C. See explanation in {@link recordIfFinished} */\n\t\trecordIfFinished();\n\t\tperformance.mark('inputlatency/start');\n\t\tperformance.mark('keydown/start');\n\t\tstate.keydown = EventPhase.InProgress;\n\t\tqueueMicrotask(markKeyDownEnd);\n\t}\n\n\t/**\n\t * Mark the end of the keydown event.\n\t */\n\tfunction markKeyDownEnd() {\n\t\tif (state.keydown === EventPhase.InProgress) {\n\t\t\tperformance.mark('keydown/end');\n\t\t\tstate.keydown = EventPhase.Finished;\n\t\t}\n\t}\n\n\t/**\n\t * Record the start of the beforeinput event.\n\t */\n\texport function onBeforeInput() {\n\t\tperformance.mark('input/start');\n\t\tstate.input = EventPhase.InProgress;\n\t\t/** Schedule Task A. See explanation in {@link recordIfFinished} */\n\t\tscheduleRecordIfFinishedTask();\n\t}\n\n\t/**\n\t * Record the start of the input event.\n\t */\n\texport function onInput() {\n\t\tif (state.input === EventPhase.Before) {\n\t\t\t// it looks like we didn't receive a `beforeinput`\n\t\t\tonBeforeInput();\n\t\t}\n\t\tqueueMicrotask(markInputEnd);\n\t}\n\n\tfunction markInputEnd() {\n\t\tif (state.input === EventPhase.InProgress) {\n\t\t\tperformance.mark('input/end');\n\t\t\tstate.input = EventPhase.Finished;\n\t\t}\n\t}\n\n\t/**\n\t * Record the start of the keyup event.\n\t */\n\texport function onKeyUp() {\n\t\t/** Direct Check D. See explanation in {@link recordIfFinished} */\n\t\trecordIfFinished();\n\t}\n\n\t/**\n\t * Record the start of the selectionchange event.\n\t */\n\texport function onSelectionChange() {\n\t\t/** Direct Check E. See explanation in {@link recordIfFinished} */\n\t\trecordIfFinished();\n\t}\n\n\t/**\n\t * Record the start of the animation frame performing the rendering.\n\t */\n\texport function onRenderStart() {\n\t\t// Render may be triggered during input, but we only measure the following animation frame\n\t\tif (state.keydown === EventPhase.Finished && state.input === EventPhase.Finished && state.render === EventPhase.Before) {\n\t\t\t// Only measure the first render after keyboard input\n\t\t\tperformance.mark('render/start');\n\t\t\tstate.render = EventPhase.InProgress;\n\t\t\tqueueMicrotask(markRenderEnd);\n\t\t\t/** Schedule Task B. See explanation in {@link recordIfFinished} */\n\t\t\tscheduleRecordIfFinishedTask();\n\t\t}\n\t}\n\n\t/**\n\t * Mark the end of the animation frame performing the rendering.\n\t */\n\tfunction markRenderEnd() {\n\t\tif (state.render === EventPhase.InProgress) {\n\t\t\tperformance.mark('render/end');\n\t\t\tstate.render = EventPhase.Finished;\n\t\t}\n\t}\n\n\tfunction scheduleRecordIfFinishedTask() {\n\t\t// Here we can safely assume that the `setTimeout` will not be\n\t\t// artificially delayed by 4ms because we schedule it from\n\t\t// event handlers\n\t\tsetTimeout(recordIfFinished);\n\t}\n\n\t/**\n\t * Record the input latency sample if input handling and rendering are finished.\n\t *\n\t * The challenge here is that we want to record the latency in such a way that it includes\n\t * also the layout and painting work the browser does during the animation frame task.\n\t *\n\t * Simply scheduling a new task (via `setTimeout`) from the animation frame task would\n\t * schedule the new task at the end of the task queue (after other code that uses `setTimeout`),\n\t * so we need to use multiple strategies to make sure our task runs before others:\n\t *\n\t * We schedule tasks (A and B):\n\t * - we schedule a task A (via a `setTimeout` call) when the input starts in `markInputStart`.\n\t * If the animation frame task is scheduled quickly by the browser, then task A has a very good\n\t * chance of being the very first task after the animation frame and thus will record the input latency.\n\t * - however, if the animation frame task is scheduled a bit later, then task A might execute\n\t * before the animation frame task. We therefore schedule another task B from `markRenderStart`.\n\t *\n\t * We do direct checks in browser event handlers (C, D, E):\n\t * - if the browser has multiple keydown events queued up, they will be scheduled before the `setTimeout` tasks,\n\t * so we do a direct check in the keydown event handler (C).\n\t * - depending on timing, sometimes the animation frame is scheduled even before the `keyup` event, so we\n\t * do a direct check there too (E).\n\t * - the browser oftentimes emits a `selectionchange` event after an `input`, so we do a direct check there (D).\n\t */\n\tfunction recordIfFinished() {\n\t\tif (state.keydown === EventPhase.Finished && state.input === EventPhase.Finished && state.render === EventPhase.Finished) {\n\t\t\tperformance.mark('inputlatency/end');\n\n\t\t\tperformance.measure('keydown', 'keydown/start', 'keydown/end');\n\t\t\tperformance.measure('input', 'input/start', 'input/end');\n\t\t\tperformance.measure('render', 'render/start', 'render/end');\n\t\t\tperformance.measure('inputlatency', 'inputlatency/start', 'inputlatency/end');\n\n\t\t\taddMeasure('keydown', totalKeydownTime);\n\t\t\taddMeasure('input', totalInputTime);\n\t\t\taddMeasure('render', totalRenderTime);\n\t\t\taddMeasure('inputlatency', totalInputLatencyTime);\n\n\t\t\t// console.info(\n\t\t\t// \t`input latency=${performance.getEntriesByName('inputlatency')[0].duration.toFixed(1)} [` +\n\t\t\t// \t`keydown=${performance.getEntriesByName('keydown')[0].duration.toFixed(1)}, ` +\n\t\t\t// \t`input=${performance.getEntriesByName('input')[0].duration.toFixed(1)}, ` +\n\t\t\t// \t`render=${performance.getEntriesByName('render')[0].duration.toFixed(1)}` +\n\t\t\t// \t`]`\n\t\t\t// );\n\n\t\t\tmeasurementsCount++;\n\n\t\t\treset();\n\t\t}\n\t}\n\n\tfunction addMeasure(entryName: string, cumulativeMeasurement: ICumulativeMeasurement): void {\n\t\tconst duration = performance.getEntriesByName(entryName)[0].duration;\n\t\tcumulativeMeasurement.total += duration;\n\t\tcumulativeMeasurement.min = Math.min(cumulativeMeasurement.min, duration);\n\t\tcumulativeMeasurement.max = Math.max(cumulativeMeasurement.max, duration);\n\t}\n\n\t/**\n\t * Clear the current sample.\n\t */\n\tfunction reset() {\n\t\tperformance.clearMarks('keydown/start');\n\t\tperformance.clearMarks('keydown/end');\n\t\tperformance.clearMarks('input/start');\n\t\tperformance.clearMarks('input/end');\n\t\tperformance.clearMarks('render/start');\n\t\tperformance.clearMarks('render/end');\n\t\tperformance.clearMarks('inputlatency/start');\n\t\tperformance.clearMarks('inputlatency/end');\n\n\t\tperformance.clearMeasures('keydown');\n\t\tperformance.clearMeasures('input');\n\t\tperformance.clearMeasures('render');\n\t\tperformance.clearMeasures('inputlatency');\n\n\t\tstate.keydown = EventPhase.Before;\n\t\tstate.input = EventPhase.Before;\n\t\tstate.render = EventPhase.Before;\n\t}\n\n\texport interface IInputLatencyMeasurements {\n\t\tkeydown: IInputLatencySingleMeasurement;\n\t\tinput: IInputLatencySingleMeasurement;\n\t\trender: IInputLatencySingleMeasurement;\n\t\ttotal: IInputLatencySingleMeasurement;\n\t\tsampleCount: number;\n\t}\n\n\texport interface IInputLatencySingleMeasurement {\n\t\taverage: number;\n\t\tmin: number;\n\t\tmax: number;\n\t}\n\n\t/**\n\t * Gets all input latency samples and clears the internal buffers to start recording a new set\n\t * of samples.\n\t */\n\texport function getAndClearMeasurements(): IInputLatencyMeasurements | undefined {\n\t\tif (measurementsCount === 0) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\t// Assemble the result\n\t\tconst result = {\n\t\t\tkeydown: cumulativeToFinalMeasurement(totalKeydownTime),\n\t\t\tinput: cumulativeToFinalMeasurement(totalInputTime),\n\t\t\trender: cumulativeToFinalMeasurement(totalRenderTime),\n\t\t\ttotal: cumulativeToFinalMeasurement(totalInputLatencyTime),\n\t\t\tsampleCount: measurementsCount\n\t\t};\n\n\t\t// Clear the cumulative measurements\n\t\tclearCumulativeMeasurement(totalKeydownTime);\n\t\tclearCumulativeMeasurement(totalInputTime);\n\t\tclearCumulativeMeasurement(totalRenderTime);\n\t\tclearCumulativeMeasurement(totalInputLatencyTime);\n\t\tmeasurementsCount = 0;\n\n\t\treturn result;\n\t}\n\n\tfunction cumulativeToFinalMeasurement(cumulative: ICumulativeMeasurement): IInputLatencySingleMeasurement {\n\t\treturn {\n\t\t\taverage: cumulative.total / measurementsCount,\n\t\t\tmax: cumulative.max,\n\t\t\tmin: cumulative.min,\n\t\t};\n\t}\n\n\tfunction clearCumulativeMeasurement(cumulative: ICumulativeMeasurement): void {\n\t\tcumulative.total = 0;\n\t\tcumulative.min = Number.MAX_VALUE;\n\t\tcumulative.max = 0;\n\t}\n\n}\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\nimport { IHoverDelegate2 } from 'vs/base/browser/ui/hover/hover';\n\nlet baseHoverDelegate: IHoverDelegate2 = {\n\tshowHover: () => undefined,\n\thideHover: () => undefined,\n\tshowAndFocusLastHover: () => undefined,\n\tsetupUpdatableHover: () => null!,\n\ttriggerUpdatableHover: () => undefined\n};\n\n/**\n * Sets the hover delegate for use **only in the `base/` layer**.\n */\nexport function setBaseLayerHoverDelegate(hoverDelegate: IHoverDelegate2): void {\n\tbaseHoverDelegate = hoverDelegate;\n}\n\n/**\n * Gets the hover delegate for use **only in the `base/` layer**.\n *\n * Since the hover service depends on various platform services, this delegate essentially bypasses\n * the standard dependency injection mechanism by injecting a global hover service at start up. The\n * only reason this should be used is if `IHoverService` is not available.\n */\nexport function getBaseLayerHoverDelegate(): IHoverDelegate2 {\n\treturn baseHoverDelegate;\n}\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\nimport { IDragAndDropData } from 'vs/base/browser/dnd';\nimport { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';\nimport { IMouseEvent } from 'vs/base/browser/mouseEvent';\nimport { GestureEvent } from 'vs/base/browser/touch';\nimport { ListViewTargetSector } from 'vs/base/browser/ui/list/listView';\nimport { IDisposable } from 'vs/base/common/lifecycle';\n\nexport interface IListVirtualDelegate {\n\tgetHeight(element: T): number;\n\tgetTemplateId(element: T): string;\n\thasDynamicHeight?(element: T): boolean;\n\tgetDynamicHeight?(element: T): number | null;\n\tsetDynamicHeight?(element: T, height: number): void;\n}\n\nexport interface IListRenderer {\n\treadonly templateId: string;\n\trenderTemplate(container: HTMLElement): TTemplateData;\n\trenderElement(element: T, index: number, templateData: TTemplateData, height: number | undefined): void;\n\tdisposeElement?(element: T, index: number, templateData: TTemplateData, height: number | undefined): void;\n\tdisposeTemplate(templateData: TTemplateData): void;\n}\n\nexport interface IListEvent {\n\treadonly elements: readonly T[];\n\treadonly indexes: readonly number[];\n\treadonly browserEvent?: UIEvent;\n}\n\nexport interface IListBrowserMouseEvent extends MouseEvent {\n\tisHandledByList?: boolean;\n}\n\nexport interface IListMouseEvent {\n\treadonly browserEvent: IListBrowserMouseEvent;\n\treadonly element: T | undefined;\n\treadonly index: number | undefined;\n}\n\nexport interface IListTouchEvent {\n\treadonly browserEvent: TouchEvent;\n\treadonly element: T | undefined;\n\treadonly index: number | undefined;\n}\n\nexport interface IListGestureEvent {\n\treadonly browserEvent: GestureEvent;\n\treadonly element: T | undefined;\n\treadonly index: number | undefined;\n}\n\nexport interface IListDragEvent {\n\treadonly browserEvent: DragEvent;\n\treadonly element: T | undefined;\n\treadonly index: number | undefined;\n\treadonly sector: ListViewTargetSector | undefined;\n}\n\nexport interface IListContextMenuEvent {\n\treadonly browserEvent: UIEvent;\n\treadonly element: T | undefined;\n\treadonly index: number | undefined;\n\treadonly anchor: HTMLElement | IMouseEvent;\n}\n\nexport interface IIdentityProvider {\n\tgetId(element: T): { toString(): string };\n}\n\nexport interface IKeyboardNavigationLabelProvider {\n\n\t/**\n\t * Return a keyboard navigation label(s) which will be used by\n\t * the list for filtering/navigating. Return `undefined` to make\n\t * an element always match.\n\t */\n\tgetKeyboardNavigationLabel(element: T): { toString(): string | undefined } | { toString(): string | undefined }[] | undefined;\n}\n\nexport interface IKeyboardNavigationDelegate {\n\tmightProducePrintableCharacter(event: IKeyboardEvent): boolean;\n}\n\nexport const enum ListDragOverEffectType {\n\tCopy,\n\tMove\n}\n\nexport const enum ListDragOverEffectPosition {\n\tOver = 'drop-target',\n\tBefore = 'drop-target-before',\n\tAfter = 'drop-target-after'\n}\n\nexport interface ListDragOverEffect {\n\ttype: ListDragOverEffectType;\n\tposition?: ListDragOverEffectPosition;\n}\n\nexport interface IListDragOverReaction {\n\taccept: boolean;\n\teffect?: ListDragOverEffect;\n\tfeedback?: number[]; // use -1 for entire list\n}\n\n/**\n * Warning: Once passed to a list, that list takes up\n * the responsibility of disposing it.\n */\nexport interface IListDragAndDrop extends IDisposable {\n\tgetDragURI(element: T): string | null;\n\tgetDragLabel?(elements: T[], originalEvent: DragEvent): string | undefined;\n\tonDragStart?(data: IDragAndDropData, originalEvent: DragEvent): void;\n\tonDragOver(data: IDragAndDropData, targetElement: T | undefined, targetIndex: number | undefined, targetSector: ListViewTargetSector | undefined, originalEvent: DragEvent): boolean | IListDragOverReaction;\n\tonDragLeave?(data: IDragAndDropData, targetElement: T | undefined, targetIndex: number | undefined, originalEvent: DragEvent): void;\n\tdrop(data: IDragAndDropData, targetElement: T | undefined, targetIndex: number | undefined, targetSector: ListViewTargetSector | undefined, originalEvent: DragEvent): void;\n\tonDragEnd?(originalEvent: DragEvent): void;\n}\n\nexport class ListError extends Error {\n\n\tconstructor(user: string, message: string) {\n\t\tsuper(`ListError [${user}] ${message}`);\n\t}\n}\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\nimport { ISpliceable } from 'vs/base/common/sequence';\n\nexport class CombinedSpliceable implements ISpliceable {\n\n\tconstructor(private spliceables: ISpliceable[]) { }\n\n\tsplice(start: number, deleteCount: number, elements: T[]): void {\n\t\tthis.spliceables.forEach(s => s.splice(start, deleteCount, elements));\n\t}\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 * The minimal size of the slider (such that it can still be clickable) -- it is artificially enlarged.\n */\nconst MINIMUM_SLIDER_SIZE = 20;\n\nexport class ScrollbarState {\n\n\t/**\n\t * For the vertical scrollbar: the width.\n\t * For the horizontal scrollbar: the height.\n\t */\n\tprivate _scrollbarSize: number;\n\n\t/**\n\t * For the vertical scrollbar: the height of the pair horizontal scrollbar.\n\t * For the horizontal scrollbar: the width of the pair vertical scrollbar.\n\t */\n\tprivate _oppositeScrollbarSize: number;\n\n\t/**\n\t * For the vertical scrollbar: the height of the scrollbar's arrows.\n\t * For the horizontal scrollbar: the width of the scrollbar's arrows.\n\t */\n\tprivate readonly _arrowSize: number;\n\n\t// --- variables\n\t/**\n\t * For the vertical scrollbar: the viewport height.\n\t * For the horizontal scrollbar: the viewport width.\n\t */\n\tprivate _visibleSize: number;\n\n\t/**\n\t * For the vertical scrollbar: the scroll height.\n\t * For the horizontal scrollbar: the scroll width.\n\t */\n\tprivate _scrollSize: number;\n\n\t/**\n\t * For the vertical scrollbar: the scroll top.\n\t * For the horizontal scrollbar: the scroll left.\n\t */\n\tprivate _scrollPosition: number;\n\n\t// --- computed variables\n\n\t/**\n\t * `visibleSize` - `oppositeScrollbarSize`\n\t */\n\tprivate _computedAvailableSize: number;\n\t/**\n\t * (`scrollSize` > 0 && `scrollSize` > `visibleSize`)\n\t */\n\tprivate _computedIsNeeded: boolean;\n\n\tprivate _computedSliderSize: number;\n\tprivate _computedSliderRatio: number;\n\tprivate _computedSliderPosition: number;\n\n\tconstructor(arrowSize: number, scrollbarSize: number, oppositeScrollbarSize: number, visibleSize: number, scrollSize: number, scrollPosition: number) {\n\t\tthis._scrollbarSize = Math.round(scrollbarSize);\n\t\tthis._oppositeScrollbarSize = Math.round(oppositeScrollbarSize);\n\t\tthis._arrowSize = Math.round(arrowSize);\n\n\t\tthis._visibleSize = visibleSize;\n\t\tthis._scrollSize = scrollSize;\n\t\tthis._scrollPosition = scrollPosition;\n\n\t\tthis._computedAvailableSize = 0;\n\t\tthis._computedIsNeeded = false;\n\t\tthis._computedSliderSize = 0;\n\t\tthis._computedSliderRatio = 0;\n\t\tthis._computedSliderPosition = 0;\n\n\t\tthis._refreshComputedValues();\n\t}\n\n\tpublic clone(): ScrollbarState {\n\t\treturn new ScrollbarState(this._arrowSize, this._scrollbarSize, this._oppositeScrollbarSize, this._visibleSize, this._scrollSize, this._scrollPosition);\n\t}\n\n\tpublic setVisibleSize(visibleSize: number): boolean {\n\t\tconst iVisibleSize = Math.round(visibleSize);\n\t\tif (this._visibleSize !== iVisibleSize) {\n\t\t\tthis._visibleSize = iVisibleSize;\n\t\t\tthis._refreshComputedValues();\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tpublic setScrollSize(scrollSize: number): boolean {\n\t\tconst iScrollSize = Math.round(scrollSize);\n\t\tif (this._scrollSize !== iScrollSize) {\n\t\t\tthis._scrollSize = iScrollSize;\n\t\t\tthis._refreshComputedValues();\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tpublic setScrollPosition(scrollPosition: number): boolean {\n\t\tconst iScrollPosition = Math.round(scrollPosition);\n\t\tif (this._scrollPosition !== iScrollPosition) {\n\t\t\tthis._scrollPosition = iScrollPosition;\n\t\t\tthis._refreshComputedValues();\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tpublic setScrollbarSize(scrollbarSize: number): void {\n\t\tthis._scrollbarSize = Math.round(scrollbarSize);\n\t}\n\n\tpublic setOppositeScrollbarSize(oppositeScrollbarSize: number): void {\n\t\tthis._oppositeScrollbarSize = Math.round(oppositeScrollbarSize);\n\t}\n\n\tprivate static _computeValues(oppositeScrollbarSize: number, arrowSize: number, visibleSize: number, scrollSize: number, scrollPosition: number) {\n\t\tconst computedAvailableSize = Math.max(0, visibleSize - oppositeScrollbarSize);\n\t\tconst computedRepresentableSize = Math.max(0, computedAvailableSize - 2 * arrowSize);\n\t\tconst computedIsNeeded = (scrollSize > 0 && scrollSize > visibleSize);\n\n\t\tif (!computedIsNeeded) {\n\t\t\t// There is no need for a slider\n\t\t\treturn {\n\t\t\t\tcomputedAvailableSize: Math.round(computedAvailableSize),\n\t\t\t\tcomputedIsNeeded: computedIsNeeded,\n\t\t\t\tcomputedSliderSize: Math.round(computedRepresentableSize),\n\t\t\t\tcomputedSliderRatio: 0,\n\t\t\t\tcomputedSliderPosition: 0,\n\t\t\t};\n\t\t}\n\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\n\t\tconst computedSliderSize = Math.round(Math.max(MINIMUM_SLIDER_SIZE, Math.floor(visibleSize * computedRepresentableSize / scrollSize)));\n\n\t\t// The slider can move from 0 to `computedRepresentableSize` - `computedSliderSize`\n\t\t// in the same way `scrollPosition` can move from 0 to `scrollSize` - `visibleSize`.\n\t\tconst computedSliderRatio = (computedRepresentableSize - computedSliderSize) / (scrollSize - visibleSize);\n\t\tconst computedSliderPosition = (scrollPosition * computedSliderRatio);\n\n\t\treturn {\n\t\t\tcomputedAvailableSize: Math.round(computedAvailableSize),\n\t\t\tcomputedIsNeeded: computedIsNeeded,\n\t\t\tcomputedSliderSize: Math.round(computedSliderSize),\n\t\t\tcomputedSliderRatio: computedSliderRatio,\n\t\t\tcomputedSliderPosition: Math.round(computedSliderPosition),\n\t\t};\n\t}\n\n\tprivate _refreshComputedValues(): void {\n\t\tconst r = ScrollbarState._computeValues(this._oppositeScrollbarSize, this._arrowSize, this._visibleSize, this._scrollSize, this._scrollPosition);\n\t\tthis._computedAvailableSize = r.computedAvailableSize;\n\t\tthis._computedIsNeeded = r.computedIsNeeded;\n\t\tthis._computedSliderSize = r.computedSliderSize;\n\t\tthis._computedSliderRatio = r.computedSliderRatio;\n\t\tthis._computedSliderPosition = r.computedSliderPosition;\n\t}\n\n\tpublic getArrowSize(): number {\n\t\treturn this._arrowSize;\n\t}\n\n\tpublic getScrollPosition(): number {\n\t\treturn this._scrollPosition;\n\t}\n\n\tpublic getRectangleLargeSize(): number {\n\t\treturn this._computedAvailableSize;\n\t}\n\n\tpublic getRectangleSmallSize(): number {\n\t\treturn this._scrollbarSize;\n\t}\n\n\tpublic isNeeded(): boolean {\n\t\treturn this._computedIsNeeded;\n\t}\n\n\tpublic getSliderSize(): number {\n\t\treturn this._computedSliderSize;\n\t}\n\n\tpublic getSliderPosition(): number {\n\t\treturn this._computedSliderPosition;\n\t}\n\n\t/**\n\t * Compute a desired `scrollPosition` such that `offset` ends up in the center of the slider.\n\t * `offset` is based on the same coordinate system as the `sliderPosition`.\n\t */\n\tpublic getDesiredScrollPositionFromOffset(offset: number): number {\n\t\tif (!this._computedIsNeeded) {\n\t\t\t// no need for a slider\n\t\t\treturn 0;\n\t\t}\n\n\t\tconst desiredSliderPosition = offset - this._arrowSize - this._computedSliderSize / 2;\n\t\treturn Math.round(desiredSliderPosition / this._computedSliderRatio);\n\t}\n\n\t/**\n\t * Compute a desired `scrollPosition` from if offset is before or after the slider position.\n\t * If offset is before slider, treat as a page up (or left). If after, page down (or right).\n\t * `offset` and `_computedSliderPosition` are based on the same coordinate system.\n\t * `_visibleSize` corresponds to a \"page\" of lines in the returned coordinate system.\n\t */\n\tpublic getDesiredScrollPositionFromOffsetPaged(offset: number): number {\n\t\tif (!this._computedIsNeeded) {\n\t\t\t// no need for a slider\n\t\t\treturn 0;\n\t\t}\n\n\t\tconst correctedOffset = offset - this._arrowSize; // compensate if has arrows\n\t\tlet desiredScrollPosition = this._scrollPosition;\n\t\tif (correctedOffset < this._computedSliderPosition) {\n\t\t\tdesiredScrollPosition -= this._visibleSize; // page up/left\n\t\t} else {\n\t\t\tdesiredScrollPosition += this._visibleSize; // page down/right\n\t\t}\n\t\treturn desiredScrollPosition;\n\t}\n\n\t/**\n\t * Compute a desired `scrollPosition` such that the slider moves by `delta`.\n\t */\n\tpublic getDesiredScrollPositionFromDelta(delta: number): number {\n\t\tif (!this._computedIsNeeded) {\n\t\t\t// no need for a slider\n\t\t\treturn 0;\n\t\t}\n\n\t\tconst desiredSliderPosition = this._computedSliderPosition + delta;\n\t\treturn Math.round(desiredSliderPosition / this._computedSliderRatio);\n\t}\n}\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\nimport { IDragAndDropData } from 'vs/base/browser/dnd';\nimport { IMouseEvent } from 'vs/base/browser/mouseEvent';\nimport { IListDragAndDrop, IListDragOverReaction, IListRenderer } from 'vs/base/browser/ui/list/list';\nimport { ListViewTargetSector } from 'vs/base/browser/ui/list/listView';\nimport { Event } from 'vs/base/common/event';\n\nexport const enum TreeVisibility {\n\n\t/**\n\t * The tree node should be hidden.\n\t */\n\tHidden,\n\n\t/**\n\t * The tree node should be visible.\n\t */\n\tVisible,\n\n\t/**\n\t * The tree node should be visible if any of its descendants is visible.\n\t */\n\tRecurse\n}\n\n/**\n * A composed filter result containing the visibility result as well as\n * metadata.\n */\nexport interface ITreeFilterDataResult {\n\n\t/**\n\t * Whether the node should be visible.\n\t */\n\tvisibility: boolean | TreeVisibility;\n\n\t/**\n\t * Metadata about the element's visibility which gets forwarded to the\n\t * renderer once the element gets rendered.\n\t */\n\tdata: TFilterData;\n}\n\n/**\n * The result of a filter call can be a boolean value indicating whether\n * the element should be visible or not, a value of type `TreeVisibility` or\n * an object composed of the visibility result as well as additional metadata\n * which gets forwarded to the renderer once the element gets rendered.\n */\nexport type TreeFilterResult = boolean | TreeVisibility | ITreeFilterDataResult;\n\n/**\n * A tree filter is responsible for controlling the visibility of\n * elements in a tree.\n */\nexport interface ITreeFilter {\n\n\t/**\n\t * Returns whether this elements should be visible and, if affirmative,\n\t * additional metadata which gets forwarded to the renderer once the element\n\t * gets rendered.\n\t *\n\t * @param element The tree element.\n\t */\n\tfilter(element: T, parentVisibility: TreeVisibility): TreeFilterResult;\n}\n\nexport interface ITreeSorter {\n\tcompare(element: T, otherElement: T): number;\n}\n\nexport interface ITreeElement {\n\treadonly element: T;\n\treadonly children?: Iterable>;\n\treadonly collapsible?: boolean;\n\treadonly collapsed?: boolean;\n}\n\nexport enum ObjectTreeElementCollapseState {\n\tExpanded,\n\tCollapsed,\n\n\t/**\n\t * If the element is already in the tree, preserve its current state. Else, expand it.\n\t */\n\tPreserveOrExpanded,\n\n\t/**\n\t * If the element is already in the tree, preserve its current state. Else, collapse it.\n\t */\n\tPreserveOrCollapsed,\n}\n\nexport interface IObjectTreeElement {\n\treadonly element: T;\n\treadonly children?: Iterable>;\n\treadonly collapsible?: boolean;\n\treadonly collapsed?: boolean | ObjectTreeElementCollapseState;\n}\n\nexport interface ITreeNode {\n\treadonly element: T;\n\treadonly children: ITreeNode[];\n\treadonly depth: number;\n\treadonly visibleChildrenCount: number;\n\treadonly visibleChildIndex: number;\n\treadonly collapsible: boolean;\n\treadonly collapsed: boolean;\n\treadonly visible: boolean;\n\treadonly filterData: TFilterData | undefined;\n}\n\nexport interface ICollapseStateChangeEvent {\n\tnode: ITreeNode;\n\tdeep: boolean;\n}\n\nexport interface ITreeModelSpliceEvent {\n\tinsertedNodes: ITreeNode[];\n\tdeletedNodes: ITreeNode[];\n}\n\nexport interface ITreeModel {\n\n\treadonly onDidSplice: Event>;\n\treadonly onDidChangeCollapseState: Event>;\n\n\thas(location: TRef): boolean;\n\n\tgetListIndex(location: TRef): number;\n\tgetListRenderCount(location: TRef): number;\n\tgetNode(location?: TRef): ITreeNode;\n\tgetNodeLocation(node: ITreeNode): TRef;\n\tgetParentNodeLocation(location: TRef): TRef | undefined;\n\n\tgetFirstElementChild(location: TRef): T | undefined;\n\n\tisCollapsible(location: TRef): boolean;\n\tsetCollapsible(location: TRef, collapsible?: boolean): boolean;\n\tisCollapsed(location: TRef): boolean;\n\tsetCollapsed(location: TRef, collapsed?: boolean, recursive?: boolean): boolean;\n\texpandTo(location: TRef): void;\n\n\trerender(location: TRef): void;\n\trefilter(): void;\n}\n\nexport interface ITreeRenderer extends IListRenderer, TTemplateData> {\n\trenderTwistie?(element: T, twistieElement: HTMLElement): boolean;\n\tonDidChangeTwistieState?: Event;\n}\n\nexport interface ITreeEvent {\n\treadonly elements: readonly T[];\n\treadonly browserEvent?: UIEvent;\n}\n\nexport enum TreeMouseEventTarget {\n\tUnknown,\n\tTwistie,\n\tElement,\n\tFilter\n}\n\nexport interface ITreeMouseEvent {\n\treadonly browserEvent: MouseEvent;\n\treadonly element: T | null;\n\treadonly target: TreeMouseEventTarget;\n}\n\nexport interface ITreeContextMenuEvent {\n\treadonly browserEvent: UIEvent;\n\treadonly element: T | null;\n\treadonly anchor: HTMLElement | IMouseEvent;\n\treadonly isStickyScroll: boolean;\n}\n\nexport interface IDataSource {\n}\n\nexport interface IAsyncDataSource {\n\thasChildren(element: TInput | T): boolean;\n\tgetChildren(element: TInput | T): Iterable | Promise>;\n}\n\nexport const enum TreeDragOverBubble {\n\tDown,\n\tUp\n}\n\nexport interface ITreeDragOverReaction extends IListDragOverReaction {\n\tbubble?: TreeDragOverBubble;\n\tautoExpand?: boolean;\n}\n\nexport interface ITreeDragAndDrop extends IListDragAndDrop {\n\tonDragOver(data: IDragAndDropData, targetElement: T | undefined, targetIndex: number | undefined, targetSector: ListViewTargetSector | undefined, originalEvent: DragEvent): boolean | ITreeDragOverReaction;\n}\n\nexport class TreeError extends Error {\n\n\tconstructor(user: string, message: string) {\n\t\tsuper(`TreeError [${user}] ${message}`);\n\t}\n}\n\nexport class WeakMapper {\n\n\tconstructor(private fn: (k: K) => V) { }\n\n\tprivate _map = new WeakMap();\n\n\tmap(key: K): V {\n\t\tlet result = this._map.get(key);\n\n\t\tif (!result) {\n\t\t\tresult = this.fn(key);\n\t\t\tthis._map.set(key, result);\n\t\t}\n\n\t\treturn result;\n\t}\n}\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\nexport type CodeWindow = Window & typeof globalThis & {\n\treadonly vscodeWindowId: number;\n};\n\nexport function ensureCodeWindow(targetWindow: Window, fallbackWindowId: number): asserts targetWindow is CodeWindow {\n\tconst codeWindow = targetWindow as Partial;\n\n\tif (typeof codeWindow.vscodeWindowId !== 'number') {\n\t\tObject.defineProperty(codeWindow, 'vscodeWindowId', {\n\t\t\tget: () => fallbackWindowId\n\t\t});\n\t}\n}\n\n// eslint-disable-next-line no-restricted-globals\nexport const mainWindow = window as CodeWindow;\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\nimport { CodeWindow, mainWindow } from 'vs/base/browser/window';\n\nclass WindowManager {\n\n\tstatic readonly INSTANCE = new WindowManager();\n\n\t// --- Zoom Factor\n\n\tprivate readonly mapWindowIdToZoomFactor = new Map();\n\n\tgetZoomFactor(targetWindow: Window): number {\n\t\treturn this.mapWindowIdToZoomFactor.get(this.getWindowId(targetWindow)) ?? 1;\n\t}\n\n\tprivate getWindowId(targetWindow: Window): number {\n\t\treturn (targetWindow as CodeWindow).vscodeWindowId;\n\t}\n}\n\nexport function addMatchMediaChangeListener(targetWindow: Window, query: string | MediaQueryList, callback: (this: MediaQueryList, ev: MediaQueryListEvent) => any): void {\n\tif (typeof query === 'string') {\n\t\tquery = targetWindow.matchMedia(query);\n\t}\n\tquery.addEventListener('change', callback);\n}\n\n/** The zoom scale for an index, e.g. 1, 1.2, 1.4 */\nexport function getZoomFactor(targetWindow: Window): number {\n\treturn WindowManager.INSTANCE.getZoomFactor(targetWindow);\n}\n\nconst userAgent = navigator.userAgent;\n\nexport const isFirefox = (userAgent.indexOf('Firefox') >= 0);\nexport const isWebKit = (userAgent.indexOf('AppleWebKit') >= 0);\nexport const isChrome = (userAgent.indexOf('Chrome') >= 0);\nexport const isSafari = (!isChrome && (userAgent.indexOf('Safari') >= 0));\nexport const isWebkitWebView = (!isChrome && !isSafari && isWebKit);\nexport const isElectron = (userAgent.indexOf('Electron/') >= 0);\nexport const isAndroid = (userAgent.indexOf('Android') >= 0);\n\nlet standalone = false;\nif (typeof mainWindow.matchMedia === 'function') {\n\tconst standaloneMatchMedia = mainWindow.matchMedia('(display-mode: standalone) or (display-mode: window-controls-overlay)');\n\tconst fullScreenMatchMedia = mainWindow.matchMedia('(display-mode: fullscreen)');\n\tstandalone = standaloneMatchMedia.matches;\n\taddMatchMediaChangeListener(mainWindow, standaloneMatchMedia, ({ matches }) => {\n\t\t// entering fullscreen would change standaloneMatchMedia.matches to false\n\t\t// if standalone is true (running as PWA) and entering fullscreen, skip this change\n\t\tif (standalone && fullScreenMatchMedia.matches) {\n\t\t\treturn;\n\t\t}\n\t\t// otherwise update standalone (browser to PWA or PWA to browser)\n\t\tstandalone = matches;\n\t});\n}\nexport function isStandalone(): boolean {\n\treturn standalone;\n}\n","\n\n/**\n * Returns the last element of an array.\n * @param array The array.\n * @param n Which element from the end (default is zero).\n */\nexport function tail(array: ArrayLike, n: number = 0): T | undefined {\n\treturn array[array.length - (1 + n)];\n}\n\nexport function tail2(arr: T[]): [T[], T] {\n\tif (arr.length === 0) {\n\t\tthrow new Error('Invalid tail call');\n\t}\n\n\treturn [arr.slice(0, arr.length - 1), arr[arr.length - 1]];\n}\n\nexport function equals(one: ReadonlyArray | undefined, other: ReadonlyArray | undefined, itemEquals: (a: T, b: T) => boolean = (a, b) => a === b): boolean {\n\tif (one === other) {\n\t\treturn true;\n\t}\n\n\tif (!one || !other) {\n\t\treturn false;\n\t}\n\n\tif (one.length !== other.length) {\n\t\treturn false;\n\t}\n\n\tfor (let i = 0, len = one.length; i < len; i++) {\n\t\tif (!itemEquals(one[i], other[i])) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\treturn true;\n}\n\n/**\n * Remove the element at `index` by replacing it with the last element. This is faster than `splice`\n * but changes the order of the array\n */\nexport function removeFastWithoutKeepingOrder(array: T[], index: number) {\n\tconst last = array.length - 1;\n\tif (index < last) {\n\t\tarray[index] = array[last];\n\t}\n\tarray.pop();\n}\n\n/**\n * Performs a binary search algorithm over a sorted array.\n *\n * @param array The array being searched.\n * @param key The value we search for.\n * @param comparator A function that takes two array elements and returns zero\n * if they are equal, a negative number if the first element precedes the\n * second one in the sorting order, or a positive number if the second element\n * precedes the first one.\n * @return See {@link binarySearch2}\n */\nexport function binarySearch(array: ReadonlyArray, key: T, comparator: (op1: T, op2: T) => number): number {\n\treturn binarySearch2(array.length, i => comparator(array[i], key));\n}\n\n/**\n * Performs a binary search algorithm over a sorted collection. Useful for cases\n * when we need to perform a binary search over something that isn't actually an\n * array, and converting data to an array would defeat the use of binary search\n * in the first place.\n *\n * @param length The collection length.\n * @param compareToKey A function that takes an index of an element in the\n * collection and returns zero if the value at this index is equal to the\n * search key, a negative number if the value precedes the search key in the\n * sorting order, or a positive number if the search key precedes the value.\n * @return A non-negative index of an element, if found. If not found, the\n * result is -(n+1) (or ~n, using bitwise notation), where n is the index\n * where the key should be inserted to maintain the sorting order.\n */\nexport function binarySearch2(length: number, compareToKey: (index: number) => number): number {\n\tlet low = 0,\n\t\thigh = length - 1;\n\n\twhile (low <= high) {\n\t\tconst mid = ((low + high) / 2) | 0;\n\t\tconst comp = compareToKey(mid);\n\t\tif (comp < 0) {\n\t\t\tlow = mid + 1;\n\t\t} else if (comp > 0) {\n\t\t\thigh = mid - 1;\n\t\t} else {\n\t\t\treturn mid;\n\t\t}\n\t}\n\treturn -(low + 1);\n}\n\ntype Compare = (a: T, b: T) => number;\n\n\nexport function quickSelect(nth: number, data: T[], compare: Compare): T {\n\n\tnth = nth | 0;\n\n\tif (nth >= data.length) {\n\t\tthrow new TypeError('invalid index');\n\t}\n\n\tconst pivotValue = data[Math.floor(data.length * Math.random())];\n\tconst lower: T[] = [];\n\tconst higher: T[] = [];\n\tconst pivots: T[] = [];\n\n\tfor (const value of data) {\n\t\tconst val = compare(value, pivotValue);\n\t\tif (val < 0) {\n\t\t\tlower.push(value);\n\t\t} else if (val > 0) {\n\t\t\thigher.push(value);\n\t\t} else {\n\t\t\tpivots.push(value);\n\t\t}\n\t}\n\n\tif (nth < lower.length) {\n\t\treturn quickSelect(nth, lower, compare);\n\t} else if (nth < lower.length + pivots.length) {\n\t\treturn pivots[0];\n\t} else {\n\t\treturn quickSelect(nth - (lower.length + pivots.length), higher, compare);\n\t}\n}\n\nexport function groupBy(data: ReadonlyArray, compare: (a: T, b: T) => number): T[][] {\n\tconst result: T[][] = [];\n\tlet currentGroup: T[] | undefined = undefined;\n\tfor (const element of data.slice(0).sort(compare)) {\n\t\tif (!currentGroup || compare(currentGroup[0], element) !== 0) {\n\t\t\tcurrentGroup = [element];\n\t\t\tresult.push(currentGroup);\n\t\t} else {\n\t\t\tcurrentGroup.push(element);\n\t\t}\n\t}\n\treturn result;\n}\n\n/**\n * Splits the given items into a list of (non-empty) groups.\n * `shouldBeGrouped` is used to decide if two consecutive items should be in the same group.\n * The order of the items is preserved.\n */\nexport function* groupAdjacentBy(items: Iterable, shouldBeGrouped: (item1: T, item2: T) => boolean): Iterable {\n\tlet currentGroup: T[] | undefined;\n\tlet last: T | undefined;\n\tfor (const item of items) {\n\t\tif (last !== undefined && shouldBeGrouped(last, item)) {\n\t\t\tcurrentGroup!.push(item);\n\t\t} else {\n\t\t\tif (currentGroup) {\n\t\t\t\tyield currentGroup;\n\t\t\t}\n\t\t\tcurrentGroup = [item];\n\t\t}\n\t\tlast = item;\n\t}\n\tif (currentGroup) {\n\t\tyield currentGroup;\n\t}\n}\n\nexport function forEachAdjacent(arr: T[], f: (item1: T | undefined, item2: T | undefined) => void): void {\n\tfor (let i = 0; i <= arr.length; i++) {\n\t\tf(i === 0 ? undefined : arr[i - 1], i === arr.length ? undefined : arr[i]);\n\t}\n}\n\nexport function forEachWithNeighbors(arr: T[], f: (before: T | undefined, element: T, after: T | undefined) => void): void {\n\tfor (let i = 0; i < arr.length; i++) {\n\t\tf(i === 0 ? undefined : arr[i - 1], arr[i], i + 1 === arr.length ? undefined : arr[i + 1]);\n\t}\n}\n\n/**\n * @returns New array with all falsy values removed. The original array IS NOT modified.\n */\nexport function coalesce(array: ReadonlyArray): T[] {\n\treturn array.filter((e): e is T => !!e);\n}\n\n/**\n * Remove all falsy values from `array`. The original array IS modified.\n */\nexport function coalesceInPlace(array: Array): asserts array is Array {\n\tlet to = 0;\n\tfor (let i = 0; i < array.length; i++) {\n\t\tif (!!array[i]) {\n\t\t\tarray[to] = array[i];\n\t\t\tto += 1;\n\t\t}\n\t}\n\tarray.length = to;\n}\n\n/**\n * @returns false if the provided object is an array and not empty.\n */\nexport function isFalsyOrEmpty(obj: any): boolean {\n\treturn !Array.isArray(obj) || obj.length === 0;\n}\n\n/**\n * @returns True if the provided object is an array and has at least one element.\n */\nexport function isNonEmptyArray(obj: T[] | undefined | null): obj is T[];\nexport function isNonEmptyArray(obj: readonly T[] | undefined | null): obj is readonly T[];\nexport function isNonEmptyArray(obj: T[] | readonly T[] | undefined | null): obj is T[] | readonly T[] {\n\treturn Array.isArray(obj) && obj.length > 0;\n}\n\n/**\n * Removes duplicates from the given array. The optional keyFn allows to specify\n * how elements are checked for equality by returning an alternate value for each.\n */\nexport function distinct(array: ReadonlyArray, keyFn: (value: T) => any = value => value): T[] {\n\tconst seen = new Set();\n\n\treturn array.filter(element => {\n\t\tconst key = keyFn!(element);\n\t\tif (seen.has(key)) {\n\t\t\treturn false;\n\t\t}\n\t\tseen.add(key);\n\t\treturn true;\n\t});\n}\n\nexport function firstOrDefault(array: ReadonlyArray, notFoundValue: NotFound): T | NotFound;\nexport function firstOrDefault(array: ReadonlyArray): T | undefined;\nexport function firstOrDefault(array: ReadonlyArray, notFoundValue?: NotFound): T | NotFound | undefined {\n\treturn array.length > 0 ? array[0] : notFoundValue;\n}\n\nexport function range(to: number): number[];\nexport function range(from: number, to: number): number[];\nexport function range(arg: number, to?: number): number[] {\n\tlet from = typeof to === 'number' ? arg : 0;\n\n\tif (typeof to === 'number') {\n\t\tfrom = arg;\n\t} else {\n\t\tfrom = 0;\n\t\tto = arg;\n\t}\n\n\tconst result: number[] = [];\n\n\tif (from <= to) {\n\t\tfor (let i = from; i < to; i++) {\n\t\t\tresult.push(i);\n\t\t}\n\t} else {\n\t\tfor (let i = from; i > to; i--) {\n\t\t\tresult.push(i);\n\t\t}\n\t}\n\n\treturn result;\n}\n\n/**\n * Insert `insertArr` inside `target` at `insertIndex`.\n * Please don't touch unless you understand https://jsperf.com/inserting-an-array-within-an-array\n */\nexport function arrayInsert(target: T[], insertIndex: number, insertArr: T[]): T[] {\n\tconst before = target.slice(0, insertIndex);\n\tconst after = target.slice(insertIndex);\n\treturn before.concat(insertArr, after);\n}\n\n/**\n * Pushes an element to the start of the array, if found.\n */\nexport function pushToStart(arr: T[], value: T): void {\n\tconst index = arr.indexOf(value);\n\n\tif (index > -1) {\n\t\tarr.splice(index, 1);\n\t\tarr.unshift(value);\n\t}\n}\n\n/**\n * Pushes an element to the end of the array, if found.\n */\nexport function pushToEnd(arr: T[], value: T): void {\n\tconst index = arr.indexOf(value);\n\n\tif (index > -1) {\n\t\tarr.splice(index, 1);\n\t\tarr.push(value);\n\t}\n}\n\nexport function pushMany(arr: T[], items: ReadonlyArray): void {\n\tfor (const item of items) {\n\t\tarr.push(item);\n\t}\n}\n\nexport function asArray(x: T | T[]): T[];\nexport function asArray(x: T | readonly T[]): readonly T[];\nexport function asArray(x: T | T[]): T[] {\n\treturn Array.isArray(x) ? x : [x];\n}\n\n/**\n * Insert the new items in the array.\n * @param array The original array.\n * @param start The zero-based location in the array from which to start inserting elements.\n * @param newItems The items to be inserted\n */\nexport function insertInto(array: T[], start: number, newItems: T[]): void {\n\tconst startIdx = getActualStartIndex(array, start);\n\tconst originalLength = array.length;\n\tconst newItemsLength = newItems.length;\n\tarray.length = originalLength + newItemsLength;\n\t// Move the items after the start index, start from the end so that we don't overwrite any value.\n\tfor (let i = originalLength - 1; i >= startIdx; i--) {\n\t\tarray[i + newItemsLength] = array[i];\n\t}\n\n\tfor (let i = 0; i < newItemsLength; i++) {\n\t\tarray[i + startIdx] = newItems[i];\n\t}\n}\n\n/**\n * Removes elements from an array and inserts new elements in their place, returning the deleted elements. Alternative to the native Array.splice method, it\n * can only support limited number of items due to the maximum call stack size limit.\n * @param array The original array.\n * @param start The zero-based location in the array from which to start removing elements.\n * @param deleteCount The number of elements to remove.\n * @returns An array containing the elements that were deleted.\n */\nexport function splice(array: T[], start: number, deleteCount: number, newItems: T[]): T[] {\n\tconst index = getActualStartIndex(array, start);\n\tlet result = array.splice(index, deleteCount);\n\tif (result === undefined) {\n\t\t// see https://bugs.webkit.org/show_bug.cgi?id=261140\n\t\tresult = [];\n\t}\n\tinsertInto(array, index, newItems);\n\treturn result;\n}\n\n/**\n * Determine the actual start index (same logic as the native splice() or slice())\n * If greater than the length of the array, start will be set to the length of the array. In this case, no element will be deleted but the method will behave as an adding function, adding as many element as item[n*] provided.\n * If negative, it will begin that many elements from the end of the array. (In this case, the origin -1, meaning -n is the index of the nth last element, and is therefore equivalent to the index of array.length - n.) If array.length + start is less than 0, it will begin from index 0.\n * @param array The target array.\n * @param start The operation index.\n */\nfunction getActualStartIndex(array: T[], start: number): number {\n\treturn start < 0 ? Math.max(start + array.length, 0) : Math.min(start, array.length);\n}\n\n/**\n * When comparing two values,\n * a negative number indicates that the first value is less than the second,\n * a positive number indicates that the first value is greater than the second,\n * and zero indicates that neither is the case.\n*/\nexport type CompareResult = number;\n\nexport namespace CompareResult {\n\texport function isLessThan(result: CompareResult): boolean {\n\t\treturn result < 0;\n\t}\n\n\texport function isLessThanOrEqual(result: CompareResult): boolean {\n\t\treturn result <= 0;\n\t}\n\n\texport function isGreaterThan(result: CompareResult): boolean {\n\t\treturn result > 0;\n\t}\n\n\texport function isNeitherLessOrGreaterThan(result: CompareResult): boolean {\n\t\treturn result === 0;\n\t}\n\n\texport const greaterThan = 1;\n\texport const lessThan = -1;\n\texport const neitherLessOrGreaterThan = 0;\n}\n\n/**\n * A comparator `c` defines a total order `<=` on `T` as following:\n * `c(a, b) <= 0` iff `a` <= `b`.\n * We also have `c(a, b) == 0` iff `c(b, a) == 0`.\n*/\nexport type Comparator = (a: T, b: T) => CompareResult;\n\nexport function compareBy(selector: (item: TItem) => TCompareBy, comparator: Comparator): Comparator {\n\treturn (a, b) => comparator(selector(a), selector(b));\n}\n\nexport function tieBreakComparators(...comparators: Comparator[]): Comparator {\n\treturn (item1, item2) => {\n\t\tfor (const comparator of comparators) {\n\t\t\tconst result = comparator(item1, item2);\n\t\t\tif (!CompareResult.isNeitherLessOrGreaterThan(result)) {\n\t\t\t\treturn result;\n\t\t\t}\n\t\t}\n\t\treturn CompareResult.neitherLessOrGreaterThan;\n\t};\n}\n\n/**\n * The natural order on numbers.\n*/\nexport const numberComparator: Comparator = (a, b) => a - b;\n\nexport const booleanComparator: Comparator = (a, b) => numberComparator(a ? 1 : 0, b ? 1 : 0);\n\nexport function reverseOrder(comparator: Comparator): Comparator {\n\treturn (a, b) => -comparator(a, b);\n}\n\nexport class ArrayQueue {\n\tprivate firstIdx = 0;\n\tprivate lastIdx = this.items.length - 1;\n\n\t/**\n\t * Constructs a queue that is backed by the given array. Runtime is O(1).\n\t*/\n\tconstructor(private readonly items: readonly T[]) { }\n\n\tget length(): number {\n\t\treturn this.lastIdx - this.firstIdx + 1;\n\t}\n\n\t/**\n\t * Consumes elements from the beginning of the queue as long as the predicate returns true.\n\t * If no elements were consumed, `null` is returned. Has a runtime of O(result.length).\n\t*/\n\ttakeWhile(predicate: (value: T) => boolean): T[] | null {\n\t\t// P(k) := k <= this.lastIdx && predicate(this.items[k])\n\t\t// Find s := min { k | k >= this.firstIdx && !P(k) } and return this.data[this.firstIdx...s)\n\n\t\tlet startIdx = this.firstIdx;\n\t\twhile (startIdx < this.items.length && predicate(this.items[startIdx])) {\n\t\t\tstartIdx++;\n\t\t}\n\t\tconst result = startIdx === this.firstIdx ? null : this.items.slice(this.firstIdx, startIdx);\n\t\tthis.firstIdx = startIdx;\n\t\treturn result;\n\t}\n\n\t/**\n\t * Consumes elements from the end of the queue as long as the predicate returns true.\n\t * If no elements were consumed, `null` is returned.\n\t * The result has the same order as the underlying array!\n\t*/\n\ttakeFromEndWhile(predicate: (value: T) => boolean): T[] | null {\n\t\t// P(k) := this.firstIdx >= k && predicate(this.items[k])\n\t\t// Find s := max { k | k <= this.lastIdx && !P(k) } and return this.data(s...this.lastIdx]\n\n\t\tlet endIdx = this.lastIdx;\n\t\twhile (endIdx >= 0 && predicate(this.items[endIdx])) {\n\t\t\tendIdx--;\n\t\t}\n\t\tconst result = endIdx === this.lastIdx ? null : this.items.slice(endIdx + 1, this.lastIdx + 1);\n\t\tthis.lastIdx = endIdx;\n\t\treturn result;\n\t}\n\n\tpeek(): T | undefined {\n\t\tif (this.length === 0) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn this.items[this.firstIdx];\n\t}\n\n\tdequeue(): T | undefined {\n\t\tconst result = this.items[this.firstIdx];\n\t\tthis.firstIdx++;\n\t\treturn result;\n\t}\n\n\ttakeCount(count: number): T[] {\n\t\tconst result = this.items.slice(this.firstIdx, this.firstIdx + count);\n\t\tthis.firstIdx += count;\n\t\treturn result;\n\t}\n}\n\n/**\n * This class is faster than an iterator and array for lazy computed data.\n*/\nexport class CallbackIterable {\n\tpublic static readonly empty = new CallbackIterable(_callback => { });\n\n\tconstructor(\n\t\t/**\n\t\t * Calls the callback for every item.\n\t\t * Stops when the callback returns false.\n\t\t*/\n\t\tpublic readonly iterate: (callback: (item: T) => boolean) => void\n\t) {\n\t}\n\n\ttoArray(): T[] {\n\t\tconst result: T[] = [];\n\t\tthis.iterate(item => { result.push(item); return true; });\n\t\treturn result;\n\t}\n\n\tfilter(predicate: (item: T) => boolean): CallbackIterable {\n\t\treturn new CallbackIterable(cb => this.iterate(item => predicate(item) ? cb(item) : true));\n\t}\n\n\tmap(mapFn: (item: T) => TResult): CallbackIterable {\n\t\treturn new CallbackIterable(cb => this.iterate(item => cb(mapFn(item))));\n\t}\n\n\tfindLast(predicate: (item: T) => boolean): T | undefined {\n\t\tlet result: T | undefined;\n\t\tthis.iterate(item => {\n\t\t\tif (predicate(item)) {\n\t\t\t\tresult = item;\n\t\t\t}\n\t\t\treturn true;\n\t\t});\n\t\treturn result;\n\t}\n\n\tfindLastMaxBy(comparator: Comparator): T | undefined {\n\t\tlet result: T | undefined;\n\t\tlet first = true;\n\t\tthis.iterate(item => {\n\t\t\tif (first || CompareResult.isGreaterThan(comparator(item, result!))) {\n\t\t\t\tfirst = false;\n\t\t\t\tresult = item;\n\t\t\t}\n\t\t\treturn true;\n\t\t});\n\t\treturn result;\n\t}\n}\n\n/**\n * Represents a re-arrangement of items in an array.\n */\nexport class Permutation {\n\tconstructor(private readonly _indexMap: readonly number[]) { }\n\n\t/**\n\t * Returns a permutation that sorts the given array according to the given compare function.\n\t */\n\tpublic static createSortPermutation(arr: readonly T[], compareFn: (a: T, b: T) => number): Permutation {\n\t\tconst sortIndices = Array.from(arr.keys()).sort((index1, index2) => compareFn(arr[index1], arr[index2]));\n\t\treturn new Permutation(sortIndices);\n\t}\n\n\t/**\n\t * Returns a new array with the elements of the given array re-arranged according to this permutation.\n\t */\n\tapply(arr: readonly T[]): T[] {\n\t\treturn arr.map((_, index) => arr[this._indexMap[index]]);\n\t}\n\n\t/**\n\t * Returns a new permutation that undoes the re-arrangement of this permutation.\n\t*/\n\tinverse(): Permutation {\n\t\tconst inverseIndexMap = this._indexMap.slice();\n\t\tfor (let i = 0; i < this._indexMap.length; i++) {\n\t\t\tinverseIndexMap[this._indexMap[i]] = i;\n\t\t}\n\t\treturn new Permutation(inverseIndexMap);\n\t}\n}\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\nimport { Comparator } from './arrays';\n\nexport function findLast(array: readonly T[], predicate: (item: T) => boolean): T | undefined {\n\tconst idx = findLastIdx(array, predicate);\n\tif (idx === -1) {\n\t\treturn undefined;\n\t}\n\treturn array[idx];\n}\n\nexport function findLastIdx(array: readonly T[], predicate: (item: T) => boolean, fromIndex = array.length - 1): number {\n\tfor (let i = fromIndex; i >= 0; i--) {\n\t\tconst element = array[i];\n\n\t\tif (predicate(element)) {\n\t\t\treturn i;\n\t\t}\n\t}\n\n\treturn -1;\n}\n\n/**\n * Finds the last item where predicate is true using binary search.\n * `predicate` must be monotonous, i.e. `arr.map(predicate)` must be like `[true, ..., true, false, ..., false]`!\n *\n * @returns `undefined` if no item matches, otherwise the last item that matches the predicate.\n */\nexport function findLastMonotonous(array: readonly T[], predicate: (item: T) => boolean): T | undefined {\n\tconst idx = findLastIdxMonotonous(array, predicate);\n\treturn idx === -1 ? undefined : array[idx];\n}\n\n/**\n * Finds the last item where predicate is true using binary search.\n * `predicate` must be monotonous, i.e. `arr.map(predicate)` must be like `[true, ..., true, false, ..., false]`!\n *\n * @returns `startIdx - 1` if predicate is false for all items, otherwise the index of the last item that matches the predicate.\n */\nexport function findLastIdxMonotonous(array: readonly T[], predicate: (item: T) => boolean, startIdx = 0, endIdxEx = array.length): number {\n\tlet i = startIdx;\n\tlet j = endIdxEx;\n\twhile (i < j) {\n\t\tconst k = Math.floor((i + j) / 2);\n\t\tif (predicate(array[k])) {\n\t\t\ti = k + 1;\n\t\t} else {\n\t\t\tj = k;\n\t\t}\n\t}\n\treturn i - 1;\n}\n\n/**\n * Finds the first item where predicate is true using binary search.\n * `predicate` must be monotonous, i.e. `arr.map(predicate)` must be like `[false, ..., false, true, ..., true]`!\n *\n * @returns `undefined` if no item matches, otherwise the first item that matches the predicate.\n */\nexport function findFirstMonotonous(array: readonly T[], predicate: (item: T) => boolean): T | undefined {\n\tconst idx = findFirstIdxMonotonousOrArrLen(array, predicate);\n\treturn idx === array.length ? undefined : array[idx];\n}\n\n/**\n * Finds the first item where predicate is true using binary search.\n * `predicate` must be monotonous, i.e. `arr.map(predicate)` must be like `[false, ..., false, true, ..., true]`!\n *\n * @returns `endIdxEx` if predicate is false for all items, otherwise the index of the first item that matches the predicate.\n */\nexport function findFirstIdxMonotonousOrArrLen(array: readonly T[], predicate: (item: T) => boolean, startIdx = 0, endIdxEx = array.length): number {\n\tlet i = startIdx;\n\tlet j = endIdxEx;\n\twhile (i < j) {\n\t\tconst k = Math.floor((i + j) / 2);\n\t\tif (predicate(array[k])) {\n\t\t\tj = k;\n\t\t} else {\n\t\t\ti = k + 1;\n\t\t}\n\t}\n\treturn i;\n}\n\n/**\n * Use this when\n * * You have a sorted array\n * * You query this array with a monotonous predicate to find the last item that has a certain property.\n * * You query this array multiple times with monotonous predicates that get weaker and weaker.\n */\nexport class MonotonousArray {\n\tpublic static assertInvariants = false;\n\n\tprivate _findLastMonotonousLastIdx = 0;\n\tprivate _prevFindLastPredicate: ((item: T) => boolean) | undefined;\n\n\tconstructor(private readonly _array: readonly T[]) {\n\t}\n\n\t/**\n\t * The predicate must be monotonous, i.e. `arr.map(predicate)` must be like `[true, ..., true, false, ..., false]`!\n\t * For subsequent calls, current predicate must be weaker than (or equal to) the previous predicate, i.e. more entries must be `true`.\n\t */\n\tfindLastMonotonous(predicate: (item: T) => boolean): T | undefined {\n\t\tif (MonotonousArray.assertInvariants) {\n\t\t\tif (this._prevFindLastPredicate) {\n\t\t\t\tfor (const item of this._array) {\n\t\t\t\t\tif (this._prevFindLastPredicate(item) && !predicate(item)) {\n\t\t\t\t\t\tthrow new Error('MonotonousArray: current predicate must be weaker than (or equal to) the previous predicate.');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis._prevFindLastPredicate = predicate;\n\t\t}\n\n\t\tconst idx = findLastIdxMonotonous(this._array, predicate, this._findLastMonotonousLastIdx);\n\t\tthis._findLastMonotonousLastIdx = idx + 1;\n\t\treturn idx === -1 ? undefined : this._array[idx];\n\t}\n}\n\n/**\n * Returns the first item that is equal to or greater than every other item.\n*/\nexport function findFirstMax(array: readonly T[], comparator: Comparator): T | undefined {\n\tif (array.length === 0) {\n\t\treturn undefined;\n\t}\n\n\tlet max = array[0];\n\tfor (let i = 1; i < array.length; i++) {\n\t\tconst item = array[i];\n\t\tif (comparator(item, max) > 0) {\n\t\t\tmax = item;\n\t\t}\n\t}\n\treturn max;\n}\n\n/**\n * Returns the last item that is equal to or greater than every other item.\n*/\nexport function findLastMax(array: readonly T[], comparator: Comparator): T | undefined {\n\tif (array.length === 0) {\n\t\treturn undefined;\n\t}\n\n\tlet max = array[0];\n\tfor (let i = 1; i < array.length; i++) {\n\t\tconst item = array[i];\n\t\tif (comparator(item, max) >= 0) {\n\t\t\tmax = item;\n\t\t}\n\t}\n\treturn max;\n}\n\n/**\n * Returns the first item that is equal to or less than every other item.\n*/\nexport function findFirstMin(array: readonly T[], comparator: Comparator): T | undefined {\n\treturn findFirstMax(array, (a, b) => -comparator(a, b));\n}\n\nexport function findMaxIdx(array: readonly T[], comparator: Comparator): number {\n\tif (array.length === 0) {\n\t\treturn -1;\n\t}\n\n\tlet maxIdx = 0;\n\tfor (let i = 1; i < array.length; i++) {\n\t\tconst item = array[i];\n\t\tif (comparator(item, array[maxIdx]) > 0) {\n\t\t\tmaxIdx = i;\n\t\t}\n\t}\n\treturn maxIdx;\n}\n\n/**\n * Returns the first mapped value of the array which is not undefined.\n */\nexport function mapFindFirst(items: Iterable, mapFn: (value: T) => R | undefined): R | undefined {\n\tfor (const value of items) {\n\t\tconst mapped = mapFn(value);\n\t\tif (mapped !== undefined) {\n\t\t\treturn mapped;\n\t\t}\n\t}\n\n\treturn undefined;\n}\n","\n\nexport function identity(t: T): T {\n\treturn t;\n}\n\ninterface ICacheOptions {\n\t/**\n\t * The cache key is used to identify the cache entry.\n\t * Strict equality is used to compare cache keys.\n\t*/\n\tgetCacheKey: (arg: TArg) => unknown;\n}\n\n/**\n * Uses a LRU cache to make a given parametrized function cached.\n * Caches just the last key/value.\n*/\nexport class LRUCachedFunction {\n\tprivate lastCache: TComputed | undefined = undefined;\n\tprivate lastArgKey: unknown | undefined = undefined;\n\n\tprivate readonly _fn: (arg: TArg) => TComputed;\n\tprivate readonly _computeKey: (arg: TArg) => unknown;\n\n\tconstructor(fn: (arg: TArg) => TComputed);\n\tconstructor(options: ICacheOptions, fn: (arg: TArg) => TComputed);\n\tconstructor(arg1: ICacheOptions | ((arg: TArg) => TComputed), arg2?: (arg: TArg) => TComputed) {\n\t\tif (typeof arg1 === 'function') {\n\t\t\tthis._fn = arg1;\n\t\t\tthis._computeKey = identity;\n\t\t} else {\n\t\t\tthis._fn = arg2!;\n\t\t\tthis._computeKey = arg1.getCacheKey;\n\t\t}\n\t}\n\n\tpublic get(arg: TArg): TComputed {\n\t\tconst key = this._computeKey(arg);\n\t\tif (this.lastArgKey !== key) {\n\t\t\tthis.lastArgKey = key;\n\t\t\tthis.lastCache = this._fn(arg);\n\t\t}\n\t\treturn this.lastCache!;\n\t}\n}\n\n/**\n * Uses an unbounded cache to memoize the results of the given function.\n*/\nexport class CachedFunction {\n\tprivate readonly _map = new Map();\n\tprivate readonly _map2 = new Map();\n\tpublic get cachedValues(): ReadonlyMap {\n\t\treturn this._map;\n\t}\n\n\tprivate readonly _fn: (arg: TArg) => TComputed;\n\tprivate readonly _computeKey: (arg: TArg) => unknown;\n\n\tconstructor(fn: (arg: TArg) => TComputed);\n\tconstructor(options: ICacheOptions, fn: (arg: TArg) => TComputed);\n\tconstructor(arg1: ICacheOptions | ((arg: TArg) => TComputed), arg2?: (arg: TArg) => TComputed) {\n\t\tif (typeof arg1 === 'function') {\n\t\t\tthis._fn = arg1;\n\t\t\tthis._computeKey = identity;\n\t\t} else {\n\t\t\tthis._fn = arg2!;\n\t\t\tthis._computeKey = arg1.getCacheKey;\n\t\t}\n\t}\n\n\tpublic get(arg: TArg): TComputed {\n\t\tconst key = this._computeKey(arg);\n\t\tif (this._map2.has(key)) {\n\t\t\treturn this._map2.get(key)!;\n\t\t}\n\n\t\tconst value = this._fn(arg);\n\t\tthis._map.set(arg, value);\n\t\tthis._map2.set(key, value);\n\t\treturn value;\n\t}\n}\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 * An interface for a JavaScript object that\n * acts a dictionary. The keys are strings.\n */\nexport type IStringDictionary = Record;\n\nexport function diffSets(before: Set, after: Set): { removed: T[]; added: T[] } {\n\tconst removed: T[] = [];\n\tconst added: T[] = [];\n\tfor (const element of before) {\n\t\tif (!after.has(element)) {\n\t\t\tremoved.push(element);\n\t\t}\n\t}\n\tfor (const element of after) {\n\t\tif (!before.has(element)) {\n\t\t\tadded.push(element);\n\t\t}\n\t}\n\treturn { removed, added };\n}\n\n/**\n * Computes the intersection of two sets.\n *\n * @param setA - The first set.\n * @param setB - The second iterable.\n * @returns A new set containing the elements that are in both `setA` and `setB`.\n */\nexport function intersection(setA: Set, setB: Iterable): Set {\n\tconst result = new Set();\n\tfor (const elem of setB) {\n\t\tif (setA.has(elem)) {\n\t\t\tresult.add(elem);\n\t\t}\n\t}\n\treturn result;\n}\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\nimport { CharCode } from 'vs/base/common/charCode';\n\nfunction roundFloat(number: number, decimalPoints: number): number {\n\tconst decimal = Math.pow(10, decimalPoints);\n\treturn Math.round(number * decimal) / decimal;\n}\n\nexport class RGBA {\n\t_rgbaBrand: void = undefined;\n\n\t/**\n\t * Red: integer in [0-255]\n\t */\n\treadonly r: number;\n\n\t/**\n\t * Green: integer in [0-255]\n\t */\n\treadonly g: number;\n\n\t/**\n\t * Blue: integer in [0-255]\n\t */\n\treadonly b: number;\n\n\t/**\n\t * Alpha: float in [0-1]\n\t */\n\treadonly a: number;\n\n\tconstructor(r: number, g: number, b: number, a: number = 1) {\n\t\tthis.r = Math.min(255, Math.max(0, r)) | 0;\n\t\tthis.g = Math.min(255, Math.max(0, g)) | 0;\n\t\tthis.b = Math.min(255, Math.max(0, b)) | 0;\n\t\tthis.a = roundFloat(Math.max(Math.min(1, a), 0), 3);\n\t}\n\n\tstatic equals(a: RGBA, b: RGBA): boolean {\n\t\treturn a.r === b.r && a.g === b.g && a.b === b.b && a.a === b.a;\n\t}\n}\n\nexport class HSLA {\n\n\t_hslaBrand: void = undefined;\n\n\t/**\n\t * Hue: integer in [0, 360]\n\t */\n\treadonly h: number;\n\n\t/**\n\t * Saturation: float in [0, 1]\n\t */\n\treadonly s: number;\n\n\t/**\n\t * Luminosity: float in [0, 1]\n\t */\n\treadonly l: number;\n\n\t/**\n\t * Alpha: float in [0, 1]\n\t */\n\treadonly a: number;\n\n\tconstructor(h: number, s: number, l: number, a: number) {\n\t\tthis.h = Math.max(Math.min(360, h), 0) | 0;\n\t\tthis.s = roundFloat(Math.max(Math.min(1, s), 0), 3);\n\t\tthis.l = roundFloat(Math.max(Math.min(1, l), 0), 3);\n\t\tthis.a = roundFloat(Math.max(Math.min(1, a), 0), 3);\n\t}\n\n\tstatic equals(a: HSLA, b: HSLA): boolean {\n\t\treturn a.h === b.h && a.s === b.s && a.l === b.l && a.a === b.a;\n\t}\n\n\t/**\n\t * Converts an RGB color value to HSL. Conversion formula\n\t * adapted from http://en.wikipedia.org/wiki/HSL_color_space.\n\t * Assumes r, g, and b are contained in the set [0, 255] and\n\t * returns h in the set [0, 360], s, and l in the set [0, 1].\n\t */\n\tstatic fromRGBA(rgba: RGBA): HSLA {\n\t\tconst r = rgba.r / 255;\n\t\tconst g = rgba.g / 255;\n\t\tconst b = rgba.b / 255;\n\t\tconst a = rgba.a;\n\n\t\tconst max = Math.max(r, g, b);\n\t\tconst min = Math.min(r, g, b);\n\t\tlet h = 0;\n\t\tlet s = 0;\n\t\tconst l = (min + max) / 2;\n\t\tconst chroma = max - min;\n\n\t\tif (chroma > 0) {\n\t\t\ts = Math.min((l <= 0.5 ? chroma / (2 * l) : chroma / (2 - (2 * l))), 1);\n\n\t\t\tswitch (max) {\n\t\t\t\tcase r: h = (g - b) / chroma + (g < b ? 6 : 0); break;\n\t\t\t\tcase g: h = (b - r) / chroma + 2; break;\n\t\t\t\tcase b: h = (r - g) / chroma + 4; break;\n\t\t\t}\n\n\t\t\th *= 60;\n\t\t\th = Math.round(h);\n\t\t}\n\t\treturn new HSLA(h, s, l, a);\n\t}\n\n\tprivate static _hue2rgb(p: number, q: number, t: number): number {\n\t\tif (t < 0) {\n\t\t\tt += 1;\n\t\t}\n\t\tif (t > 1) {\n\t\t\tt -= 1;\n\t\t}\n\t\tif (t < 1 / 6) {\n\t\t\treturn p + (q - p) * 6 * t;\n\t\t}\n\t\tif (t < 1 / 2) {\n\t\t\treturn q;\n\t\t}\n\t\tif (t < 2 / 3) {\n\t\t\treturn p + (q - p) * (2 / 3 - t) * 6;\n\t\t}\n\t\treturn p;\n\t}\n\n\t/**\n\t * Converts an HSL color value to RGB. Conversion formula\n\t * adapted from http://en.wikipedia.org/wiki/HSL_color_space.\n\t * Assumes h in the set [0, 360] s, and l are contained in the set [0, 1] and\n\t * returns r, g, and b in the set [0, 255].\n\t */\n\tstatic toRGBA(hsla: HSLA): RGBA {\n\t\tconst h = hsla.h / 360;\n\t\tconst { s, l, a } = hsla;\n\t\tlet r: number, g: number, b: number;\n\n\t\tif (s === 0) {\n\t\t\tr = g = b = l; // achromatic\n\t\t} else {\n\t\t\tconst q = l < 0.5 ? l * (1 + s) : l + s - l * s;\n\t\t\tconst p = 2 * l - q;\n\t\t\tr = HSLA._hue2rgb(p, q, h + 1 / 3);\n\t\t\tg = HSLA._hue2rgb(p, q, h);\n\t\t\tb = HSLA._hue2rgb(p, q, h - 1 / 3);\n\t\t}\n\n\t\treturn new RGBA(Math.round(r * 255), Math.round(g * 255), Math.round(b * 255), a);\n\t}\n}\n\nexport class HSVA {\n\n\t_hsvaBrand: void = undefined;\n\n\t/**\n\t * Hue: integer in [0, 360]\n\t */\n\treadonly h: number;\n\n\t/**\n\t * Saturation: float in [0, 1]\n\t */\n\treadonly s: number;\n\n\t/**\n\t * Value: float in [0, 1]\n\t */\n\treadonly v: number;\n\n\t/**\n\t * Alpha: float in [0, 1]\n\t */\n\treadonly a: number;\n\n\tconstructor(h: number, s: number, v: number, a: number) {\n\t\tthis.h = Math.max(Math.min(360, h), 0) | 0;\n\t\tthis.s = roundFloat(Math.max(Math.min(1, s), 0), 3);\n\t\tthis.v = roundFloat(Math.max(Math.min(1, v), 0), 3);\n\t\tthis.a = roundFloat(Math.max(Math.min(1, a), 0), 3);\n\t}\n\n\tstatic equals(a: HSVA, b: HSVA): boolean {\n\t\treturn a.h === b.h && a.s === b.s && a.v === b.v && a.a === b.a;\n\t}\n\n\t// from http://www.rapidtables.com/convert/color/rgb-to-hsv.htm\n\tstatic fromRGBA(rgba: RGBA): HSVA {\n\t\tconst r = rgba.r / 255;\n\t\tconst g = rgba.g / 255;\n\t\tconst b = rgba.b / 255;\n\t\tconst cmax = Math.max(r, g, b);\n\t\tconst cmin = Math.min(r, g, b);\n\t\tconst delta = cmax - cmin;\n\t\tconst s = cmax === 0 ? 0 : (delta / cmax);\n\t\tlet m: number;\n\n\t\tif (delta === 0) {\n\t\t\tm = 0;\n\t\t} else if (cmax === r) {\n\t\t\tm = ((((g - b) / delta) % 6) + 6) % 6;\n\t\t} else if (cmax === g) {\n\t\t\tm = ((b - r) / delta) + 2;\n\t\t} else {\n\t\t\tm = ((r - g) / delta) + 4;\n\t\t}\n\n\t\treturn new HSVA(Math.round(m * 60), s, cmax, rgba.a);\n\t}\n\n\t// from http://www.rapidtables.com/convert/color/hsv-to-rgb.htm\n\tstatic toRGBA(hsva: HSVA): RGBA {\n\t\tconst { h, s, v, a } = hsva;\n\t\tconst c = v * s;\n\t\tconst x = c * (1 - Math.abs((h / 60) % 2 - 1));\n\t\tconst m = v - c;\n\t\tlet [r, g, b] = [0, 0, 0];\n\n\t\tif (h < 60) {\n\t\t\tr = c;\n\t\t\tg = x;\n\t\t} else if (h < 120) {\n\t\t\tr = x;\n\t\t\tg = c;\n\t\t} else if (h < 180) {\n\t\t\tg = c;\n\t\t\tb = x;\n\t\t} else if (h < 240) {\n\t\t\tg = x;\n\t\t\tb = c;\n\t\t} else if (h < 300) {\n\t\t\tr = x;\n\t\t\tb = c;\n\t\t} else if (h <= 360) {\n\t\t\tr = c;\n\t\t\tb = x;\n\t\t}\n\n\t\tr = Math.round((r + m) * 255);\n\t\tg = Math.round((g + m) * 255);\n\t\tb = Math.round((b + m) * 255);\n\n\t\treturn new RGBA(r, g, b, a);\n\t}\n}\n\nexport class Color {\n\n\tstatic fromHex(hex: string): Color {\n\t\treturn Color.Format.CSS.parseHex(hex) || Color.red;\n\t}\n\n\tstatic equals(a: Color | null, b: Color | null): boolean {\n\t\tif (!a && !b) {\n\t\t\treturn true;\n\t\t}\n\t\tif (!a || !b) {\n\t\t\treturn false;\n\t\t}\n\t\treturn a.equals(b);\n\t}\n\n\treadonly rgba: RGBA;\n\tprivate _hsla?: HSLA;\n\tget hsla(): HSLA {\n\t\tif (this._hsla) {\n\t\t\treturn this._hsla;\n\t\t} else {\n\t\t\treturn HSLA.fromRGBA(this.rgba);\n\t\t}\n\t}\n\n\tprivate _hsva?: HSVA;\n\tget hsva(): HSVA {\n\t\tif (this._hsva) {\n\t\t\treturn this._hsva;\n\t\t}\n\t\treturn HSVA.fromRGBA(this.rgba);\n\t}\n\n\tconstructor(arg: RGBA | HSLA | HSVA) {\n\t\tif (!arg) {\n\t\t\tthrow new Error('Color needs a value');\n\t\t} else if (arg instanceof RGBA) {\n\t\t\tthis.rgba = arg;\n\t\t} else if (arg instanceof HSLA) {\n\t\t\tthis._hsla = arg;\n\t\t\tthis.rgba = HSLA.toRGBA(arg);\n\t\t} else if (arg instanceof HSVA) {\n\t\t\tthis._hsva = arg;\n\t\t\tthis.rgba = HSVA.toRGBA(arg);\n\t\t} else {\n\t\t\tthrow new Error('Invalid color ctor argument');\n\t\t}\n\t}\n\n\tequals(other: Color | null): boolean {\n\t\treturn !!other && RGBA.equals(this.rgba, other.rgba) && HSLA.equals(this.hsla, other.hsla) && HSVA.equals(this.hsva, other.hsva);\n\t}\n\n\t/**\n\t * http://www.w3.org/TR/WCAG20/#relativeluminancedef\n\t * Returns the number in the set [0, 1]. O => Darkest Black. 1 => Lightest white.\n\t */\n\tgetRelativeLuminance(): number {\n\t\tconst R = Color._relativeLuminanceForComponent(this.rgba.r);\n\t\tconst G = Color._relativeLuminanceForComponent(this.rgba.g);\n\t\tconst B = Color._relativeLuminanceForComponent(this.rgba.b);\n\t\tconst luminance = 0.2126 * R + 0.7152 * G + 0.0722 * B;\n\n\t\treturn roundFloat(luminance, 4);\n\t}\n\n\tprivate static _relativeLuminanceForComponent(color: number): number {\n\t\tconst c = color / 255;\n\t\treturn (c <= 0.03928) ? c / 12.92 : Math.pow(((c + 0.055) / 1.055), 2.4);\n\t}\n\n\t/**\n\t *\thttp://24ways.org/2010/calculating-color-contrast\n\t * Return 'true' if lighter color otherwise 'false'\n\t */\n\tisLighter(): boolean {\n\t\tconst yiq = (this.rgba.r * 299 + this.rgba.g * 587 + this.rgba.b * 114) / 1000;\n\t\treturn yiq >= 128;\n\t}\n\n\tisLighterThan(another: Color): boolean {\n\t\tconst lum1 = this.getRelativeLuminance();\n\t\tconst lum2 = another.getRelativeLuminance();\n\t\treturn lum1 > lum2;\n\t}\n\n\tisDarkerThan(another: Color): boolean {\n\t\tconst lum1 = this.getRelativeLuminance();\n\t\tconst lum2 = another.getRelativeLuminance();\n\t\treturn lum1 < lum2;\n\t}\n\n\tlighten(factor: number): Color {\n\t\treturn new Color(new HSLA(this.hsla.h, this.hsla.s, this.hsla.l + this.hsla.l * factor, this.hsla.a));\n\t}\n\n\tdarken(factor: number): Color {\n\t\treturn new Color(new HSLA(this.hsla.h, this.hsla.s, this.hsla.l - this.hsla.l * factor, this.hsla.a));\n\t}\n\n\ttransparent(factor: number): Color {\n\t\tconst { r, g, b, a } = this.rgba;\n\t\treturn new Color(new RGBA(r, g, b, a * factor));\n\t}\n\n\tisTransparent(): boolean {\n\t\treturn this.rgba.a === 0;\n\t}\n\n\tisOpaque(): boolean {\n\t\treturn this.rgba.a === 1;\n\t}\n\n\topposite(): Color {\n\t\treturn new Color(new RGBA(255 - this.rgba.r, 255 - this.rgba.g, 255 - this.rgba.b, this.rgba.a));\n\t}\n\n\tmakeOpaque(opaqueBackground: Color): Color {\n\t\tif (this.isOpaque() || opaqueBackground.rgba.a !== 1) {\n\t\t\t// only allow to blend onto a non-opaque color onto a opaque color\n\t\t\treturn this;\n\t\t}\n\n\t\tconst { r, g, b, a } = this.rgba;\n\n\t\t// https://stackoverflow.com/questions/12228548/finding-equivalent-color-with-opacity\n\t\treturn new Color(new RGBA(\n\t\t\topaqueBackground.rgba.r - a * (opaqueBackground.rgba.r - r),\n\t\t\topaqueBackground.rgba.g - a * (opaqueBackground.rgba.g - g),\n\t\t\topaqueBackground.rgba.b - a * (opaqueBackground.rgba.b - b),\n\t\t\t1\n\t\t));\n\t}\n\n\tprivate _toString?: string;\n\ttoString(): string {\n\t\tif (!this._toString) {\n\t\t\tthis._toString = Color.Format.CSS.format(this);\n\t\t}\n\t\treturn this._toString;\n\t}\n\n\tstatic getLighterColor(of: Color, relative: Color, factor?: number): Color {\n\t\tif (of.isLighterThan(relative)) {\n\t\t\treturn of;\n\t\t}\n\t\tfactor = factor ? factor : 0.5;\n\t\tconst lum1 = of.getRelativeLuminance();\n\t\tconst lum2 = relative.getRelativeLuminance();\n\t\tfactor = factor * (lum2 - lum1) / lum2;\n\t\treturn of.lighten(factor);\n\t}\n\n\tstatic getDarkerColor(of: Color, relative: Color, factor?: number): Color {\n\t\tif (of.isDarkerThan(relative)) {\n\t\t\treturn of;\n\t\t}\n\t\tfactor = factor ? factor : 0.5;\n\t\tconst lum1 = of.getRelativeLuminance();\n\t\tconst lum2 = relative.getRelativeLuminance();\n\t\tfactor = factor * (lum1 - lum2) / lum1;\n\t\treturn of.darken(factor);\n\t}\n\n\tstatic readonly white = new Color(new RGBA(255, 255, 255, 1));\n\tstatic readonly black = new Color(new RGBA(0, 0, 0, 1));\n\tstatic readonly red = new Color(new RGBA(255, 0, 0, 1));\n\tstatic readonly blue = new Color(new RGBA(0, 0, 255, 1));\n\tstatic readonly green = new Color(new RGBA(0, 255, 0, 1));\n\tstatic readonly cyan = new Color(new RGBA(0, 255, 255, 1));\n\tstatic readonly lightgrey = new Color(new RGBA(211, 211, 211, 1));\n\tstatic readonly transparent = new Color(new RGBA(0, 0, 0, 0));\n}\n\nexport namespace Color {\n\texport namespace Format {\n\t\texport namespace CSS {\n\n\t\t\texport function formatRGB(color: Color): string {\n\t\t\t\tif (color.rgba.a === 1) {\n\t\t\t\t\treturn `rgb(${color.rgba.r}, ${color.rgba.g}, ${color.rgba.b})`;\n\t\t\t\t}\n\n\t\t\t\treturn Color.Format.CSS.formatRGBA(color);\n\t\t\t}\n\n\t\t\texport function formatRGBA(color: Color): string {\n\t\t\t\treturn `rgba(${color.rgba.r}, ${color.rgba.g}, ${color.rgba.b}, ${+(color.rgba.a).toFixed(2)})`;\n\t\t\t}\n\n\t\t\texport function formatHSL(color: Color): string {\n\t\t\t\tif (color.hsla.a === 1) {\n\t\t\t\t\treturn `hsl(${color.hsla.h}, ${(color.hsla.s * 100).toFixed(2)}%, ${(color.hsla.l * 100).toFixed(2)}%)`;\n\t\t\t\t}\n\n\t\t\t\treturn Color.Format.CSS.formatHSLA(color);\n\t\t\t}\n\n\t\t\texport function formatHSLA(color: Color): string {\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)})`;\n\t\t\t}\n\n\t\t\tfunction _toTwoDigitHex(n: number): string {\n\t\t\t\tconst r = n.toString(16);\n\t\t\t\treturn r.length !== 2 ? '0' + r : r;\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Formats the color as #RRGGBB\n\t\t\t */\n\t\t\texport function formatHex(color: Color): string {\n\t\t\t\treturn `#${_toTwoDigitHex(color.rgba.r)}${_toTwoDigitHex(color.rgba.g)}${_toTwoDigitHex(color.rgba.b)}`;\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Formats the color as #RRGGBBAA\n\t\t\t * If 'compact' is set, colors without transparancy will be printed as #RRGGBB\n\t\t\t */\n\t\t\texport function formatHexA(color: Color, compact = false): string {\n\t\t\t\tif (compact && color.rgba.a === 1) {\n\t\t\t\t\treturn Color.Format.CSS.formatHex(color);\n\t\t\t\t}\n\n\t\t\t\treturn `#${_toTwoDigitHex(color.rgba.r)}${_toTwoDigitHex(color.rgba.g)}${_toTwoDigitHex(color.rgba.b)}${_toTwoDigitHex(Math.round(color.rgba.a * 255))}`;\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * The default format will use HEX if opaque and RGBA otherwise.\n\t\t\t */\n\t\t\texport function format(color: Color): string {\n\t\t\t\tif (color.isOpaque()) {\n\t\t\t\t\treturn Color.Format.CSS.formatHex(color);\n\t\t\t\t}\n\n\t\t\t\treturn Color.Format.CSS.formatRGBA(color);\n\t\t\t}\n\n\t\t\t/**\n\t\t\t * Converts an Hex color value to a Color.\n\t\t\t * returns r, g, and b are contained in the set [0, 255]\n\t\t\t * @param hex string (#RGB, #RGBA, #RRGGBB or #RRGGBBAA).\n\t\t\t */\n\t\t\texport function parseHex(hex: string): Color | null {\n\t\t\t\tconst length = hex.length;\n\n\t\t\t\tif (length === 0) {\n\t\t\t\t\t// Invalid color\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\tif (hex.charCodeAt(0) !== CharCode.Hash) {\n\t\t\t\t\t// Does not begin with a #\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\tif (length === 7) {\n\t\t\t\t\t// #RRGGBB format\n\t\t\t\t\tconst r = 16 * _parseHexDigit(hex.charCodeAt(1)) + _parseHexDigit(hex.charCodeAt(2));\n\t\t\t\t\tconst g = 16 * _parseHexDigit(hex.charCodeAt(3)) + _parseHexDigit(hex.charCodeAt(4));\n\t\t\t\t\tconst b = 16 * _parseHexDigit(hex.charCodeAt(5)) + _parseHexDigit(hex.charCodeAt(6));\n\t\t\t\t\treturn new Color(new RGBA(r, g, b, 1));\n\t\t\t\t}\n\n\t\t\t\tif (length === 9) {\n\t\t\t\t\t// #RRGGBBAA format\n\t\t\t\t\tconst r = 16 * _parseHexDigit(hex.charCodeAt(1)) + _parseHexDigit(hex.charCodeAt(2));\n\t\t\t\t\tconst g = 16 * _parseHexDigit(hex.charCodeAt(3)) + _parseHexDigit(hex.charCodeAt(4));\n\t\t\t\t\tconst b = 16 * _parseHexDigit(hex.charCodeAt(5)) + _parseHexDigit(hex.charCodeAt(6));\n\t\t\t\t\tconst a = 16 * _parseHexDigit(hex.charCodeAt(7)) + _parseHexDigit(hex.charCodeAt(8));\n\t\t\t\t\treturn new Color(new RGBA(r, g, b, a / 255));\n\t\t\t\t}\n\n\t\t\t\tif (length === 4) {\n\t\t\t\t\t// #RGB format\n\t\t\t\t\tconst r = _parseHexDigit(hex.charCodeAt(1));\n\t\t\t\t\tconst g = _parseHexDigit(hex.charCodeAt(2));\n\t\t\t\t\tconst b = _parseHexDigit(hex.charCodeAt(3));\n\t\t\t\t\treturn new Color(new RGBA(16 * r + r, 16 * g + g, 16 * b + b));\n\t\t\t\t}\n\n\t\t\t\tif (length === 5) {\n\t\t\t\t\t// #RGBA format\n\t\t\t\t\tconst r = _parseHexDigit(hex.charCodeAt(1));\n\t\t\t\t\tconst g = _parseHexDigit(hex.charCodeAt(2));\n\t\t\t\t\tconst b = _parseHexDigit(hex.charCodeAt(3));\n\t\t\t\t\tconst a = _parseHexDigit(hex.charCodeAt(4));\n\t\t\t\t\treturn new Color(new RGBA(16 * r + r, 16 * g + g, 16 * b + b, (16 * a + a) / 255));\n\t\t\t\t}\n\n\t\t\t\t// Invalid color\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tfunction _parseHexDigit(charCode: CharCode): number {\n\t\t\t\tswitch (charCode) {\n\t\t\t\t\tcase CharCode.Digit0: return 0;\n\t\t\t\t\tcase CharCode.Digit1: return 1;\n\t\t\t\t\tcase CharCode.Digit2: return 2;\n\t\t\t\t\tcase CharCode.Digit3: return 3;\n\t\t\t\t\tcase CharCode.Digit4: return 4;\n\t\t\t\t\tcase CharCode.Digit5: return 5;\n\t\t\t\t\tcase CharCode.Digit6: return 6;\n\t\t\t\t\tcase CharCode.Digit7: return 7;\n\t\t\t\t\tcase CharCode.Digit8: return 8;\n\t\t\t\t\tcase CharCode.Digit9: return 9;\n\t\t\t\t\tcase CharCode.a: return 10;\n\t\t\t\t\tcase CharCode.A: return 10;\n\t\t\t\t\tcase CharCode.b: return 11;\n\t\t\t\t\tcase CharCode.B: return 11;\n\t\t\t\t\tcase CharCode.c: return 12;\n\t\t\t\t\tcase CharCode.C: return 12;\n\t\t\t\t\tcase CharCode.d: return 13;\n\t\t\t\t\tcase CharCode.D: return 13;\n\t\t\t\t\tcase CharCode.e: return 14;\n\t\t\t\t\tcase CharCode.E: return 14;\n\t\t\t\t\tcase CharCode.f: return 15;\n\t\t\t\t\tcase CharCode.F: return 15;\n\t\t\t\t}\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t}\n\t}\n}\n","\n\nexport function memoize(_target: any, key: string, descriptor: any) {\n\tlet fnKey: string | null = null;\n\tlet fn: Function | null = null;\n\n\tif (typeof descriptor.value === 'function') {\n\t\tfnKey = 'value';\n\t\tfn = descriptor.value;\n\n\t\tif (fn!.length !== 0) {\n\t\t\tconsole.warn('Memoize should only be used in functions with zero parameters');\n\t\t}\n\t} else if (typeof descriptor.get === 'function') {\n\t\tfnKey = 'get';\n\t\tfn = descriptor.get;\n\t}\n\n\tif (!fn) {\n\t\tthrow new Error('not supported');\n\t}\n\n\tconst memoizeKey = `$memoize$${key}`;\n\tdescriptor[fnKey!] = function (...args: any[]) {\n\t\tif (!this.hasOwnProperty(memoizeKey)) {\n\t\t\tObject.defineProperty(this, memoizeKey, {\n\t\t\t\tconfigurable: false,\n\t\t\t\tenumerable: false,\n\t\t\t\twritable: false,\n\t\t\t\tvalue: fn.apply(this, args)\n\t\t\t});\n\t\t}\n\n\t\treturn this[memoizeKey];\n\t};\n}\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 * Represents information about a specific difference between two sequences.\n */\nexport class DiffChange {\n\n\t/**\n\t * The position of the first element in the original sequence which\n\t * this change affects.\n\t */\n\tpublic originalStart: number;\n\n\t/**\n\t * The number of elements from the original sequence which were\n\t * affected.\n\t */\n\tpublic originalLength: number;\n\n\t/**\n\t * The position of the first element in the modified sequence which\n\t * this change affects.\n\t */\n\tpublic modifiedStart: number;\n\n\t/**\n\t * The number of elements from the modified sequence which were\n\t * affected (added).\n\t */\n\tpublic modifiedLength: number;\n\n\t/**\n\t * Constructs a new DiffChange with the given sequence information\n\t * and content.\n\t */\n\tconstructor(originalStart: number, originalLength: number, modifiedStart: number, modifiedLength: number) {\n\t\t//Debug.Assert(originalLength > 0 || modifiedLength > 0, \"originalLength and modifiedLength cannot both be <= 0\");\n\t\tthis.originalStart = originalStart;\n\t\tthis.originalLength = originalLength;\n\t\tthis.modifiedStart = modifiedStart;\n\t\tthis.modifiedLength = modifiedLength;\n\t}\n\n\t/**\n\t * The end point (exclusive) of the change in the original sequence.\n\t */\n\tpublic getOriginalEnd() {\n\t\treturn this.originalStart + this.originalLength;\n\t}\n\n\t/**\n\t * The end point (exclusive) of the change in the modified sequence.\n\t */\n\tpublic getModifiedEnd() {\n\t\treturn this.modifiedStart + this.modifiedLength;\n\t}\n}\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\nimport * as arrays from 'vs/base/common/arrays';\n\nexport type EqualityComparer = (a: T, b: T) => boolean;\nexport const strictEquals: EqualityComparer = (a, b) => a === b;\n\n/**\n * Checks if the items of two arrays are equal.\n * By default, strict equality is used to compare elements, but a custom equality comparer can be provided.\n */\nexport function itemsEquals(itemEquals: EqualityComparer = strictEquals): EqualityComparer {\n\treturn (a, b) => arrays.equals(a, b, itemEquals);\n}\n\n/**\n * Uses `item.equals(other)` to determine equality.\n */\nexport function itemEquals(): EqualityComparer {\n\treturn (a, b) => a.equals(b);\n}\n\nexport function equalsIfDefined(v1: T | undefined, v2: T | undefined, equals: EqualityComparer): boolean {\n\tif (!v1 || !v2) {\n\t\treturn v1 === v2;\n\t}\n\treturn equals(v1, v2);\n}\nconst objIds = new WeakMap();\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\nexport interface ErrorListenerCallback {\n\t(error: any): void;\n}\n\n// Avoid circular dependency on EventEmitter by implementing a subset of the interface.\nexport class ErrorHandler {\n\tprivate unexpectedErrorHandler: (e: any) => void;\n\tprivate listeners: ErrorListenerCallback[];\n\n\tconstructor() {\n\n\t\tthis.listeners = [];\n\n\t\tthis.unexpectedErrorHandler = function (e: any) {\n\t\t\tsetTimeout(() => {\n\t\t\t\tif (e.stack) {\n\t\t\t\t\tif (ErrorNoTelemetry.isErrorNoTelemetry(e)) {\n\t\t\t\t\t\tthrow new ErrorNoTelemetry(e.message + '\\n\\n' + e.stack);\n\t\t\t\t\t}\n\n\t\t\t\t\tthrow new Error(e.message + '\\n\\n' + e.stack);\n\t\t\t\t}\n\n\t\t\t\tthrow e;\n\t\t\t}, 0);\n\t\t};\n\t}\n\n\tprivate emit(e: any): void {\n\t\tthis.listeners.forEach((listener) => {\n\t\t\tlistener(e);\n\t\t});\n\t}\n\n\tonUnexpectedError(e: any): void {\n\t\tthis.unexpectedErrorHandler(e);\n\t\tthis.emit(e);\n\t}\n\n\t// For external errors, we don't want the listeners to be called\n\tonUnexpectedExternalError(e: any): void {\n\t\tthis.unexpectedErrorHandler(e);\n\t}\n}\n\nexport const errorHandler = new ErrorHandler();\n\nexport function onUnexpectedError(e: any): undefined {\n\t// ignore errors from cancelled promises\n\tif (!isCancellationError(e)) {\n\t\terrorHandler.onUnexpectedError(e);\n\t}\n\treturn undefined;\n}\n\nexport function onUnexpectedExternalError(e: any): undefined {\n\t// ignore errors from cancelled promises\n\tif (!isCancellationError(e)) {\n\t\terrorHandler.onUnexpectedExternalError(e);\n\t}\n\treturn undefined;\n}\n\nexport interface SerializedError {\n}\n\nexport function transformErrorForSerialization(error: Error): SerializedError;\nexport function transformErrorForSerialization(error: any): any;\nexport function transformErrorForSerialization(error: any): any {\n\tif (error instanceof Error) {\n\t\tconst { name, message } = error;\n\t\tconst stack: string = (error).stacktrace || (error).stack;\n\t\treturn {\n\t\t\t$isError: true,\n\t\t\tname,\n\t\t\tmessage,\n\t\t\tstack,\n\t\t\tnoTelemetry: ErrorNoTelemetry.isErrorNoTelemetry(error)\n\t\t};\n\t}\n\n\t// return as is\n\treturn error;\n}\n\nconst canceledName = 'Canceled';\n\n/**\n * Checks if the given error is a promise in canceled state\n */\nexport function isCancellationError(error: any): boolean {\n\tif (error instanceof CancellationError) {\n\t\treturn true;\n\t}\n\treturn error instanceof Error && error.name === canceledName && error.message === canceledName;\n}\n\n// !!!IMPORTANT!!!\n// Do NOT change this class because it is also used as an API-type.\nexport class CancellationError extends Error {\n\tconstructor() {\n\t\tsuper(canceledName);\n\t\tthis.name = this.message;\n\t}\n}\n\n/**\n * @deprecated use {@link CancellationError `new CancellationError()`} instead\n */\nexport function canceled(): Error {\n\tconst error = new Error(canceledName);\n\terror.name = error.message;\n\treturn error;\n}\n\nexport function illegalArgument(name?: string): Error {\n\tif (name) {\n\t\treturn new Error(`Illegal argument: ${name}`);\n\t} else {\n\t\treturn new Error('Illegal argument');\n\t}\n}\n\nexport function illegalState(name?: string): Error {\n\tif (name) {\n\t\treturn new Error(`Illegal state: ${name}`);\n\t} else {\n\t\treturn new Error('Illegal state');\n\t}\n}\n\nexport class NotSupportedError extends Error {\n\tconstructor(message?: string) {\n\t\tsuper('NotSupported');\n\t\tif (message) {\n\t\t\tthis.message = message;\n\t\t}\n\t}\n}\n\n/**\n * Error that when thrown won't be logged in telemetry as an unhandled error.\n */\nexport class ErrorNoTelemetry extends Error {\n\toverride readonly name: string;\n\n\tconstructor(msg?: string) {\n\t\tsuper(msg);\n\t\tthis.name = 'CodeExpectedError';\n\t}\n\n\tpublic static fromError(err: Error): ErrorNoTelemetry {\n\t\tif (err instanceof ErrorNoTelemetry) {\n\t\t\treturn err;\n\t\t}\n\n\t\tconst result = new ErrorNoTelemetry();\n\t\tresult.message = err.message;\n\t\tresult.stack = err.stack;\n\t\treturn result;\n\t}\n\n\tpublic static isErrorNoTelemetry(err: Error): err is ErrorNoTelemetry {\n\t\treturn err.name === 'CodeExpectedError';\n\t}\n}\n\n/**\n * This error indicates a bug.\n * Do not throw this for invalid user input.\n * Only catch this error to recover gracefully from bugs.\n */\nexport class BugIndicatingError extends Error {\n\tconstructor(message?: string) {\n\t\tsuper(message || 'An unexpected bug occurred.');\n\t\tObject.setPrototypeOf(this, BugIndicatingError.prototype);\n\n\t\t// Because we know for sure only buggy code throws this,\n\t\t// we definitely want to break here and fix the bug.\n\t\t// eslint-disable-next-line no-debugger\n\t\t// debugger;\n\t}\n}\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\nimport { mainWindow } from 'vs/base/browser/window';\nimport { onUnexpectedError } from 'vs/base/common/errors';\n\nexport function createTrustedTypesPolicy(\n\tpolicyName: string,\n\tpolicyOptions?: Options,\n): undefined | Pick, 'name' | Extract> {\n\n\tinterface IMonacoEnvironment {\n\t\tcreateTrustedTypesPolicy(\n\t\t\tpolicyName: string,\n\t\t\tpolicyOptions?: Options,\n\t\t): undefined | Pick, 'name' | Extract>;\n\t}\n\tconst monacoEnvironment: IMonacoEnvironment | undefined = (globalThis as any).MonacoEnvironment;\n\n\tif (monacoEnvironment?.createTrustedTypesPolicy) {\n\t\ttry {\n\t\t\treturn monacoEnvironment.createTrustedTypesPolicy(policyName, policyOptions);\n\t\t} catch (err) {\n\t\t\tonUnexpectedError(err);\n\t\t\treturn undefined;\n\t\t}\n\t}\n\ttry {\n\t\treturn mainWindow.trustedTypes?.createPolicy(policyName, policyOptions);\n\t} catch (err) {\n\t\tonUnexpectedError(err);\n\t\treturn undefined;\n\t}\n}\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\nimport { BugIndicatingError, onUnexpectedError } from 'vs/base/common/errors';\n\n/**\n * Throws an error with the provided message if the provided value does not evaluate to a true Javascript value.\n *\n * @deprecated Use `assert(...)` instead.\n * This method is usually used like this:\n * ```ts\n * import * as assert from 'vs/base/common/assert';\n * assert.ok(...);\n * ```\n *\n * However, `assert` in that example is a user chosen name.\n * There is no tooling for generating such an import statement.\n * Thus, the `assert(...)` function should be used instead.\n */\nexport function ok(value?: unknown, message?: string) {\n\tif (!value) {\n\t\tthrow new Error(message ? `Assertion failed (${message})` : 'Assertion Failed');\n\t}\n}\n\nexport function assertNever(value: never, message = 'Unreachable'): never {\n\tthrow new Error(message);\n}\n\n/**\n * Like assert, but doesn't throw.\n */\nexport function softAssert(condition: boolean): void {\n\tif (!condition) {\n\t\tonUnexpectedError(new BugIndicatingError('Soft Assertion Failed'));\n\t}\n}\n\n/**\n * condition must be side-effect free!\n */\nexport function assertFn(condition: () => boolean): void {\n\tif (!condition()) {\n\t\t// eslint-disable-next-line no-debugger\n\t\tdebugger;\n\t\t// Reevaluate `condition` again to make debugging easier\n\t\tcondition();\n\t\tonUnexpectedError(new BugIndicatingError('Assertion Failed'));\n\t}\n}\n\nexport function checkAdjacentItems(items: readonly T[], predicate: (item1: T, item2: T) => boolean): boolean {\n\tlet i = 0;\n\twhile (i < items.length - 1) {\n\t\tconst a = items[i];\n\t\tconst b = items[i + 1];\n\t\tif (!predicate(a, b)) {\n\t\t\treturn false;\n\t\t}\n\t\ti++;\n\t}\n\treturn true;\n}\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 * Given a function, returns a function that is only calling that function once.\n */\nexport function createSingleCallFunction(this: unknown, fn: T, fnDidRunCallback?: () => void): T {\n\tconst _this = this;\n\tlet didCall = false;\n\tlet result: unknown;\n\n\treturn function () {\n\t\tif (didCall) {\n\t\t\treturn result;\n\t\t}\n\n\t\tdidCall = true;\n\t\tif (fnDidRunCallback) {\n\t\t\ttry {\n\t\t\t\tresult = fn.apply(_this, arguments);\n\t\t\t} finally {\n\t\t\t\tfnDidRunCallback();\n\t\t\t}\n\t\t} else {\n\t\t\tresult = fn.apply(_this, arguments);\n\t\t}\n\n\t\treturn result;\n\t} as unknown as T;\n}\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\nexport class HierarchicalKind {\n\tpublic static readonly sep = '.';\n\n\tpublic static readonly None = new HierarchicalKind('@@none@@'); // Special kind that matches nothing\n\tpublic static readonly Empty = new HierarchicalKind('');\n\n\tconstructor(\n\t\tpublic readonly value: string\n\t) { }\n\n\tpublic equals(other: HierarchicalKind): boolean {\n\t\treturn this.value === other.value;\n\t}\n\n\tpublic contains(other: HierarchicalKind): boolean {\n\t\treturn this.equals(other) || this.value === '' || other.value.startsWith(this.value + HierarchicalKind.sep);\n\t}\n\n\tpublic intersects(other: HierarchicalKind): boolean {\n\t\treturn this.contains(other) || other.contains(this);\n\t}\n\n\tpublic append(...parts: string[]): HierarchicalKind {\n\t\treturn new HierarchicalKind((this.value ? [this.value, ...parts] : parts).join(HierarchicalKind.sep));\n\t}\n}\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\nexport class IdGenerator {\n\n\tprivate _prefix: string;\n\tprivate _lastId: number;\n\n\tconstructor(prefix: string) {\n\t\tthis._prefix = prefix;\n\t\tthis._lastId = 0;\n\t}\n\n\tpublic nextId(): string {\n\t\treturn this._prefix + (++this._lastId);\n\t}\n}\n\nexport const defaultGenerator = new IdGenerator('id#');","/*---------------------------------------------------------------------------------------------\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\nexport namespace Iterable {\n\n\texport function is(thing: any): thing is Iterable {\n\t\treturn thing && typeof thing === 'object' && typeof thing[Symbol.iterator] === 'function';\n\t}\n\n\tconst _empty: Iterable = Object.freeze([]);\n\texport function empty(): Iterable {\n\t\treturn _empty;\n\t}\n\n\texport function* single(element: T): Iterable {\n\t\tyield element;\n\t}\n\n\texport function wrap(iterableOrElement: Iterable | T): Iterable {\n\t\tif (is(iterableOrElement)) {\n\t\t\treturn iterableOrElement;\n\t\t} else {\n\t\t\treturn single(iterableOrElement);\n\t\t}\n\t}\n\n\texport function from(iterable: Iterable | undefined | null): Iterable {\n\t\treturn iterable || _empty;\n\t}\n\n\texport function* reverse(array: Array): Iterable {\n\t\tfor (let i = array.length - 1; i >= 0; i--) {\n\t\t\tyield array[i];\n\t\t}\n\t}\n\n\texport function isEmpty(iterable: Iterable | undefined | null): boolean {\n\t\treturn !iterable || iterable[Symbol.iterator]().next().done === true;\n\t}\n\n\texport function first(iterable: Iterable): T | undefined {\n\t\treturn iterable[Symbol.iterator]().next().value;\n\t}\n\n\texport function some(iterable: Iterable, predicate: (t: T) => unknown): boolean {\n\t\tfor (const element of iterable) {\n\t\t\tif (predicate(element)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\texport function find(iterable: Iterable, predicate: (t: T) => t is R): R | undefined;\n\texport function find(iterable: Iterable, predicate: (t: T) => boolean): T | undefined;\n\texport function find(iterable: Iterable, predicate: (t: T) => boolean): T | undefined {\n\t\tfor (const element of iterable) {\n\t\t\tif (predicate(element)) {\n\t\t\t\treturn element;\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\texport function filter(iterable: Iterable, predicate: (t: T) => t is R): Iterable;\n\texport function filter(iterable: Iterable, predicate: (t: T) => boolean): Iterable;\n\texport function* filter(iterable: Iterable, predicate: (t: T) => boolean): Iterable {\n\t\tfor (const element of iterable) {\n\t\t\tif (predicate(element)) {\n\t\t\t\tyield element;\n\t\t\t}\n\t\t}\n\t}\n\n\texport function* map(iterable: Iterable, fn: (t: T, index: number) => R): Iterable {\n\t\tlet index = 0;\n\t\tfor (const element of iterable) {\n\t\t\tyield fn(element, index++);\n\t\t}\n\t}\n\n\texport function* concat(...iterables: Iterable[]): Iterable {\n\t\tfor (const iterable of iterables) {\n\t\t\tyield* iterable;\n\t\t}\n\t}\n\n\texport function reduce(iterable: Iterable, reducer: (previousValue: R, currentValue: T) => R, initialValue: R): R {\n\t\tlet value = initialValue;\n\t\tfor (const element of iterable) {\n\t\t\tvalue = reducer(value, element);\n\t\t}\n\t\treturn value;\n\t}\n\n\t/**\n\t * Returns an iterable slice of the array, with the same semantics as `array.slice()`.\n\t */\n\texport function* slice(arr: ReadonlyArray, from: number, to = arr.length): Iterable {\n\t\tif (from < 0) {\n\t\t\tfrom += arr.length;\n\t\t}\n\n\t\tif (to < 0) {\n\t\t\tto += arr.length;\n\t\t} else if (to > arr.length) {\n\t\t\tto = arr.length;\n\t\t}\n\n\t\tfor (; from < to; from++) {\n\t\t\tyield arr[from];\n\t\t}\n\t}\n\n\t/**\n\t * Consumes `atMost` elements from iterable and returns the consumed elements,\n\t * and an iterable for the rest of the elements.\n\t */\n\texport function consume(iterable: Iterable, atMost: number = Number.POSITIVE_INFINITY): [T[], Iterable] {\n\t\tconst consumed: T[] = [];\n\n\t\tif (atMost === 0) {\n\t\t\treturn [consumed, iterable];\n\t\t}\n\n\t\tconst iterator = iterable[Symbol.iterator]();\n\n\t\tfor (let i = 0; i < atMost; i++) {\n\t\t\tconst next = iterator.next();\n\n\t\t\tif (next.done) {\n\t\t\t\treturn [consumed, Iterable.empty()];\n\t\t\t}\n\n\t\t\tconsumed.push(next.value);\n\t\t}\n\n\t\treturn [consumed, { [Symbol.iterator]() { return iterator; } }];\n\t}\n\n\texport async function asyncToArray(iterable: AsyncIterable): Promise {\n\t\tconst result: T[] = [];\n\t\tfor await (const item of iterable) {\n\t\t\tresult.push(item);\n\t\t}\n\t\treturn Promise.resolve(result);\n\t}\n}\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 * 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 const enum KeyCode {\n\tDependsOnKbLayout = -1,\n\n\t/**\n\t * Placed first to cover the 0 value of the enum.\n\t */\n\tUnknown = 0,\n\n\tBackspace,\n\tTab,\n\tEnter,\n\tShift,\n\tCtrl,\n\tAlt,\n\tPauseBreak,\n\tCapsLock,\n\tEscape,\n\tSpace,\n\tPageUp,\n\tPageDown,\n\tEnd,\n\tHome,\n\tLeftArrow,\n\tUpArrow,\n\tRightArrow,\n\tDownArrow,\n\tInsert,\n\tDelete,\n\n\tDigit0,\n\tDigit1,\n\tDigit2,\n\tDigit3,\n\tDigit4,\n\tDigit5,\n\tDigit6,\n\tDigit7,\n\tDigit8,\n\tDigit9,\n\n\tKeyA,\n\tKeyB,\n\tKeyC,\n\tKeyD,\n\tKeyE,\n\tKeyF,\n\tKeyG,\n\tKeyH,\n\tKeyI,\n\tKeyJ,\n\tKeyK,\n\tKeyL,\n\tKeyM,\n\tKeyN,\n\tKeyO,\n\tKeyP,\n\tKeyQ,\n\tKeyR,\n\tKeyS,\n\tKeyT,\n\tKeyU,\n\tKeyV,\n\tKeyW,\n\tKeyX,\n\tKeyY,\n\tKeyZ,\n\n\tMeta,\n\tContextMenu,\n\n\tF1,\n\tF2,\n\tF3,\n\tF4,\n\tF5,\n\tF6,\n\tF7,\n\tF8,\n\tF9,\n\tF10,\n\tF11,\n\tF12,\n\tF13,\n\tF14,\n\tF15,\n\tF16,\n\tF17,\n\tF18,\n\tF19,\n\tF20,\n\tF21,\n\tF22,\n\tF23,\n\tF24,\n\n\tNumLock,\n\tScrollLock,\n\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\tSemicolon,\n\t/**\n\t * For any country/region, the '+' key\n\t * For the US standard keyboard, the '=+' key\n\t */\n\tEqual,\n\t/**\n\t * For any country/region, the ',' key\n\t * For the US standard keyboard, the ',<' key\n\t */\n\tComma,\n\t/**\n\t * For any country/region, the '-' key\n\t * For the US standard keyboard, the '-_' key\n\t */\n\tMinus,\n\t/**\n\t * For any country/region, the '.' key\n\t * For the US standard keyboard, the '.>' key\n\t */\n\tPeriod,\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\tSlash,\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\tBackquote,\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\tBracketLeft,\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\tBackslash,\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\tBracketRight,\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\tQuote,\n\t/**\n\t * Used for miscellaneous characters; it can vary by keyboard.\n\t */\n\tOEM_8,\n\t/**\n\t * Either the angle bracket key or the backslash key on the RT 102-key keyboard.\n\t */\n\tIntlBackslash,\n\n\tNumpad0, // VK_NUMPAD0, 0x60, Numeric keypad 0 key\n\tNumpad1, // VK_NUMPAD1, 0x61, Numeric keypad 1 key\n\tNumpad2, // VK_NUMPAD2, 0x62, Numeric keypad 2 key\n\tNumpad3, // VK_NUMPAD3, 0x63, Numeric keypad 3 key\n\tNumpad4, // VK_NUMPAD4, 0x64, Numeric keypad 4 key\n\tNumpad5, // VK_NUMPAD5, 0x65, Numeric keypad 5 key\n\tNumpad6, // VK_NUMPAD6, 0x66, Numeric keypad 6 key\n\tNumpad7, // VK_NUMPAD7, 0x67, Numeric keypad 7 key\n\tNumpad8, // VK_NUMPAD8, 0x68, Numeric keypad 8 key\n\tNumpad9, // VK_NUMPAD9, 0x69, Numeric keypad 9 key\n\n\tNumpadMultiply,\t// VK_MULTIPLY, 0x6A, Multiply key\n\tNumpadAdd,\t\t// VK_ADD, 0x6B, Add key\n\tNUMPAD_SEPARATOR,\t// VK_SEPARATOR, 0x6C, Separator key\n\tNumpadSubtract,\t// VK_SUBTRACT, 0x6D, Subtract key\n\tNumpadDecimal,\t// VK_DECIMAL, 0x6E, Decimal key\n\tNumpadDivide,\t// VK_DIVIDE, 0x6F,\n\n\t/**\n\t * Cover all key codes when IME is processing input.\n\t */\n\tKEY_IN_COMPOSITION,\n\n\tABNT_C1, // Brazilian (ABNT) Keyboard\n\tABNT_C2, // Brazilian (ABNT) Keyboard\n\n\tAudioVolumeMute,\n\tAudioVolumeUp,\n\tAudioVolumeDown,\n\n\tBrowserSearch,\n\tBrowserHome,\n\tBrowserBack,\n\tBrowserForward,\n\n\tMediaTrackNext,\n\tMediaTrackPrevious,\n\tMediaStop,\n\tMediaPlayPause,\n\tLaunchMediaPlayer,\n\tLaunchMail,\n\tLaunchApp2,\n\n\t/**\n\t * VK_CLEAR, 0x0C, CLEAR key\n\t */\n\tClear,\n\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\n}\n\n/**\n * keyboardEvent.code\n */\nexport const enum ScanCode {\n\tDependsOnKbLayout = -1,\n\tNone,\n\tHyper,\n\tSuper,\n\tFn,\n\tFnLock,\n\tSuspend,\n\tResume,\n\tTurbo,\n\tSleep,\n\tWakeUp,\n\tKeyA,\n\tKeyB,\n\tKeyC,\n\tKeyD,\n\tKeyE,\n\tKeyF,\n\tKeyG,\n\tKeyH,\n\tKeyI,\n\tKeyJ,\n\tKeyK,\n\tKeyL,\n\tKeyM,\n\tKeyN,\n\tKeyO,\n\tKeyP,\n\tKeyQ,\n\tKeyR,\n\tKeyS,\n\tKeyT,\n\tKeyU,\n\tKeyV,\n\tKeyW,\n\tKeyX,\n\tKeyY,\n\tKeyZ,\n\tDigit1,\n\tDigit2,\n\tDigit3,\n\tDigit4,\n\tDigit5,\n\tDigit6,\n\tDigit7,\n\tDigit8,\n\tDigit9,\n\tDigit0,\n\tEnter,\n\tEscape,\n\tBackspace,\n\tTab,\n\tSpace,\n\tMinus,\n\tEqual,\n\tBracketLeft,\n\tBracketRight,\n\tBackslash,\n\tIntlHash,\n\tSemicolon,\n\tQuote,\n\tBackquote,\n\tComma,\n\tPeriod,\n\tSlash,\n\tCapsLock,\n\tF1,\n\tF2,\n\tF3,\n\tF4,\n\tF5,\n\tF6,\n\tF7,\n\tF8,\n\tF9,\n\tF10,\n\tF11,\n\tF12,\n\tPrintScreen,\n\tScrollLock,\n\tPause,\n\tInsert,\n\tHome,\n\tPageUp,\n\tDelete,\n\tEnd,\n\tPageDown,\n\tArrowRight,\n\tArrowLeft,\n\tArrowDown,\n\tArrowUp,\n\tNumLock,\n\tNumpadDivide,\n\tNumpadMultiply,\n\tNumpadSubtract,\n\tNumpadAdd,\n\tNumpadEnter,\n\tNumpad1,\n\tNumpad2,\n\tNumpad3,\n\tNumpad4,\n\tNumpad5,\n\tNumpad6,\n\tNumpad7,\n\tNumpad8,\n\tNumpad9,\n\tNumpad0,\n\tNumpadDecimal,\n\tIntlBackslash,\n\tContextMenu,\n\tPower,\n\tNumpadEqual,\n\tF13,\n\tF14,\n\tF15,\n\tF16,\n\tF17,\n\tF18,\n\tF19,\n\tF20,\n\tF21,\n\tF22,\n\tF23,\n\tF24,\n\tOpen,\n\tHelp,\n\tSelect,\n\tAgain,\n\tUndo,\n\tCut,\n\tCopy,\n\tPaste,\n\tFind,\n\tAudioVolumeMute,\n\tAudioVolumeUp,\n\tAudioVolumeDown,\n\tNumpadComma,\n\tIntlRo,\n\tKanaMode,\n\tIntlYen,\n\tConvert,\n\tNonConvert,\n\tLang1,\n\tLang2,\n\tLang3,\n\tLang4,\n\tLang5,\n\tAbort,\n\tProps,\n\tNumpadParenLeft,\n\tNumpadParenRight,\n\tNumpadBackspace,\n\tNumpadMemoryStore,\n\tNumpadMemoryRecall,\n\tNumpadMemoryClear,\n\tNumpadMemoryAdd,\n\tNumpadMemorySubtract,\n\tNumpadClear,\n\tNumpadClearEntry,\n\tControlLeft,\n\tShiftLeft,\n\tAltLeft,\n\tMetaLeft,\n\tControlRight,\n\tShiftRight,\n\tAltRight,\n\tMetaRight,\n\tBrightnessUp,\n\tBrightnessDown,\n\tMediaPlay,\n\tMediaRecord,\n\tMediaFastForward,\n\tMediaRewind,\n\tMediaTrackNext,\n\tMediaTrackPrevious,\n\tMediaStop,\n\tEject,\n\tMediaPlayPause,\n\tMediaSelect,\n\tLaunchMail,\n\tLaunchApp2,\n\tLaunchApp1,\n\tSelectTask,\n\tLaunchScreenSaver,\n\tBrowserSearch,\n\tBrowserHome,\n\tBrowserBack,\n\tBrowserForward,\n\tBrowserStop,\n\tBrowserRefresh,\n\tBrowserFavorites,\n\tZoomToggle,\n\tMailReply,\n\tMailForward,\n\tMailSend,\n\n\tMAX_VALUE\n}\n\nclass KeyCodeStrMap {\n\n\tpublic _keyCodeToStr: string[];\n\tpublic _strToKeyCode: { [str: string]: KeyCode };\n\n\tconstructor() {\n\t\tthis._keyCodeToStr = [];\n\t\tthis._strToKeyCode = Object.create(null);\n\t}\n\n\tdefine(keyCode: KeyCode, str: string): void {\n\t\tthis._keyCodeToStr[keyCode] = str;\n\t\tthis._strToKeyCode[str.toLowerCase()] = keyCode;\n\t}\n\n\tkeyCodeToStr(keyCode: KeyCode): string {\n\t\treturn this._keyCodeToStr[keyCode];\n\t}\n\n\tstrToKeyCode(str: string): KeyCode {\n\t\treturn this._strToKeyCode[str.toLowerCase()] || KeyCode.Unknown;\n\t}\n}\n\nconst uiMap = new KeyCodeStrMap();\nconst userSettingsUSMap = new KeyCodeStrMap();\nconst userSettingsGeneralMap = new KeyCodeStrMap();\nexport const EVENT_KEY_CODE_MAP: { [keyCode: number]: KeyCode } = new Array(230);\nexport const NATIVE_WINDOWS_KEY_CODE_TO_KEY_CODE: { [nativeKeyCode: string]: KeyCode } = {};\nconst scanCodeIntToStr: string[] = [];\nconst scanCodeStrToInt: { [code: string]: number } = Object.create(null);\nconst scanCodeLowerCaseStrToInt: { [code: string]: number } = Object.create(null);\n\n/**\n * -1 if a ScanCode => KeyCode mapping depends on kb layout.\n */\nexport const IMMUTABLE_CODE_TO_KEY_CODE: KeyCode[] = [];\n\n/**\n * -1 if a KeyCode => ScanCode mapping depends on kb layout.\n */\nexport const IMMUTABLE_KEY_CODE_TO_CODE: ScanCode[] = [];\n\nfor (let i = 0; i <= ScanCode.MAX_VALUE; i++) {\n\tIMMUTABLE_CODE_TO_KEY_CODE[i] = KeyCode.DependsOnKbLayout;\n}\n\nfor (let i = 0; i <= KeyCode.MAX_VALUE; i++) {\n\tIMMUTABLE_KEY_CODE_TO_CODE[i] = ScanCode.DependsOnKbLayout;\n}\n\n(function () {\n\n\t// See https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx\n\t// See https://github.com/microsoft/node-native-keymap/blob/88c0b0e5/deps/chromium/keyboard_codes_win.h\n\n\tconst empty = '';\n\ttype IMappingEntry = [0 | 1, ScanCode, string, KeyCode, string, number, string, string, string];\n\tconst mappings: IMappingEntry[] = [\n\t\t// immutable, scanCode, scanCodeStr, keyCode, keyCodeStr, eventKeyCode, vkey, usUserSettingsLabel, generalUserSettingsLabel\n\t\t[1, ScanCode.None, 'None', KeyCode.Unknown, 'unknown', 0, 'VK_UNKNOWN', empty, empty],\n\t\t[1, ScanCode.Hyper, 'Hyper', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\t\t[1, ScanCode.Super, 'Super', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\t\t[1, ScanCode.Fn, 'Fn', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\t\t[1, ScanCode.FnLock, 'FnLock', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\t\t[1, ScanCode.Suspend, 'Suspend', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\t\t[1, ScanCode.Resume, 'Resume', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\t\t[1, ScanCode.Turbo, 'Turbo', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\t\t[1, ScanCode.Sleep, 'Sleep', KeyCode.Unknown, empty, 0, 'VK_SLEEP', empty, empty],\n\t\t[1, ScanCode.WakeUp, 'WakeUp', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\t\t[0, ScanCode.KeyA, 'KeyA', KeyCode.KeyA, 'A', 65, 'VK_A', empty, empty],\n\t\t[0, ScanCode.KeyB, 'KeyB', KeyCode.KeyB, 'B', 66, 'VK_B', empty, empty],\n\t\t[0, ScanCode.KeyC, 'KeyC', KeyCode.KeyC, 'C', 67, 'VK_C', empty, empty],\n\t\t[0, ScanCode.KeyD, 'KeyD', KeyCode.KeyD, 'D', 68, 'VK_D', empty, empty],\n\t\t[0, ScanCode.KeyE, 'KeyE', KeyCode.KeyE, 'E', 69, 'VK_E', empty, empty],\n\t\t[0, ScanCode.KeyF, 'KeyF', KeyCode.KeyF, 'F', 70, 'VK_F', empty, empty],\n\t\t[0, ScanCode.KeyG, 'KeyG', KeyCode.KeyG, 'G', 71, 'VK_G', empty, empty],\n\t\t[0, ScanCode.KeyH, 'KeyH', KeyCode.KeyH, 'H', 72, 'VK_H', empty, empty],\n\t\t[0, ScanCode.KeyI, 'KeyI', KeyCode.KeyI, 'I', 73, 'VK_I', empty, empty],\n\t\t[0, ScanCode.KeyJ, 'KeyJ', KeyCode.KeyJ, 'J', 74, 'VK_J', empty, empty],\n\t\t[0, ScanCode.KeyK, 'KeyK', KeyCode.KeyK, 'K', 75, 'VK_K', empty, empty],\n\t\t[0, ScanCode.KeyL, 'KeyL', KeyCode.KeyL, 'L', 76, 'VK_L', empty, empty],\n\t\t[0, ScanCode.KeyM, 'KeyM', KeyCode.KeyM, 'M', 77, 'VK_M', empty, empty],\n\t\t[0, ScanCode.KeyN, 'KeyN', KeyCode.KeyN, 'N', 78, 'VK_N', empty, empty],\n\t\t[0, ScanCode.KeyO, 'KeyO', KeyCode.KeyO, 'O', 79, 'VK_O', empty, empty],\n\t\t[0, ScanCode.KeyP, 'KeyP', KeyCode.KeyP, 'P', 80, 'VK_P', empty, empty],\n\t\t[0, ScanCode.KeyQ, 'KeyQ', KeyCode.KeyQ, 'Q', 81, 'VK_Q', empty, empty],\n\t\t[0, ScanCode.KeyR, 'KeyR', KeyCode.KeyR, 'R', 82, 'VK_R', empty, empty],\n\t\t[0, ScanCode.KeyS, 'KeyS', KeyCode.KeyS, 'S', 83, 'VK_S', empty, empty],\n\t\t[0, ScanCode.KeyT, 'KeyT', KeyCode.KeyT, 'T', 84, 'VK_T', empty, empty],\n\t\t[0, ScanCode.KeyU, 'KeyU', KeyCode.KeyU, 'U', 85, 'VK_U', empty, empty],\n\t\t[0, ScanCode.KeyV, 'KeyV', KeyCode.KeyV, 'V', 86, 'VK_V', empty, empty],\n\t\t[0, ScanCode.KeyW, 'KeyW', KeyCode.KeyW, 'W', 87, 'VK_W', empty, empty],\n\t\t[0, ScanCode.KeyX, 'KeyX', KeyCode.KeyX, 'X', 88, 'VK_X', empty, empty],\n\t\t[0, ScanCode.KeyY, 'KeyY', KeyCode.KeyY, 'Y', 89, 'VK_Y', empty, empty],\n\t\t[0, ScanCode.KeyZ, 'KeyZ', KeyCode.KeyZ, 'Z', 90, 'VK_Z', empty, empty],\n\t\t[0, ScanCode.Digit1, 'Digit1', KeyCode.Digit1, '1', 49, 'VK_1', empty, empty],\n\t\t[0, ScanCode.Digit2, 'Digit2', KeyCode.Digit2, '2', 50, 'VK_2', empty, empty],\n\t\t[0, ScanCode.Digit3, 'Digit3', KeyCode.Digit3, '3', 51, 'VK_3', empty, empty],\n\t\t[0, ScanCode.Digit4, 'Digit4', KeyCode.Digit4, '4', 52, 'VK_4', empty, empty],\n\t\t[0, ScanCode.Digit5, 'Digit5', KeyCode.Digit5, '5', 53, 'VK_5', empty, empty],\n\t\t[0, ScanCode.Digit6, 'Digit6', KeyCode.Digit6, '6', 54, 'VK_6', empty, empty],\n\t\t[0, ScanCode.Digit7, 'Digit7', KeyCode.Digit7, '7', 55, 'VK_7', empty, empty],\n\t\t[0, ScanCode.Digit8, 'Digit8', KeyCode.Digit8, '8', 56, 'VK_8', empty, empty],\n\t\t[0, ScanCode.Digit9, 'Digit9', KeyCode.Digit9, '9', 57, 'VK_9', empty, empty],\n\t\t[0, ScanCode.Digit0, 'Digit0', KeyCode.Digit0, '0', 48, 'VK_0', empty, empty],\n\t\t[1, ScanCode.Enter, 'Enter', KeyCode.Enter, 'Enter', 13, 'VK_RETURN', empty, empty],\n\t\t[1, ScanCode.Escape, 'Escape', KeyCode.Escape, 'Escape', 27, 'VK_ESCAPE', empty, empty],\n\t\t[1, ScanCode.Backspace, 'Backspace', KeyCode.Backspace, 'Backspace', 8, 'VK_BACK', empty, empty],\n\t\t[1, ScanCode.Tab, 'Tab', KeyCode.Tab, 'Tab', 9, 'VK_TAB', empty, empty],\n\t\t[1, ScanCode.Space, 'Space', KeyCode.Space, 'Space', 32, 'VK_SPACE', empty, empty],\n\t\t[0, ScanCode.Minus, 'Minus', KeyCode.Minus, '-', 189, 'VK_OEM_MINUS', '-', 'OEM_MINUS'],\n\t\t[0, ScanCode.Equal, 'Equal', KeyCode.Equal, '=', 187, 'VK_OEM_PLUS', '=', 'OEM_PLUS'],\n\t\t[0, ScanCode.BracketLeft, 'BracketLeft', KeyCode.BracketLeft, '[', 219, 'VK_OEM_4', '[', 'OEM_4'],\n\t\t[0, ScanCode.BracketRight, 'BracketRight', KeyCode.BracketRight, ']', 221, 'VK_OEM_6', ']', 'OEM_6'],\n\t\t[0, ScanCode.Backslash, 'Backslash', KeyCode.Backslash, '\\\\', 220, 'VK_OEM_5', '\\\\', 'OEM_5'],\n\t\t[0, ScanCode.IntlHash, 'IntlHash', KeyCode.Unknown, empty, 0, empty, empty, empty], // has been dropped from the w3c spec\n\t\t[0, ScanCode.Semicolon, 'Semicolon', KeyCode.Semicolon, ';', 186, 'VK_OEM_1', ';', 'OEM_1'],\n\t\t[0, ScanCode.Quote, 'Quote', KeyCode.Quote, '\\'', 222, 'VK_OEM_7', '\\'', 'OEM_7'],\n\t\t[0, ScanCode.Backquote, 'Backquote', KeyCode.Backquote, '`', 192, 'VK_OEM_3', '`', 'OEM_3'],\n\t\t[0, ScanCode.Comma, 'Comma', KeyCode.Comma, ',', 188, 'VK_OEM_COMMA', ',', 'OEM_COMMA'],\n\t\t[0, ScanCode.Period, 'Period', KeyCode.Period, '.', 190, 'VK_OEM_PERIOD', '.', 'OEM_PERIOD'],\n\t\t[0, ScanCode.Slash, 'Slash', KeyCode.Slash, '/', 191, 'VK_OEM_2', '/', 'OEM_2'],\n\t\t[1, ScanCode.CapsLock, 'CapsLock', KeyCode.CapsLock, 'CapsLock', 20, 'VK_CAPITAL', empty, empty],\n\t\t[1, ScanCode.F1, 'F1', KeyCode.F1, 'F1', 112, 'VK_F1', empty, empty],\n\t\t[1, ScanCode.F2, 'F2', KeyCode.F2, 'F2', 113, 'VK_F2', empty, empty],\n\t\t[1, ScanCode.F3, 'F3', KeyCode.F3, 'F3', 114, 'VK_F3', empty, empty],\n\t\t[1, ScanCode.F4, 'F4', KeyCode.F4, 'F4', 115, 'VK_F4', empty, empty],\n\t\t[1, ScanCode.F5, 'F5', KeyCode.F5, 'F5', 116, 'VK_F5', empty, empty],\n\t\t[1, ScanCode.F6, 'F6', KeyCode.F6, 'F6', 117, 'VK_F6', empty, empty],\n\t\t[1, ScanCode.F7, 'F7', KeyCode.F7, 'F7', 118, 'VK_F7', empty, empty],\n\t\t[1, ScanCode.F8, 'F8', KeyCode.F8, 'F8', 119, 'VK_F8', empty, empty],\n\t\t[1, ScanCode.F9, 'F9', KeyCode.F9, 'F9', 120, 'VK_F9', empty, empty],\n\t\t[1, ScanCode.F10, 'F10', KeyCode.F10, 'F10', 121, 'VK_F10', empty, empty],\n\t\t[1, ScanCode.F11, 'F11', KeyCode.F11, 'F11', 122, 'VK_F11', empty, empty],\n\t\t[1, ScanCode.F12, 'F12', KeyCode.F12, 'F12', 123, 'VK_F12', empty, empty],\n\t\t[1, ScanCode.PrintScreen, 'PrintScreen', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\t\t[1, ScanCode.ScrollLock, 'ScrollLock', KeyCode.ScrollLock, 'ScrollLock', 145, 'VK_SCROLL', empty, empty],\n\t\t[1, ScanCode.Pause, 'Pause', KeyCode.PauseBreak, 'PauseBreak', 19, 'VK_PAUSE', empty, empty],\n\t\t[1, ScanCode.Insert, 'Insert', KeyCode.Insert, 'Insert', 45, 'VK_INSERT', empty, empty],\n\t\t[1, ScanCode.Home, 'Home', KeyCode.Home, 'Home', 36, 'VK_HOME', empty, empty],\n\t\t[1, ScanCode.PageUp, 'PageUp', KeyCode.PageUp, 'PageUp', 33, 'VK_PRIOR', empty, empty],\n\t\t[1, ScanCode.Delete, 'Delete', KeyCode.Delete, 'Delete', 46, 'VK_DELETE', empty, empty],\n\t\t[1, ScanCode.End, 'End', KeyCode.End, 'End', 35, 'VK_END', empty, empty],\n\t\t[1, ScanCode.PageDown, 'PageDown', KeyCode.PageDown, 'PageDown', 34, 'VK_NEXT', empty, empty],\n\t\t[1, ScanCode.ArrowRight, 'ArrowRight', KeyCode.RightArrow, 'RightArrow', 39, 'VK_RIGHT', 'Right', empty],\n\t\t[1, ScanCode.ArrowLeft, 'ArrowLeft', KeyCode.LeftArrow, 'LeftArrow', 37, 'VK_LEFT', 'Left', empty],\n\t\t[1, ScanCode.ArrowDown, 'ArrowDown', KeyCode.DownArrow, 'DownArrow', 40, 'VK_DOWN', 'Down', empty],\n\t\t[1, ScanCode.ArrowUp, 'ArrowUp', KeyCode.UpArrow, 'UpArrow', 38, 'VK_UP', 'Up', empty],\n\t\t[1, ScanCode.NumLock, 'NumLock', KeyCode.NumLock, 'NumLock', 144, 'VK_NUMLOCK', empty, empty],\n\t\t[1, ScanCode.NumpadDivide, 'NumpadDivide', KeyCode.NumpadDivide, 'NumPad_Divide', 111, 'VK_DIVIDE', empty, empty],\n\t\t[1, ScanCode.NumpadMultiply, 'NumpadMultiply', KeyCode.NumpadMultiply, 'NumPad_Multiply', 106, 'VK_MULTIPLY', empty, empty],\n\t\t[1, ScanCode.NumpadSubtract, 'NumpadSubtract', KeyCode.NumpadSubtract, 'NumPad_Subtract', 109, 'VK_SUBTRACT', empty, empty],\n\t\t[1, ScanCode.NumpadAdd, 'NumpadAdd', KeyCode.NumpadAdd, 'NumPad_Add', 107, 'VK_ADD', empty, empty],\n\t\t[1, ScanCode.NumpadEnter, 'NumpadEnter', KeyCode.Enter, empty, 0, empty, empty, empty],\n\t\t[1, ScanCode.Numpad1, 'Numpad1', KeyCode.Numpad1, 'NumPad1', 97, 'VK_NUMPAD1', empty, empty],\n\t\t[1, ScanCode.Numpad2, 'Numpad2', KeyCode.Numpad2, 'NumPad2', 98, 'VK_NUMPAD2', empty, empty],\n\t\t[1, ScanCode.Numpad3, 'Numpad3', KeyCode.Numpad3, 'NumPad3', 99, 'VK_NUMPAD3', empty, empty],\n\t\t[1, ScanCode.Numpad4, 'Numpad4', KeyCode.Numpad4, 'NumPad4', 100, 'VK_NUMPAD4', empty, empty],\n\t\t[1, ScanCode.Numpad5, 'Numpad5', KeyCode.Numpad5, 'NumPad5', 101, 'VK_NUMPAD5', empty, empty],\n\t\t[1, ScanCode.Numpad6, 'Numpad6', KeyCode.Numpad6, 'NumPad6', 102, 'VK_NUMPAD6', empty, empty],\n\t\t[1, ScanCode.Numpad7, 'Numpad7', KeyCode.Numpad7, 'NumPad7', 103, 'VK_NUMPAD7', empty, empty],\n\t\t[1, ScanCode.Numpad8, 'Numpad8', KeyCode.Numpad8, 'NumPad8', 104, 'VK_NUMPAD8', empty, empty],\n\t\t[1, ScanCode.Numpad9, 'Numpad9', KeyCode.Numpad9, 'NumPad9', 105, 'VK_NUMPAD9', empty, empty],\n\t\t[1, ScanCode.Numpad0, 'Numpad0', KeyCode.Numpad0, 'NumPad0', 96, 'VK_NUMPAD0', empty, empty],\n\t\t[1, ScanCode.NumpadDecimal, 'NumpadDecimal', KeyCode.NumpadDecimal, 'NumPad_Decimal', 110, 'VK_DECIMAL', empty, empty],\n\t\t[0, ScanCode.IntlBackslash, 'IntlBackslash', KeyCode.IntlBackslash, 'OEM_102', 226, 'VK_OEM_102', empty, empty],\n\t\t[1, ScanCode.ContextMenu, 'ContextMenu', KeyCode.ContextMenu, 'ContextMenu', 93, empty, empty, empty],\n\t\t[1, ScanCode.Power, 'Power', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\t\t[1, ScanCode.NumpadEqual, 'NumpadEqual', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\t\t[1, ScanCode.F13, 'F13', KeyCode.F13, 'F13', 124, 'VK_F13', empty, empty],\n\t\t[1, ScanCode.F14, 'F14', KeyCode.F14, 'F14', 125, 'VK_F14', empty, empty],\n\t\t[1, ScanCode.F15, 'F15', KeyCode.F15, 'F15', 126, 'VK_F15', empty, empty],\n\t\t[1, ScanCode.F16, 'F16', KeyCode.F16, 'F16', 127, 'VK_F16', empty, empty],\n\t\t[1, ScanCode.F17, 'F17', KeyCode.F17, 'F17', 128, 'VK_F17', empty, empty],\n\t\t[1, ScanCode.F18, 'F18', KeyCode.F18, 'F18', 129, 'VK_F18', empty, empty],\n\t\t[1, ScanCode.F19, 'F19', KeyCode.F19, 'F19', 130, 'VK_F19', empty, empty],\n\t\t[1, ScanCode.F20, 'F20', KeyCode.F20, 'F20', 131, 'VK_F20', empty, empty],\n\t\t[1, ScanCode.F21, 'F21', KeyCode.F21, 'F21', 132, 'VK_F21', empty, empty],\n\t\t[1, ScanCode.F22, 'F22', KeyCode.F22, 'F22', 133, 'VK_F22', empty, empty],\n\t\t[1, ScanCode.F23, 'F23', KeyCode.F23, 'F23', 134, 'VK_F23', empty, empty],\n\t\t[1, ScanCode.F24, 'F24', KeyCode.F24, 'F24', 135, 'VK_F24', empty, empty],\n\t\t[1, ScanCode.Open, 'Open', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\t\t[1, ScanCode.Help, 'Help', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\t\t[1, ScanCode.Select, 'Select', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\t\t[1, ScanCode.Again, 'Again', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\t\t[1, ScanCode.Undo, 'Undo', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\t\t[1, ScanCode.Cut, 'Cut', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\t\t[1, ScanCode.Copy, 'Copy', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\t\t[1, ScanCode.Paste, 'Paste', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\t\t[1, ScanCode.Find, 'Find', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\t\t[1, ScanCode.AudioVolumeMute, 'AudioVolumeMute', KeyCode.AudioVolumeMute, 'AudioVolumeMute', 173, 'VK_VOLUME_MUTE', empty, empty],\n\t\t[1, ScanCode.AudioVolumeUp, 'AudioVolumeUp', KeyCode.AudioVolumeUp, 'AudioVolumeUp', 175, 'VK_VOLUME_UP', empty, empty],\n\t\t[1, ScanCode.AudioVolumeDown, 'AudioVolumeDown', KeyCode.AudioVolumeDown, 'AudioVolumeDown', 174, 'VK_VOLUME_DOWN', empty, empty],\n\t\t[1, ScanCode.NumpadComma, 'NumpadComma', KeyCode.NUMPAD_SEPARATOR, 'NumPad_Separator', 108, 'VK_SEPARATOR', empty, empty],\n\t\t[0, ScanCode.IntlRo, 'IntlRo', KeyCode.ABNT_C1, 'ABNT_C1', 193, 'VK_ABNT_C1', empty, empty],\n\t\t[1, ScanCode.KanaMode, 'KanaMode', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\t\t[0, ScanCode.IntlYen, 'IntlYen', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\t\t[1, ScanCode.Convert, 'Convert', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\t\t[1, ScanCode.NonConvert, 'NonConvert', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\t\t[1, ScanCode.Lang1, 'Lang1', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\t\t[1, ScanCode.Lang2, 'Lang2', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\t\t[1, ScanCode.Lang3, 'Lang3', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\t\t[1, ScanCode.Lang4, 'Lang4', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\t\t[1, ScanCode.Lang5, 'Lang5', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\t\t[1, ScanCode.Abort, 'Abort', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\t\t[1, ScanCode.Props, 'Props', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\t\t[1, ScanCode.NumpadParenLeft, 'NumpadParenLeft', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\t\t[1, ScanCode.NumpadParenRight, 'NumpadParenRight', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\t\t[1, ScanCode.NumpadBackspace, 'NumpadBackspace', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\t\t[1, ScanCode.NumpadMemoryStore, 'NumpadMemoryStore', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\t\t[1, ScanCode.NumpadMemoryRecall, 'NumpadMemoryRecall', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\t\t[1, ScanCode.NumpadMemoryClear, 'NumpadMemoryClear', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\t\t[1, ScanCode.NumpadMemoryAdd, 'NumpadMemoryAdd', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\t\t[1, ScanCode.NumpadMemorySubtract, 'NumpadMemorySubtract', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\t\t[1, ScanCode.NumpadClear, 'NumpadClear', KeyCode.Clear, 'Clear', 12, 'VK_CLEAR', empty, empty],\n\t\t[1, ScanCode.NumpadClearEntry, 'NumpadClearEntry', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\t\t[1, ScanCode.None, empty, KeyCode.Ctrl, 'Ctrl', 17, 'VK_CONTROL', empty, empty],\n\t\t[1, ScanCode.None, empty, KeyCode.Shift, 'Shift', 16, 'VK_SHIFT', empty, empty],\n\t\t[1, ScanCode.None, empty, KeyCode.Alt, 'Alt', 18, 'VK_MENU', empty, empty],\n\t\t[1, ScanCode.None, empty, KeyCode.Meta, 'Meta', 91, 'VK_COMMAND', empty, empty],\n\t\t[1, ScanCode.ControlLeft, 'ControlLeft', KeyCode.Ctrl, empty, 0, 'VK_LCONTROL', empty, empty],\n\t\t[1, ScanCode.ShiftLeft, 'ShiftLeft', KeyCode.Shift, empty, 0, 'VK_LSHIFT', empty, empty],\n\t\t[1, ScanCode.AltLeft, 'AltLeft', KeyCode.Alt, empty, 0, 'VK_LMENU', empty, empty],\n\t\t[1, ScanCode.MetaLeft, 'MetaLeft', KeyCode.Meta, empty, 0, 'VK_LWIN', empty, empty],\n\t\t[1, ScanCode.ControlRight, 'ControlRight', KeyCode.Ctrl, empty, 0, 'VK_RCONTROL', empty, empty],\n\t\t[1, ScanCode.ShiftRight, 'ShiftRight', KeyCode.Shift, empty, 0, 'VK_RSHIFT', empty, empty],\n\t\t[1, ScanCode.AltRight, 'AltRight', KeyCode.Alt, empty, 0, 'VK_RMENU', empty, empty],\n\t\t[1, ScanCode.MetaRight, 'MetaRight', KeyCode.Meta, empty, 0, 'VK_RWIN', empty, empty],\n\t\t[1, ScanCode.BrightnessUp, 'BrightnessUp', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\t\t[1, ScanCode.BrightnessDown, 'BrightnessDown', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\t\t[1, ScanCode.MediaPlay, 'MediaPlay', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\t\t[1, ScanCode.MediaRecord, 'MediaRecord', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\t\t[1, ScanCode.MediaFastForward, 'MediaFastForward', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\t\t[1, ScanCode.MediaRewind, 'MediaRewind', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\t\t[1, ScanCode.MediaTrackNext, 'MediaTrackNext', KeyCode.MediaTrackNext, 'MediaTrackNext', 176, 'VK_MEDIA_NEXT_TRACK', empty, empty],\n\t\t[1, ScanCode.MediaTrackPrevious, 'MediaTrackPrevious', KeyCode.MediaTrackPrevious, 'MediaTrackPrevious', 177, 'VK_MEDIA_PREV_TRACK', empty, empty],\n\t\t[1, ScanCode.MediaStop, 'MediaStop', KeyCode.MediaStop, 'MediaStop', 178, 'VK_MEDIA_STOP', empty, empty],\n\t\t[1, ScanCode.Eject, 'Eject', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\t\t[1, ScanCode.MediaPlayPause, 'MediaPlayPause', KeyCode.MediaPlayPause, 'MediaPlayPause', 179, 'VK_MEDIA_PLAY_PAUSE', empty, empty],\n\t\t[1, ScanCode.MediaSelect, 'MediaSelect', KeyCode.LaunchMediaPlayer, 'LaunchMediaPlayer', 181, 'VK_MEDIA_LAUNCH_MEDIA_SELECT', empty, empty],\n\t\t[1, ScanCode.LaunchMail, 'LaunchMail', KeyCode.LaunchMail, 'LaunchMail', 180, 'VK_MEDIA_LAUNCH_MAIL', empty, empty],\n\t\t[1, ScanCode.LaunchApp2, 'LaunchApp2', KeyCode.LaunchApp2, 'LaunchApp2', 183, 'VK_MEDIA_LAUNCH_APP2', empty, empty],\n\t\t[1, ScanCode.LaunchApp1, 'LaunchApp1', KeyCode.Unknown, empty, 0, 'VK_MEDIA_LAUNCH_APP1', empty, empty],\n\t\t[1, ScanCode.SelectTask, 'SelectTask', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\t\t[1, ScanCode.LaunchScreenSaver, 'LaunchScreenSaver', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\t\t[1, ScanCode.BrowserSearch, 'BrowserSearch', KeyCode.BrowserSearch, 'BrowserSearch', 170, 'VK_BROWSER_SEARCH', empty, empty],\n\t\t[1, ScanCode.BrowserHome, 'BrowserHome', KeyCode.BrowserHome, 'BrowserHome', 172, 'VK_BROWSER_HOME', empty, empty],\n\t\t[1, ScanCode.BrowserBack, 'BrowserBack', KeyCode.BrowserBack, 'BrowserBack', 166, 'VK_BROWSER_BACK', empty, empty],\n\t\t[1, ScanCode.BrowserForward, 'BrowserForward', KeyCode.BrowserForward, 'BrowserForward', 167, 'VK_BROWSER_FORWARD', empty, empty],\n\t\t[1, ScanCode.BrowserStop, 'BrowserStop', KeyCode.Unknown, empty, 0, 'VK_BROWSER_STOP', empty, empty],\n\t\t[1, ScanCode.BrowserRefresh, 'BrowserRefresh', KeyCode.Unknown, empty, 0, 'VK_BROWSER_REFRESH', empty, empty],\n\t\t[1, ScanCode.BrowserFavorites, 'BrowserFavorites', KeyCode.Unknown, empty, 0, 'VK_BROWSER_FAVORITES', empty, empty],\n\t\t[1, ScanCode.ZoomToggle, 'ZoomToggle', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\t\t[1, ScanCode.MailReply, 'MailReply', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\t\t[1, ScanCode.MailForward, 'MailForward', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\t\t[1, ScanCode.MailSend, 'MailSend', KeyCode.Unknown, empty, 0, empty, empty, empty],\n\n\t\t// See https://lists.w3.org/Archives/Public/www-dom/2010JulSep/att-0182/keyCode-spec.html\n\t\t// If an Input Method Editor is processing key input and the event is keydown, return 229.\n\t\t[1, ScanCode.None, empty, KeyCode.KEY_IN_COMPOSITION, 'KeyInComposition', 229, empty, empty, empty],\n\t\t[1, ScanCode.None, empty, KeyCode.ABNT_C2, 'ABNT_C2', 194, 'VK_ABNT_C2', empty, empty],\n\t\t[1, ScanCode.None, empty, KeyCode.OEM_8, 'OEM_8', 223, 'VK_OEM_8', empty, empty],\n\t\t[1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_KANA', empty, empty],\n\t\t[1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_HANGUL', empty, empty],\n\t\t[1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_JUNJA', empty, empty],\n\t\t[1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_FINAL', empty, empty],\n\t\t[1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_HANJA', empty, empty],\n\t\t[1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_KANJI', empty, empty],\n\t\t[1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_CONVERT', empty, empty],\n\t\t[1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_NONCONVERT', empty, empty],\n\t\t[1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_ACCEPT', empty, empty],\n\t\t[1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_MODECHANGE', empty, empty],\n\t\t[1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_SELECT', empty, empty],\n\t\t[1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_PRINT', empty, empty],\n\t\t[1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_EXECUTE', empty, empty],\n\t\t[1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_SNAPSHOT', empty, empty],\n\t\t[1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_HELP', empty, empty],\n\t\t[1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_APPS', empty, empty],\n\t\t[1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_PROCESSKEY', empty, empty],\n\t\t[1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_PACKET', empty, empty],\n\t\t[1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_DBE_SBCSCHAR', empty, empty],\n\t\t[1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_DBE_DBCSCHAR', empty, empty],\n\t\t[1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_ATTN', empty, empty],\n\t\t[1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_CRSEL', empty, empty],\n\t\t[1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_EXSEL', empty, empty],\n\t\t[1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_EREOF', empty, empty],\n\t\t[1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_PLAY', empty, empty],\n\t\t[1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_ZOOM', empty, empty],\n\t\t[1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_NONAME', empty, empty],\n\t\t[1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_PA1', empty, empty],\n\t\t[1, ScanCode.None, empty, KeyCode.Unknown, empty, 0, 'VK_OEM_CLEAR', empty, empty],\n\t];\n\n\tconst seenKeyCode: boolean[] = [];\n\tconst seenScanCode: boolean[] = [];\n\tfor (const mapping of mappings) {\n\t\tconst [immutable, scanCode, scanCodeStr, keyCode, keyCodeStr, eventKeyCode, vkey, usUserSettingsLabel, generalUserSettingsLabel] = mapping;\n\t\tif (!seenScanCode[scanCode]) {\n\t\t\tseenScanCode[scanCode] = true;\n\t\t\tscanCodeIntToStr[scanCode] = scanCodeStr;\n\t\t\tscanCodeStrToInt[scanCodeStr] = scanCode;\n\t\t\tscanCodeLowerCaseStrToInt[scanCodeStr.toLowerCase()] = scanCode;\n\t\t\tif (immutable) {\n\t\t\t\tIMMUTABLE_CODE_TO_KEY_CODE[scanCode] = keyCode;\n\t\t\t\tif (\n\t\t\t\t\t(keyCode !== KeyCode.Unknown)\n\t\t\t\t\t&& (keyCode !== KeyCode.Enter)\n\t\t\t\t\t&& (keyCode !== KeyCode.Ctrl)\n\t\t\t\t\t&& (keyCode !== KeyCode.Shift)\n\t\t\t\t\t&& (keyCode !== KeyCode.Alt)\n\t\t\t\t\t&& (keyCode !== KeyCode.Meta)\n\t\t\t\t) {\n\t\t\t\t\tIMMUTABLE_KEY_CODE_TO_CODE[keyCode] = scanCode;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (!seenKeyCode[keyCode]) {\n\t\t\tseenKeyCode[keyCode] = true;\n\t\t\tif (!keyCodeStr) {\n\t\t\t\tthrow new Error(`String representation missing for key code ${keyCode} around scan code ${scanCodeStr}`);\n\t\t\t}\n\t\t\tuiMap.define(keyCode, keyCodeStr);\n\t\t\tuserSettingsUSMap.define(keyCode, usUserSettingsLabel || keyCodeStr);\n\t\t\tuserSettingsGeneralMap.define(keyCode, generalUserSettingsLabel || usUserSettingsLabel || keyCodeStr);\n\t\t}\n\t\tif (eventKeyCode) {\n\t\t\tEVENT_KEY_CODE_MAP[eventKeyCode] = keyCode;\n\t\t}\n\t\tif (vkey) {\n\t\t\tNATIVE_WINDOWS_KEY_CODE_TO_KEY_CODE[vkey] = keyCode;\n\t\t}\n\t}\n\t// Manually added due to the exclusion above (due to duplication with NumpadEnter)\n\tIMMUTABLE_KEY_CODE_TO_CODE[KeyCode.Enter] = ScanCode.Enter;\n\n})();\n\nexport namespace KeyCodeUtils {\n\texport function toString(keyCode: KeyCode): string {\n\t\treturn uiMap.keyCodeToStr(keyCode);\n\t}\n\texport function fromString(key: string): KeyCode {\n\t\treturn uiMap.strToKeyCode(key);\n\t}\n\n\texport function toUserSettingsUS(keyCode: KeyCode): string {\n\t\treturn userSettingsUSMap.keyCodeToStr(keyCode);\n\t}\n\texport function toUserSettingsGeneral(keyCode: KeyCode): string {\n\t\treturn userSettingsGeneralMap.keyCodeToStr(keyCode);\n\t}\n\texport function fromUserSettings(key: string): KeyCode {\n\t\treturn userSettingsUSMap.strToKeyCode(key) || userSettingsGeneralMap.strToKeyCode(key);\n\t}\n\n\texport function toElectronAccelerator(keyCode: KeyCode): string | null {\n\t\tif (keyCode >= KeyCode.Numpad0 && keyCode <= KeyCode.NumpadDivide) {\n\t\t\t// [Electron Accelerators] Electron is able to parse numpad keys, but unfortunately it\n\t\t\t// renders them just as regular keys in menus. For example, num0 is rendered as \"0\",\n\t\t\t// numdiv is rendered as \"/\", numsub is rendered as \"-\".\n\t\t\t//\n\t\t\t// This can lead to incredible confusion, as it makes numpad based keybindings indistinguishable\n\t\t\t// from keybindings based on regular keys.\n\t\t\t//\n\t\t\t// We therefore need to fall back to custom rendering for numpad keys.\n\t\t\treturn null;\n\t\t}\n\n\t\tswitch (keyCode) {\n\t\t\tcase KeyCode.UpArrow:\n\t\t\t\treturn 'Up';\n\t\t\tcase KeyCode.DownArrow:\n\t\t\t\treturn 'Down';\n\t\t\tcase KeyCode.LeftArrow:\n\t\t\t\treturn 'Left';\n\t\t\tcase KeyCode.RightArrow:\n\t\t\t\treturn 'Right';\n\t\t}\n\n\t\treturn uiMap.keyCodeToStr(keyCode);\n\t}\n}\n\nexport const enum KeyMod {\n\tCtrlCmd = (1 << 11) >>> 0,\n\tShift = (1 << 10) >>> 0,\n\tAlt = (1 << 9) >>> 0,\n\tWinCtrl = (1 << 8) >>> 0,\n}\n\nexport function KeyChord(firstPart: number, secondPart: number): number {\n\tconst chordPart = ((secondPart & 0x0000FFFF) << 16) >>> 0;\n\treturn (firstPart | chordPart) >>> 0;\n}\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\nimport { illegalArgument } from 'vs/base/common/errors';\nimport { KeyCode, ScanCode } from 'vs/base/common/keyCodes';\nimport { OperatingSystem } from 'vs/base/common/platform';\n\n/**\n * Binary encoding strategy:\n * ```\n * 1111 11\n * 5432 1098 7654 3210\n * ---- CSAW KKKK KKKK\n * C = bit 11 = ctrlCmd flag\n * S = bit 10 = shift flag\n * A = bit 9 = alt flag\n * W = bit 8 = winCtrl flag\n * K = bits 0-7 = key code\n * ```\n */\nconst enum BinaryKeybindingsMask {\n\tCtrlCmd = (1 << 11) >>> 0,\n\tShift = (1 << 10) >>> 0,\n\tAlt = (1 << 9) >>> 0,\n\tWinCtrl = (1 << 8) >>> 0,\n\tKeyCode = 0x000000FF\n}\n\nexport function decodeKeybinding(keybinding: number | number[], OS: OperatingSystem): Keybinding | null {\n\tif (typeof keybinding === 'number') {\n\t\tif (keybinding === 0) {\n\t\t\treturn null;\n\t\t}\n\t\tconst firstChord = (keybinding & 0x0000FFFF) >>> 0;\n\t\tconst secondChord = (keybinding & 0xFFFF0000) >>> 16;\n\t\tif (secondChord !== 0) {\n\t\t\treturn new Keybinding([\n\t\t\t\tcreateSimpleKeybinding(firstChord, OS),\n\t\t\t\tcreateSimpleKeybinding(secondChord, OS)\n\t\t\t]);\n\t\t}\n\t\treturn new Keybinding([createSimpleKeybinding(firstChord, OS)]);\n\t} else {\n\t\tconst chords = [];\n\t\tfor (let i = 0; i < keybinding.length; i++) {\n\t\t\tchords.push(createSimpleKeybinding(keybinding[i], OS));\n\t\t}\n\t\treturn new Keybinding(chords);\n\t}\n}\n\nexport function createSimpleKeybinding(keybinding: number, OS: OperatingSystem): KeyCodeChord {\n\n\tconst ctrlCmd = (keybinding & BinaryKeybindingsMask.CtrlCmd ? true : false);\n\tconst winCtrl = (keybinding & BinaryKeybindingsMask.WinCtrl ? true : false);\n\n\tconst ctrlKey = (OS === OperatingSystem.Macintosh ? winCtrl : ctrlCmd);\n\tconst shiftKey = (keybinding & BinaryKeybindingsMask.Shift ? true : false);\n\tconst altKey = (keybinding & BinaryKeybindingsMask.Alt ? true : false);\n\tconst metaKey = (OS === OperatingSystem.Macintosh ? ctrlCmd : winCtrl);\n\tconst keyCode = (keybinding & BinaryKeybindingsMask.KeyCode);\n\n\treturn new KeyCodeChord(ctrlKey, shiftKey, altKey, metaKey, keyCode);\n}\n\nexport interface Modifiers {\n\treadonly ctrlKey: boolean;\n\treadonly shiftKey: boolean;\n\treadonly altKey: boolean;\n\treadonly metaKey: boolean;\n}\n\n/**\n * Represents a chord which uses the `keyCode` field of keyboard events.\n * A chord is a combination of keys pressed simultaneously.\n */\nexport class KeyCodeChord implements Modifiers {\n\n\tconstructor(\n\t\tpublic readonly ctrlKey: boolean,\n\t\tpublic readonly shiftKey: boolean,\n\t\tpublic readonly altKey: boolean,\n\t\tpublic readonly metaKey: boolean,\n\t\tpublic readonly keyCode: KeyCode\n\t) { }\n\n\tpublic equals(other: Chord): boolean {\n\t\treturn (\n\t\t\tother instanceof KeyCodeChord\n\t\t\t&& this.ctrlKey === other.ctrlKey\n\t\t\t&& this.shiftKey === other.shiftKey\n\t\t\t&& this.altKey === other.altKey\n\t\t\t&& this.metaKey === other.metaKey\n\t\t\t&& this.keyCode === other.keyCode\n\t\t);\n\t}\n\n\tpublic isModifierKey(): boolean {\n\t\treturn (\n\t\t\tthis.keyCode === KeyCode.Unknown\n\t\t\t|| this.keyCode === KeyCode.Ctrl\n\t\t\t|| this.keyCode === KeyCode.Meta\n\t\t\t|| this.keyCode === KeyCode.Alt\n\t\t\t|| this.keyCode === KeyCode.Shift\n\t\t);\n\t}\n\n\t/**\n\t * Does this keybinding refer to the key code of a modifier and it also has the modifier flag?\n\t */\n\tpublic isDuplicateModifierCase(): boolean {\n\t\treturn (\n\t\t\t(this.ctrlKey && this.keyCode === KeyCode.Ctrl)\n\t\t\t|| (this.shiftKey && this.keyCode === KeyCode.Shift)\n\t\t\t|| (this.altKey && this.keyCode === KeyCode.Alt)\n\t\t\t|| (this.metaKey && this.keyCode === KeyCode.Meta)\n\t\t);\n\t}\n}\n\n/**\n * Represents a chord which uses the `code` field of keyboard events.\n * A chord is a combination of keys pressed simultaneously.\n */\nexport class ScanCodeChord implements Modifiers {\n\n\tconstructor(\n\t\tpublic readonly ctrlKey: boolean,\n\t\tpublic readonly shiftKey: boolean,\n\t\tpublic readonly altKey: boolean,\n\t\tpublic readonly metaKey: boolean,\n\t\tpublic readonly scanCode: ScanCode\n\t) { }\n\n\t/**\n\t * Does this keybinding refer to the key code of a modifier and it also has the modifier flag?\n\t */\n\tpublic isDuplicateModifierCase(): boolean {\n\t\treturn (\n\t\t\t(this.ctrlKey && (this.scanCode === ScanCode.ControlLeft || this.scanCode === ScanCode.ControlRight))\n\t\t\t|| (this.shiftKey && (this.scanCode === ScanCode.ShiftLeft || this.scanCode === ScanCode.ShiftRight))\n\t\t\t|| (this.altKey && (this.scanCode === ScanCode.AltLeft || this.scanCode === ScanCode.AltRight))\n\t\t\t|| (this.metaKey && (this.scanCode === ScanCode.MetaLeft || this.scanCode === ScanCode.MetaRight))\n\t\t);\n\t}\n}\n\nexport type Chord = KeyCodeChord | ScanCodeChord;\n\n/**\n * A keybinding is a sequence of chords.\n */\nexport class Keybinding {\n\n\tpublic readonly chords: Chord[];\n\n\tconstructor(chords: Chord[]) {\n\t\tif (chords.length === 0) {\n\t\t\tthrow illegalArgument(`chords`);\n\t\t}\n\t\tthis.chords = chords;\n\t}\n}\n\nexport class ResolvedChord {\n\tconstructor(\n\t\tpublic readonly ctrlKey: boolean,\n\t\tpublic readonly shiftKey: boolean,\n\t\tpublic readonly altKey: boolean,\n\t\tpublic readonly metaKey: boolean,\n\t\tpublic readonly keyLabel: string | null,\n\t\tpublic readonly keyAriaLabel: string | null\n\t) { }\n}\n\nexport type SingleModifierChord = 'ctrl' | 'shift' | 'alt' | 'meta';\n\n/**\n * A resolved keybinding. Consists of one or multiple chords.\n */\nexport abstract class ResolvedKeybinding {\n\t/**\n\t * This prints the binding in a format suitable for displaying in the UI.\n\t */\n\tpublic abstract getLabel(): string | null;\n\t/**\n\t * This prints the binding in a format suitable for ARIA.\n\t */\n\tpublic abstract getAriaLabel(): string | null;\n\t/**\n\t * This prints the binding in a format suitable for electron's accelerators.\n\t * See https://github.com/electron/electron/blob/master/docs/api/accelerator.md\n\t */\n\tpublic abstract getElectronAccelerator(): string | null;\n\t/**\n\t * This prints the binding in a format suitable for user settings.\n\t */\n\tpublic abstract getUserSettingsLabel(): string | null;\n\t/**\n\t * Does the keybinding consist of more than one chord?\n\t */\n\tpublic abstract hasMultipleChords(): boolean;\n\t/**\n\t * Returns the chords that comprise of the keybinding.\n\t */\n\tpublic abstract getChords(): ResolvedChord[];\n\t/**\n\t * Returns the chords as strings useful for dispatching.\n\t * Returns null for modifier only chords.\n\t * @example keybinding \"Shift\" -> null\n\t * @example keybinding (\"D\" with shift == true) -> \"shift+D\"\n\t */\n\tpublic abstract getDispatchChords(): (string | null)[];\n\t/**\n\t * Returns the modifier only chords as strings useful for dispatching.\n\t * Returns null for chords that contain more than one modifier or a regular key.\n\t * @example keybinding \"Shift\" -> \"shift\"\n\t * @example keybinding (\"D\" with shift == true\") -> null\n\t */\n\tpublic abstract getSingleModifierDispatchChords(): (SingleModifierChord | null)[];\n}\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\nexport class Lazy {\n\n\tprivate _didRun: boolean = false;\n\tprivate _value?: T;\n\tprivate _error: Error | undefined;\n\n\tconstructor(\n\t\tprivate readonly executor: () => T,\n\t) { }\n\n\t/**\n\t * Get the wrapped value.\n\t *\n\t * This will force evaluation of the lazy value if it has not been resolved yet. Lazy values are only\n\t * resolved once. `getValue` will re-throw exceptions that are hit while resolving the value\n\t */\n\tget value(): T {\n\t\tif (!this._didRun) {\n\t\t\ttry {\n\t\t\t\tthis._value = this.executor();\n\t\t\t} catch (err) {\n\t\t\t\tthis._error = err;\n\t\t\t} finally {\n\t\t\t\tthis._didRun = true;\n\t\t\t}\n\t\t}\n\t\tif (this._error) {\n\t\t\tthrow this._error;\n\t\t}\n\t\treturn this._value!;\n\t}\n\n\t/**\n\t * Get the wrapped value without forcing evaluation.\n\t */\n\tget rawValue(): T | undefined { return this._value; }\n}\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\nimport { IHoverDelegate, IScopedHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate';\nimport { Lazy } from 'vs/base/common/lazy';\n\nconst nullHoverDelegateFactory = () => ({\n\tget delay(): number { return -1; },\n\tdispose: () => { },\n\tshowHover: () => { return undefined; },\n});\n\nlet hoverDelegateFactory: (placement: 'mouse' | 'element', enableInstantHover: boolean) => IScopedHoverDelegate = nullHoverDelegateFactory;\nconst defaultHoverDelegateMouse = new Lazy(() => hoverDelegateFactory('mouse', false));\nconst defaultHoverDelegateElement = new Lazy(() => hoverDelegateFactory('element', false));\n\n// TODO: Remove when getDefaultHoverDelegate is no longer used\nexport function setHoverDelegateFactory(hoverDelegateProvider: ((placement: 'mouse' | 'element', enableInstantHover: boolean) => IScopedHoverDelegate)): void {\n\thoverDelegateFactory = hoverDelegateProvider;\n}\n\n// TODO: Refine type for use in new IHoverService interface\nexport function getDefaultHoverDelegate(placement: 'mouse' | 'element'): IHoverDelegate {\n\tif (placement === 'element') {\n\t\treturn defaultHoverDelegateElement.value;\n\t}\n\treturn defaultHoverDelegateMouse.value;\n}\n\n// TODO: Create equivalent in IHoverService\nexport function createInstantHoverDelegate(): IScopedHoverDelegate {\n\t// Creates a hover delegate with instant hover enabled.\n\t// This hover belongs to the consumer and requires the them to dispose it.\n\t// Instant hover only makes sense for 'element' placement.\n\treturn hoverDelegateFactory('element', true);\n}\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\nimport { Lazy } from 'vs/base/common/lazy';\n\ndeclare const Buffer: any;\n\nconst hasBuffer = (typeof Buffer !== 'undefined');\nconst indexOfTable = new Lazy(() => new Uint8Array(256));\nlet textDecoder: TextDecoder | null;\n\nexport class VSBuffer {\n\n\t/**\n\t * When running in a nodejs context, if `actual` is not a nodejs Buffer, the backing store for\n\t * the returned `VSBuffer` instance might use a nodejs Buffer allocated from node's Buffer pool,\n\t * which is not transferrable.\n\t */\n\tstatic wrap(actual: Uint8Array): VSBuffer {\n\t\tif (hasBuffer && !(Buffer.isBuffer(actual))) {\n\t\t\t// https://nodejs.org/dist/latest-v10.x/docs/api/buffer.html#buffer_class_method_buffer_from_arraybuffer_byteoffset_length\n\t\t\t// Create a zero-copy Buffer wrapper around the ArrayBuffer pointed to by the Uint8Array\n\t\t\tactual = Buffer.from(actual.buffer, actual.byteOffset, actual.byteLength);\n\t\t}\n\t\treturn new VSBuffer(actual);\n\t}\n\n\treadonly buffer: Uint8Array;\n\treadonly byteLength: number;\n\n\tprivate constructor(buffer: Uint8Array) {\n\t\tthis.buffer = buffer;\n\t\tthis.byteLength = this.buffer.byteLength;\n\t}\n\n\ttoString(): string {\n\t\tif (hasBuffer) {\n\t\t\treturn this.buffer.toString();\n\t\t} else {\n\t\t\tif (!textDecoder) {\n\t\t\t\ttextDecoder = new TextDecoder();\n\t\t\t}\n\t\t\treturn textDecoder.decode(this.buffer);\n\t\t}\n\t}\n}\n\nexport function readUInt16LE(source: Uint8Array, offset: number): number {\n\treturn (\n\t\t((source[offset + 0] << 0) >>> 0) |\n\t\t((source[offset + 1] << 8) >>> 0)\n\t);\n}\n\nexport function writeUInt16LE(destination: Uint8Array, value: number, offset: number): void {\n\tdestination[offset + 0] = (value & 0b11111111);\n\tvalue = value >>> 8;\n\tdestination[offset + 1] = (value & 0b11111111);\n}\n\nexport function readUInt32BE(source: Uint8Array, offset: number): number {\n\treturn (\n\t\tsource[offset] * 2 ** 24\n\t\t+ source[offset + 1] * 2 ** 16\n\t\t+ source[offset + 2] * 2 ** 8\n\t\t+ source[offset + 3]\n\t);\n}\n\nexport function writeUInt32BE(destination: Uint8Array, value: number, offset: number): void {\n\tdestination[offset + 3] = value;\n\tvalue = value >>> 8;\n\tdestination[offset + 2] = value;\n\tvalue = value >>> 8;\n\tdestination[offset + 1] = value;\n\tvalue = value >>> 8;\n\tdestination[offset] = value;\n}\n\nexport function readUInt8(source: Uint8Array, offset: number): number {\n\treturn source[offset];\n}\n\nexport function writeUInt8(destination: Uint8Array, value: number, offset: number): void {\n\tdestination[offset] = value;\n}\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\nimport { Lazy } from 'vs/base/common/lazy';\n\n// When comparing large numbers of strings it's better for performance to create an\n// Intl.Collator object and use the function provided by its compare property\n// than it is to use String.prototype.localeCompare()\n\n// A collator with numeric sorting enabled, and no sensitivity to case, accents or diacritics.\nconst intlFileNameCollatorBaseNumeric: Lazy<{ collator: Intl.Collator; collatorIsNumeric: boolean }> = new Lazy(() => {\n\tconst collator = new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' });\n\treturn {\n\t\tcollator,\n\t\tcollatorIsNumeric: collator.resolvedOptions().numeric\n\t};\n});\n\n// A collator with numeric sorting enabled.\nconst intlFileNameCollatorNumeric: Lazy<{ collator: Intl.Collator }> = new Lazy(() => {\n\tconst collator = new Intl.Collator(undefined, { numeric: true });\n\treturn {\n\t\tcollator\n\t};\n});\n\n// A collator with numeric sorting enabled, and sensitivity to accents and diacritics but not case.\nconst intlFileNameCollatorNumericCaseInsensitive: Lazy<{ collator: Intl.Collator }> = new Lazy(() => {\n\tconst collator = new Intl.Collator(undefined, { numeric: true, sensitivity: 'accent' });\n\treturn {\n\t\tcollator\n\t};\n});\n\n/** Compares filenames without distinguishing the name from the extension. Disambiguates by unicode comparison. */\nexport function compareFileNames(one: string | null, other: string | null, caseSensitive = false): number {\n\tconst a = one || '';\n\tconst b = other || '';\n\tconst result = intlFileNameCollatorBaseNumeric.value.collator.compare(a, b);\n\n\t// Using the numeric option will make compare(`foo1`, `foo01`) === 0. Disambiguate.\n\tif (intlFileNameCollatorBaseNumeric.value.collatorIsNumeric && result === 0 && a !== b) {\n\t\treturn a < b ? -1 : 1;\n\t}\n\n\treturn result;\n}\n\nexport function compareAnything(one: string, other: string, lookFor: string): number {\n\tconst elementAName = one.toLowerCase();\n\tconst elementBName = other.toLowerCase();\n\n\t// Sort prefix matches over non prefix matches\n\tconst prefixCompare = compareByPrefix(one, other, lookFor);\n\tif (prefixCompare) {\n\t\treturn prefixCompare;\n\t}\n\n\t// Sort suffix matches over non suffix matches\n\tconst elementASuffixMatch = elementAName.endsWith(lookFor);\n\tconst elementBSuffixMatch = elementBName.endsWith(lookFor);\n\tif (elementASuffixMatch !== elementBSuffixMatch) {\n\t\treturn elementASuffixMatch ? -1 : 1;\n\t}\n\n\t// Understand file names\n\tconst r = compareFileNames(elementAName, elementBName);\n\tif (r !== 0) {\n\t\treturn r;\n\t}\n\n\t// Compare by name\n\treturn elementAName.localeCompare(elementBName);\n}\n\nexport function compareByPrefix(one: string, other: string, lookFor: string): number {\n\tconst elementAName = one.toLowerCase();\n\tconst elementBName = other.toLowerCase();\n\n\t// Sort prefix matches over non prefix matches\n\tconst elementAPrefixMatch = elementAName.startsWith(lookFor);\n\tconst elementBPrefixMatch = elementBName.startsWith(lookFor);\n\tif (elementAPrefixMatch !== elementBPrefixMatch) {\n\t\treturn elementAPrefixMatch ? -1 : 1;\n\t}\n\n\t// Same prefix: Sort shorter matches to the top to have those on top that match more precisely\n\telse if (elementAPrefixMatch && elementBPrefixMatch) {\n\t\tif (elementAName.length < elementBName.length) {\n\t\t\treturn -1;\n\t\t}\n\n\t\tif (elementAName.length > elementBName.length) {\n\t\t\treturn 1;\n\t\t}\n\t}\n\n\treturn 0;\n}\n","\nimport { createSingleCallFunction } from 'vs/base/common/functional';\nimport { Iterable } from 'vs/base/common/iterator';\n\n// #region Disposable Tracking\n\n/**\n * Enables logging of potentially leaked disposables.\n *\n * A disposable is considered leaked if it is not disposed or not registered as the child of\n * another disposable. This tracking is very simple an only works for classes that either\n * extend Disposable or use a DisposableStore. This means there are a lot of false positives.\n */\nconst TRACK_DISPOSABLES = false;\nlet disposableTracker: IDisposableTracker | null = null;\n\nexport interface IDisposableTracker {\n\t/**\n\t * Is called on construction of a disposable.\n\t*/\n\ttrackDisposable(disposable: IDisposable): void;\n\n\t/**\n\t * Is called when a disposable is registered as child of another disposable (e.g. {@link DisposableStore}).\n\t * If parent is `null`, the disposable is removed from its former parent.\n\t*/\n\tsetParent(child: IDisposable, parent: IDisposable | null): void;\n\n\t/**\n\t * Is called after a disposable is disposed.\n\t*/\n\tmarkAsDisposed(disposable: IDisposable): void;\n\n\t/**\n\t * Indicates that the given object is a singleton which does not need to be disposed.\n\t*/\n\tmarkAsSingleton(disposable: IDisposable): void;\n}\n\nexport function setDisposableTracker(tracker: IDisposableTracker | null): void {\n\tdisposableTracker = tracker;\n}\n\nif (TRACK_DISPOSABLES) {\n\tconst __is_disposable_tracked__ = '__is_disposable_tracked__';\n\tsetDisposableTracker(new class implements IDisposableTracker {\n\t\ttrackDisposable(x: IDisposable): void {\n\t\t\tconst stack = new Error('Potentially leaked disposable').stack!;\n\t\t\tsetTimeout(() => {\n\t\t\t\tif (!(x as any)[__is_disposable_tracked__]) {\n\t\t\t\t\tconsole.log(stack);\n\t\t\t\t}\n\t\t\t}, 3000);\n\t\t}\n\n\t\tsetParent(child: IDisposable, parent: IDisposable | null): void {\n\t\t\tif (child && child !== Disposable.None) {\n\t\t\t\ttry {\n\t\t\t\t\t(child as any)[__is_disposable_tracked__] = true;\n\t\t\t\t} catch {\n\t\t\t\t\t// noop\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tmarkAsDisposed(disposable: IDisposable): void {\n\t\t\tif (disposable && disposable !== Disposable.None) {\n\t\t\t\ttry {\n\t\t\t\t\t(disposable as any)[__is_disposable_tracked__] = true;\n\t\t\t\t} catch {\n\t\t\t\t\t// noop\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tmarkAsSingleton(disposable: IDisposable): void { }\n\t});\n}\n\nexport function trackDisposable(x: T): T {\n\tdisposableTracker?.trackDisposable(x);\n\treturn x;\n}\n\nexport function markAsDisposed(disposable: IDisposable): void {\n\tdisposableTracker?.markAsDisposed(disposable);\n}\n\nfunction setParentOfDisposable(child: IDisposable, parent: IDisposable | null): void {\n\tdisposableTracker?.setParent(child, parent);\n}\n\nfunction setParentOfDisposables(children: IDisposable[], parent: IDisposable | null): void {\n\tif (!disposableTracker) {\n\t\treturn;\n\t}\n\tfor (const child of children) {\n\t\tdisposableTracker.setParent(child, parent);\n\t}\n}\n\n/**\n * Indicates that the given object is a singleton which does not need to be disposed.\n*/\nexport function markAsSingleton(singleton: T): T {\n\tdisposableTracker?.markAsSingleton(singleton);\n\treturn singleton;\n}\n\n// #endregion\n\n/**\n * An object that performs a cleanup operation when `.dispose()` is called.\n *\n * Some examples of how disposables are used:\n *\n * - An event listener that removes itself when `.dispose()` is called.\n * - A resource such as a file system watcher that cleans up the resource when `.dispose()` is called.\n * - The return value from registering a provider. When `.dispose()` is called, the provider is unregistered.\n */\nexport interface IDisposable {\n\tdispose(): void;\n}\n\n/**\n * Check if `thing` is {@link IDisposable disposable}.\n */\nexport function isDisposable(thing: E): thing is E & IDisposable {\n\treturn typeof thing === 'object' && thing !== null && typeof (thing).dispose === 'function' && (thing).dispose.length === 0;\n}\n\n/**\n * Disposes of the value(s) passed in.\n */\nexport function dispose(disposable: T): T;\nexport function dispose(disposable: T | undefined): T | undefined;\nexport function dispose = Iterable>(disposables: A): A;\nexport function dispose(disposables: Array): Array;\nexport function dispose(disposables: ReadonlyArray): ReadonlyArray;\nexport function dispose(arg: T | Iterable | undefined): any {\n\tif (Iterable.is(arg)) {\n\t\tconst errors: any[] = [];\n\n\t\tfor (const d of arg) {\n\t\t\tif (d) {\n\t\t\t\ttry {\n\t\t\t\t\td.dispose();\n\t\t\t\t} catch (e) {\n\t\t\t\t\terrors.push(e);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (errors.length === 1) {\n\t\t\tthrow errors[0];\n\t\t} else if (errors.length > 1) {\n\t\t\tthrow new AggregateError(errors, 'Encountered errors while disposing of store');\n\t\t}\n\n\t\treturn Array.isArray(arg) ? [] : arg;\n\t} else if (arg) {\n\t\targ.dispose();\n\t\treturn arg;\n\t}\n}\n\n/**\n * Combine multiple disposable values into a single {@link IDisposable}.\n */\nexport function combinedDisposable(...disposables: IDisposable[]): IDisposable {\n\tconst parent = toDisposable(() => dispose(disposables));\n\tsetParentOfDisposables(disposables, parent);\n\treturn parent;\n}\n\n/**\n * Turn a function that implements dispose into an {@link IDisposable}.\n *\n * @param fn Clean up function, guaranteed to be called only **once**.\n */\nexport function toDisposable(fn: () => void): IDisposable {\n\tconst self = trackDisposable({\n\t\tdispose: createSingleCallFunction(() => {\n\t\t\tmarkAsDisposed(self);\n\t\t\tfn();\n\t\t})\n\t});\n\treturn self;\n}\n\n/**\n * Manages a collection of disposable values.\n *\n * This is the preferred way to manage multiple disposables. A `DisposableStore` is safer to work with than an\n * `IDisposable[]` as it considers edge cases, such as registering the same value multiple times or adding an item to a\n * store that has already been disposed of.\n */\nexport class DisposableStore implements IDisposable {\n\n\tstatic DISABLE_DISPOSED_WARNING = false;\n\n\tprivate readonly _toDispose = new Set();\n\tprivate _isDisposed = false;\n\n\tconstructor() {\n\t\ttrackDisposable(this);\n\t}\n\n\t/**\n\t * Dispose of all registered disposables and mark this object as disposed.\n\t *\n\t * Any future disposables added to this object will be disposed of on `add`.\n\t */\n\tpublic dispose(): void {\n\t\tif (this._isDisposed) {\n\t\t\treturn;\n\t\t}\n\n\t\tmarkAsDisposed(this);\n\t\tthis._isDisposed = true;\n\t\tthis.clear();\n\t}\n\n\t/**\n\t * @return `true` if this object has been disposed of.\n\t */\n\tpublic get isDisposed(): boolean {\n\t\treturn this._isDisposed;\n\t}\n\n\t/**\n\t * Dispose of all registered disposables but do not mark this object as disposed.\n\t */\n\tpublic clear(): void {\n\t\tif (this._toDispose.size === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tdispose(this._toDispose);\n\t\t} finally {\n\t\t\tthis._toDispose.clear();\n\t\t}\n\t}\n\n\t/**\n\t * Add a new {@link IDisposable disposable} to the collection.\n\t */\n\tpublic add(o: T): T {\n\t\tif (!o) {\n\t\t\treturn o;\n\t\t}\n\t\tif ((o as unknown as DisposableStore) === this) {\n\t\t\tthrow new Error('Cannot register a disposable on itself!');\n\t\t}\n\n\t\tsetParentOfDisposable(o, this);\n\t\tif (this._isDisposed) {\n\t\t\tif (!DisposableStore.DISABLE_DISPOSED_WARNING) {\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);\n\t\t\t}\n\t\t} else {\n\t\t\tthis._toDispose.add(o);\n\t\t}\n\n\t\treturn o;\n\t}\n\n\t/**\n\t * Deletes the value from the store, but does not dispose it.\n\t */\n\tpublic deleteAndLeak(o: T): void {\n\t\tif (!o) {\n\t\t\treturn;\n\t\t}\n\t\tif (this._toDispose.has(o)) {\n\t\t\tthis._toDispose.delete(o);\n\t\t\tsetParentOfDisposable(o, null);\n\t\t}\n\t}\n}\n\n/**\n * Abstract base class for a {@link IDisposable disposable} object.\n *\n * Subclasses can {@linkcode _register} disposables that will be automatically cleaned up when this object is disposed of.\n */\nexport abstract class Disposable implements IDisposable {\n\n\t/**\n\t * A disposable that does nothing when it is disposed of.\n\t *\n\t * TODO: This should not be a static property.\n\t */\n\tstatic readonly None = Object.freeze({ dispose() { } });\n\n\tprotected readonly _store = new DisposableStore();\n\n\tconstructor() {\n\t\ttrackDisposable(this);\n\t\tsetParentOfDisposable(this._store, this);\n\t}\n\n\tpublic dispose(): void {\n\t\tmarkAsDisposed(this);\n\n\t\tthis._store.dispose();\n\t}\n\n\t/**\n\t * Adds `o` to the collection of disposables managed by this object.\n\t */\n\tprotected _register(o: T): T {\n\t\tif ((o as unknown as Disposable) === this) {\n\t\t\tthrow new Error('Cannot register a disposable on itself!');\n\t\t}\n\t\treturn this._store.add(o);\n\t}\n}\n\n/**\n * Manages the lifecycle of a disposable value that may be changed.\n *\n * This ensures that when the disposable value is changed, the previously held disposable is disposed of. You can\n * also register a `MutableDisposable` on a `Disposable` to ensure it is automatically cleaned up.\n */\nexport class MutableDisposable implements IDisposable {\n\tprivate _value?: T;\n\tprivate _isDisposed = false;\n\n\tconstructor() {\n\t\ttrackDisposable(this);\n\t}\n\n\tget value(): T | undefined {\n\t\treturn this._isDisposed ? undefined : this._value;\n\t}\n\n\tset value(value: T | undefined) {\n\t\tif (this._isDisposed || value === this._value) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._value?.dispose();\n\t\tif (value) {\n\t\t\tsetParentOfDisposable(value, this);\n\t\t}\n\t\tthis._value = value;\n\t}\n\n\t/**\n\t * Resets the stored value and disposed of the previously stored value.\n\t */\n\tclear(): void {\n\t\tthis.value = undefined;\n\t}\n\n\tdispose(): void {\n\t\tthis._isDisposed = true;\n\t\tmarkAsDisposed(this);\n\t\tthis._value?.dispose();\n\t\tthis._value = undefined;\n\t}\n}\n\nexport class RefCountedDisposable {\n\n\tprivate _counter: number = 1;\n\n\tconstructor(\n\t\tprivate readonly _disposable: IDisposable,\n\t) { }\n\n\tacquire() {\n\t\tthis._counter++;\n\t\treturn this;\n\t}\n\n\trelease() {\n\t\tif (--this._counter === 0) {\n\t\t\tthis._disposable.dispose();\n\t\t}\n\t\treturn this;\n\t}\n}\n\nexport interface IReference extends IDisposable {\n\treadonly object: T;\n}\n\nexport class ImmortalReference implements IReference {\n\tconstructor(public object: T) { }\n\tdispose(): void { /* noop */ }\n}\n\n/**\n * A map the manages the lifecycle of the values that it stores.\n */\nexport class DisposableMap implements IDisposable {\n\n\tprivate readonly _store = new Map();\n\tprivate _isDisposed = false;\n\n\tconstructor() {\n\t\ttrackDisposable(this);\n\t}\n\n\t/**\n\t * Disposes of all stored values and mark this object as disposed.\n\t *\n\t * Trying to use this object after it has been disposed of is an error.\n\t */\n\tdispose(): void {\n\t\tmarkAsDisposed(this);\n\t\tthis._isDisposed = true;\n\t\tthis.clearAndDisposeAll();\n\t}\n\n\t/**\n\t * Disposes of all stored values and clear the map, but DO NOT mark this object as disposed.\n\t */\n\tclearAndDisposeAll(): void {\n\t\tif (!this._store.size) {\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tdispose(this._store.values());\n\t\t} finally {\n\t\t\tthis._store.clear();\n\t\t}\n\t}\n\n\tget(key: K): V | undefined {\n\t\treturn this._store.get(key);\n\t}\n\n\tset(key: K, value: V, skipDisposeOnOverwrite = false): void {\n\t\tif (this._isDisposed) {\n\t\t\tconsole.warn(new Error('Trying to add a disposable to a DisposableMap that has already been disposed of. The added object will be leaked!').stack);\n\t\t}\n\n\t\tif (!skipDisposeOnOverwrite) {\n\t\t\tthis._store.get(key)?.dispose();\n\t\t}\n\n\t\tthis._store.set(key, value);\n\t}\n\n\t/**\n\t * Delete the value stored for `key` from this map and also dispose of it.\n\t */\n\tdeleteAndDispose(key: K): void {\n\t\tthis._store.get(key)?.dispose();\n\t\tthis._store.delete(key);\n\t}\n\n\t[Symbol.iterator](): IterableIterator<[K, V]> {\n\t\treturn this._store[Symbol.iterator]();\n\t}\n}\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\nclass Node {\n\n\tstatic readonly Undefined = new Node(undefined);\n\n\telement: E;\n\tnext: Node;\n\tprev: Node;\n\n\tconstructor(element: E) {\n\t\tthis.element = element;\n\t\tthis.next = Node.Undefined;\n\t\tthis.prev = Node.Undefined;\n\t}\n}\n\nexport class LinkedList {\n\n\tprivate _first: Node = Node.Undefined;\n\tprivate _last: Node = Node.Undefined;\n\tprivate _size: number = 0;\n\n\tget size(): number {\n\t\treturn this._size;\n\t}\n\n\tisEmpty(): boolean {\n\t\treturn this._first === Node.Undefined;\n\t}\n\n\tclear(): void {\n\t\tlet node = this._first;\n\t\twhile (node !== Node.Undefined) {\n\t\t\tconst next = node.next;\n\t\t\tnode.prev = Node.Undefined;\n\t\t\tnode.next = Node.Undefined;\n\t\t\tnode = next;\n\t\t}\n\n\t\tthis._first = Node.Undefined;\n\t\tthis._last = Node.Undefined;\n\t\tthis._size = 0;\n\t}\n\n\tunshift(element: E): () => void {\n\t\treturn this._insert(element, false);\n\t}\n\n\tpush(element: E): () => void {\n\t\treturn this._insert(element, true);\n\t}\n\n\tprivate _insert(element: E, atTheEnd: boolean): () => void {\n\t\tconst newNode = new Node(element);\n\t\tif (this._first === Node.Undefined) {\n\t\t\tthis._first = newNode;\n\t\t\tthis._last = newNode;\n\n\t\t} else if (atTheEnd) {\n\t\t\t// push\n\t\t\tconst oldLast = this._last;\n\t\t\tthis._last = newNode;\n\t\t\tnewNode.prev = oldLast;\n\t\t\toldLast.next = newNode;\n\n\t\t} else {\n\t\t\t// unshift\n\t\t\tconst oldFirst = this._first;\n\t\t\tthis._first = newNode;\n\t\t\tnewNode.next = oldFirst;\n\t\t\toldFirst.prev = newNode;\n\t\t}\n\t\tthis._size += 1;\n\n\t\tlet didRemove = false;\n\t\treturn () => {\n\t\t\tif (!didRemove) {\n\t\t\t\tdidRemove = true;\n\t\t\t\tthis._remove(newNode);\n\t\t\t}\n\t\t};\n\t}\n\n\tshift(): E | undefined {\n\t\tif (this._first === Node.Undefined) {\n\t\t\treturn undefined;\n\t\t} else {\n\t\t\tconst res = this._first.element;\n\t\t\tthis._remove(this._first);\n\t\t\treturn res;\n\t\t}\n\t}\n\n\tpop(): E | undefined {\n\t\tif (this._last === Node.Undefined) {\n\t\t\treturn undefined;\n\t\t} else {\n\t\t\tconst res = this._last.element;\n\t\t\tthis._remove(this._last);\n\t\t\treturn res;\n\t\t}\n\t}\n\n\tprivate _remove(node: Node): void {\n\t\tif (node.prev !== Node.Undefined && node.next !== Node.Undefined) {\n\t\t\t// middle\n\t\t\tconst anchor = node.prev;\n\t\t\tanchor.next = node.next;\n\t\t\tnode.next.prev = anchor;\n\n\t\t} else if (node.prev === Node.Undefined && node.next === Node.Undefined) {\n\t\t\t// only node\n\t\t\tthis._first = Node.Undefined;\n\t\t\tthis._last = Node.Undefined;\n\n\t\t} else if (node.next === Node.Undefined) {\n\t\t\t// last\n\t\t\tthis._last = this._last.prev!;\n\t\t\tthis._last.next = Node.Undefined;\n\n\t\t} else if (node.prev === Node.Undefined) {\n\t\t\t// first\n\t\t\tthis._first = this._first.next!;\n\t\t\tthis._first.prev = Node.Undefined;\n\t\t}\n\n\t\t// done\n\t\tthis._size -= 1;\n\t}\n\n\t*[Symbol.iterator](): Iterator {\n\t\tlet node = this._first;\n\t\twhile (node !== Node.Undefined) {\n\t\t\tyield node.element;\n\t\t\tnode = node.next;\n\t\t}\n\t}\n}\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\nimport { memoize } from 'vs/base/common/decorators';\n\nexport interface ILink {\n\treadonly label: string;\n\treadonly href: string;\n\treadonly title?: string;\n}\n\nexport type LinkedTextNode = string | ILink;\n\nexport class LinkedText {\n\n\tconstructor(readonly nodes: LinkedTextNode[]) { }\n\n\t@memoize\n\ttoString(): string {\n\t\treturn this.nodes.map(node => typeof node === 'string' ? node : node.label).join('');\n\t}\n}\n\nconst LINK_REGEX = /\\[([^\\]]+)\\]\\(((?:https?:\\/\\/|command:|file:)[^\\)\\s]+)(?: ([\"'])(.+?)(\\3))?\\)/gi;\n\nexport function parseLinkedText(text: string): LinkedText {\n\tconst result: LinkedTextNode[] = [];\n\n\tlet index = 0;\n\tlet match: RegExpExecArray | null;\n\n\twhile (match = LINK_REGEX.exec(text)) {\n\t\tif (match.index - index > 0) {\n\t\t\tresult.push(text.substring(index, match.index));\n\t\t}\n\n\t\tconst [, label, href, , title] = match;\n\n\t\tif (title) {\n\t\t\tresult.push({ label, href, title });\n\t\t} else {\n\t\t\tresult.push({ label, href });\n\t\t}\n\n\t\tindex = match.index + match[0].length;\n\t}\n\n\tif (index < text.length) {\n\t\tresult.push(text.substring(index));\n\t}\n\n\treturn new LinkedText(result);\n}\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\nimport { URI } from 'vs/base/common/uri';\n\ninterface ResourceMapKeyFn {\n\t(resource: URI): string;\n}\n\nclass ResourceMapEntry {\n\tconstructor(readonly uri: URI, readonly value: T) { }\n}\n\nfunction isEntries(arg: ResourceMap | ResourceMapKeyFn | readonly (readonly [URI, T])[] | undefined): arg is readonly (readonly [URI, T])[] {\n\treturn Array.isArray(arg);\n}\n\nexport class ResourceMap implements Map {\n\n\tprivate static readonly defaultToKey = (resource: URI) => resource.toString();\n\n\treadonly [Symbol.toStringTag] = 'ResourceMap';\n\n\tprivate readonly map: Map>;\n\tprivate readonly toKey: ResourceMapKeyFn;\n\n\t/**\n\t *\n\t * @param toKey Custom uri identity function, e.g use an existing `IExtUri#getComparison`-util\n\t */\n\tconstructor(toKey?: ResourceMapKeyFn);\n\n\t/**\n\t *\n\t * @param other Another resource which this maps is created from\n\t * @param toKey Custom uri identity function, e.g use an existing `IExtUri#getComparison`-util\n\t */\n\tconstructor(other?: ResourceMap, toKey?: ResourceMapKeyFn);\n\n\t/**\n\t *\n\t * @param other Another resource which this maps is created from\n\t * @param toKey Custom uri identity function, e.g use an existing `IExtUri#getComparison`-util\n\t */\n\tconstructor(entries?: readonly (readonly [URI, T])[], toKey?: ResourceMapKeyFn);\n\n\tconstructor(arg?: ResourceMap | ResourceMapKeyFn | readonly (readonly [URI, T])[], toKey?: ResourceMapKeyFn) {\n\t\tif (arg instanceof ResourceMap) {\n\t\t\tthis.map = new Map(arg.map);\n\t\t\tthis.toKey = toKey ?? ResourceMap.defaultToKey;\n\t\t} else if (isEntries(arg)) {\n\t\t\tthis.map = new Map();\n\t\t\tthis.toKey = toKey ?? ResourceMap.defaultToKey;\n\n\t\t\tfor (const [resource, value] of arg) {\n\t\t\t\tthis.set(resource, value);\n\t\t\t}\n\t\t} else {\n\t\t\tthis.map = new Map();\n\t\t\tthis.toKey = arg ?? ResourceMap.defaultToKey;\n\t\t}\n\t}\n\n\tset(resource: URI, value: T): this {\n\t\tthis.map.set(this.toKey(resource), new ResourceMapEntry(resource, value));\n\t\treturn this;\n\t}\n\n\tget(resource: URI): T | undefined {\n\t\treturn this.map.get(this.toKey(resource))?.value;\n\t}\n\n\thas(resource: URI): boolean {\n\t\treturn this.map.has(this.toKey(resource));\n\t}\n\n\tget size(): number {\n\t\treturn this.map.size;\n\t}\n\n\tclear(): void {\n\t\tthis.map.clear();\n\t}\n\n\tdelete(resource: URI): boolean {\n\t\treturn this.map.delete(this.toKey(resource));\n\t}\n\n\tforEach(clb: (value: T, key: URI, map: Map) => void, thisArg?: any): void {\n\t\tif (typeof thisArg !== 'undefined') {\n\t\t\tclb = clb.bind(thisArg);\n\t\t}\n\t\tfor (const [_, entry] of this.map) {\n\t\t\tclb(entry.value, entry.uri, this);\n\t\t}\n\t}\n\n\t*values(): IterableIterator {\n\t\tfor (const entry of this.map.values()) {\n\t\t\tyield entry.value;\n\t\t}\n\t}\n\n\t*keys(): IterableIterator {\n\t\tfor (const entry of this.map.values()) {\n\t\t\tyield entry.uri;\n\t\t}\n\t}\n\n\t*entries(): IterableIterator<[URI, T]> {\n\t\tfor (const entry of this.map.values()) {\n\t\t\tyield [entry.uri, entry.value];\n\t\t}\n\t}\n\n\t*[Symbol.iterator](): IterableIterator<[URI, T]> {\n\t\tfor (const [, entry] of this.map) {\n\t\t\tyield [entry.uri, entry.value];\n\t\t}\n\t}\n}\n\n\ninterface Item {\n\tprevious: Item | undefined;\n\tnext: Item | undefined;\n\tkey: K;\n\tvalue: V;\n}\n\nexport const enum Touch {\n\tNone = 0,\n\tAsOld = 1,\n\tAsNew = 2\n}\n\nexport class LinkedMap implements Map {\n\n\treadonly [Symbol.toStringTag] = 'LinkedMap';\n\n\tprivate _map: Map>;\n\tprivate _head: Item | undefined;\n\tprivate _tail: Item | undefined;\n\tprivate _size: number;\n\n\tprivate _state: number;\n\n\tconstructor() {\n\t\tthis._map = new Map>();\n\t\tthis._head = undefined;\n\t\tthis._tail = undefined;\n\t\tthis._size = 0;\n\t\tthis._state = 0;\n\t}\n\n\tclear(): void {\n\t\tthis._map.clear();\n\t\tthis._head = undefined;\n\t\tthis._tail = undefined;\n\t\tthis._size = 0;\n\t\tthis._state++;\n\t}\n\n\tisEmpty(): boolean {\n\t\treturn !this._head && !this._tail;\n\t}\n\n\tget size(): number {\n\t\treturn this._size;\n\t}\n\n\tget first(): V | undefined {\n\t\treturn this._head?.value;\n\t}\n\n\tget last(): V | undefined {\n\t\treturn this._tail?.value;\n\t}\n\n\thas(key: K): boolean {\n\t\treturn this._map.has(key);\n\t}\n\n\tget(key: K, touch: Touch = Touch.None): V | undefined {\n\t\tconst item = this._map.get(key);\n\t\tif (!item) {\n\t\t\treturn undefined;\n\t\t}\n\t\tif (touch !== Touch.None) {\n\t\t\tthis.touch(item, touch);\n\t\t}\n\t\treturn item.value;\n\t}\n\n\tset(key: K, value: V, touch: Touch = Touch.None): this {\n\t\tlet item = this._map.get(key);\n\t\tif (item) {\n\t\t\titem.value = value;\n\t\t\tif (touch !== Touch.None) {\n\t\t\t\tthis.touch(item, touch);\n\t\t\t}\n\t\t} else {\n\t\t\titem = { key, value, next: undefined, previous: undefined };\n\t\t\tswitch (touch) {\n\t\t\t\tcase Touch.None:\n\t\t\t\t\tthis.addItemLast(item);\n\t\t\t\t\tbreak;\n\t\t\t\tcase Touch.AsOld:\n\t\t\t\t\tthis.addItemFirst(item);\n\t\t\t\t\tbreak;\n\t\t\t\tcase Touch.AsNew:\n\t\t\t\t\tthis.addItemLast(item);\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tthis.addItemLast(item);\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\tthis._map.set(key, item);\n\t\t\tthis._size++;\n\t\t}\n\t\treturn this;\n\t}\n\n\tdelete(key: K): boolean {\n\t\treturn !!this.remove(key);\n\t}\n\n\tremove(key: K): V | undefined {\n\t\tconst item = this._map.get(key);\n\t\tif (!item) {\n\t\t\treturn undefined;\n\t\t}\n\t\tthis._map.delete(key);\n\t\tthis.removeItem(item);\n\t\tthis._size--;\n\t\treturn item.value;\n\t}\n\n\tshift(): V | undefined {\n\t\tif (!this._head && !this._tail) {\n\t\t\treturn undefined;\n\t\t}\n\t\tif (!this._head || !this._tail) {\n\t\t\tthrow new Error('Invalid list');\n\t\t}\n\t\tconst item = this._head;\n\t\tthis._map.delete(item.key);\n\t\tthis.removeItem(item);\n\t\tthis._size--;\n\t\treturn item.value;\n\t}\n\n\tforEach(callbackfn: (value: V, key: K, map: LinkedMap) => void, thisArg?: any): void {\n\t\tconst state = this._state;\n\t\tlet current = this._head;\n\t\twhile (current) {\n\t\t\tif (thisArg) {\n\t\t\t\tcallbackfn.bind(thisArg)(current.value, current.key, this);\n\t\t\t} else {\n\t\t\t\tcallbackfn(current.value, current.key, this);\n\t\t\t}\n\t\t\tif (this._state !== state) {\n\t\t\t\tthrow new Error(`LinkedMap got modified during iteration.`);\n\t\t\t}\n\t\t\tcurrent = current.next;\n\t\t}\n\t}\n\n\tkeys(): IterableIterator {\n\t\tconst map = this;\n\t\tconst state = this._state;\n\t\tlet current = this._head;\n\t\tconst iterator: IterableIterator = {\n\t\t\t[Symbol.iterator]() {\n\t\t\t\treturn iterator;\n\t\t\t},\n\t\t\tnext(): IteratorResult {\n\t\t\t\tif (map._state !== state) {\n\t\t\t\t\tthrow new Error(`LinkedMap got modified during iteration.`);\n\t\t\t\t}\n\t\t\t\tif (current) {\n\t\t\t\t\tconst result = { value: current.key, done: false };\n\t\t\t\t\tcurrent = current.next;\n\t\t\t\t\treturn result;\n\t\t\t\t} else {\n\t\t\t\t\treturn { value: undefined, done: true };\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\treturn iterator;\n\t}\n\n\tvalues(): IterableIterator {\n\t\tconst map = this;\n\t\tconst state = this._state;\n\t\tlet current = this._head;\n\t\tconst iterator: IterableIterator = {\n\t\t\t[Symbol.iterator]() {\n\t\t\t\treturn iterator;\n\t\t\t},\n\t\t\tnext(): IteratorResult {\n\t\t\t\tif (map._state !== state) {\n\t\t\t\t\tthrow new Error(`LinkedMap got modified during iteration.`);\n\t\t\t\t}\n\t\t\t\tif (current) {\n\t\t\t\t\tconst result = { value: current.value, done: false };\n\t\t\t\t\tcurrent = current.next;\n\t\t\t\t\treturn result;\n\t\t\t\t} else {\n\t\t\t\t\treturn { value: undefined, done: true };\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\treturn iterator;\n\t}\n\n\tentries(): IterableIterator<[K, V]> {\n\t\tconst map = this;\n\t\tconst state = this._state;\n\t\tlet current = this._head;\n\t\tconst iterator: IterableIterator<[K, V]> = {\n\t\t\t[Symbol.iterator]() {\n\t\t\t\treturn iterator;\n\t\t\t},\n\t\t\tnext(): IteratorResult<[K, V]> {\n\t\t\t\tif (map._state !== state) {\n\t\t\t\t\tthrow new Error(`LinkedMap got modified during iteration.`);\n\t\t\t\t}\n\t\t\t\tif (current) {\n\t\t\t\t\tconst result: IteratorResult<[K, V]> = { value: [current.key, current.value], done: false };\n\t\t\t\t\tcurrent = current.next;\n\t\t\t\t\treturn result;\n\t\t\t\t} else {\n\t\t\t\t\treturn { value: undefined, done: true };\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\treturn iterator;\n\t}\n\n\t[Symbol.iterator](): IterableIterator<[K, V]> {\n\t\treturn this.entries();\n\t}\n\n\tprotected trimOld(newSize: number) {\n\t\tif (newSize >= this.size) {\n\t\t\treturn;\n\t\t}\n\t\tif (newSize === 0) {\n\t\t\tthis.clear();\n\t\t\treturn;\n\t\t}\n\t\tlet current = this._head;\n\t\tlet currentSize = this.size;\n\t\twhile (current && currentSize > newSize) {\n\t\t\tthis._map.delete(current.key);\n\t\t\tcurrent = current.next;\n\t\t\tcurrentSize--;\n\t\t}\n\t\tthis._head = current;\n\t\tthis._size = currentSize;\n\t\tif (current) {\n\t\t\tcurrent.previous = undefined;\n\t\t}\n\t\tthis._state++;\n\t}\n\n\tprotected trimNew(newSize: number) {\n\t\tif (newSize >= this.size) {\n\t\t\treturn;\n\t\t}\n\t\tif (newSize === 0) {\n\t\t\tthis.clear();\n\t\t\treturn;\n\t\t}\n\t\tlet current = this._tail;\n\t\tlet currentSize = this.size;\n\t\twhile (current && currentSize > newSize) {\n\t\t\tthis._map.delete(current.key);\n\t\t\tcurrent = current.previous;\n\t\t\tcurrentSize--;\n\t\t}\n\t\tthis._tail = current;\n\t\tthis._size = currentSize;\n\t\tif (current) {\n\t\t\tcurrent.next = undefined;\n\t\t}\n\t\tthis._state++;\n\t}\n\n\tprivate addItemFirst(item: Item): void {\n\t\t// First time Insert\n\t\tif (!this._head && !this._tail) {\n\t\t\tthis._tail = item;\n\t\t} else if (!this._head) {\n\t\t\tthrow new Error('Invalid list');\n\t\t} else {\n\t\t\titem.next = this._head;\n\t\t\tthis._head.previous = item;\n\t\t}\n\t\tthis._head = item;\n\t\tthis._state++;\n\t}\n\n\tprivate addItemLast(item: Item): void {\n\t\t// First time Insert\n\t\tif (!this._head && !this._tail) {\n\t\t\tthis._head = item;\n\t\t} else if (!this._tail) {\n\t\t\tthrow new Error('Invalid list');\n\t\t} else {\n\t\t\titem.previous = this._tail;\n\t\t\tthis._tail.next = item;\n\t\t}\n\t\tthis._tail = item;\n\t\tthis._state++;\n\t}\n\n\tprivate removeItem(item: Item): void {\n\t\tif (item === this._head && item === this._tail) {\n\t\t\tthis._head = undefined;\n\t\t\tthis._tail = undefined;\n\t\t}\n\t\telse if (item === this._head) {\n\t\t\t// This can only happen if size === 1 which is handled\n\t\t\t// by the case above.\n\t\t\tif (!item.next) {\n\t\t\t\tthrow new Error('Invalid list');\n\t\t\t}\n\t\t\titem.next.previous = undefined;\n\t\t\tthis._head = item.next;\n\t\t}\n\t\telse if (item === this._tail) {\n\t\t\t// This can only happen if size === 1 which is handled\n\t\t\t// by the case above.\n\t\t\tif (!item.previous) {\n\t\t\t\tthrow new Error('Invalid list');\n\t\t\t}\n\t\t\titem.previous.next = undefined;\n\t\t\tthis._tail = item.previous;\n\t\t}\n\t\telse {\n\t\t\tconst next = item.next;\n\t\t\tconst previous = item.previous;\n\t\t\tif (!next || !previous) {\n\t\t\t\tthrow new Error('Invalid list');\n\t\t\t}\n\t\t\tnext.previous = previous;\n\t\t\tprevious.next = next;\n\t\t}\n\t\titem.next = undefined;\n\t\titem.previous = undefined;\n\t\tthis._state++;\n\t}\n\n\tprivate touch(item: Item, touch: Touch): void {\n\t\tif (!this._head || !this._tail) {\n\t\t\tthrow new Error('Invalid list');\n\t\t}\n\t\tif ((touch !== Touch.AsOld && touch !== Touch.AsNew)) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (touch === Touch.AsOld) {\n\t\t\tif (item === this._head) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst next = item.next;\n\t\t\tconst previous = item.previous;\n\n\t\t\t// Unlink the item\n\t\t\tif (item === this._tail) {\n\t\t\t\t// previous must be defined since item was not head but is tail\n\t\t\t\t// So there are more than on item in the map\n\t\t\t\tprevious!.next = undefined;\n\t\t\t\tthis._tail = previous;\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Both next and previous are not undefined since item was neither head nor tail.\n\t\t\t\tnext!.previous = previous;\n\t\t\t\tprevious!.next = next;\n\t\t\t}\n\n\t\t\t// Insert the node at head\n\t\t\titem.previous = undefined;\n\t\t\titem.next = this._head;\n\t\t\tthis._head.previous = item;\n\t\t\tthis._head = item;\n\t\t\tthis._state++;\n\t\t} else if (touch === Touch.AsNew) {\n\t\t\tif (item === this._tail) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst next = item.next;\n\t\t\tconst previous = item.previous;\n\n\t\t\t// Unlink the item.\n\t\t\tif (item === this._head) {\n\t\t\t\t// next must be defined since item was not tail but is head\n\t\t\t\t// So there are more than on item in the map\n\t\t\t\tnext!.previous = undefined;\n\t\t\t\tthis._head = next;\n\t\t\t} else {\n\t\t\t\t// Both next and previous are not undefined since item was neither head nor tail.\n\t\t\t\tnext!.previous = previous;\n\t\t\t\tprevious!.next = next;\n\t\t\t}\n\t\t\titem.next = undefined;\n\t\t\titem.previous = this._tail;\n\t\t\tthis._tail.next = item;\n\t\t\tthis._tail = item;\n\t\t\tthis._state++;\n\t\t}\n\t}\n\n\ttoJSON(): [K, V][] {\n\t\tconst data: [K, V][] = [];\n\n\t\tthis.forEach((value, key) => {\n\t\t\tdata.push([key, value]);\n\t\t});\n\n\t\treturn data;\n\t}\n\n\tfromJSON(data: [K, V][]): void {\n\t\tthis.clear();\n\n\t\tfor (const [key, value] of data) {\n\t\t\tthis.set(key, value);\n\t\t}\n\t}\n}\n\nabstract class Cache extends LinkedMap {\n\n\tprotected _limit: number;\n\tprotected _ratio: number;\n\n\tconstructor(limit: number, ratio: number = 1) {\n\t\tsuper();\n\t\tthis._limit = limit;\n\t\tthis._ratio = Math.min(Math.max(0, ratio), 1);\n\t}\n\n\tget limit(): number {\n\t\treturn this._limit;\n\t}\n\n\tset limit(limit: number) {\n\t\tthis._limit = limit;\n\t\tthis.checkTrim();\n\t}\n\n\toverride get(key: K, touch: Touch = Touch.AsNew): V | undefined {\n\t\treturn super.get(key, touch);\n\t}\n\n\tpeek(key: K): V | undefined {\n\t\treturn super.get(key, Touch.None);\n\t}\n\n\toverride set(key: K, value: V): this {\n\t\tsuper.set(key, value, Touch.AsNew);\n\t\treturn this;\n\t}\n\n\tprotected checkTrim() {\n\t\tif (this.size > this._limit) {\n\t\t\tthis.trim(Math.round(this._limit * this._ratio));\n\t\t}\n\t}\n\n\tprotected abstract trim(newSize: number): void;\n}\n\nexport class LRUCache extends Cache {\n\n\tconstructor(limit: number, ratio: number = 1) {\n\t\tsuper(limit, ratio);\n\t}\n\n\tprotected override trim(newSize: number) {\n\t\tthis.trimOld(newSize);\n\t}\n\n\toverride set(key: K, value: V): this {\n\t\tsuper.set(key, value);\n\t\tthis.checkTrim();\n\t\treturn this;\n\t}\n}\n\n/**\n * A map that allows access both by keys and values.\n * **NOTE**: values need to be unique.\n */\nexport class BidirectionalMap {\n\n\tprivate readonly _m1 = new Map();\n\tprivate readonly _m2 = new Map();\n\n\tconstructor(entries?: readonly (readonly [K, V])[]) {\n\t\tif (entries) {\n\t\t\tfor (const [key, value] of entries) {\n\t\t\t\tthis.set(key, value);\n\t\t\t}\n\t\t}\n\t}\n\n\tclear(): void {\n\t\tthis._m1.clear();\n\t\tthis._m2.clear();\n\t}\n\n\tset(key: K, value: V): void {\n\t\tthis._m1.set(key, value);\n\t\tthis._m2.set(value, key);\n\t}\n\n\tget(key: K): V | undefined {\n\t\treturn this._m1.get(key);\n\t}\n\n\tgetKey(value: V): K | undefined {\n\t\treturn this._m2.get(value);\n\t}\n\n\tdelete(key: K): boolean {\n\t\tconst value = this._m1.get(key);\n\t\tif (value === undefined) {\n\t\t\treturn false;\n\t\t}\n\t\tthis._m1.delete(key);\n\t\tthis._m2.delete(value);\n\t\treturn true;\n\t}\n\n\tkeys(): IterableIterator {\n\t\treturn this._m1.keys();\n\t}\n\n\tvalues(): IterableIterator {\n\t\treturn this._m1.values();\n\t}\n}\n\nexport class SetMap {\n\n\tprivate map = new Map>();\n\n\tadd(key: K, value: V): void {\n\t\tlet values = this.map.get(key);\n\n\t\tif (!values) {\n\t\t\tvalues = new Set();\n\t\t\tthis.map.set(key, values);\n\t\t}\n\n\t\tvalues.add(value);\n\t}\n\n\tdelete(key: K, value: V): void {\n\t\tconst values = this.map.get(key);\n\n\t\tif (!values) {\n\t\t\treturn;\n\t\t}\n\n\t\tvalues.delete(value);\n\n\t\tif (values.size === 0) {\n\t\t\tthis.map.delete(key);\n\t\t}\n\t}\n\n\tforEach(key: K, fn: (value: V) => void): void {\n\t\tconst values = this.map.get(key);\n\n\t\tif (!values) {\n\t\t\treturn;\n\t\t}\n\n\t\tvalues.forEach(fn);\n\t}\n\n\tget(key: K): ReadonlySet {\n\t\tconst values = this.map.get(key);\n\t\tif (!values) {\n\t\t\treturn new Set();\n\t\t}\n\t\treturn values;\n\t}\n}\n","/**\n * marked - a markdown parser\n * Copyright (c) 2011-2022, 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// ESM-uncomment-begin\n// let __marked_exports = {};\n// (function() {\n// function define(deps, factory) {\n// factory(__marked_exports);\n// }\n// define.amd = true;\n// ESM-uncomment-end\n\n (function (global, factory) {\n typeof define === 'function' && define.amd ? define(__m[430/*vs/base/common/marked/marked*/], __M([0/*exports*/]), factory) :\n typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :\n (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.marked = {}));\n})(this, (function (exports) { '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 Object.defineProperty(Constructor, \"prototype\", {\n writable: false\n });\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 = typeof Symbol !== \"undefined\" && o[Symbol.iterator] || o[\"@@iterator\"];\n if (it) return (it = it.call(o)).next.bind(it);\n\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 function getDefaults() {\n return {\n async: false,\n baseUrl: null,\n breaks: false,\n extensions: null,\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 exports.defaults = getDefaults();\n function changeDefaults(newDefaults) {\n exports.defaults = newDefaults;\n }\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 var unescapeTest = /&(#(?:\\d+)|(?:#x[0-9A-Fa-f]+)|(?:\\w+));?/ig;\n /**\n * @param {string} html\n */\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 var caret = /(^|[^\\[])\\^/g;\n /**\n * @param {string | RegExp} regex\n * @param {string} opt\n */\n\n function edit(regex, opt) {\n regex = typeof regex === 'string' ? regex : regex.source;\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 var nonWordAndColonTest = /[^\\w:]/g;\n var originIndependentUrl = /^$|^[a-z][a-z0-9+.-]*:|^[?#]/i;\n /**\n * @param {boolean} sanitize\n * @param {string} base\n * @param {string} href\n */\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 var baseUrls = {};\n var justDomain = /^[^:]+:\\/*[^/]*$/;\n var protocol = /^([^:]+:)[\\s\\S]*$/;\n var domain = /^([^:]+:\\/*[^/]*)[\\s\\S]*$/;\n /**\n * @param {string} base\n * @param {string} href\n */\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 var noopTest = {\n exec: function noopTest() {}\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 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; // First/last cell in a row cannot be empty if it has no leading/trailing pipe\n\n if (!cells[0].trim()) {\n cells.shift();\n }\n\n if (cells.length > 0 && !cells[cells.length - 1].trim()) {\n cells.pop();\n }\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 }\n /**\n * Remove trailing 'c's. Equivalent to str.replace(/c*$/, '').\n * /c*$/ is vulnerable to REDOS.\n *\n * @param {string} str\n * @param {string} c\n * @param {boolean} 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.slice(0, l - suffLen);\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 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 * @param {string} pattern\n * @param {number} count\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 function outputLink(cap, link, raw, lexer) {\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 lexer.state.inLink = true;\n var token = {\n type: 'link',\n raw: raw,\n href: href,\n title: title,\n text: text,\n tokens: lexer.inlineTokens(text)\n };\n lexer.state.inLink = false;\n return token;\n }\n\n return {\n type: 'image',\n raw: raw,\n href: href,\n title: title,\n text: escape(text)\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 = /*#__PURE__*/function () {\n function Tokenizer(options) {\n this.options = options || exports.defaults;\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 && cap[0].length > 0) {\n return {\n type: 'space',\n raw: cap[0]\n };\n }\n };\n\n _proto.code = function code(src) {\n var cap = this.rules.block.code.exec(src);\n\n if (cap) {\n var text = cap[0].replace(/^ {1,4}/gm, '');\n return {\n type: 'code',\n raw: cap[0],\n codeBlockStyle: 'indented',\n text: !this.options.pedantic ? rtrim(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 var text = cap[2].trim(); // remove trailing #s\n\n if (/#$/.test(text)) {\n var trimmed = rtrim(text, '#');\n\n if (this.options.pedantic) {\n text = trimmed.trim();\n } else if (!trimmed || / $/.test(trimmed)) {\n // CommonMark requires space before trailing #s\n text = trimmed.trim();\n }\n }\n\n return {\n type: 'heading',\n raw: cap[0],\n depth: cap[1].length,\n text: text,\n tokens: this.lexer.inline(text)\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(/^ *>[ \\t]?/gm, '');\n return {\n type: 'blockquote',\n raw: cap[0],\n tokens: this.lexer.blockTokens(text, []),\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, istask, ischecked, indent, i, blankLine, endsWithBlankLine, line, nextLine, rawLine, itemContents, endEarly;\n var bull = cap[1].trim();\n var isordered = bull.length > 1;\n var list = {\n type: 'list',\n raw: '',\n ordered: isordered,\n start: isordered ? +bull.slice(0, -1) : '',\n loose: false,\n items: []\n };\n bull = isordered ? \"\\\\d{1,9}\\\\\" + bull.slice(-1) : \"\\\\\" + bull;\n\n if (this.options.pedantic) {\n bull = isordered ? bull : '[*+-]';\n } // Get next list item\n\n\n var itemRegex = new RegExp(\"^( {0,3}\" + bull + \")((?:[\\t ][^\\\\n]*)?(?:\\\\n|$))\"); // Check if current bullet point can start a new List Item\n\n while (src) {\n endEarly = false;\n\n if (!(cap = itemRegex.exec(src))) {\n break;\n }\n\n if (this.rules.block.hr.test(src)) {\n // End list if bullet was actually HR (possibly move into itemRegex?)\n break;\n }\n\n raw = cap[0];\n src = src.substring(raw.length);\n line = cap[2].split('\\n', 1)[0];\n nextLine = src.split('\\n', 1)[0];\n\n if (this.options.pedantic) {\n indent = 2;\n itemContents = line.trimLeft();\n } else {\n indent = cap[2].search(/[^ ]/); // Find first non-space char\n\n indent = indent > 4 ? 1 : indent; // Treat indented code blocks (> 4 spaces) as having only 1 indent\n\n itemContents = line.slice(indent);\n indent += cap[1].length;\n }\n\n blankLine = false;\n\n if (!line && /^ *$/.test(nextLine)) {\n // Items begin with at most one blank line\n raw += nextLine + '\\n';\n src = src.substring(nextLine.length + 1);\n endEarly = true;\n }\n\n if (!endEarly) {\n var nextBulletRegex = new RegExp(\"^ {0,\" + Math.min(3, indent - 1) + \"}(?:[*+-]|\\\\d{1,9}[.)])((?: [^\\\\n]*)?(?:\\\\n|$))\");\n var hrRegex = new RegExp(\"^ {0,\" + Math.min(3, indent - 1) + \"}((?:- *){3,}|(?:_ *){3,}|(?:\\\\* *){3,})(?:\\\\n+|$)\");\n var fencesBeginRegex = new RegExp(\"^ {0,\" + Math.min(3, indent - 1) + \"}(?:```|~~~)\");\n var headingBeginRegex = new RegExp(\"^ {0,\" + Math.min(3, indent - 1) + \"}#\"); // Check if following lines should be included in List Item\n\n while (src) {\n rawLine = src.split('\\n', 1)[0];\n line = rawLine; // Re-align to follow commonmark nesting rules\n\n if (this.options.pedantic) {\n line = line.replace(/^ {1,4}(?=( {4})*[^ ])/g, ' ');\n } // End list item if found code fences\n\n\n if (fencesBeginRegex.test(line)) {\n break;\n } // End list item if found start of new heading\n\n\n if (headingBeginRegex.test(line)) {\n break;\n } // End list item if found start of new bullet\n\n\n if (nextBulletRegex.test(line)) {\n break;\n } // Horizontal rule found\n\n\n if (hrRegex.test(src)) {\n break;\n }\n\n if (line.search(/[^ ]/) >= indent || !line.trim()) {\n // Dedent if possible\n itemContents += '\\n' + line.slice(indent);\n } else if (!blankLine) {\n // Until blank line, item doesn't need indentation\n itemContents += '\\n' + line;\n } else {\n // Otherwise, improper indentation ends this item\n break;\n }\n\n if (!blankLine && !line.trim()) {\n // Check if current line is blank\n blankLine = true;\n }\n\n raw += rawLine + '\\n';\n src = src.substring(rawLine.length + 1);\n }\n }\n\n if (!list.loose) {\n // If the previous item ended with a blank line, the list is loose\n if (endsWithBlankLine) {\n list.loose = true;\n } else if (/\\n *\\n *$/.test(raw)) {\n endsWithBlankLine = true;\n }\n } // Check for task list items\n\n\n if (this.options.gfm) {\n istask = /^\\[[ xX]\\] /.exec(itemContents);\n\n if (istask) {\n ischecked = istask[0] !== '[ ] ';\n itemContents = itemContents.replace(/^\\[[ xX]\\] +/, '');\n }\n }\n\n list.items.push({\n type: 'list_item',\n raw: raw,\n task: !!istask,\n checked: ischecked,\n loose: false,\n text: itemContents\n });\n list.raw += raw;\n } // Do not consume newlines at end of final item. Alternatively, make itemRegex *start* with any newlines to simplify/speed up endsWithBlankLine logic\n\n\n list.items[list.items.length - 1].raw = raw.trimRight();\n list.items[list.items.length - 1].text = itemContents.trimRight();\n list.raw = list.raw.trimRight();\n var l = list.items.length; // Item child tokens handled here at end because we needed to have the final item to trim it first\n\n for (i = 0; i < l; i++) {\n this.lexer.state.top = false;\n list.items[i].tokens = this.lexer.blockTokens(list.items[i].text, []);\n var spacers = list.items[i].tokens.filter(function (t) {\n return t.type === 'space';\n });\n var hasMultipleLineBreaks = spacers.every(function (t) {\n var chars = t.raw.split('');\n var lineBreaks = 0;\n\n for (var _iterator = _createForOfIteratorHelperLoose(chars), _step; !(_step = _iterator()).done;) {\n var _char = _step.value;\n\n if (_char === '\\n') {\n lineBreaks += 1;\n }\n\n if (lineBreaks > 1) {\n return true;\n }\n }\n\n return false;\n });\n\n if (!list.loose && spacers.length && hasMultipleLineBreaks) {\n // Having a single line break doesn't mean a list is loose. A single line break is terminating the last list item\n list.loose = true;\n list.items[i].loose = true;\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 var token = {\n type: 'html',\n raw: cap[0],\n pre: !this.options.sanitizer && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),\n text: cap[0]\n };\n\n if (this.options.sanitize) {\n var text = this.options.sanitizer ? this.options.sanitizer(cap[0]) : escape(cap[0]);\n token.type = 'paragraph';\n token.text = text;\n token.tokens = this.lexer.inline(text);\n }\n\n return token;\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 type: 'def',\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(cap[1]).map(function (c) {\n return {\n text: c\n };\n }),\n align: cap[2].replace(/^ *|\\| *$/g, '').split(/ *\\| */),\n rows: cap[3] && cap[3].trim() ? cap[3].replace(/\\n[ \\t]*$/, '').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, j, k, row;\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.rows.length;\n\n for (i = 0; i < l; i++) {\n item.rows[i] = splitCells(item.rows[i], item.header.length).map(function (c) {\n return {\n text: c\n };\n });\n } // parse child tokens inside headers and cells\n // header child tokens\n\n\n l = item.header.length;\n\n for (j = 0; j < l; j++) {\n item.header[j].tokens = this.lexer.inline(item.header[j].text);\n } // cell child tokens\n\n\n l = item.rows.length;\n\n for (j = 0; j < l; j++) {\n row = item.rows[j];\n\n for (k = 0; k < row.length; k++) {\n row[k].tokens = this.lexer.inline(row[k].text);\n }\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 tokens: this.lexer.inline(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 var text = cap[1].charAt(cap[1].length - 1) === '\\n' ? cap[1].slice(0, -1) : cap[1];\n return {\n type: 'paragraph',\n raw: cap[0],\n text: text,\n tokens: this.lexer.inline(text)\n };\n }\n };\n\n _proto.text = function text(src) {\n var cap = this.rules.block.text.exec(src);\n\n if (cap) {\n return {\n type: 'text',\n raw: cap[0],\n text: cap[0],\n tokens: this.lexer.inline(cap[0])\n };\n }\n };\n\n _proto.escape = function escape$1(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) {\n var cap = this.rules.inline.tag.exec(src);\n\n if (cap) {\n if (!this.lexer.state.inLink && /^/i.test(cap[0])) {\n this.lexer.state.inLink = false;\n }\n\n if (!this.lexer.state.inRawBlock && /^<(pre|code|kbd|script)(\\s|>)/i.test(cap[0])) {\n this.lexer.state.inRawBlock = true;\n } else if (this.lexer.state.inRawBlock && /^<\\/(pre|code|kbd|script)(\\s|>)/i.test(cap[0])) {\n this.lexer.state.inRawBlock = false;\n }\n\n return {\n type: this.options.sanitize ? 'text' : 'html',\n raw: cap[0],\n inLink: this.lexer.state.inLink,\n inRawBlock: this.lexer.state.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 trimmedUrl = cap[2].trim();\n\n if (!this.options.pedantic && /^$/.test(trimmedUrl)) {\n return;\n } // ending angle bracket cannot be escaped\n\n\n var rtrimSlash = rtrim(trimmedUrl.slice(0, -1), '\\\\');\n\n if ((trimmedUrl.length - rtrimSlash.length) % 2 === 0) {\n return;\n }\n } else {\n // find closing parenthesis\n var lastParenIndex = findClosingBracket(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\n var href = cap[2];\n var title = '';\n\n if (this.options.pedantic) {\n // split pedantic href and title\n var link = /^([^'\"]*[^\\s])\\s+(['\"])(.*)\\2/.exec(href);\n\n if (link) {\n href = link[1];\n title = link[3];\n }\n } else {\n title = cap[3] ? cap[3].slice(1, -1) : '';\n }\n\n href = href.trim();\n\n if (/^$/.test(trimmedUrl)) {\n // pedantic allows starting angle bracket without ending angle bracket\n href = href.slice(1);\n } else {\n href = href.slice(1, -1);\n }\n }\n\n return 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], this.lexer);\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 return outputLink(cap, link, cap[0], this.lexer);\n }\n };\n\n _proto.emStrong = function emStrong(src, maskedSrc, prevChar) {\n if (prevChar === void 0) {\n prevChar = '';\n }\n\n var match = this.rules.inline.emStrong.lDelim.exec(src);\n if (!match) return; // _ can't be between two alphanumerics. \\p{L}\\p{N} includes non-english alphabet/numbers as well\n\n if (match[3] && prevChar.match(/(?:[0-9A-Za-z\\xAA\\xB2\\xB3\\xB5\\xB9\\xBA\\xBC-\\xBE\\xC0-\\xD6\\xD8-\\xF6\\xF8-\\u02C1\\u02C6-\\u02D1\\u02E0-\\u02E4\\u02EC\\u02EE\\u0370-\\u0374\\u0376\\u0377\\u037A-\\u037D\\u037F\\u0386\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03F5\\u03F7-\\u0481\\u048A-\\u052F\\u0531-\\u0556\\u0559\\u0560-\\u0588\\u05D0-\\u05EA\\u05EF-\\u05F2\\u0620-\\u064A\\u0660-\\u0669\\u066E\\u066F\\u0671-\\u06D3\\u06D5\\u06E5\\u06E6\\u06EE-\\u06FC\\u06FF\\u0710\\u0712-\\u072F\\u074D-\\u07A5\\u07B1\\u07C0-\\u07EA\\u07F4\\u07F5\\u07FA\\u0800-\\u0815\\u081A\\u0824\\u0828\\u0840-\\u0858\\u0860-\\u086A\\u0870-\\u0887\\u0889-\\u088E\\u08A0-\\u08C9\\u0904-\\u0939\\u093D\\u0950\\u0958-\\u0961\\u0966-\\u096F\\u0971-\\u0980\\u0985-\\u098C\\u098F\\u0990\\u0993-\\u09A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BD\\u09CE\\u09DC\\u09DD\\u09DF-\\u09E1\\u09E6-\\u09F1\\u09F4-\\u09F9\\u09FC\\u0A05-\\u0A0A\\u0A0F\\u0A10\\u0A13-\\u0A28\\u0A2A-\\u0A30\\u0A32\\u0A33\\u0A35\\u0A36\\u0A38\\u0A39\\u0A59-\\u0A5C\\u0A5E\\u0A66-\\u0A6F\\u0A72-\\u0A74\\u0A85-\\u0A8D\\u0A8F-\\u0A91\\u0A93-\\u0AA8\\u0AAA-\\u0AB0\\u0AB2\\u0AB3\\u0AB5-\\u0AB9\\u0ABD\\u0AD0\\u0AE0\\u0AE1\\u0AE6-\\u0AEF\\u0AF9\\u0B05-\\u0B0C\\u0B0F\\u0B10\\u0B13-\\u0B28\\u0B2A-\\u0B30\\u0B32\\u0B33\\u0B35-\\u0B39\\u0B3D\\u0B5C\\u0B5D\\u0B5F-\\u0B61\\u0B66-\\u0B6F\\u0B71-\\u0B77\\u0B83\\u0B85-\\u0B8A\\u0B8E-\\u0B90\\u0B92-\\u0B95\\u0B99\\u0B9A\\u0B9C\\u0B9E\\u0B9F\\u0BA3\\u0BA4\\u0BA8-\\u0BAA\\u0BAE-\\u0BB9\\u0BD0\\u0BE6-\\u0BF2\\u0C05-\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u0C2A-\\u0C39\\u0C3D\\u0C58-\\u0C5A\\u0C5D\\u0C60\\u0C61\\u0C66-\\u0C6F\\u0C78-\\u0C7E\\u0C80\\u0C85-\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBD\\u0CDD\\u0CDE\\u0CE0\\u0CE1\\u0CE6-\\u0CEF\\u0CF1\\u0CF2\\u0D04-\\u0D0C\\u0D0E-\\u0D10\\u0D12-\\u0D3A\\u0D3D\\u0D4E\\u0D54-\\u0D56\\u0D58-\\u0D61\\u0D66-\\u0D78\\u0D7A-\\u0D7F\\u0D85-\\u0D96\\u0D9A-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD\\u0DC0-\\u0DC6\\u0DE6-\\u0DEF\\u0E01-\\u0E30\\u0E32\\u0E33\\u0E40-\\u0E46\\u0E50-\\u0E59\\u0E81\\u0E82\\u0E84\\u0E86-\\u0E8A\\u0E8C-\\u0EA3\\u0EA5\\u0EA7-\\u0EB0\\u0EB2\\u0EB3\\u0EBD\\u0EC0-\\u0EC4\\u0EC6\\u0ED0-\\u0ED9\\u0EDC-\\u0EDF\\u0F00\\u0F20-\\u0F33\\u0F40-\\u0F47\\u0F49-\\u0F6C\\u0F88-\\u0F8C\\u1000-\\u102A\\u103F-\\u1049\\u1050-\\u1055\\u105A-\\u105D\\u1061\\u1065\\u1066\\u106E-\\u1070\\u1075-\\u1081\\u108E\\u1090-\\u1099\\u10A0-\\u10C5\\u10C7\\u10CD\\u10D0-\\u10FA\\u10FC-\\u1248\\u124A-\\u124D\\u1250-\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288\\u128A-\\u128D\\u1290-\\u12B0\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-\\u12C5\\u12C8-\\u12D6\\u12D8-\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u1369-\\u137C\\u1380-\\u138F\\u13A0-\\u13F5\\u13F8-\\u13FD\\u1401-\\u166C\\u166F-\\u167F\\u1681-\\u169A\\u16A0-\\u16EA\\u16EE-\\u16F8\\u1700-\\u1711\\u171F-\\u1731\\u1740-\\u1751\\u1760-\\u176C\\u176E-\\u1770\\u1780-\\u17B3\\u17D7\\u17DC\\u17E0-\\u17E9\\u17F0-\\u17F9\\u1810-\\u1819\\u1820-\\u1878\\u1880-\\u1884\\u1887-\\u18A8\\u18AA\\u18B0-\\u18F5\\u1900-\\u191E\\u1946-\\u196D\\u1970-\\u1974\\u1980-\\u19AB\\u19B0-\\u19C9\\u19D0-\\u19DA\\u1A00-\\u1A16\\u1A20-\\u1A54\\u1A80-\\u1A89\\u1A90-\\u1A99\\u1AA7\\u1B05-\\u1B33\\u1B45-\\u1B4C\\u1B50-\\u1B59\\u1B83-\\u1BA0\\u1BAE-\\u1BE5\\u1C00-\\u1C23\\u1C40-\\u1C49\\u1C4D-\\u1C7D\\u1C80-\\u1C88\\u1C90-\\u1CBA\\u1CBD-\\u1CBF\\u1CE9-\\u1CEC\\u1CEE-\\u1CF3\\u1CF5\\u1CF6\\u1CFA\\u1D00-\\u1DBF\\u1E00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F7D\\u1F80-\\u1FB4\\u1FB6-\\u1FBC\\u1FBE\\u1FC2-\\u1FC4\\u1FC6-\\u1FCC\\u1FD0-\\u1FD3\\u1FD6-\\u1FDB\\u1FE0-\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FFC\\u2070\\u2071\\u2074-\\u2079\\u207F-\\u2089\\u2090-\\u209C\\u2102\\u2107\\u210A-\\u2113\\u2115\\u2119-\\u211D\\u2124\\u2126\\u2128\\u212A-\\u212D\\u212F-\\u2139\\u213C-\\u213F\\u2145-\\u2149\\u214E\\u2150-\\u2189\\u2460-\\u249B\\u24EA-\\u24FF\\u2776-\\u2793\\u2C00-\\u2CE4\\u2CEB-\\u2CEE\\u2CF2\\u2CF3\\u2CFD\\u2D00-\\u2D25\\u2D27\\u2D2D\\u2D30-\\u2D67\\u2D6F\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u2E2F\\u3005-\\u3007\\u3021-\\u3029\\u3031-\\u3035\\u3038-\\u303C\\u3041-\\u3096\\u309D-\\u309F\\u30A1-\\u30FA\\u30FC-\\u30FF\\u3105-\\u312F\\u3131-\\u318E\\u3192-\\u3195\\u31A0-\\u31BF\\u31F0-\\u31FF\\u3220-\\u3229\\u3248-\\u324F\\u3251-\\u325F\\u3280-\\u3289\\u32B1-\\u32BF\\u3400-\\u4DBF\\u4E00-\\uA48C\\uA4D0-\\uA4FD\\uA500-\\uA60C\\uA610-\\uA62B\\uA640-\\uA66E\\uA67F-\\uA69D\\uA6A0-\\uA6EF\\uA717-\\uA71F\\uA722-\\uA788\\uA78B-\\uA7CA\\uA7D0\\uA7D1\\uA7D3\\uA7D5-\\uA7D9\\uA7F2-\\uA801\\uA803-\\uA805\\uA807-\\uA80A\\uA80C-\\uA822\\uA830-\\uA835\\uA840-\\uA873\\uA882-\\uA8B3\\uA8D0-\\uA8D9\\uA8F2-\\uA8F7\\uA8FB\\uA8FD\\uA8FE\\uA900-\\uA925\\uA930-\\uA946\\uA960-\\uA97C\\uA984-\\uA9B2\\uA9CF-\\uA9D9\\uA9E0-\\uA9E4\\uA9E6-\\uA9FE\\uAA00-\\uAA28\\uAA40-\\uAA42\\uAA44-\\uAA4B\\uAA50-\\uAA59\\uAA60-\\uAA76\\uAA7A\\uAA7E-\\uAAAF\\uAAB1\\uAAB5\\uAAB6\\uAAB9-\\uAABD\\uAAC0\\uAAC2\\uAADB-\\uAADD\\uAAE0-\\uAAEA\\uAAF2-\\uAAF4\\uAB01-\\uAB06\\uAB09-\\uAB0E\\uAB11-\\uAB16\\uAB20-\\uAB26\\uAB28-\\uAB2E\\uAB30-\\uAB5A\\uAB5C-\\uAB69\\uAB70-\\uABE2\\uABF0-\\uABF9\\uAC00-\\uD7A3\\uD7B0-\\uD7C6\\uD7CB-\\uD7FB\\uF900-\\uFA6D\\uFA70-\\uFAD9\\uFB00-\\uFB06\\uFB13-\\uFB17\\uFB1D\\uFB1F-\\uFB28\\uFB2A-\\uFB36\\uFB38-\\uFB3C\\uFB3E\\uFB40\\uFB41\\uFB43\\uFB44\\uFB46-\\uFBB1\\uFBD3-\\uFD3D\\uFD50-\\uFD8F\\uFD92-\\uFDC7\\uFDF0-\\uFDFB\\uFE70-\\uFE74\\uFE76-\\uFEFC\\uFF10-\\uFF19\\uFF21-\\uFF3A\\uFF41-\\uFF5A\\uFF66-\\uFFBE\\uFFC2-\\uFFC7\\uFFCA-\\uFFCF\\uFFD2-\\uFFD7\\uFFDA-\\uFFDC]|\\uD800[\\uDC00-\\uDC0B\\uDC0D-\\uDC26\\uDC28-\\uDC3A\\uDC3C\\uDC3D\\uDC3F-\\uDC4D\\uDC50-\\uDC5D\\uDC80-\\uDCFA\\uDD07-\\uDD33\\uDD40-\\uDD78\\uDD8A\\uDD8B\\uDE80-\\uDE9C\\uDEA0-\\uDED0\\uDEE1-\\uDEFB\\uDF00-\\uDF23\\uDF2D-\\uDF4A\\uDF50-\\uDF75\\uDF80-\\uDF9D\\uDFA0-\\uDFC3\\uDFC8-\\uDFCF\\uDFD1-\\uDFD5]|\\uD801[\\uDC00-\\uDC9D\\uDCA0-\\uDCA9\\uDCB0-\\uDCD3\\uDCD8-\\uDCFB\\uDD00-\\uDD27\\uDD30-\\uDD63\\uDD70-\\uDD7A\\uDD7C-\\uDD8A\\uDD8C-\\uDD92\\uDD94\\uDD95\\uDD97-\\uDDA1\\uDDA3-\\uDDB1\\uDDB3-\\uDDB9\\uDDBB\\uDDBC\\uDE00-\\uDF36\\uDF40-\\uDF55\\uDF60-\\uDF67\\uDF80-\\uDF85\\uDF87-\\uDFB0\\uDFB2-\\uDFBA]|\\uD802[\\uDC00-\\uDC05\\uDC08\\uDC0A-\\uDC35\\uDC37\\uDC38\\uDC3C\\uDC3F-\\uDC55\\uDC58-\\uDC76\\uDC79-\\uDC9E\\uDCA7-\\uDCAF\\uDCE0-\\uDCF2\\uDCF4\\uDCF5\\uDCFB-\\uDD1B\\uDD20-\\uDD39\\uDD80-\\uDDB7\\uDDBC-\\uDDCF\\uDDD2-\\uDE00\\uDE10-\\uDE13\\uDE15-\\uDE17\\uDE19-\\uDE35\\uDE40-\\uDE48\\uDE60-\\uDE7E\\uDE80-\\uDE9F\\uDEC0-\\uDEC7\\uDEC9-\\uDEE4\\uDEEB-\\uDEEF\\uDF00-\\uDF35\\uDF40-\\uDF55\\uDF58-\\uDF72\\uDF78-\\uDF91\\uDFA9-\\uDFAF]|\\uD803[\\uDC00-\\uDC48\\uDC80-\\uDCB2\\uDCC0-\\uDCF2\\uDCFA-\\uDD23\\uDD30-\\uDD39\\uDE60-\\uDE7E\\uDE80-\\uDEA9\\uDEB0\\uDEB1\\uDF00-\\uDF27\\uDF30-\\uDF45\\uDF51-\\uDF54\\uDF70-\\uDF81\\uDFB0-\\uDFCB\\uDFE0-\\uDFF6]|\\uD804[\\uDC03-\\uDC37\\uDC52-\\uDC6F\\uDC71\\uDC72\\uDC75\\uDC83-\\uDCAF\\uDCD0-\\uDCE8\\uDCF0-\\uDCF9\\uDD03-\\uDD26\\uDD36-\\uDD3F\\uDD44\\uDD47\\uDD50-\\uDD72\\uDD76\\uDD83-\\uDDB2\\uDDC1-\\uDDC4\\uDDD0-\\uDDDA\\uDDDC\\uDDE1-\\uDDF4\\uDE00-\\uDE11\\uDE13-\\uDE2B\\uDE80-\\uDE86\\uDE88\\uDE8A-\\uDE8D\\uDE8F-\\uDE9D\\uDE9F-\\uDEA8\\uDEB0-\\uDEDE\\uDEF0-\\uDEF9\\uDF05-\\uDF0C\\uDF0F\\uDF10\\uDF13-\\uDF28\\uDF2A-\\uDF30\\uDF32\\uDF33\\uDF35-\\uDF39\\uDF3D\\uDF50\\uDF5D-\\uDF61]|\\uD805[\\uDC00-\\uDC34\\uDC47-\\uDC4A\\uDC50-\\uDC59\\uDC5F-\\uDC61\\uDC80-\\uDCAF\\uDCC4\\uDCC5\\uDCC7\\uDCD0-\\uDCD9\\uDD80-\\uDDAE\\uDDD8-\\uDDDB\\uDE00-\\uDE2F\\uDE44\\uDE50-\\uDE59\\uDE80-\\uDEAA\\uDEB8\\uDEC0-\\uDEC9\\uDF00-\\uDF1A\\uDF30-\\uDF3B\\uDF40-\\uDF46]|\\uD806[\\uDC00-\\uDC2B\\uDCA0-\\uDCF2\\uDCFF-\\uDD06\\uDD09\\uDD0C-\\uDD13\\uDD15\\uDD16\\uDD18-\\uDD2F\\uDD3F\\uDD41\\uDD50-\\uDD59\\uDDA0-\\uDDA7\\uDDAA-\\uDDD0\\uDDE1\\uDDE3\\uDE00\\uDE0B-\\uDE32\\uDE3A\\uDE50\\uDE5C-\\uDE89\\uDE9D\\uDEB0-\\uDEF8]|\\uD807[\\uDC00-\\uDC08\\uDC0A-\\uDC2E\\uDC40\\uDC50-\\uDC6C\\uDC72-\\uDC8F\\uDD00-\\uDD06\\uDD08\\uDD09\\uDD0B-\\uDD30\\uDD46\\uDD50-\\uDD59\\uDD60-\\uDD65\\uDD67\\uDD68\\uDD6A-\\uDD89\\uDD98\\uDDA0-\\uDDA9\\uDEE0-\\uDEF2\\uDFB0\\uDFC0-\\uDFD4]|\\uD808[\\uDC00-\\uDF99]|\\uD809[\\uDC00-\\uDC6E\\uDC80-\\uDD43]|\\uD80B[\\uDF90-\\uDFF0]|[\\uD80C\\uD81C-\\uD820\\uD822\\uD840-\\uD868\\uD86A-\\uD86C\\uD86F-\\uD872\\uD874-\\uD879\\uD880-\\uD883][\\uDC00-\\uDFFF]|\\uD80D[\\uDC00-\\uDC2E]|\\uD811[\\uDC00-\\uDE46]|\\uD81A[\\uDC00-\\uDE38\\uDE40-\\uDE5E\\uDE60-\\uDE69\\uDE70-\\uDEBE\\uDEC0-\\uDEC9\\uDED0-\\uDEED\\uDF00-\\uDF2F\\uDF40-\\uDF43\\uDF50-\\uDF59\\uDF5B-\\uDF61\\uDF63-\\uDF77\\uDF7D-\\uDF8F]|\\uD81B[\\uDE40-\\uDE96\\uDF00-\\uDF4A\\uDF50\\uDF93-\\uDF9F\\uDFE0\\uDFE1\\uDFE3]|\\uD821[\\uDC00-\\uDFF7]|\\uD823[\\uDC00-\\uDCD5\\uDD00-\\uDD08]|\\uD82B[\\uDFF0-\\uDFF3\\uDFF5-\\uDFFB\\uDFFD\\uDFFE]|\\uD82C[\\uDC00-\\uDD22\\uDD50-\\uDD52\\uDD64-\\uDD67\\uDD70-\\uDEFB]|\\uD82F[\\uDC00-\\uDC6A\\uDC70-\\uDC7C\\uDC80-\\uDC88\\uDC90-\\uDC99]|\\uD834[\\uDEE0-\\uDEF3\\uDF60-\\uDF78]|\\uD835[\\uDC00-\\uDC54\\uDC56-\\uDC9C\\uDC9E\\uDC9F\\uDCA2\\uDCA5\\uDCA6\\uDCA9-\\uDCAC\\uDCAE-\\uDCB9\\uDCBB\\uDCBD-\\uDCC3\\uDCC5-\\uDD05\\uDD07-\\uDD0A\\uDD0D-\\uDD14\\uDD16-\\uDD1C\\uDD1E-\\uDD39\\uDD3B-\\uDD3E\\uDD40-\\uDD44\\uDD46\\uDD4A-\\uDD50\\uDD52-\\uDEA5\\uDEA8-\\uDEC0\\uDEC2-\\uDEDA\\uDEDC-\\uDEFA\\uDEFC-\\uDF14\\uDF16-\\uDF34\\uDF36-\\uDF4E\\uDF50-\\uDF6E\\uDF70-\\uDF88\\uDF8A-\\uDFA8\\uDFAA-\\uDFC2\\uDFC4-\\uDFCB\\uDFCE-\\uDFFF]|\\uD837[\\uDF00-\\uDF1E]|\\uD838[\\uDD00-\\uDD2C\\uDD37-\\uDD3D\\uDD40-\\uDD49\\uDD4E\\uDE90-\\uDEAD\\uDEC0-\\uDEEB\\uDEF0-\\uDEF9]|\\uD839[\\uDFE0-\\uDFE6\\uDFE8-\\uDFEB\\uDFED\\uDFEE\\uDFF0-\\uDFFE]|\\uD83A[\\uDC00-\\uDCC4\\uDCC7-\\uDCCF\\uDD00-\\uDD43\\uDD4B\\uDD50-\\uDD59]|\\uD83B[\\uDC71-\\uDCAB\\uDCAD-\\uDCAF\\uDCB1-\\uDCB4\\uDD01-\\uDD2D\\uDD2F-\\uDD3D\\uDE00-\\uDE03\\uDE05-\\uDE1F\\uDE21\\uDE22\\uDE24\\uDE27\\uDE29-\\uDE32\\uDE34-\\uDE37\\uDE39\\uDE3B\\uDE42\\uDE47\\uDE49\\uDE4B\\uDE4D-\\uDE4F\\uDE51\\uDE52\\uDE54\\uDE57\\uDE59\\uDE5B\\uDE5D\\uDE5F\\uDE61\\uDE62\\uDE64\\uDE67-\\uDE6A\\uDE6C-\\uDE72\\uDE74-\\uDE77\\uDE79-\\uDE7C\\uDE7E\\uDE80-\\uDE89\\uDE8B-\\uDE9B\\uDEA1-\\uDEA3\\uDEA5-\\uDEA9\\uDEAB-\\uDEBB]|\\uD83C[\\uDD00-\\uDD0C]|\\uD83E[\\uDFF0-\\uDFF9]|\\uD869[\\uDC00-\\uDEDF\\uDF00-\\uDFFF]|\\uD86D[\\uDC00-\\uDF38\\uDF40-\\uDFFF]|\\uD86E[\\uDC00-\\uDC1D\\uDC20-\\uDFFF]|\\uD873[\\uDC00-\\uDEA1\\uDEB0-\\uDFFF]|\\uD87A[\\uDC00-\\uDFE0]|\\uD87E[\\uDC00-\\uDE1D]|\\uD884[\\uDC00-\\uDF4A])/)) return;\n var nextChar = match[1] || match[2] || '';\n\n if (!nextChar || nextChar && (prevChar === '' || this.rules.inline.punctuation.exec(prevChar))) {\n var lLength = match[0].length - 1;\n var rDelim,\n rLength,\n delimTotal = lLength,\n midDelimTotal = 0;\n var endReg = match[0][0] === '*' ? this.rules.inline.emStrong.rDelimAst : this.rules.inline.emStrong.rDelimUnd;\n endReg.lastIndex = 0; // Clip maskedSrc to same section of string as src (move to lexer?)\n\n maskedSrc = maskedSrc.slice(-1 * src.length + lLength);\n\n while ((match = endReg.exec(maskedSrc)) != null) {\n rDelim = match[1] || match[2] || match[3] || match[4] || match[5] || match[6];\n if (!rDelim) continue; // skip single * in __abc*abc__\n\n rLength = rDelim.length;\n\n if (match[3] || match[4]) {\n // found another Left Delim\n delimTotal += rLength;\n continue;\n } else if (match[5] || match[6]) {\n // either Left or Right Delim\n if (lLength % 3 && !((lLength + rLength) % 3)) {\n midDelimTotal += rLength;\n continue; // CommonMark Emphasis Rules 9-10\n }\n }\n\n delimTotal -= rLength;\n if (delimTotal > 0) continue; // Haven't found enough closing delimiters\n // Remove extra characters. *a*** -> *a*\n\n rLength = Math.min(rLength, rLength + delimTotal + midDelimTotal); // Create `em` if smallest delimiter has odd char count. *a***\n\n if (Math.min(lLength, rLength) % 2) {\n var _text = src.slice(1, lLength + match.index + rLength);\n\n return {\n type: 'em',\n raw: src.slice(0, lLength + match.index + rLength + 1),\n text: _text,\n tokens: this.lexer.inlineTokens(_text)\n };\n } // Create 'strong' if smallest delimiter has even char count. **a***\n\n\n var text = src.slice(2, lLength + match.index + rLength - 1);\n return {\n type: 'strong',\n raw: src.slice(0, lLength + match.index + rLength + 1),\n text: text,\n tokens: this.lexer.inlineTokens(text)\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 = /^ /.test(text) && / $/.test(text);\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[2],\n tokens: this.lexer.inlineTokens(cap[2])\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, smartypants) {\n var cap = this.rules.inline.text.exec(src);\n\n if (cap) {\n var text;\n\n if (this.lexer.state.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 /**\n * Block-Level Grammar\n */\n\n var block = {\n newline: /^(?: *(?:\\n|$))+/,\n code: /^( {4}[^\\n]+(?:\\n(?: *(?:\\n|$))*)?)+/,\n fences: /^ {0,3}(`{3,}(?=[^`\\n]*\\n)|~{3,})([^\\n]*)\\n(?:|([\\s\\S]*?)\\n)(?: {0,3}\\1[~`]* *(?=\\n|$)|$)/,\n hr: /^ {0,3}((?:-[\\t ]*){3,}|(?:_[ \\t]*){3,}|(?:\\*[ \\t]*){3,})(?:\\n+|$)/,\n heading: /^ {0,3}(#{1,6})(?=\\s|$)(.*)(?:\\n+|$)/,\n blockquote: /^( {0,3}> ?(paragraph|[^\\n]*)(?:\\n|$))+/,\n list: /^( {0,3}bull)([ \\t][^\\n]+?)?(?:\\n|$)/,\n html: '^ {0,3}(?:' // optional indentation\n + '<(script|pre|style|textarea)[\\\\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 *)+\\\\n|$)' // (6)\n + '|<(?!script|pre|style|textarea)([a-z][\\\\w-]*)(?:attribute)*? */?>(?=[ \\\\t]*(?:\\\\n|$))[\\\\s\\\\S]*?(?:(?:\\\\n *)+\\\\n|$)' // (7) open tag\n + '|(?=[ \\\\t]*(?:\\\\n|$))[\\\\s\\\\S]*?(?:(?:\\\\n *)+\\\\n|$)' // (7) closing tag\n + ')',\n def: /^ {0,3}\\[(label)\\]: *(?:\\n *)?]+)>?(?:(?: +(?:\\n *)?| *\\n *)(title))? *(?:\\n+|$)/,\n table: noopTest,\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|table| +\\n)[^\\n]+)*)/,\n text: /^[^\\n]+/\n };\n block._label = /(?!\\s*\\])(?:\\\\.|[^\\[\\]\\\\])+/;\n block._title = /(?:\"(?:\\\\\"?|[^\"\\\\])*\"|'[^'\\n]*(?:\\n[^'\\n]+)*\\n?'|\\([^()]*\\))/;\n block.def = edit(block.def).replace('label', block._label).replace('title', block._title).getRegex();\n block.bullet = /(?:[*+-]|\\d{1,9}[.)])/;\n block.listItemStart = edit(/^( *)(bull) */).replace('bull', block.bullet).getRegex();\n block.list = edit(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(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(block._paragraph).replace('hr', block.hr).replace('heading', ' {0,3}#{1,6} ').replace('|lheading', '') // setex headings don't interrupt commonmark paragraphs\n .replace('|table', '').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|textarea|!--)').replace('tag', block._tag) // pars can be interrupted by type (6) html blocks\n .getRegex();\n block.blockquote = edit(block.blockquote).replace('paragraph', block.paragraph).getRegex();\n /**\n * Normal Block Grammar\n */\n\n block.normal = merge({}, block);\n /**\n * GFM Block Grammar\n */\n\n block.gfm = merge({}, block.normal, {\n table: '^ *([^\\\\n ].*\\\\|.*)\\\\n' // Header\n + ' {0,3}(?:\\\\| *)?(:?-+:? *(?:\\\\| *:?-+:? *)*)(?:\\\\| *)?' // Align\n + '(?:\\\\n((?:(?! *\\\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\\\n|$))*)\\\\n*|$)' // Cells\n\n });\n block.gfm.table = edit(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|textarea|!--)').replace('tag', block._tag) // tables can be interrupted by type (6) html blocks\n .getRegex();\n block.gfm.paragraph = edit(block._paragraph).replace('hr', block.hr).replace('heading', ' {0,3}#{1,6} ').replace('|lheading', '') // setex headings don't interrupt commonmark paragraphs\n .replace('table', block.gfm.table) // interrupt paragraphs with table\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|textarea|!--)').replace('tag', block._tag) // pars 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({}, block.normal, {\n html: edit('^ *(?: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 fences: noopTest,\n // fences not supported\n paragraph: edit(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,\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)\\]\\[(ref)\\]/,\n nolink: /^!?\\[(ref)\\](?:\\[\\])?/,\n reflinkSearch: 'reflink|nolink(?!\\\\()',\n emStrong: {\n lDelim: /^(?:\\*+(?:([punct_])|[^\\s*]))|^_+(?:([punct*])|([^\\s_]))/,\n // (1) and (2) can only be a Right Delimiter. (3) and (4) can only be Left. (5) and (6) can be either Left or Right.\n // () Skip orphan inside strong () Consume to delim (1) #*** (2) a***#, a*** (3) #***a, ***a (4) ***# (5) #***# (6) a***a\n rDelimAst: /^[^_*]*?\\_\\_[^_*]*?\\*[^_*]*?(?=\\_\\_)|[^*]+(?=[^*])|[punct_](\\*+)(?=[\\s]|$)|[^punct*_\\s](\\*+)(?=[punct_\\s]|$)|[punct_\\s](\\*+)(?=[^punct*_\\s])|[\\s](\\*+)(?=[punct_])|[punct_](\\*+)(?=[punct_])|[^punct*_\\s](\\*+)(?=[^punct*_\\s])/,\n rDelimUnd: /^[^_*]*?\\*\\*[^_*]*?\\_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|[punct*](\\_+)(?=[\\s]|$)|[^punct*_\\s](\\_+)(?=[punct*\\s]|$)|[punct*\\s](\\_+)(?=[^punct*_\\s])|[\\s](\\_+)(?=[punct*])|[punct*](\\_+)(?=[punct*])/ // ^- Not allowed for _\n\n },\n code: /^(`+)([^`]|[^`][\\s\\S]*?[^`])\\1(?!`)/,\n br: /^( {2,}|\\\\)\\n(?!\\s*$)/,\n del: noopTest,\n text: /^(`+|[^`])(?:(?= {2,}\\n)|[\\s\\S]*?(?:(?=[\\\\?@\\\\[\\\\]`^{|}~';\n inline.punctuation = edit(inline.punctuation).replace(/punctuation/g, inline._punctuation).getRegex(); // sequences em should skip over [title](link), `code`, \n\n inline.blockSkip = /\\[[^\\]]*?\\]\\([^\\)]*?\\)|`[^`]*?`|<[^>]*?>/g;\n inline.escapedEmSt = /\\\\\\*|\\\\_/g;\n inline._comment = edit(block._comment).replace('(?:-->|$)', '-->').getRegex();\n inline.emStrong.lDelim = edit(inline.emStrong.lDelim).replace(/punct/g, inline._punctuation).getRegex();\n inline.emStrong.rDelimAst = edit(inline.emStrong.rDelimAst, 'g').replace(/punct/g, inline._punctuation).getRegex();\n inline.emStrong.rDelimUnd = edit(inline.emStrong.rDelimUnd, 'g').replace(/punct/g, inline._punctuation).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(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(inline.tag).replace('comment', inline._comment).replace('attribute', inline._attribute).getRegex();\n inline._label = /(?:\\[(?:\\\\.|[^\\[\\]\\\\])*\\]|\\\\.|`[^`]*`|[^\\[\\]\\\\`])*?/;\n inline._href = /<(?:\\\\.|[^\\n<>\\\\])+>|[^\\s\\x00-\\x1f]*/;\n inline._title = /\"(?:\\\\\"?|[^\"\\\\])*\"|'(?:\\\\'?|[^'\\\\])*'|\\((?:\\\\\\)?|[^)\\\\])*\\)/;\n inline.link = edit(inline.link).replace('label', inline._label).replace('href', inline._href).replace('title', inline._title).getRegex();\n inline.reflink = edit(inline.reflink).replace('label', inline._label).replace('ref', block._label).getRegex();\n inline.nolink = edit(inline.nolink).replace('ref', block._label).getRegex();\n inline.reflinkSearch = edit(inline.reflinkSearch, 'g').replace('reflink', inline.reflink).replace('nolink', inline.nolink).getRegex();\n /**\n * Normal Inline Grammar\n */\n\n inline.normal = merge({}, inline);\n /**\n * Pedantic Inline Grammar\n */\n\n inline.pedantic = merge({}, 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(/^!?\\[(label)\\]\\((.*?)\\)/).replace('label', inline._label).getRegex(),\n reflink: edit(/^!?\\[(label)\\]\\s*\\[([^\\]]*)\\]/).replace('label', inline._label).getRegex()\n });\n /**\n * GFM Inline Grammar\n */\n\n inline.gfm = merge({}, inline.normal, {\n escape: edit(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~])\\1(?=[^~]|$)/,\n text: /^([`~]+|[^`~])(?:(?= {2,}\\n)|(?=[a-zA-Z0-9.!#$%&'*+\\/=?_`{\\|}~-]+@)|[\\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 = /*#__PURE__*/function () {\n function Lexer(options) {\n this.tokens = [];\n this.tokens.links = Object.create(null);\n this.options = options || exports.defaults;\n this.options.tokenizer = this.options.tokenizer || new Tokenizer();\n this.tokenizer = this.options.tokenizer;\n this.tokenizer.options = this.options;\n this.tokenizer.lexer = this;\n this.inlineQueue = [];\n this.state = {\n inLink: false,\n inRawBlock: false,\n top: true\n };\n var rules = {\n block: block.normal,\n inline: inline.normal\n };\n\n if (this.options.pedantic) {\n rules.block = block.pedantic;\n rules.inline = inline.pedantic;\n } else if (this.options.gfm) {\n rules.block = block.gfm;\n\n if (this.options.breaks) {\n rules.inline = inline.breaks;\n } else {\n rules.inline = inline.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');\n this.blockTokens(src, this.tokens);\n var next;\n\n while (next = this.inlineQueue.shift()) {\n this.inlineTokens(next.src, next.tokens);\n }\n\n return this.tokens;\n }\n /**\n * Lexing\n */\n ;\n\n _proto.blockTokens = function blockTokens(src, tokens) {\n var _this = this;\n\n if (tokens === void 0) {\n tokens = [];\n }\n\n if (this.options.pedantic) {\n src = src.replace(/\\t/g, ' ').replace(/^ +$/gm, '');\n } else {\n src = src.replace(/^( *)(\\t+)/gm, function (_, leading, tabs) {\n return leading + ' '.repeat(tabs.length);\n });\n }\n\n var token, lastToken, cutSrc, lastParagraphClipped;\n\n while (src) {\n if (this.options.extensions && this.options.extensions.block && this.options.extensions.block.some(function (extTokenizer) {\n if (token = extTokenizer.call({\n lexer: _this\n }, src, tokens)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n return true;\n }\n\n return false;\n })) {\n continue;\n } // newline\n\n\n if (token = this.tokenizer.space(src)) {\n src = src.substring(token.raw.length);\n\n if (token.raw.length === 1 && tokens.length > 0) {\n // if there's a single \\n as a spacer, it's terminating the last line,\n // so move it there so that we don't get unecessary paragraph tags\n tokens[tokens.length - 1].raw += '\\n';\n } else {\n tokens.push(token);\n }\n\n continue;\n } // code\n\n\n if (token = this.tokenizer.code(src)) {\n src = src.substring(token.raw.length);\n lastToken = tokens[tokens.length - 1]; // An indented code block cannot interrupt a paragraph.\n\n if (lastToken && (lastToken.type === 'paragraph' || lastToken.type === 'text')) {\n lastToken.raw += '\\n' + token.raw;\n lastToken.text += '\\n' + token.text;\n this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text;\n } else {\n tokens.push(token);\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 } // 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 tokens.push(token);\n continue;\n } // list\n\n\n if (token = this.tokenizer.list(src)) {\n src = src.substring(token.raw.length);\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 (token = this.tokenizer.def(src)) {\n src = src.substring(token.raw.length);\n lastToken = tokens[tokens.length - 1];\n\n if (lastToken && (lastToken.type === 'paragraph' || lastToken.type === 'text')) {\n lastToken.raw += '\\n' + token.raw;\n lastToken.text += '\\n' + token.raw;\n this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text;\n } else 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 // prevent paragraph consuming extensions by clipping 'src' to extension start\n\n\n cutSrc = src;\n\n if (this.options.extensions && this.options.extensions.startBlock) {\n (function () {\n var startIndex = Infinity;\n var tempSrc = src.slice(1);\n var tempStart = void 0;\n\n _this.options.extensions.startBlock.forEach(function (getStartIndex) {\n tempStart = getStartIndex.call({\n lexer: this\n }, tempSrc);\n\n if (typeof tempStart === 'number' && tempStart >= 0) {\n startIndex = Math.min(startIndex, tempStart);\n }\n });\n\n if (startIndex < Infinity && startIndex >= 0) {\n cutSrc = src.substring(0, startIndex + 1);\n }\n })();\n }\n\n if (this.state.top && (token = this.tokenizer.paragraph(cutSrc))) {\n lastToken = tokens[tokens.length - 1];\n\n if (lastParagraphClipped && lastToken.type === 'paragraph') {\n lastToken.raw += '\\n' + token.raw;\n lastToken.text += '\\n' + token.text;\n this.inlineQueue.pop();\n this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text;\n } else {\n tokens.push(token);\n }\n\n lastParagraphClipped = cutSrc.length !== src.length;\n src = src.substring(token.raw.length);\n continue;\n } // text\n\n\n if (token = this.tokenizer.text(src)) {\n src = src.substring(token.raw.length);\n lastToken = tokens[tokens.length - 1];\n\n if (lastToken && lastToken.type === 'text') {\n lastToken.raw += '\\n' + token.raw;\n lastToken.text += '\\n' + token.text;\n this.inlineQueue.pop();\n this.inlineQueue[this.inlineQueue.length - 1].src = lastToken.text;\n } else {\n tokens.push(token);\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 this.state.top = true;\n return tokens;\n };\n\n _proto.inline = function inline(src, tokens) {\n if (tokens === void 0) {\n tokens = [];\n }\n\n this.inlineQueue.push({\n src: src,\n tokens: tokens\n });\n return tokens;\n }\n /**\n * Lexing/Compiling\n */\n ;\n\n _proto.inlineTokens = function inlineTokens(src, tokens) {\n var _this2 = this;\n\n if (tokens === void 0) {\n tokens = [];\n }\n\n var token, lastToken, cutSrc; // String with links masked to avoid interference with em and strong\n\n var maskedSrc = src;\n var match;\n var keepPrevChar, prevChar; // 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('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('a', match[0].length - 2) + ']' + maskedSrc.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);\n } // Mask out escaped em & strong delimiters\n\n\n while ((match = this.tokenizer.rules.inline.escapedEmSt.exec(maskedSrc)) != null) {\n maskedSrc = maskedSrc.slice(0, match.index) + '++' + maskedSrc.slice(this.tokenizer.rules.inline.escapedEmSt.lastIndex);\n }\n\n while (src) {\n if (!keepPrevChar) {\n prevChar = '';\n }\n\n keepPrevChar = false; // extensions\n\n if (this.options.extensions && this.options.extensions.inline && this.options.extensions.inline.some(function (extTokenizer) {\n if (token = extTokenizer.call({\n lexer: _this2\n }, src, tokens)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n return true;\n }\n\n return false;\n })) {\n continue;\n } // escape\n\n\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)) {\n src = src.substring(token.raw.length);\n lastToken = tokens[tokens.length - 1];\n\n if (lastToken && token.type === 'text' && lastToken.type === 'text') {\n lastToken.raw += token.raw;\n lastToken.text += token.text;\n } else {\n tokens.push(token);\n }\n\n continue;\n } // link\n\n\n if (token = this.tokenizer.link(src)) {\n src = src.substring(token.raw.length);\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 lastToken = tokens[tokens.length - 1];\n\n if (lastToken && token.type === 'text' && lastToken.type === 'text') {\n lastToken.raw += token.raw;\n lastToken.text += token.text;\n } else {\n tokens.push(token);\n }\n\n continue;\n } // em & strong\n\n\n if (token = this.tokenizer.emStrong(src, maskedSrc, prevChar)) {\n src = src.substring(token.raw.length);\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 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 (!this.state.inLink && (token = this.tokenizer.url(src, mangle))) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n } // text\n // prevent inlineText consuming extensions by clipping 'src' to extension start\n\n\n cutSrc = src;\n\n if (this.options.extensions && this.options.extensions.startInline) {\n (function () {\n var startIndex = Infinity;\n var tempSrc = src.slice(1);\n var tempStart = void 0;\n\n _this2.options.extensions.startInline.forEach(function (getStartIndex) {\n tempStart = getStartIndex.call({\n lexer: this\n }, tempSrc);\n\n if (typeof tempStart === 'number' && tempStart >= 0) {\n startIndex = Math.min(startIndex, tempStart);\n }\n });\n\n if (startIndex < Infinity && startIndex >= 0) {\n cutSrc = src.substring(0, startIndex + 1);\n }\n })();\n }\n\n if (token = this.tokenizer.inlineText(cutSrc, smartypants)) {\n src = src.substring(token.raw.length);\n\n if (token.raw.slice(-1) !== '_') {\n // Track prevChar before string of ____ started\n prevChar = token.raw.slice(-1);\n }\n\n keepPrevChar = true;\n lastToken = tokens[tokens.length - 1];\n\n if (lastToken && lastToken.type === 'text') {\n lastToken.raw += token.raw;\n lastToken.text += token.text;\n } else {\n tokens.push(token);\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 _createClass(Lexer, null, [{\n key: \"rules\",\n get: function get() {\n return {\n block: block,\n inline: inline\n };\n }\n }]);\n\n return Lexer;\n }();\n\n /**\n * Renderer\n */\n\n var Renderer = /*#__PURE__*/function () {\n function Renderer(options) {\n this.options = options || exports.defaults;\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 _code = _code.replace(/\\n$/, '') + '\\n';\n\n if (!lang) {\n return '
' + (escaped ? _code : escape(_code, true)) + '
\\n';\n }\n\n return '
' + (escaped ? _code : escape(_code, true)) + '
\\n';\n }\n /**\n * @param {string} quote\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 * @param {string} text\n * @param {string} level\n * @param {string} raw\n * @param {any} slugger\n */\n ;\n\n _proto.heading = function heading(text, level, raw, slugger) {\n if (this.options.headerIds) {\n var id = this.options.headerPrefix + slugger.slug(raw);\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 * @param {string} text\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 * @param {string} text\n */\n ;\n\n _proto.paragraph = function paragraph(text) {\n return \"

    \" + text + \"

    \\n\";\n }\n /**\n * @param {string} header\n * @param {string} body\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 * @param {string} content\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 }\n /**\n * span level renderer\n * @param {string} text\n */\n ;\n\n _proto.strong = function strong(text) {\n return \"\" + text + \"\";\n }\n /**\n * @param {string} text\n */\n ;\n\n _proto.em = function em(text) {\n return \"\" + text + \"\";\n }\n /**\n * @param {string} text\n */\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 * @param {string} text\n */\n ;\n\n _proto.del = function del(text) {\n return \"\" + text + \"\";\n }\n /**\n * @param {string} href\n * @param {string} title\n * @param {string} text\n */\n ;\n\n _proto.link = function link(href, title, text) {\n href = cleanUrl(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 * @param {string} href\n * @param {string} title\n * @param {string} text\n */\n ;\n\n _proto.image = function image(href, title, text) {\n href = cleanUrl(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 = /*#__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 = /*#__PURE__*/function () {\n function Slugger() {\n this.seen = {};\n }\n /**\n * @param {string} value\n */\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 * @param {string} originalSlug\n * @param {boolean} isDryRun\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\n * 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 /**\n * Parsing & Compiling\n */\n\n var Parser = /*#__PURE__*/function () {\n function Parser(options) {\n this.options = options || exports.defaults;\n this.options.renderer = this.options.renderer || new Renderer();\n this.renderer = this.options.renderer;\n this.renderer.options = this.options;\n this.textRenderer = new TextRenderer();\n this.slugger = new Slugger();\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 ret;\n var l = tokens.length;\n\n for (i = 0; i < l; i++) {\n token = tokens[i]; // Run any renderer extensions\n\n if (this.options.extensions && this.options.extensions.renderers && this.options.extensions.renderers[token.type]) {\n ret = this.options.extensions.renderers[token.type].call({\n parser: this\n }, token);\n\n if (ret !== false || !['space', 'hr', 'heading', 'code', 'table', 'blockquote', 'list', 'html', 'paragraph', 'text'].includes(token.type)) {\n out += ret || '';\n continue;\n }\n }\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(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.header[j].tokens), {\n header: true,\n align: token.align[j]\n });\n }\n\n header += this.renderer.tablerow(cell);\n body = '';\n l2 = token.rows.length;\n\n for (j = 0; j < l2; j++) {\n row = token.rows[j];\n cell = '';\n l3 = row.length;\n\n for (k = 0; k < l3; k++) {\n cell += this.renderer.tablecell(this.parseInline(row[k].tokens), {\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 === 'paragraph') {\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 ret;\n var l = tokens.length;\n\n for (i = 0; i < l; i++) {\n token = tokens[i]; // Run any renderer extensions\n\n if (this.options.extensions && this.options.extensions.renderers && this.options.extensions.renderers[token.type]) {\n ret = this.options.extensions.renderers[token.type].call({\n parser: this\n }, token);\n\n if (ret !== false || !['escape', 'html', 'link', 'image', 'strong', 'em', 'codespan', 'br', 'del', 'text'].includes(token.type)) {\n out += ret || '';\n continue;\n }\n }\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 /**\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({}, marked.defaults, opt || {});\n checkSanitizeDeprecation(opt);\n\n if (callback) {\n var highlight = opt.highlight;\n var tokens;\n\n try {\n tokens = Lexer.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 if (opt.walkTokens) {\n marked.walkTokens(tokens, opt.walkTokens);\n }\n\n out = Parser.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 function onError(e) {\n e.message += '\\nPlease report this to https://github.com/markedjs/marked.';\n\n if (opt.silent) {\n return '

    An error occurred:

    ' + escape(e.message + '', true) + '
    ';\n }\n\n throw e;\n }\n\n try {\n var _tokens = Lexer.lex(src, opt);\n\n if (opt.walkTokens) {\n if (opt.async) {\n return Promise.all(marked.walkTokens(_tokens, opt.walkTokens)).then(function () {\n return Parser.parse(_tokens, opt);\n })[\"catch\"](onError);\n }\n\n marked.walkTokens(_tokens, opt.walkTokens);\n }\n\n return Parser.parse(_tokens, opt);\n } catch (e) {\n onError(e);\n }\n }\n /**\n * Options\n */\n\n marked.options = marked.setOptions = function (opt) {\n merge(marked.defaults, opt);\n changeDefaults(marked.defaults);\n return marked;\n };\n\n marked.getDefaults = getDefaults;\n marked.defaults = exports.defaults;\n /**\n * Use Extension\n */\n\n marked.use = 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 opts = merge.apply(void 0, [{}].concat(args));\n var extensions = marked.defaults.extensions || {\n renderers: {},\n childTokens: {}\n };\n var hasExtensions;\n args.forEach(function (pack) {\n // ==-- Parse \"addon\" extensions --== //\n if (pack.extensions) {\n hasExtensions = true;\n pack.extensions.forEach(function (ext) {\n if (!ext.name) {\n throw new Error('extension name required');\n }\n\n if (ext.renderer) {\n // Renderer extensions\n var prevRenderer = extensions.renderers ? extensions.renderers[ext.name] : null;\n\n if (prevRenderer) {\n // Replace extension with func to run new extension but fall back if false\n extensions.renderers[ext.name] = 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 = ext.renderer.apply(this, args);\n\n if (ret === false) {\n ret = prevRenderer.apply(this, args);\n }\n\n return ret;\n };\n } else {\n extensions.renderers[ext.name] = ext.renderer;\n }\n }\n\n if (ext.tokenizer) {\n // Tokenizer Extensions\n if (!ext.level || ext.level !== 'block' && ext.level !== 'inline') {\n throw new Error(\"extension level must be 'block' or 'inline'\");\n }\n\n if (extensions[ext.level]) {\n extensions[ext.level].unshift(ext.tokenizer);\n } else {\n extensions[ext.level] = [ext.tokenizer];\n }\n\n if (ext.start) {\n // Function to check for start of token\n if (ext.level === 'block') {\n if (extensions.startBlock) {\n extensions.startBlock.push(ext.start);\n } else {\n extensions.startBlock = [ext.start];\n }\n } else if (ext.level === 'inline') {\n if (extensions.startInline) {\n extensions.startInline.push(ext.start);\n } else {\n extensions.startInline = [ext.start];\n }\n }\n }\n }\n\n if (ext.childTokens) {\n // Child tokens to be visited by walkTokens\n extensions.childTokens[ext.name] = ext.childTokens;\n }\n });\n } // ==-- Parse \"overwrite\" extensions --== //\n\n\n if (pack.renderer) {\n (function () {\n var renderer = marked.defaults.renderer || new Renderer();\n\n var _loop = function _loop(prop) {\n var prevRenderer = renderer[prop]; // Replace renderer with func to run extension, but fall back if false\n\n renderer[prop] = function () {\n for (var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {\n args[_key3] = arguments[_key3];\n }\n\n var ret = pack.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 pack.renderer) {\n _loop(prop);\n }\n\n opts.renderer = renderer;\n })();\n }\n\n if (pack.tokenizer) {\n (function () {\n var tokenizer = marked.defaults.tokenizer || new Tokenizer();\n\n var _loop2 = function _loop2(prop) {\n var prevTokenizer = tokenizer[prop]; // Replace tokenizer with func to run extension, but fall back if false\n\n tokenizer[prop] = function () {\n for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) {\n args[_key4] = arguments[_key4];\n }\n\n var ret = pack.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 pack.tokenizer) {\n _loop2(prop);\n }\n\n opts.tokenizer = tokenizer;\n })();\n } // ==-- Parse WalkTokens extensions --== //\n\n\n if (pack.walkTokens) {\n var _walkTokens = marked.defaults.walkTokens;\n\n opts.walkTokens = function (token) {\n var values = [];\n values.push(pack.walkTokens.call(this, token));\n\n if (_walkTokens) {\n values = values.concat(_walkTokens.call(this, token));\n }\n\n return values;\n };\n }\n\n if (hasExtensions) {\n opts.extensions = extensions;\n }\n\n marked.setOptions(opts);\n });\n };\n /**\n * Run callback for every token\n */\n\n\n marked.walkTokens = function (tokens, callback) {\n var values = [];\n\n var _loop3 = function _loop3() {\n var token = _step.value;\n values = values.concat(callback.call(marked, token));\n\n switch (token.type) {\n case 'table':\n {\n for (var _iterator2 = _createForOfIteratorHelperLoose(token.header), _step2; !(_step2 = _iterator2()).done;) {\n var cell = _step2.value;\n values = values.concat(marked.walkTokens(cell.tokens, callback));\n }\n\n for (var _iterator3 = _createForOfIteratorHelperLoose(token.rows), _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 values = values.concat(marked.walkTokens(_cell.tokens, callback));\n }\n }\n\n break;\n }\n\n case 'list':\n {\n values = values.concat(marked.walkTokens(token.items, callback));\n break;\n }\n\n default:\n {\n if (marked.defaults.extensions && marked.defaults.extensions.childTokens && marked.defaults.extensions.childTokens[token.type]) {\n // Walk any extensions\n marked.defaults.extensions.childTokens[token.type].forEach(function (childTokens) {\n values = values.concat(marked.walkTokens(token[childTokens], callback));\n });\n } else if (token.tokens) {\n values = values.concat(marked.walkTokens(token.tokens, callback));\n }\n }\n }\n };\n\n for (var _iterator = _createForOfIteratorHelperLoose(tokens), _step; !(_step = _iterator()).done;) {\n _loop3();\n }\n\n return values;\n };\n /**\n * Parse Inline\n * @param {string} src\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({}, marked.defaults, opt || {});\n checkSanitizeDeprecation(opt);\n\n try {\n var tokens = Lexer.lexInline(src, opt);\n\n if (opt.walkTokens) {\n marked.walkTokens(tokens, opt.walkTokens);\n }\n\n return Parser.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(e.message + '', true) + '
    ';\n }\n\n throw e;\n }\n };\n /**\n * Expose\n */\n\n\n marked.Parser = Parser;\n marked.parser = Parser.parse;\n marked.Renderer = Renderer;\n marked.TextRenderer = TextRenderer;\n marked.Lexer = Lexer;\n marked.lexer = Lexer.lex;\n marked.Tokenizer = Tokenizer;\n marked.Slugger = Slugger;\n marked.parse = marked;\n var options = marked.options;\n var setOptions = marked.setOptions;\n var use = marked.use;\n var walkTokens = marked.walkTokens;\n var parseInline = marked.parseInline;\n var parse = marked;\n var parser = Parser.parse;\n var lexer = Lexer.lex;\n\n exports.Lexer = Lexer;\n exports.Parser = Parser;\n exports.Renderer = Renderer;\n exports.Slugger = Slugger;\n exports.TextRenderer = TextRenderer;\n exports.Tokenizer = Tokenizer;\n exports.getDefaults = getDefaults;\n exports.lexer = lexer;\n exports.marked = marked;\n exports.options = options;\n exports.parse = parse;\n exports.parseInline = parseInline;\n exports.parser = parser;\n exports.setOptions = setOptions;\n exports.use = use;\n exports.walkTokens = walkTokens;\n\n Object.defineProperty(exports, '__esModule', { value: true });\n\n}));\n\n// ESM-uncomment-begin\n// })();\n// export var Lexer = (__marked_exports.Lexer || exports.Lexer);\n// export var Parser = (__marked_exports.Parser || exports.Parser);\n// export var Renderer = (__marked_exports.Renderer || exports.Renderer);\n// export var Slugger = (__marked_exports.Slugger || exports.Slugger);\n// export var TextRenderer = (__marked_exports.TextRenderer || exports.TextRenderer);\n// export var Tokenizer = (__marked_exports.Tokenizer || exports.Tokenizer);\n// export var getDefaults = (__marked_exports.getDefaults || exports.getDefaults);\n// export var lexer = (__marked_exports.lexer || exports.lexer);\n// export var marked = (__marked_exports.marked || exports.marked);\n// export var options = (__marked_exports.options || exports.options);\n// export var parse = (__marked_exports.parse || exports.parse);\n// export var parseInline = (__marked_exports.parseInline || exports.parseInline);\n// export var parser = (__marked_exports.parser || exports.parser);\n// export var setOptions = (__marked_exports.setOptions || exports.setOptions);\n// export var use = (__marked_exports.use || exports.use);\n// export var walkTokens = (__marked_exports.walkTokens || exports.walkTokens);\n// ESM-uncomment-end\n","\n\nexport const Mimes = Object.freeze({\n\ttext: 'text/plain',\n\tbinary: 'application/octet-stream',\n\tunknown: 'application/unknown',\n\tmarkdown: 'text/markdown',\n\tlatex: 'text/latex',\n\turiList: 'text/uri-list',\n});\n","\nimport { Mimes } from 'vs/base/common/mime';\n\n// Common data transfers\nexport const DataTransfers = {\n\n\t/**\n\t * Application specific resource transfer type\n\t */\n\tRESOURCES: 'ResourceURLs',\n\n\t/**\n\t * Browser specific transfer type to download\n\t */\n\tDOWNLOAD_URL: 'DownloadURL',\n\n\t/**\n\t * Browser specific transfer type for files\n\t */\n\tFILES: 'Files',\n\n\t/**\n\t * Typically transfer type for copy/paste transfers.\n\t */\n\tTEXT: Mimes.text,\n\n\t/**\n\t * Internal type used to pass around text/uri-list data.\n\t *\n\t * This is needed to work around https://bugs.chromium.org/p/chromium/issues/detail?id=239745.\n\t */\n\tINTERNAL_URI_LIST: 'application/vnd.code.uri-list',\n};\n\nexport interface IDragAndDropData {\n\tupdate(dataTransfer: DataTransfer): void;\n\tgetData(): unknown;\n}\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// allow-any-unicode-comment-file\n\n/**\n * Gets alternative Korean characters for the character code. This will return the ascii\n * character code(s) that a Hangul character may have been input with using a qwerty layout.\n *\n * This only aims to cover modern (not archaic) Hangul syllables.\n *\n * @param code The character code to get alternate characters for\n */\nexport function getKoreanAltChars(code: number): ArrayLike | undefined {\n\tconst result = disassembleKorean(code);\n\tif (result && result.length > 0) {\n\t\treturn new Uint32Array(result);\n\t}\n\treturn undefined;\n}\n\nlet codeBufferLength = 0;\nconst codeBuffer = new Uint32Array(10);\nfunction disassembleKorean(code: number): Uint32Array | undefined {\n\tcodeBufferLength = 0;\n\n\t// Initial consonants (초성)\n\tgetCodesFromArray(code, modernConsonants, HangulRangeStartCode.InitialConsonant);\n\tif (codeBufferLength > 0) {\n\t\treturn codeBuffer.subarray(0, codeBufferLength);\n\t}\n\n\t// Vowels (중성)\n\tgetCodesFromArray(code, modernVowels, HangulRangeStartCode.Vowel);\n\tif (codeBufferLength > 0) {\n\t\treturn codeBuffer.subarray(0, codeBufferLength);\n\t}\n\n\t// Final consonants (종성)\n\tgetCodesFromArray(code, modernFinalConsonants, HangulRangeStartCode.FinalConsonant);\n\tif (codeBufferLength > 0) {\n\t\treturn codeBuffer.subarray(0, codeBufferLength);\n\t}\n\n\t// Hangul Compatibility Jamo\n\tgetCodesFromArray(code, compatibilityJamo, HangulRangeStartCode.CompatibilityJamo);\n\tif (codeBufferLength) {\n\t\treturn codeBuffer.subarray(0, codeBufferLength);\n\t}\n\n\t// Hangul Syllables\n\tif (code >= 0xAC00 && code <= 0xD7A3) {\n\t\tconst hangulIndex = code - 0xAC00;\n\t\tconst vowelAndFinalConsonantProduct = hangulIndex % 588;\n\n\t\t// 0-based starting at 0x1100\n\t\tconst initialConsonantIndex = Math.floor(hangulIndex / 588);\n\t\t// 0-based starting at 0x1161\n\t\tconst vowelIndex = Math.floor(vowelAndFinalConsonantProduct / 28);\n\t\t// 0-based starting at 0x11A8\n\t\t// Subtract 1 as the standard algorithm uses the 0 index to represent no\n\t\t// final consonant\n\t\tconst finalConsonantIndex = vowelAndFinalConsonantProduct % 28 - 1;\n\n\t\tif (initialConsonantIndex < modernConsonants.length) {\n\t\t\tgetCodesFromArray(initialConsonantIndex, modernConsonants, 0);\n\t\t} else if (HangulRangeStartCode.InitialConsonant + initialConsonantIndex - HangulRangeStartCode.CompatibilityJamo < compatibilityJamo.length) {\n\t\t\tgetCodesFromArray(HangulRangeStartCode.InitialConsonant + initialConsonantIndex, compatibilityJamo, HangulRangeStartCode.CompatibilityJamo);\n\t\t}\n\n\t\tif (vowelIndex < modernVowels.length) {\n\t\t\tgetCodesFromArray(vowelIndex, modernVowels, 0);\n\t\t} else if (HangulRangeStartCode.Vowel + vowelIndex - HangulRangeStartCode.CompatibilityJamo < compatibilityJamo.length) {\n\t\t\tgetCodesFromArray(HangulRangeStartCode.Vowel + vowelIndex - HangulRangeStartCode.CompatibilityJamo, compatibilityJamo, HangulRangeStartCode.CompatibilityJamo);\n\t\t}\n\n\t\tif (finalConsonantIndex >= 0) {\n\t\t\tif (finalConsonantIndex < modernFinalConsonants.length) {\n\t\t\t\tgetCodesFromArray(finalConsonantIndex, modernFinalConsonants, 0);\n\t\t\t} else if (HangulRangeStartCode.FinalConsonant + finalConsonantIndex - HangulRangeStartCode.CompatibilityJamo < compatibilityJamo.length) {\n\t\t\t\tgetCodesFromArray(HangulRangeStartCode.FinalConsonant + finalConsonantIndex - HangulRangeStartCode.CompatibilityJamo, compatibilityJamo, HangulRangeStartCode.CompatibilityJamo);\n\t\t\t}\n\t\t}\n\n\t\tif (codeBufferLength > 0) {\n\t\t\treturn codeBuffer.subarray(0, codeBufferLength);\n\t\t}\n\t}\n\treturn undefined;\n}\n\nfunction getCodesFromArray(code: number, array: ArrayLike, arrayStartIndex: number): void {\n\t// Verify the code is within the array's range\n\tif (code >= arrayStartIndex && code < arrayStartIndex + array.length) {\n\t\taddCodesToBuffer(array[code - arrayStartIndex]);\n\t}\n}\n\nfunction addCodesToBuffer(codes: number): void {\n\t// NUL is ignored, this is used for archaic characters to avoid using a Map\n\t// for the data\n\tif (codes === AsciiCode.NUL) {\n\t\treturn;\n\t}\n\t// Number stored in format: OptionalThirdCode << 16 | OptionalSecondCode << 8 | Code\n\tcodeBuffer[codeBufferLength++] = codes & 0xFF;\n\tif (codes >> 8) {\n\t\tcodeBuffer[codeBufferLength++] = (codes >> 8) & 0xFF;\n\t}\n\tif (codes >> 16) {\n\t\tcodeBuffer[codeBufferLength++] = (codes >> 16) & 0xFF;\n\t}\n}\n\nconst enum HangulRangeStartCode {\n\tInitialConsonant = 0x1100,\n\tVowel = 0x1161,\n\tFinalConsonant = 0x11A8,\n\tCompatibilityJamo = 0x3131,\n}\n\nconst enum AsciiCode {\n\tNUL = 0,\n\tA = 65,\n\tB = 66,\n\tC = 67,\n\tD = 68,\n\tE = 69,\n\tF = 70,\n\tG = 71,\n\tH = 72,\n\tI = 73,\n\tJ = 74,\n\tK = 75,\n\tL = 76,\n\tM = 77,\n\tN = 78,\n\tO = 79,\n\tP = 80,\n\tQ = 81,\n\tR = 82,\n\tS = 83,\n\tT = 84,\n\tU = 85,\n\tV = 86,\n\tW = 87,\n\tX = 88,\n\tY = 89,\n\tZ = 90,\n\ta = 97,\n\tb = 98,\n\tc = 99,\n\td = 100,\n\te = 101,\n\tf = 102,\n\tg = 103,\n\th = 104,\n\ti = 105,\n\tj = 106,\n\tk = 107,\n\tl = 108,\n\tm = 109,\n\tn = 110,\n\to = 111,\n\tp = 112,\n\tq = 113,\n\tr = 114,\n\ts = 115,\n\tt = 116,\n\tu = 117,\n\tv = 118,\n\tw = 119,\n\tx = 120,\n\ty = 121,\n\tz = 122,\n}\n\n/**\n * Numbers that represent multiple ascii codes. These are precomputed at compile time to reduce\n * bundle and runtime overhead.\n */\nconst enum AsciiCodeCombo {\n\tfa = AsciiCode.a << 8 | AsciiCode.f,\n\tfg = AsciiCode.g << 8 | AsciiCode.f,\n\tfq = AsciiCode.q << 8 | AsciiCode.f,\n\tfr = AsciiCode.r << 8 | AsciiCode.f,\n\tft = AsciiCode.t << 8 | AsciiCode.f,\n\tfv = AsciiCode.v << 8 | AsciiCode.f,\n\tfx = AsciiCode.x << 8 | AsciiCode.f,\n\thk = AsciiCode.k << 8 | AsciiCode.h,\n\thl = AsciiCode.l << 8 | AsciiCode.h,\n\tho = AsciiCode.o << 8 | AsciiCode.h,\n\tml = AsciiCode.l << 8 | AsciiCode.m,\n\tnj = AsciiCode.j << 8 | AsciiCode.n,\n\tnl = AsciiCode.l << 8 | AsciiCode.n,\n\tnp = AsciiCode.p << 8 | AsciiCode.n,\n\tqt = AsciiCode.t << 8 | AsciiCode.q,\n\trt = AsciiCode.t << 8 | AsciiCode.r,\n\tsg = AsciiCode.g << 8 | AsciiCode.s,\n\tsw = AsciiCode.w << 8 | AsciiCode.s,\n}\n\n/**\n * Hangul Jamo - Modern consonants #1\n *\n * Range U+1100..U+1112\n *\n * | | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |\n * |--------|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|\n * | U+110x | ᄀ | ᄁ | ᄂ | ᄃ | ᄄ | ᄅ | ᄆ | ᄇ | ᄈ | ᄉ | ᄊ | ᄋ | ᄌ | ᄍ | ᄎ | ᄏ |\n * | U+111x | ᄐ | ᄑ | ᄒ |\n */\nconst modernConsonants = new Uint8Array([\n\tAsciiCode.r, // ㄱ\n\tAsciiCode.R, // ㄲ\n\tAsciiCode.s, // ㄴ\n\tAsciiCode.e, // ㄷ\n\tAsciiCode.E, // ㄸ\n\tAsciiCode.f, // ㄹ\n\tAsciiCode.a, // ㅁ\n\tAsciiCode.q, // ㅂ\n\tAsciiCode.Q, // ㅃ\n\tAsciiCode.t, // ㅅ\n\tAsciiCode.T, // ㅆ\n\tAsciiCode.d, // ㅇ\n\tAsciiCode.w, // ㅈ\n\tAsciiCode.W, // ㅉ\n\tAsciiCode.c, // ㅊ\n\tAsciiCode.z, // ㅋ\n\tAsciiCode.x, // ㅌ\n\tAsciiCode.v, // ㅍ\n\tAsciiCode.g, // ㅎ\n]);\n\n/**\n * Hangul Jamo - Modern Vowels\n *\n * Range U+1161..U+1175\n *\n * | | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |\n * |--------|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|\n * | U+116x | | ᅡ | ᅢ | ᅣ | ᅤ | ᅥ | ᅦ | ᅧ | ᅨ | ᅩ | ᅪ | ᅫ | ᅬ | ᅭ | ᅮ | ᅯ |\n * | U+117x | ᅰ | ᅱ | ᅲ | ᅳ | ᅴ | ᅵ |\n */\nconst modernVowels = new Uint16Array([\n\tAsciiCode.k, // -> ㅏ\n\tAsciiCode.o, // -> ㅐ\n\tAsciiCode.i, // -> ㅑ\n\tAsciiCode.O, // -> ㅒ\n\tAsciiCode.j, // -> ㅓ\n\tAsciiCode.p, // -> ㅔ\n\tAsciiCode.u, // -> ㅕ\n\tAsciiCode.P, // -> ㅖ\n\tAsciiCode.h, // -> ㅗ\n\tAsciiCodeCombo.hk, // -> ㅘ\n\tAsciiCodeCombo.ho, // -> ㅙ\n\tAsciiCodeCombo.hl, // -> ㅚ\n\tAsciiCode.y, // -> ㅛ\n\tAsciiCode.n, // -> ㅜ\n\tAsciiCodeCombo.nj, // -> ㅝ\n\tAsciiCodeCombo.np, // -> ㅞ\n\tAsciiCodeCombo.nl, // -> ㅟ\n\tAsciiCode.b, // -> ㅠ\n\tAsciiCode.m, // -> ㅡ\n\tAsciiCodeCombo.ml, // -> ㅢ\n\tAsciiCode.l, // -> ㅣ\n]);\n\n/**\n * Hangul Jamo - Modern Consonants #2\n *\n * Range U+11A8..U+11C2\n *\n * | | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |\n * |--------|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|\n * | U+11Ax | | | | | | | | | ᆨ | ᆩ | ᆪ | ᆫ | ᆬ | ᆭ | ᆮ | ᆯ |\n * | U+11Bx | ᆰ | ᆱ | ᆲ | ᆳ | ᆴ | ᆵ | ᆶ | ᆷ | ᆸ | ᆹ | ᆺ | ᆻ | ᆼ | ᆽ | ᆾ | ᆿ |\n * | U+11Cx | ᇀ | ᇁ | ᇂ |\n */\nconst modernFinalConsonants = new Uint16Array([\n\tAsciiCode.r, // ㄱ\n\tAsciiCode.R, // ㄲ\n\tAsciiCodeCombo.rt, // ㄳ\n\tAsciiCode.s, // ㄴ\n\tAsciiCodeCombo.sw, // ㄵ\n\tAsciiCodeCombo.sg, // ㄶ\n\tAsciiCode.e, // ㄷ\n\tAsciiCode.f, // ㄹ\n\tAsciiCodeCombo.fr, // ㄺ\n\tAsciiCodeCombo.fa, // ㄻ\n\tAsciiCodeCombo.fq, // ㄼ\n\tAsciiCodeCombo.ft, // ㄽ\n\tAsciiCodeCombo.fx, // ㄾ\n\tAsciiCodeCombo.fv, // ㄿ\n\tAsciiCodeCombo.fg, // ㅀ\n\tAsciiCode.a, // ㅁ\n\tAsciiCode.q, // ㅂ\n\tAsciiCodeCombo.qt, // ㅄ\n\tAsciiCode.t, // ㅅ\n\tAsciiCode.T, // ㅆ\n\tAsciiCode.d, // ㅇ\n\tAsciiCode.w, // ㅈ\n\tAsciiCode.c, // ㅊ\n\tAsciiCode.z, // ㅋ\n\tAsciiCode.x, // ㅌ\n\tAsciiCode.v, // ㅍ\n\tAsciiCode.g, // ㅎ\n]);\n\n/**\n * Hangul Compatibility Jamo\n *\n * Range U+3131..U+318F\n *\n * This includes range includes archaic jamo which we don't consider, these are\n * given the NUL character code in order to be ignored.\n *\n * | | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |\n * |--------|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|\n * | U+313x | | ㄱ | ㄲ | ㄳ | ㄴ | ㄵ | ㄶ | ㄷ | ㄸ | ㄹ | ㄺ | ㄻ | ㄼ | ㄽ | ㄾ | ㄿ |\n * | U+314x | ㅀ | ㅁ | ㅂ | ㅃ | ㅄ | ㅅ | ㅆ | ㅇ | ㅈ | ㅉ | ㅊ | ㅋ | ㅌ | ㅍ | ㅎ | ㅏ |\n * | U+315x | ㅐ | ㅑ | ㅒ | ㅓ | ㅔ | ㅕ | ㅖ | ㅗ | ㅘ | ㅙ | ㅚ | ㅛ | ㅜ | ㅝ | ㅞ | ㅟ |\n * | U+316x | ㅠ | ㅡ | ㅢ | ㅣ | HF | ㅥ | ㅦ | ㅧ | ㅨ | ㅩ | ㅪ | ㅫ | ㅬ | ㅭ | ㅮ | ㅯ |\n * | U+317x | ㅰ | ㅱ | ㅲ | ㅳ | ㅴ | ㅵ | ㅶ | ㅷ | ㅸ | ㅹ | ㅺ | ㅻ | ㅼ | ㅽ | ㅾ | ㅿ |\n * | U+318x | ㆀ | ㆁ | ㆂ | ㆃ | ㆄ | ㆅ | ㆆ | ㆇ | ㆈ | ㆉ | ㆊ | ㆋ | ㆌ | ㆍ | ㆎ |\n */\nconst compatibilityJamo = new Uint16Array([\n\tAsciiCode.r, // ㄱ\n\tAsciiCode.R, // ㄲ\n\tAsciiCodeCombo.rt, // ㄳ\n\tAsciiCode.s, // ㄴ\n\tAsciiCodeCombo.sw, // ㄵ\n\tAsciiCodeCombo.sg, // ㄶ\n\tAsciiCode.e, // ㄷ\n\tAsciiCode.E, // ㄸ\n\tAsciiCode.f, // ㄹ\n\tAsciiCodeCombo.fr, // ㄺ\n\tAsciiCodeCombo.fa, // ㄻ\n\tAsciiCodeCombo.fq, // ㄼ\n\tAsciiCodeCombo.ft, // ㄽ\n\tAsciiCodeCombo.fx, // ㄾ\n\tAsciiCodeCombo.fv, // ㄿ\n\tAsciiCodeCombo.fg, // ㅀ\n\tAsciiCode.a, // ㅁ\n\tAsciiCode.q, // ㅂ\n\tAsciiCode.Q, // ㅃ\n\tAsciiCodeCombo.qt, // ㅄ\n\tAsciiCode.t, // ㅅ\n\tAsciiCode.T, // ㅆ\n\tAsciiCode.d, // ㅇ\n\tAsciiCode.w, // ㅈ\n\tAsciiCode.W, // ㅉ\n\tAsciiCode.c, // ㅊ\n\tAsciiCode.z, // ㅋ\n\tAsciiCode.x, // ㅌ\n\tAsciiCode.v, // ㅍ\n\tAsciiCode.g, // ㅎ\n\tAsciiCode.k, // ㅏ\n\tAsciiCode.o, // ㅐ\n\tAsciiCode.i, // ㅑ\n\tAsciiCode.O, // ㅒ\n\tAsciiCode.j, // ㅓ\n\tAsciiCode.p, // ㅔ\n\tAsciiCode.u, // ㅕ\n\tAsciiCode.P, // ㅖ\n\tAsciiCode.h, // ㅗ\n\tAsciiCodeCombo.hk, // ㅘ\n\tAsciiCodeCombo.ho, // ㅙ\n\tAsciiCodeCombo.hl, // ㅚ\n\tAsciiCode.y, // ㅛ\n\tAsciiCode.n, // ㅜ\n\tAsciiCodeCombo.nj, // ㅝ\n\tAsciiCodeCombo.np, // ㅞ\n\tAsciiCodeCombo.nl, // ㅟ\n\tAsciiCode.b, // ㅠ\n\tAsciiCode.m, // ㅡ\n\tAsciiCodeCombo.ml, // ㅢ\n\tAsciiCode.l, // ㅣ\n\t// HF: Hangul Filler (everything after this is archaic)\n\t// ㅥ\n\t// ㅦ\n\t// ㅧ\n\t// ㅨ\n\t// ㅩ\n\t// ㅪ\n\t// ㅫ\n\t// ㅬ\n\t// ㅮ\n\t// ㅯ\n\t// ㅰ\n\t// ㅱ\n\t// ㅲ\n\t// ㅳ\n\t// ㅴ\n\t// ㅵ\n\t// ㅶ\n\t// ㅷ\n\t// ㅸ\n\t// ㅹ\n\t// ㅺ\n\t// ㅻ\n\t// ㅼ\n\t// ㅽ\n\t// ㅾ\n\t// ㅿ\n\t// ㆀ\n\t// ㆁ\n\t// ㆂ\n\t// ㆃ\n\t// ㆄ\n\t// ㆅ\n\t// ㆆ\n\t// ㆇ\n\t// ㆈ\n\t// ㆉ\n\t// ㆊ\n\t// ㆋ\n\t// ㆌ\n\t// ㆍ\n\t// ㆎ\n]);\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\nexport interface INavigator {\n}\n\nexport class ArrayNavigator implements INavigator {\n\n\tconstructor(\n\t\tprivate readonly items: readonly T[],\n\t\tprotected start: number = 0,\n\t\tprotected end: number = items.length,\n\t\tprotected index = start - 1\n\t) { }\n\n\tcurrent(): T | null {\n\t\tif (this.index === this.start - 1 || this.index === this.end) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn this.items[this.index];\n\t}\n\n\tnext(): T | null {\n\t\tthis.index = Math.min(this.index + 1, this.end);\n\t\treturn this.current();\n\t}\n\n\tprevious(): T | null {\n\t\tthis.index = Math.max(this.index - 1, this.start - 1);\n\t\treturn this.current();\n\t}\n\n\tfirst(): T | null {\n\t\tthis.index = this.start;\n\t\treturn this.current();\n\t}\n\n\tlast(): T | null {\n\t\tthis.index = this.end - 1;\n\t\treturn this.current();\n\t}\n}\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\nimport { ArrayNavigator, INavigator } from 'vs/base/common/navigator';\n\nexport class HistoryNavigator implements INavigator {\n\n\tprivate _history!: Set;\n\tprivate _limit: number;\n\tprivate _navigator!: ArrayNavigator;\n\n\tconstructor(history: readonly T[] = [], limit: number = 10) {\n\t\tthis._initialize(history);\n\t\tthis._limit = limit;\n\t\tthis._onChange();\n\t}\n\n\tpublic getHistory(): T[] {\n\t\treturn this._elements;\n\t}\n\n\tpublic add(t: T) {\n\t\tthis._history.delete(t);\n\t\tthis._history.add(t);\n\t\tthis._onChange();\n\t}\n\n\tpublic next(): T | null {\n\t\t// This will navigate past the end of the last element, and in that case the input should be cleared\n\t\treturn this._navigator.next();\n\t}\n\n\tpublic previous(): T | null {\n\t\tif (this._currentPosition() !== 0) {\n\t\t\treturn this._navigator.previous();\n\t\t}\n\t\treturn null;\n\t}\n\n\tpublic current(): T | null {\n\t\treturn this._navigator.current();\n\t}\n\n\tpublic first(): T | null {\n\t\treturn this._navigator.first();\n\t}\n\n\tpublic last(): T | null {\n\t\treturn this._navigator.last();\n\t}\n\n\tpublic isLast(): boolean {\n\t\treturn this._currentPosition() >= this._elements.length - 1;\n\t}\n\n\tpublic isNowhere(): boolean {\n\t\treturn this._navigator.current() === null;\n\t}\n\n\tpublic has(t: T): boolean {\n\t\treturn this._history.has(t);\n\t}\n\n\tprivate _onChange() {\n\t\tthis._reduceToLimit();\n\t\tconst elements = this._elements;\n\t\tthis._navigator = new ArrayNavigator(elements, 0, elements.length, elements.length);\n\t}\n\n\tprivate _reduceToLimit() {\n\t\tconst data = this._elements;\n\t\tif (data.length > this._limit) {\n\t\t\tthis._initialize(data.slice(data.length - this._limit));\n\t\t}\n\t}\n\n\tprivate _currentPosition(): number {\n\t\tconst currentElement = this._navigator.current();\n\t\tif (!currentElement) {\n\t\t\treturn -1;\n\t\t}\n\n\t\treturn this._elements.indexOf(currentElement);\n\t}\n\n\tprivate _initialize(history: readonly T[]): void {\n\t\tthis._history = new Set();\n\t\tfor (const entry of history) {\n\t\t\tthis._history.add(entry);\n\t\t}\n\t}\n\n\tprivate get _elements(): T[] {\n\t\tconst elements: T[] = [];\n\t\tthis._history.forEach(e => elements.push(e));\n\t\treturn elements;\n\t}\n}\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\nexport function clamp(value: number, min: number, max: number): number {\n\treturn Math.min(Math.max(value, min), max);\n}\n\nexport class MovingAverage {\n\n\tprivate _n = 1;\n\tprivate _val = 0;\n\n\tupdate(value: number): number {\n\t\tthis._val = this._val + (value - this._val) / this._n;\n\t\tthis._n += 1;\n\t\treturn this._val;\n\t}\n\n\tget value(): number {\n\t\treturn this._val;\n\t}\n}\n\nexport class SlidingWindowAverage {\n\n\tprivate _n: number = 0;\n\tprivate _val = 0;\n\n\tprivate readonly _values: number[] = [];\n\tprivate _index: number = 0;\n\tprivate _sum = 0;\n\n\tconstructor(size: number) {\n\t\tthis._values = new Array(size);\n\t\tthis._values.fill(0, 0, size);\n\t}\n\n\tupdate(value: number): number {\n\t\tconst oldValue = this._values[this._index];\n\t\tthis._values[this._index] = value;\n\t\tthis._index = (this._index + 1) % this._values.length;\n\n\t\tthis._sum -= oldValue;\n\t\tthis._sum += value;\n\n\t\tif (this._n < this._values.length) {\n\t\t\tthis._n += 1;\n\t\t}\n\n\t\tthis._val = this._sum / this._n;\n\t\treturn this._val;\n\t}\n\n\tget value(): number {\n\t\treturn this._val;\n\t}\n}\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\nexport interface IDebugNameData {\n\t/**\n\t * The owner object of an observable.\n\t * Used for debugging only, such as computing a name for the observable by iterating over the fields of the owner.\n\t */\n\treadonly owner?: Owner | undefined;\n\n\t/**\n\t * A string or function that returns a string that represents the name of the observable.\n\t * Used for debugging only.\n\t */\n\treadonly debugName?: DebugNameSource | undefined;\n\n\t/**\n\t * A function that points to the defining function of the object.\n\t * Used for debugging only.\n\t */\n\treadonly debugReferenceFn?: Function | undefined;\n}\n\nexport class DebugNameData {\n\tconstructor(\n\t\tpublic readonly owner: Owner | undefined,\n\t\tpublic readonly debugNameSource: DebugNameSource | undefined,\n\t\tpublic readonly referenceFn: Function | undefined,\n\t) { }\n\n\tpublic getDebugName(target: object): string | undefined {\n\t\treturn getDebugName(target, this);\n\t}\n}\n\n/**\n * The owner object of an observable.\n * Is only used for debugging purposes, such as computing a name for the observable by iterating over the fields of the owner.\n */\nexport type Owner = object | undefined;\nexport type DebugNameSource = string | (() => string | undefined);\n\nconst countPerName = new Map();\nconst cachedDebugName = new WeakMap();\n\nexport function getDebugName(target: object, data: DebugNameData): string | undefined {\n\tconst cached = cachedDebugName.get(target);\n\tif (cached) {\n\t\treturn cached;\n\t}\n\n\tconst dbgName = computeDebugName(target, data);\n\tif (dbgName) {\n\t\tlet count = countPerName.get(dbgName) ?? 0;\n\t\tcount++;\n\t\tcountPerName.set(dbgName, count);\n\t\tconst result = count === 1 ? dbgName : `${dbgName}#${count}`;\n\t\tcachedDebugName.set(target, result);\n\t\treturn result;\n\t}\n\treturn undefined;\n}\n\nfunction computeDebugName(self: object, data: DebugNameData): string | undefined {\n\tconst cached = cachedDebugName.get(self);\n\tif (cached) {\n\t\treturn cached;\n\t}\n\n\tconst ownerStr = data.owner ? formatOwner(data.owner) + `.` : '';\n\n\tlet result: string | undefined;\n\tconst debugNameSource = data.debugNameSource;\n\tif (debugNameSource !== undefined) {\n\t\tif (typeof debugNameSource === 'function') {\n\t\t\tresult = debugNameSource();\n\t\t\tif (result !== undefined) {\n\t\t\t\treturn ownerStr + result;\n\t\t\t}\n\t\t} else {\n\t\t\treturn ownerStr + debugNameSource;\n\t\t}\n\t}\n\n\tconst referenceFn = data.referenceFn;\n\tif (referenceFn !== undefined) {\n\t\tresult = getFunctionName(referenceFn);\n\t\tif (result !== undefined) {\n\t\t\treturn ownerStr + result;\n\t\t}\n\t}\n\n\tif (data.owner !== undefined) {\n\t\tconst key = findKey(data.owner, self);\n\t\tif (key !== undefined) {\n\t\t\treturn ownerStr + key;\n\t\t}\n\t}\n\treturn undefined;\n}\n\nfunction findKey(obj: object, value: object): string | undefined {\n\tfor (const key in obj) {\n\t\tif ((obj as any)[key] === value) {\n\t\t\treturn key;\n\t\t}\n\t}\n\treturn undefined;\n}\n\nconst countPerClassName = new Map();\nconst ownerId = new WeakMap();\n\nfunction formatOwner(owner: object): string {\n\tconst id = ownerId.get(owner);\n\tif (id) {\n\t\treturn id;\n\t}\n\tconst className = getClassName(owner);\n\tlet count = countPerClassName.get(className) ?? 0;\n\tcount++;\n\tcountPerClassName.set(className, count);\n\tconst result = count === 1 ? className : `${className}#${count}`;\n\townerId.set(owner, result);\n\treturn result;\n}\n\nfunction getClassName(obj: object): string {\n\tconst ctor = obj.constructor;\n\tif (ctor) {\n\t\treturn ctor.name;\n\t}\n\treturn 'Object';\n}\n\nexport function getFunctionName(fn: Function): string | undefined {\n\tconst fnSrc = fn.toString();\n\t// Pattern: /** @description ... */\n\tconst regexp = /\\/\\*\\*\\s*@description\\s*([^*]*)\\*\\//;\n\tconst match = regexp.exec(fnSrc);\n\tconst result = match ? match[1] : undefined;\n\treturn result?.trim();\n}\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\nimport { AutorunObserver } from 'vs/base/common/observableInternal/autorun';\nimport { IObservable, ObservableValue, TransactionImpl } from 'vs/base/common/observableInternal/base';\nimport { Derived } from 'vs/base/common/observableInternal/derived';\nimport { FromEventObservable } from 'vs/base/common/observableInternal/utils';\n\nlet globalObservableLogger: IObservableLogger | undefined;\n\nexport function setLogger(logger: IObservableLogger): void {\n\tglobalObservableLogger = logger;\n}\n\nexport function getLogger(): IObservableLogger | undefined {\n\treturn globalObservableLogger;\n}\n\ninterface IChangeInformation {\n\toldValue: unknown;\n\tnewValue: unknown;\n\tchange: unknown;\n\tdidChange: boolean;\n\thadValue: boolean;\n}\n\nexport interface IObservableLogger {\n\thandleObservableChanged(observable: ObservableValue, info: IChangeInformation): void;\n\thandleFromEventObservableTriggered(observable: FromEventObservable, info: IChangeInformation): void;\n\n\thandleAutorunCreated(autorun: AutorunObserver): void;\n\thandleAutorunTriggered(autorun: AutorunObserver): void;\n\thandleAutorunFinished(autorun: AutorunObserver): void;\n\n\thandleDerivedCreated(observable: Derived): void;\n\thandleDerivedRecomputed(observable: Derived, info: IChangeInformation): void;\n\n\thandleBeginTransaction(transaction: TransactionImpl): void;\n\thandleEndTransaction(): void;\n}\n\nexport class ConsoleObservableLogger implements IObservableLogger {\n\tprivate indentation = 0;\n\n\tprivate textToConsoleArgs(text: ConsoleText): unknown[] {\n\t\treturn consoleTextToArgs([\n\t\t\tnormalText(repeat('| ', this.indentation)),\n\t\t\ttext,\n\t\t]);\n\t}\n\n\tprivate formatInfo(info: IChangeInformation): ConsoleText[] {\n\t\tif (!info.hadValue) {\n\t\t\treturn [\n\t\t\t\tnormalText(` `),\n\t\t\t\tstyled(formatValue(info.newValue, 60), {\n\t\t\t\t\tcolor: 'green',\n\t\t\t\t}),\n\t\t\t\tnormalText(` (initial)`),\n\t\t\t];\n\t\t}\n\t\treturn info.didChange\n\t\t\t? [\n\t\t\t\tnormalText(` `),\n\t\t\t\tstyled(formatValue(info.oldValue, 70), {\n\t\t\t\t\tcolor: 'red',\n\t\t\t\t\tstrikeThrough: true,\n\t\t\t\t}),\n\t\t\t\tnormalText(` `),\n\t\t\t\tstyled(formatValue(info.newValue, 60), {\n\t\t\t\t\tcolor: 'green',\n\t\t\t\t}),\n\t\t\t]\n\t\t\t: [normalText(` (unchanged)`)];\n\t}\n\n\thandleObservableChanged(observable: IObservable, info: IChangeInformation): void {\n\t\tconsole.log(...this.textToConsoleArgs([\n\t\t\tformatKind('observable value changed'),\n\t\t\tstyled(observable.debugName, { color: 'BlueViolet' }),\n\t\t\t...this.formatInfo(info),\n\t\t]));\n\t}\n\n\tprivate readonly changedObservablesSets = new WeakMap>>();\n\n\tformatChanges(changes: Set>): ConsoleText | undefined {\n\t\tif (changes.size === 0) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn styled(\n\t\t\t' (changed deps: ' +\n\t\t\t[...changes].map((o) => o.debugName).join(', ') +\n\t\t\t')',\n\t\t\t{ color: 'gray' }\n\t\t);\n\t}\n\n\thandleDerivedCreated(derived: Derived): void {\n\t\tconst existingHandleChange = derived.handleChange;\n\t\tthis.changedObservablesSets.set(derived, new Set());\n\t\tderived.handleChange = (observable, change) => {\n\t\t\tthis.changedObservablesSets.get(derived)!.add(observable);\n\t\t\treturn existingHandleChange.apply(derived, [observable, change]);\n\t\t};\n\t}\n\n\thandleDerivedRecomputed(derived: Derived, info: IChangeInformation): void {\n\t\tconst changedObservables = this.changedObservablesSets.get(derived)!;\n\t\tconsole.log(...this.textToConsoleArgs([\n\t\t\tformatKind('derived recomputed'),\n\t\t\tstyled(derived.debugName, { color: 'BlueViolet' }),\n\t\t\t...this.formatInfo(info),\n\t\t\tthis.formatChanges(changedObservables),\n\t\t\t{ data: [{ fn: derived._computeFn }] }\n\t\t]));\n\t\tchangedObservables.clear();\n\t}\n\n\thandleFromEventObservableTriggered(observable: FromEventObservable, info: IChangeInformation): void {\n\t\tconsole.log(...this.textToConsoleArgs([\n\t\t\tformatKind('observable from event triggered'),\n\t\t\tstyled(observable.debugName, { color: 'BlueViolet' }),\n\t\t\t...this.formatInfo(info),\n\t\t\t{ data: [{ fn: observable._getValue }] }\n\t\t]));\n\t}\n\n\thandleAutorunCreated(autorun: AutorunObserver): void {\n\t\tconst existingHandleChange = autorun.handleChange;\n\t\tthis.changedObservablesSets.set(autorun, new Set());\n\t\tautorun.handleChange = (observable, change) => {\n\t\t\tthis.changedObservablesSets.get(autorun)!.add(observable);\n\t\t\treturn existingHandleChange.apply(autorun, [observable, change]);\n\t\t};\n\t}\n\n\thandleAutorunTriggered(autorun: AutorunObserver): void {\n\t\tconst changedObservables = this.changedObservablesSets.get(autorun)!;\n\t\tconsole.log(...this.textToConsoleArgs([\n\t\t\tformatKind('autorun'),\n\t\t\tstyled(autorun.debugName, { color: 'BlueViolet' }),\n\t\t\tthis.formatChanges(changedObservables),\n\t\t\t{ data: [{ fn: autorun._runFn }] }\n\t\t]));\n\t\tchangedObservables.clear();\n\t\tthis.indentation++;\n\t}\n\n\thandleAutorunFinished(autorun: AutorunObserver): void {\n\t\tthis.indentation--;\n\t}\n\n\thandleBeginTransaction(transaction: TransactionImpl): void {\n\t\tlet transactionName = transaction.getDebugName();\n\t\tif (transactionName === undefined) {\n\t\t\ttransactionName = '';\n\t\t}\n\t\tconsole.log(...this.textToConsoleArgs([\n\t\t\tformatKind('transaction'),\n\t\t\tstyled(transactionName, { color: 'BlueViolet' }),\n\t\t\t{ data: [{ fn: transaction._fn }] }\n\t\t]));\n\t\tthis.indentation++;\n\t}\n\n\thandleEndTransaction(): void {\n\t\tthis.indentation--;\n\t}\n}\n\ntype ConsoleText =\n\t| (ConsoleText | undefined)[]\n\t| { text: string; style: string; data?: unknown[] }\n\t| { data: unknown[] };\n\nfunction consoleTextToArgs(text: ConsoleText): unknown[] {\n\tconst styles = new Array();\n\tconst data: unknown[] = [];\n\tlet firstArg = '';\n\n\tfunction process(t: ConsoleText): void {\n\t\tif ('length' in t) {\n\t\t\tfor (const item of t) {\n\t\t\t\tif (item) {\n\t\t\t\t\tprocess(item);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if ('text' in t) {\n\t\t\tfirstArg += `%c${t.text}`;\n\t\t\tstyles.push(t.style);\n\t\t\tif (t.data) {\n\t\t\t\tdata.push(...t.data);\n\t\t\t}\n\t\t} else if ('data' in t) {\n\t\t\tdata.push(...t.data);\n\t\t}\n\t}\n\n\tprocess(text);\n\n\tconst result = [firstArg, ...styles];\n\tresult.push(...data);\n\treturn result;\n}\n\nfunction normalText(text: string): ConsoleText {\n\treturn styled(text, { color: 'black' });\n}\n\nfunction formatKind(kind: string): ConsoleText {\n\treturn styled(padStr(`${kind}: `, 10), { color: 'black', bold: true });\n}\n\nfunction styled(\n\ttext: string,\n\toptions: { color: string; strikeThrough?: boolean; bold?: boolean } = {\n\t\tcolor: 'black',\n\t}\n): ConsoleText {\n\tfunction objToCss(styleObj: Record): string {\n\t\treturn Object.entries(styleObj).reduce(\n\t\t\t(styleString, [propName, propValue]) => {\n\t\t\t\treturn `${styleString}${propName}:${propValue};`;\n\t\t\t},\n\t\t\t''\n\t\t);\n\t}\n\n\tconst style: Record = {\n\t\tcolor: options.color,\n\t};\n\tif (options.strikeThrough) {\n\t\tstyle['text-decoration'] = 'line-through';\n\t}\n\tif (options.bold) {\n\t\tstyle['font-weight'] = 'bold';\n\t}\n\n\treturn {\n\t\ttext,\n\t\tstyle: objToCss(style),\n\t};\n}\n\nfunction formatValue(value: unknown, availableLen: number): string {\n\tswitch (typeof value) {\n\t\tcase 'number':\n\t\t\treturn '' + value;\n\t\tcase 'string':\n\t\t\tif (value.length + 2 <= availableLen) {\n\t\t\t\treturn `\"${value}\"`;\n\t\t\t}\n\t\t\treturn `\"${value.substr(0, availableLen - 7)}\"+...`;\n\n\t\tcase 'boolean':\n\t\t\treturn value ? 'true' : 'false';\n\t\tcase 'undefined':\n\t\t\treturn 'undefined';\n\t\tcase 'object':\n\t\t\tif (value === null) {\n\t\t\t\treturn 'null';\n\t\t\t}\n\t\t\tif (Array.isArray(value)) {\n\t\t\t\treturn formatArray(value, availableLen);\n\t\t\t}\n\t\t\treturn formatObject(value, availableLen);\n\t\tcase 'symbol':\n\t\t\treturn value.toString();\n\t\tcase 'function':\n\t\t\treturn `[[Function${value.name ? ' ' + value.name : ''}]]`;\n\t\tdefault:\n\t\t\treturn '' + value;\n\t}\n}\n\nfunction formatArray(value: unknown[], availableLen: number): string {\n\tlet result = '[ ';\n\tlet first = true;\n\tfor (const val of value) {\n\t\tif (!first) {\n\t\t\tresult += ', ';\n\t\t}\n\t\tif (result.length - 5 > availableLen) {\n\t\t\tresult += '...';\n\t\t\tbreak;\n\t\t}\n\t\tfirst = false;\n\t\tresult += `${formatValue(val, availableLen - result.length)}`;\n\t}\n\tresult += ' ]';\n\treturn result;\n}\n\nfunction formatObject(value: object, availableLen: number): string {\n\tlet result = '{ ';\n\tlet first = true;\n\tfor (const [key, val] of Object.entries(value)) {\n\t\tif (!first) {\n\t\t\tresult += ', ';\n\t\t}\n\t\tif (result.length - 5 > availableLen) {\n\t\t\tresult += '...';\n\t\t\tbreak;\n\t\t}\n\t\tfirst = false;\n\t\tresult += `${key}: ${formatValue(val, availableLen - result.length)}`;\n\t}\n\tresult += ' }';\n\treturn result;\n}\n\nfunction repeat(str: string, count: number): string {\n\tlet result = '';\n\tfor (let i = 1; i <= count; i++) {\n\t\tresult += str;\n\t}\n\treturn result;\n}\n\nfunction padStr(str: string, length: number): string {\n\twhile (str.length < length) {\n\t\tstr += ' ';\n\t}\n\treturn str;\n}\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\nimport { assertFn } from 'vs/base/common/assert';\nimport { DisposableStore, IDisposable, markAsDisposed, toDisposable, trackDisposable } from 'vs/base/common/lifecycle';\nimport { IReader, IObservable, IObserver, IChangeContext } from 'vs/base/common/observableInternal/base';\nimport { DebugNameData, IDebugNameData } from 'vs/base/common/observableInternal/debugName';\nimport { getLogger } from 'vs/base/common/observableInternal/logging';\n\n/**\n * Runs immediately and whenever a transaction ends and an observed observable changed.\n * {@link fn} should start with a JS Doc using `@description` to name the autorun.\n */\nexport function autorun(fn: (reader: IReader) => void): IDisposable {\n\treturn new AutorunObserver(\n\t\tnew DebugNameData(undefined, undefined, fn),\n\t\tfn,\n\t\tundefined,\n\t\tundefined\n\t);\n}\n\n/**\n * Runs immediately and whenever a transaction ends and an observed observable changed.\n * {@link fn} should start with a JS Doc using `@description` to name the autorun.\n */\nexport function autorunOpts(options: IDebugNameData & {}, fn: (reader: IReader) => void): IDisposable {\n\treturn new AutorunObserver(\n\t\tnew DebugNameData(options.owner, options.debugName, options.debugReferenceFn ?? fn),\n\t\tfn,\n\t\tundefined,\n\t\tundefined\n\t);\n}\n\n/**\n * Runs immediately and whenever a transaction ends and an observed observable changed.\n * {@link fn} should start with a JS Doc using `@description` to name the autorun.\n *\n * Use `createEmptyChangeSummary` to create a \"change summary\" that can collect the changes.\n * Use `handleChange` to add a reported change to the change summary.\n * The run function is given the last change summary.\n * The change summary is discarded after the run function was called.\n *\n * @see autorun\n */\nexport function autorunHandleChanges(\n\toptions: IDebugNameData & {\n\t\tcreateEmptyChangeSummary?: () => TChangeSummary;\n\t\thandleChange: (context: IChangeContext, changeSummary: TChangeSummary) => boolean;\n\t},\n\tfn: (reader: IReader, changeSummary: TChangeSummary) => void\n): IDisposable {\n\treturn new AutorunObserver(\n\t\tnew DebugNameData(options.owner, options.debugName, options.debugReferenceFn ?? fn),\n\t\tfn,\n\t\toptions.createEmptyChangeSummary,\n\t\toptions.handleChange\n\t);\n}\n\n/**\n * @see autorun (but with a disposable store that is cleared before the next run or on dispose)\n */\nexport function autorunWithStore(fn: (reader: IReader, store: DisposableStore) => void): IDisposable {\n\tconst store = new DisposableStore();\n\tconst disposable = autorunOpts(\n\t\t{\n\t\t\towner: undefined,\n\t\t\tdebugName: undefined,\n\t\t\tdebugReferenceFn: fn,\n\t\t},\n\t\treader => {\n\t\t\tstore.clear();\n\t\t\tfn(reader, store);\n\t\t}\n\t);\n\treturn toDisposable(() => {\n\t\tdisposable.dispose();\n\t\tstore.dispose();\n\t});\n}\n\n\nconst enum AutorunState {\n\t/**\n\t * A dependency could have changed.\n\t * We need to explicitly ask them if at least one dependency changed.\n\t */\n\tdependenciesMightHaveChanged = 1,\n\n\t/**\n\t * A dependency changed and we need to recompute.\n\t */\n\tstale = 2,\n\tupToDate = 3,\n}\n\nexport class AutorunObserver implements IObserver, IReader, IDisposable {\n\tprivate state = AutorunState.stale;\n\tprivate updateCount = 0;\n\tprivate disposed = false;\n\tprivate dependencies = new Set>();\n\tprivate dependenciesToBeRemoved = new Set>();\n\tprivate changeSummary: TChangeSummary | undefined;\n\n\tpublic get debugName(): string {\n\t\treturn this._debugNameData.getDebugName(this) ?? '(anonymous)';\n\t}\n\n\tconstructor(\n\t\tprivate readonly _debugNameData: DebugNameData,\n\t\tpublic readonly _runFn: (reader: IReader, changeSummary: TChangeSummary) => void,\n\t\tprivate readonly createChangeSummary: (() => TChangeSummary) | undefined,\n\t\tprivate readonly _handleChange: ((context: IChangeContext, summary: TChangeSummary) => boolean) | undefined,\n\t) {\n\t\tthis.changeSummary = this.createChangeSummary?.();\n\t\tgetLogger()?.handleAutorunCreated(this);\n\t\tthis._runIfNeeded();\n\n\t\ttrackDisposable(this);\n\t}\n\n\tpublic dispose(): void {\n\t\tthis.disposed = true;\n\t\tfor (const o of this.dependencies) {\n\t\t\to.removeObserver(this);\n\t\t}\n\t\tthis.dependencies.clear();\n\n\t\tmarkAsDisposed(this);\n\t}\n\n\tprivate _runIfNeeded() {\n\t\tif (this.state === AutorunState.upToDate) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst emptySet = this.dependenciesToBeRemoved;\n\t\tthis.dependenciesToBeRemoved = this.dependencies;\n\t\tthis.dependencies = emptySet;\n\n\t\tthis.state = AutorunState.upToDate;\n\n\t\tconst isDisposed = this.disposed;\n\t\ttry {\n\t\t\tif (!isDisposed) {\n\t\t\t\tgetLogger()?.handleAutorunTriggered(this);\n\t\t\t\tconst changeSummary = this.changeSummary!;\n\t\t\t\tthis.changeSummary = this.createChangeSummary?.();\n\t\t\t\tthis._runFn(this, changeSummary);\n\t\t\t}\n\t\t} finally {\n\t\t\tif (!isDisposed) {\n\t\t\t\tgetLogger()?.handleAutorunFinished(this);\n\t\t\t}\n\t\t\t// We don't want our observed observables to think that they are (not even temporarily) not being observed.\n\t\t\t// Thus, we only unsubscribe from observables that are definitely not read anymore.\n\t\t\tfor (const o of this.dependenciesToBeRemoved) {\n\t\t\t\to.removeObserver(this);\n\t\t\t}\n\t\t\tthis.dependenciesToBeRemoved.clear();\n\t\t}\n\t}\n\n\tpublic toString(): string {\n\t\treturn `Autorun<${this.debugName}>`;\n\t}\n\n\t// IObserver implementation\n\tpublic beginUpdate(): void {\n\t\tif (this.state === AutorunState.upToDate) {\n\t\t\tthis.state = AutorunState.dependenciesMightHaveChanged;\n\t\t}\n\t\tthis.updateCount++;\n\t}\n\n\tpublic endUpdate(): void {\n\t\tif (this.updateCount === 1) {\n\t\t\tdo {\n\t\t\t\tif (this.state === AutorunState.dependenciesMightHaveChanged) {\n\t\t\t\t\tthis.state = AutorunState.upToDate;\n\t\t\t\t\tfor (const d of this.dependencies) {\n\t\t\t\t\t\td.reportChanges();\n\t\t\t\t\t\tif (this.state as AutorunState === AutorunState.stale) {\n\t\t\t\t\t\t\t// The other dependencies will refresh on demand\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tthis._runIfNeeded();\n\t\t\t} while (this.state !== AutorunState.upToDate);\n\t\t}\n\t\tthis.updateCount--;\n\n\t\tassertFn(() => this.updateCount >= 0);\n\t}\n\n\tpublic handlePossibleChange(observable: IObservable): void {\n\t\tif (this.state === AutorunState.upToDate && this.dependencies.has(observable) && !this.dependenciesToBeRemoved.has(observable)) {\n\t\t\tthis.state = AutorunState.dependenciesMightHaveChanged;\n\t\t}\n\t}\n\n\tpublic handleChange(observable: IObservable, change: TChange): void {\n\t\tif (this.dependencies.has(observable) && !this.dependenciesToBeRemoved.has(observable)) {\n\t\t\tconst shouldReact = this._handleChange ? this._handleChange({\n\t\t\t\tchangedObservable: observable,\n\t\t\t\tchange,\n\t\t\t\tdidChange: (o): this is any => o === observable as any,\n\t\t\t}, this.changeSummary!) : true;\n\t\t\tif (shouldReact) {\n\t\t\t\tthis.state = AutorunState.stale;\n\t\t\t}\n\t\t}\n\t}\n\n\t// IReader implementation\n\tpublic readObservable(observable: IObservable): T {\n\t\t// In case the run action disposes the autorun\n\t\tif (this.disposed) {\n\t\t\treturn observable.get();\n\t\t}\n\n\t\tobservable.addObserver(this);\n\t\tconst value = observable.get();\n\t\tthis.dependencies.add(observable);\n\t\tthis.dependenciesToBeRemoved.delete(observable);\n\t\treturn value;\n\t}\n}\n\nexport namespace autorun {\n\texport const Observer = AutorunObserver;\n}\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\nimport { strictEquals, EqualityComparer } from 'vs/base/common/equals';\nimport { DisposableStore, IDisposable } from 'vs/base/common/lifecycle';\nimport { keepObserved, recomputeInitiallyAndOnChange } from 'vs/base/common/observable';\nimport { DebugNameData, IDebugNameData, Owner, getFunctionName } from 'vs/base/common/observableInternal/debugName';\nimport { derivedOpts } from 'vs/base/common/observableInternal/derived';\nimport { getLogger } from 'vs/base/common/observableInternal/logging';\n\n/**\n * Represents an observable value.\n *\n * @template T The type of the values the observable can hold.\n * @template TChange The type used to describe value changes\n * (usually `void` and only used in advanced scenarios).\n * While observers can miss temporary values of an observable,\n * they will receive all change values (as long as they are subscribed)!\n */\nexport interface IObservable {\n\t/**\n\t * Returns the current value.\n\t *\n\t * Calls {@link IObserver.handleChange} if the observable notices that the value changed.\n\t * Must not be called from {@link IObserver.handleChange}!\n\t */\n\tget(): T;\n\n\t/**\n\t * Forces the observable to check for changes and report them.\n\t *\n\t * Has the same effect as calling {@link IObservable.get}, but does not force the observable\n\t * to actually construct the value, e.g. if change deltas are used.\n\t * Calls {@link IObserver.handleChange} if the observable notices that the value changed.\n\t * Must not be called from {@link IObserver.handleChange}!\n\t */\n\treportChanges(): void;\n\n\t/**\n\t * Adds the observer to the set of subscribed observers.\n\t * This method is idempotent.\n\t */\n\taddObserver(observer: IObserver): void;\n\n\t/**\n\t * Removes the observer from the set of subscribed observers.\n\t * This method is idempotent.\n\t */\n\tremoveObserver(observer: IObserver): void;\n\n\t/**\n\t * Reads the current value and subscribes the reader to this observable.\n\t *\n\t * Calls {@link IReader.readObservable} if a reader is given, otherwise {@link IObservable.get}\n\t * (see {@link ConvenientObservable.read} for the implementation).\n\t */\n\tread(reader: IReader | undefined): T;\n\n\t/**\n\t * Creates a derived observable that depends on this observable.\n\t * Use the reader to read other observables\n\t * (see {@link ConvenientObservable.map} for the implementation).\n\t */\n\tmap(fn: (value: T, reader: IReader) => TNew): IObservable;\n\tmap(owner: object, fn: (value: T, reader: IReader) => TNew): IObservable;\n\n\t/**\n\t * Makes sure this value is computed eagerly.\n\t */\n\trecomputeInitiallyAndOnChange(store: DisposableStore, handleValue?: (value: T) => void): IObservable;\n\n\t/**\n\t * A human-readable name for debugging purposes.\n\t */\n\treadonly debugName: string;\n\n\t/**\n\t * This property captures the type of the change object. Do not use it at runtime!\n\t */\n\treadonly TChange: TChange;\n}\n\nexport interface IReader {\n\t/**\n\t * Reads the value of an observable and subscribes to it.\n\t */\n\treadObservable(observable: IObservable): T;\n}\n\n/**\n * Represents an observer that can be subscribed to an observable.\n *\n * If an observer is subscribed to an observable and that observable didn't signal\n * a change through one of the observer methods, the observer can assume that the\n * observable didn't change.\n * If an observable reported a possible change, {@link IObservable.reportChanges} forces\n * the observable to report an actual change if there was one.\n */\nexport interface IObserver {\n\t/**\n\t * Signals that the given observable might have changed and a transaction potentially modifying that observable started.\n\t * Before the given observable can call this method again, is must call {@link IObserver.endUpdate}.\n\t *\n\t * Implementations must not get/read the value of other observables, as they might not have received this event yet!\n\t * The method {@link IObservable.reportChanges} can be used to force the observable to report the changes.\n\t */\n\tbeginUpdate(observable: IObservable): void;\n\n\t/**\n\t * Signals that the transaction that potentially modified the given observable ended.\n\t * This is a good place to react to (potential) changes.\n\t */\n\tendUpdate(observable: IObservable): void;\n\n\t/**\n\t * Signals that the given observable might have changed.\n\t * The method {@link IObservable.reportChanges} can be used to force the observable to report the changes.\n\t *\n\t * Implementations must not get/read the value of other observables, as they might not have received this event yet!\n\t * The change should be processed lazily or in {@link IObserver.endUpdate}.\n\t */\n\thandlePossibleChange(observable: IObservable): void;\n\n\t/**\n\t * Signals that the given {@link observable} changed.\n\t *\n\t * Implementations must not get/read the value of other observables, as they might not have received this event yet!\n\t * The change should be processed lazily or in {@link IObserver.endUpdate}.\n\t *\n\t * @param change Indicates how or why the value changed.\n\t */\n\thandleChange(observable: IObservable, change: TChange): void;\n}\n\nexport interface ISettable {\n\t/**\n\t * Sets the value of the observable.\n\t * Use a transaction to batch multiple changes (with a transaction, observers only react at the end of the transaction).\n\t *\n\t * @param transaction When given, value changes are handled on demand or when the transaction ends.\n\t * @param change Describes how or why the value changed.\n\t */\n\tset(value: T, transaction: ITransaction | undefined, change: TChange): void;\n}\n\nexport interface ITransaction {\n\t/**\n\t * Calls {@link Observer.beginUpdate} immediately\n\t * and {@link Observer.endUpdate} when the transaction ends.\n\t */\n\tupdateObserver(observer: IObserver, observable: IObservable): void;\n}\n\nlet _recomputeInitiallyAndOnChange: typeof recomputeInitiallyAndOnChange;\nexport function _setRecomputeInitiallyAndOnChange(recomputeInitiallyAndOnChange: typeof _recomputeInitiallyAndOnChange) {\n\t_recomputeInitiallyAndOnChange = recomputeInitiallyAndOnChange;\n}\n\nlet _keepObserved: typeof keepObserved;\nexport function _setKeepObserved(keepObserved: typeof _keepObserved) {\n\t_keepObserved = keepObserved;\n}\n\n\nlet _derived: typeof derivedOpts;\n/**\n * @internal\n * This is to allow splitting files.\n*/\nexport function _setDerivedOpts(derived: typeof _derived) {\n\t_derived = derived;\n}\n\nexport abstract class ConvenientObservable implements IObservable {\n\tget TChange(): TChange { return null!; }\n\n\tpublic abstract get(): T;\n\n\tpublic reportChanges(): void {\n\t\tthis.get();\n\t}\n\n\tpublic abstract addObserver(observer: IObserver): void;\n\tpublic abstract removeObserver(observer: IObserver): void;\n\n\t/** @sealed */\n\tpublic read(reader: IReader | undefined): T {\n\t\tif (reader) {\n\t\t\treturn reader.readObservable(this);\n\t\t} else {\n\t\t\treturn this.get();\n\t\t}\n\t}\n\n\t/** @sealed */\n\tpublic map(fn: (value: T, reader: IReader) => TNew): IObservable;\n\tpublic map(owner: Owner, fn: (value: T, reader: IReader) => TNew): IObservable;\n\tpublic map(fnOrOwner: Owner | ((value: T, reader: IReader) => TNew), fnOrUndefined?: (value: T, reader: IReader) => TNew): IObservable {\n\t\tconst owner = fnOrUndefined === undefined ? undefined : fnOrOwner as Owner;\n\t\tconst fn = fnOrUndefined === undefined ? fnOrOwner as (value: T, reader: IReader) => TNew : fnOrUndefined;\n\n\t\treturn _derived(\n\t\t\t{\n\t\t\t\towner,\n\t\t\t\tdebugName: () => {\n\t\t\t\t\tconst name = getFunctionName(fn);\n\t\t\t\t\tif (name !== undefined) {\n\t\t\t\t\t\treturn name;\n\t\t\t\t\t}\n\n\t\t\t\t\t// regexp to match `x => x.y` or `x => x?.y` where x and y can be arbitrary identifiers (uses backref):\n\t\t\t\t\tconst regexp = /^\\s*\\(?\\s*([a-zA-Z_$][a-zA-Z_$0-9]*)\\s*\\)?\\s*=>\\s*\\1(?:\\??)\\.([a-zA-Z_$][a-zA-Z_$0-9]*)\\s*$/;\n\t\t\t\t\tconst match = regexp.exec(fn.toString());\n\t\t\t\t\tif (match) {\n\t\t\t\t\t\treturn `${this.debugName}.${match[2]}`;\n\t\t\t\t\t}\n\t\t\t\t\tif (!owner) {\n\t\t\t\t\t\treturn `${this.debugName} (mapped)`;\n\t\t\t\t\t}\n\t\t\t\t\treturn undefined;\n\t\t\t\t},\n\t\t\t\tdebugReferenceFn: fn,\n\t\t\t},\n\t\t\t(reader) => fn(this.read(reader), reader),\n\t\t);\n\t}\n\n\tpublic recomputeInitiallyAndOnChange(store: DisposableStore, handleValue?: (value: T) => void): IObservable {\n\t\tstore.add(_recomputeInitiallyAndOnChange!(this, handleValue));\n\t\treturn this;\n\t}\n\n\tpublic abstract get debugName(): string;\n}\n\nexport abstract class BaseObservable extends ConvenientObservable {\n\tprotected readonly observers = new Set();\n\n\tpublic addObserver(observer: IObserver): void {\n\t\tconst len = this.observers.size;\n\t\tthis.observers.add(observer);\n\t\tif (len === 0) {\n\t\t\tthis.onFirstObserverAdded();\n\t\t}\n\t}\n\n\tpublic removeObserver(observer: IObserver): void {\n\t\tconst deleted = this.observers.delete(observer);\n\t\tif (deleted && this.observers.size === 0) {\n\t\t\tthis.onLastObserverRemoved();\n\t\t}\n\t}\n\n\tprotected onFirstObserverAdded(): void { }\n\tprotected onLastObserverRemoved(): void { }\n}\n\n/**\n * Starts a transaction in which many observables can be changed at once.\n * {@link fn} should start with a JS Doc using `@description` to give the transaction a debug name.\n * Reaction run on demand or when the transaction ends.\n */\n\nexport function transaction(fn: (tx: ITransaction) => void, getDebugName?: () => string): void {\n\tconst tx = new TransactionImpl(fn, getDebugName);\n\ttry {\n\t\tfn(tx);\n\t} finally {\n\t\ttx.finish();\n\t}\n}\n\nlet _globalTransaction: ITransaction | undefined = undefined;\n\nexport function globalTransaction(fn: (tx: ITransaction) => void) {\n\tif (_globalTransaction) {\n\t\tfn(_globalTransaction);\n\t} else {\n\t\tconst tx = new TransactionImpl(fn, undefined);\n\t\t_globalTransaction = tx;\n\t\ttry {\n\t\t\tfn(tx);\n\t\t} finally {\n\t\t\ttx.finish(); // During finish, more actions might be added to the transaction.\n\t\t\t// Which is why we only clear the global transaction after finish.\n\t\t\t_globalTransaction = undefined;\n\t\t}\n\t}\n}\n\nexport async function asyncTransaction(fn: (tx: ITransaction) => Promise, getDebugName?: () => string): Promise {\n\tconst tx = new TransactionImpl(fn, getDebugName);\n\ttry {\n\t\tawait fn(tx);\n\t} finally {\n\t\ttx.finish();\n\t}\n}\n\n/**\n * Allows to chain transactions.\n */\nexport function subtransaction(tx: ITransaction | undefined, fn: (tx: ITransaction) => void, getDebugName?: () => string): void {\n\tif (!tx) {\n\t\ttransaction(fn, getDebugName);\n\t} else {\n\t\tfn(tx);\n\t}\n}\n\nexport class TransactionImpl implements ITransaction {\n\tprivate updatingObservers: { observer: IObserver; observable: IObservable }[] | null = [];\n\n\tconstructor(public readonly _fn: Function, private readonly _getDebugName?: () => string) {\n\t\tgetLogger()?.handleBeginTransaction(this);\n\t}\n\n\tpublic getDebugName(): string | undefined {\n\t\tif (this._getDebugName) {\n\t\t\treturn this._getDebugName();\n\t\t}\n\t\treturn getFunctionName(this._fn);\n\t}\n\n\tpublic updateObserver(observer: IObserver, observable: IObservable): void {\n\t\t// When this gets called while finish is active, they will still get considered\n\t\tthis.updatingObservers!.push({ observer, observable });\n\t\tobserver.beginUpdate(observable);\n\t}\n\n\tpublic finish(): void {\n\t\tconst updatingObservers = this.updatingObservers!;\n\t\tfor (let i = 0; i < updatingObservers.length; i++) {\n\t\t\tconst { observer, observable } = updatingObservers[i];\n\t\t\tobserver.endUpdate(observable);\n\t\t}\n\t\t// Prevent anyone from updating observers from now on.\n\t\tthis.updatingObservers = null;\n\t\tgetLogger()?.handleEndTransaction();\n\t}\n}\n\n/**\n * A settable observable.\n */\nexport interface ISettableObservable extends IObservable, ISettable {\n}\n\n/**\n * Creates an observable value.\n * Observers get informed when the value changes.\n * @template TChange An arbitrary type to describe how or why the value changed. Defaults to `void`.\n * Observers will receive every single change value.\n */\nexport function observableValue(name: string, initialValue: T): ISettableObservable;\nexport function observableValue(owner: object, initialValue: T): ISettableObservable;\nexport function observableValue(nameOrOwner: string | object, initialValue: T): ISettableObservable {\n\tlet debugNameData: DebugNameData;\n\tif (typeof nameOrOwner === 'string') {\n\t\tdebugNameData = new DebugNameData(undefined, nameOrOwner, undefined);\n\t} else {\n\t\tdebugNameData = new DebugNameData(nameOrOwner, undefined, undefined);\n\t}\n\treturn new ObservableValue(debugNameData, initialValue, strictEquals);\n}\n\nexport function observableValueOpts(\n\toptions: IDebugNameData & {\n\t\tequalsFn?: EqualityComparer;\n\t},\n\tinitialValue: T\n): ISettableObservable {\n\treturn new ObservableValue(\n\t\tnew DebugNameData(options.owner, options.debugName, undefined),\n\t\tinitialValue,\n\t\toptions.equalsFn ?? strictEquals,\n\t);\n}\n\nexport class ObservableValue\n\textends BaseObservable\n\timplements ISettableObservable {\n\tprotected _value: T;\n\n\tget debugName() {\n\t\treturn this._debugNameData.getDebugName(this) ?? 'ObservableValue';\n\t}\n\n\tconstructor(\n\t\tprivate readonly _debugNameData: DebugNameData,\n\t\tinitialValue: T,\n\t\tprivate readonly _equalityComparator: EqualityComparer,\n\t) {\n\t\tsuper();\n\t\tthis._value = initialValue;\n\t}\n\tpublic override get(): T {\n\t\treturn this._value;\n\t}\n\n\tpublic set(value: T, tx: ITransaction | undefined, change: TChange): void {\n\t\tif (change === undefined && this._equalityComparator(this._value, value)) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet _tx: TransactionImpl | undefined;\n\t\tif (!tx) {\n\t\t\ttx = _tx = new TransactionImpl(() => { }, () => `Setting ${this.debugName}`);\n\t\t}\n\t\ttry {\n\t\t\tconst oldValue = this._value;\n\t\t\tthis._setValue(value);\n\t\t\tgetLogger()?.handleObservableChanged(this, { oldValue, newValue: value, change, didChange: true, hadValue: true });\n\n\t\t\tfor (const observer of this.observers) {\n\t\t\t\ttx.updateObserver(observer, this);\n\t\t\t\tobserver.handleChange(this, change);\n\t\t\t}\n\t\t} finally {\n\t\t\tif (_tx) {\n\t\t\t\t_tx.finish();\n\t\t\t}\n\t\t}\n\t}\n\n\toverride toString(): string {\n\t\treturn `${this.debugName}: ${this._value}`;\n\t}\n\n\tprotected _setValue(newValue: T): void {\n\t\tthis._value = newValue;\n\t}\n}\n\n/**\n * A disposable observable. When disposed, its value is also disposed.\n * When a new value is set, the previous value is disposed.\n */\nexport function disposableObservableValue(nameOrOwner: string | object, initialValue: T): ISettableObservable & IDisposable {\n\tlet debugNameData: DebugNameData;\n\tif (typeof nameOrOwner === 'string') {\n\t\tdebugNameData = new DebugNameData(undefined, nameOrOwner, undefined);\n\t} else {\n\t\tdebugNameData = new DebugNameData(nameOrOwner, undefined, undefined);\n\t}\n\treturn new DisposableObservableValue(debugNameData, initialValue, strictEquals);\n}\n\nexport class DisposableObservableValue extends ObservableValue implements IDisposable {\n\tprotected override _setValue(newValue: T): void {\n\t\tif (this._value === newValue) {\n\t\t\treturn;\n\t\t}\n\t\tif (this._value) {\n\t\t\tthis._value.dispose();\n\t\t}\n\t\tthis._value = newValue;\n\t}\n\n\tpublic dispose(): void {\n\t\tthis._value?.dispose();\n\t}\n}\n\nexport interface IChangeContext {\n\treadonly changedObservable: IObservable;\n\treadonly change: unknown;\n\n\t/**\n\t * Returns if the given observable caused the change.\n\t */\n\tdidChange(observable: IObservable): this is { change: TChange };\n}\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\nimport { assertFn } from 'vs/base/common/assert';\nimport { EqualityComparer, strictEquals } from 'vs/base/common/equals';\nimport { DisposableStore, IDisposable } from 'vs/base/common/lifecycle';\nimport { BaseObservable, IChangeContext, IObservable, IObserver, IReader, ISettableObservable, ITransaction, _setDerivedOpts } from 'vs/base/common/observableInternal/base';\nimport { DebugNameData, IDebugNameData, Owner } from 'vs/base/common/observableInternal/debugName';\nimport { getLogger } from 'vs/base/common/observableInternal/logging';\n\n/**\n * Creates an observable that is derived from other observables.\n * The value is only recomputed when absolutely needed.\n *\n * {@link computeFn} should start with a JS Doc using `@description` to name the derived.\n */\nexport function derived(computeFn: (reader: IReader) => T): IObservable;\nexport function derived(owner: Owner, computeFn: (reader: IReader) => T): IObservable;\nexport function derived(computeFnOrOwner: ((reader: IReader) => T) | Owner, computeFn?: ((reader: IReader) => T) | undefined): IObservable {\n\tif (computeFn !== undefined) {\n\t\treturn new Derived(\n\t\t\tnew DebugNameData(computeFnOrOwner, undefined, computeFn),\n\t\t\tcomputeFn,\n\t\t\tundefined,\n\t\t\tundefined,\n\t\t\tundefined,\n\t\t\tstrictEquals\n\t\t);\n\t}\n\treturn new Derived(\n\t\tnew DebugNameData(undefined, undefined, computeFnOrOwner as any),\n\t\tcomputeFnOrOwner as any,\n\t\tundefined,\n\t\tundefined,\n\t\tundefined,\n\t\tstrictEquals\n\t);\n}\n\nexport function derivedWithSetter(owner: Owner | undefined, computeFn: (reader: IReader) => T, setter: (value: T, transaction: ITransaction | undefined) => void): ISettableObservable {\n\treturn new DerivedWithSetter(\n\t\tnew DebugNameData(owner, undefined, computeFn),\n\t\tcomputeFn,\n\t\tundefined,\n\t\tundefined,\n\t\tundefined,\n\t\tstrictEquals,\n\t\tsetter,\n\t);\n}\n\nexport function derivedOpts(\n\toptions: IDebugNameData & {\n\t\tequalsFn?: EqualityComparer;\n\t\tonLastObserverRemoved?: (() => void);\n\t},\n\tcomputeFn: (reader: IReader) => T\n): IObservable {\n\treturn new Derived(\n\t\tnew DebugNameData(options.owner, options.debugName, options.debugReferenceFn),\n\t\tcomputeFn,\n\t\tundefined,\n\t\tundefined,\n\t\toptions.onLastObserverRemoved,\n\t\toptions.equalsFn ?? strictEquals\n\t);\n}\n\n_setDerivedOpts(derivedOpts);\n\n/**\n * Represents an observable that is derived from other observables.\n * The value is only recomputed when absolutely needed.\n *\n * {@link computeFn} should start with a JS Doc using `@description` to name the derived.\n *\n * Use `createEmptyChangeSummary` to create a \"change summary\" that can collect the changes.\n * Use `handleChange` to add a reported change to the change summary.\n * The compute function is given the last change summary.\n * The change summary is discarded after the compute function was called.\n *\n * @see derived\n */\nexport function derivedHandleChanges(\n\toptions: IDebugNameData & {\n\t\tcreateEmptyChangeSummary: () => TChangeSummary;\n\t\thandleChange: (context: IChangeContext, changeSummary: TChangeSummary) => boolean;\n\t\tequalityComparer?: EqualityComparer;\n\t},\n\tcomputeFn: (reader: IReader, changeSummary: TChangeSummary) => T\n): IObservable {\n\treturn new Derived(\n\t\tnew DebugNameData(options.owner, options.debugName, undefined),\n\t\tcomputeFn,\n\t\toptions.createEmptyChangeSummary,\n\t\toptions.handleChange,\n\t\tundefined,\n\t\toptions.equalityComparer ?? strictEquals\n\t);\n}\n\nexport function derivedWithStore(computeFn: (reader: IReader, store: DisposableStore) => T): IObservable;\nexport function derivedWithStore(owner: object, computeFn: (reader: IReader, store: DisposableStore) => T): IObservable;\nexport function derivedWithStore(computeFnOrOwner: ((reader: IReader, store: DisposableStore) => T) | object, computeFnOrUndefined?: ((reader: IReader, store: DisposableStore) => T)): IObservable {\n\tlet computeFn: (reader: IReader, store: DisposableStore) => T;\n\tlet owner: Owner;\n\tif (computeFnOrUndefined === undefined) {\n\t\tcomputeFn = computeFnOrOwner as any;\n\t\towner = undefined;\n\t} else {\n\t\towner = computeFnOrOwner;\n\t\tcomputeFn = computeFnOrUndefined as any;\n\t}\n\n\tconst store = new DisposableStore();\n\treturn new Derived(\n\t\tnew DebugNameData(owner, undefined, computeFn),\n\t\tr => {\n\t\t\tstore.clear();\n\t\t\treturn computeFn(r, store);\n\t\t}, undefined,\n\t\tundefined,\n\t\t() => store.dispose(),\n\t\tstrictEquals\n\t);\n}\n\nexport function derivedDisposable(computeFn: (reader: IReader) => T): IObservable;\nexport function derivedDisposable(owner: Owner, computeFn: (reader: IReader) => T): IObservable;\nexport function derivedDisposable(computeFnOrOwner: ((reader: IReader) => T) | Owner, computeFnOrUndefined?: ((reader: IReader) => T)): IObservable {\n\tlet computeFn: (reader: IReader) => T;\n\tlet owner: Owner;\n\tif (computeFnOrUndefined === undefined) {\n\t\tcomputeFn = computeFnOrOwner as any;\n\t\towner = undefined;\n\t} else {\n\t\towner = computeFnOrOwner;\n\t\tcomputeFn = computeFnOrUndefined as any;\n\t}\n\n\tconst store = new DisposableStore();\n\treturn new Derived(\n\t\tnew DebugNameData(owner, undefined, computeFn),\n\t\tr => {\n\t\t\tstore.clear();\n\t\t\tconst result = computeFn(r);\n\t\t\tif (result) {\n\t\t\t\tstore.add(result);\n\t\t\t}\n\t\t\treturn result;\n\t\t}, undefined,\n\t\tundefined,\n\t\t() => store.dispose(),\n\t\tstrictEquals\n\t);\n}\n\nconst enum DerivedState {\n\t/** Initial state, no previous value, recomputation needed */\n\tinitial = 0,\n\n\t/**\n\t * A dependency could have changed.\n\t * We need to explicitly ask them if at least one dependency changed.\n\t */\n\tdependenciesMightHaveChanged = 1,\n\n\t/**\n\t * A dependency changed and we need to recompute.\n\t * After recomputation, we need to check the previous value to see if we changed as well.\n\t */\n\tstale = 2,\n\n\t/**\n\t * No change reported, our cached value is up to date.\n\t */\n\tupToDate = 3,\n}\n\nexport class Derived extends BaseObservable implements IReader, IObserver {\n\tprivate state = DerivedState.initial;\n\tprivate value: T | undefined = undefined;\n\tprivate updateCount = 0;\n\tprivate dependencies = new Set>();\n\tprivate dependenciesToBeRemoved = new Set>();\n\tprivate changeSummary: TChangeSummary | undefined = undefined;\n\n\tpublic override get debugName(): string {\n\t\treturn this._debugNameData.getDebugName(this) ?? '(anonymous)';\n\t}\n\n\tconstructor(\n\t\tprivate readonly _debugNameData: DebugNameData,\n\t\tpublic readonly _computeFn: (reader: IReader, changeSummary: TChangeSummary) => T,\n\t\tprivate readonly createChangeSummary: (() => TChangeSummary) | undefined,\n\t\tprivate readonly _handleChange: ((context: IChangeContext, summary: TChangeSummary) => boolean) | undefined,\n\t\tprivate readonly _handleLastObserverRemoved: (() => void) | undefined = undefined,\n\t\tprivate readonly _equalityComparator: EqualityComparer,\n\t) {\n\t\tsuper();\n\t\tthis.changeSummary = this.createChangeSummary?.();\n\t\tgetLogger()?.handleDerivedCreated(this);\n\t}\n\n\tprotected override onLastObserverRemoved(): void {\n\t\t/**\n\t\t * We are not tracking changes anymore, thus we have to assume\n\t\t * that our cache is invalid.\n\t\t */\n\t\tthis.state = DerivedState.initial;\n\t\tthis.value = undefined;\n\t\tfor (const d of this.dependencies) {\n\t\t\td.removeObserver(this);\n\t\t}\n\t\tthis.dependencies.clear();\n\n\t\tthis._handleLastObserverRemoved?.();\n\t}\n\n\tpublic override get(): T {\n\t\tif (this.observers.size === 0) {\n\t\t\t// Without observers, we don't know when to clean up stuff.\n\t\t\t// Thus, we don't cache anything to prevent memory leaks.\n\t\t\tconst result = this._computeFn(this, this.createChangeSummary?.()!);\n\t\t\t// Clear new dependencies\n\t\t\tthis.onLastObserverRemoved();\n\t\t\treturn result;\n\t\t} else {\n\t\t\tdo {\n\t\t\t\t// We might not get a notification for a dependency that changed while it is updating,\n\t\t\t\t// thus we also have to ask all our depedencies if they changed in this case.\n\t\t\t\tif (this.state === DerivedState.dependenciesMightHaveChanged) {\n\t\t\t\t\tfor (const d of this.dependencies) {\n\t\t\t\t\t\t/** might call {@link handleChange} indirectly, which could make us stale */\n\t\t\t\t\t\td.reportChanges();\n\n\t\t\t\t\t\tif (this.state as DerivedState === DerivedState.stale) {\n\t\t\t\t\t\t\t// The other dependencies will refresh on demand, so early break\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// We called report changes of all dependencies.\n\t\t\t\t// If we are still not stale, we can assume to be up to date again.\n\t\t\t\tif (this.state === DerivedState.dependenciesMightHaveChanged) {\n\t\t\t\t\tthis.state = DerivedState.upToDate;\n\t\t\t\t}\n\n\t\t\t\tthis._recomputeIfNeeded();\n\t\t\t\t// In case recomputation changed one of our dependencies, we need to recompute again.\n\t\t\t} while (this.state !== DerivedState.upToDate);\n\t\t\treturn this.value!;\n\t\t}\n\t}\n\n\tprivate _recomputeIfNeeded() {\n\t\tif (this.state === DerivedState.upToDate) {\n\t\t\treturn;\n\t\t}\n\t\tconst emptySet = this.dependenciesToBeRemoved;\n\t\tthis.dependenciesToBeRemoved = this.dependencies;\n\t\tthis.dependencies = emptySet;\n\n\t\tconst hadValue = this.state !== DerivedState.initial;\n\t\tconst oldValue = this.value;\n\t\tthis.state = DerivedState.upToDate;\n\n\t\tconst changeSummary = this.changeSummary!;\n\t\tthis.changeSummary = this.createChangeSummary?.();\n\t\ttry {\n\t\t\t/** might call {@link handleChange} indirectly, which could invalidate us */\n\t\t\tthis.value = this._computeFn(this, changeSummary);\n\t\t} finally {\n\t\t\t// We don't want our observed observables to think that they are (not even temporarily) not being observed.\n\t\t\t// Thus, we only unsubscribe from observables that are definitely not read anymore.\n\t\t\tfor (const o of this.dependenciesToBeRemoved) {\n\t\t\t\to.removeObserver(this);\n\t\t\t}\n\t\t\tthis.dependenciesToBeRemoved.clear();\n\t\t}\n\n\t\tconst didChange = hadValue && !(this._equalityComparator(oldValue!, this.value));\n\n\t\tgetLogger()?.handleDerivedRecomputed(this, {\n\t\t\toldValue,\n\t\t\tnewValue: this.value,\n\t\t\tchange: undefined,\n\t\t\tdidChange,\n\t\t\thadValue,\n\t\t});\n\n\t\tif (didChange) {\n\t\t\tfor (const r of this.observers) {\n\t\t\t\tr.handleChange(this, undefined);\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic override toString(): string {\n\t\treturn `LazyDerived<${this.debugName}>`;\n\t}\n\n\t// IObserver Implementation\n\tpublic beginUpdate(_observable: IObservable): void {\n\t\tthis.updateCount++;\n\t\tconst propagateBeginUpdate = this.updateCount === 1;\n\t\tif (this.state === DerivedState.upToDate) {\n\t\t\tthis.state = DerivedState.dependenciesMightHaveChanged;\n\t\t\t// If we propagate begin update, that will already signal a possible change.\n\t\t\tif (!propagateBeginUpdate) {\n\t\t\t\tfor (const r of this.observers) {\n\t\t\t\t\tr.handlePossibleChange(this);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (propagateBeginUpdate) {\n\t\t\tfor (const r of this.observers) {\n\t\t\t\tr.beginUpdate(this); // This signals a possible change\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic endUpdate(_observable: IObservable): void {\n\t\tthis.updateCount--;\n\t\tif (this.updateCount === 0) {\n\t\t\t// End update could change the observer list.\n\t\t\tconst observers = [...this.observers];\n\t\t\tfor (const r of observers) {\n\t\t\t\tr.endUpdate(this);\n\t\t\t}\n\t\t}\n\t\tassertFn(() => this.updateCount >= 0);\n\t}\n\n\tpublic handlePossibleChange(observable: IObservable): void {\n\t\t// In all other states, observers already know that we might have changed.\n\t\tif (this.state === DerivedState.upToDate && this.dependencies.has(observable) && !this.dependenciesToBeRemoved.has(observable)) {\n\t\t\tthis.state = DerivedState.dependenciesMightHaveChanged;\n\t\t\tfor (const r of this.observers) {\n\t\t\t\tr.handlePossibleChange(this);\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic handleChange(observable: IObservable, change: TChange): void {\n\t\tif (this.dependencies.has(observable) && !this.dependenciesToBeRemoved.has(observable)) {\n\t\t\tconst shouldReact = this._handleChange ? this._handleChange({\n\t\t\t\tchangedObservable: observable,\n\t\t\t\tchange,\n\t\t\t\tdidChange: (o): this is any => o === observable as any,\n\t\t\t}, this.changeSummary!) : true;\n\t\t\tconst wasUpToDate = this.state === DerivedState.upToDate;\n\t\t\tif (shouldReact && (this.state === DerivedState.dependenciesMightHaveChanged || wasUpToDate)) {\n\t\t\t\tthis.state = DerivedState.stale;\n\t\t\t\tif (wasUpToDate) {\n\t\t\t\t\tfor (const r of this.observers) {\n\t\t\t\t\t\tr.handlePossibleChange(this);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// IReader Implementation\n\tpublic readObservable(observable: IObservable): T {\n\t\t// Subscribe before getting the value to enable caching\n\t\tobservable.addObserver(this);\n\t\t/** This might call {@link handleChange} indirectly, which could invalidate us */\n\t\tconst value = observable.get();\n\t\t// Which is why we only add the observable to the dependencies now.\n\t\tthis.dependencies.add(observable);\n\t\tthis.dependenciesToBeRemoved.delete(observable);\n\t\treturn value;\n\t}\n\n\tpublic override addObserver(observer: IObserver): void {\n\t\tconst shouldCallBeginUpdate = !this.observers.has(observer) && this.updateCount > 0;\n\t\tsuper.addObserver(observer);\n\n\t\tif (shouldCallBeginUpdate) {\n\t\t\tobserver.beginUpdate(this);\n\t\t}\n\t}\n\n\tpublic override removeObserver(observer: IObserver): void {\n\t\tconst shouldCallEndUpdate = this.observers.has(observer) && this.updateCount > 0;\n\t\tsuper.removeObserver(observer);\n\n\t\tif (shouldCallEndUpdate) {\n\t\t\t// Calling end update after removing the observer makes sure endUpdate cannot be called twice here.\n\t\t\tobserver.endUpdate(this);\n\t\t}\n\t}\n}\n\n\nexport class DerivedWithSetter extends Derived implements ISettableObservable {\n\tconstructor(\n\t\tdebugNameData: DebugNameData,\n\t\tcomputeFn: (reader: IReader, changeSummary: TChangeSummary) => T,\n\t\tcreateChangeSummary: (() => TChangeSummary) | undefined,\n\t\thandleChange: ((context: IChangeContext, summary: TChangeSummary) => boolean) | undefined,\n\t\thandleLastObserverRemoved: (() => void) | undefined = undefined,\n\t\tequalityComparator: EqualityComparer,\n\t\tpublic readonly set: (value: T, tx: ITransaction | undefined) => void,\n\t) {\n\t\tsuper(\n\t\t\tdebugNameData,\n\t\t\tcomputeFn,\n\t\t\tcreateChangeSummary,\n\t\t\thandleChange,\n\t\t\thandleLastObserverRemoved,\n\t\t\tequalityComparator,\n\t\t);\n\t}\n}\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 *--------------------------------------------------------------------------------------------*/\nimport { autorun } from 'vs/base/common/observableInternal/autorun';\nimport { IObservable } from './base';\nimport { CancellationToken } from 'vs/base/common/cancellation';\nimport { CancellationError } from 'vs/base/common/errors';\n\n/**\n * Resolves the promise when the observables state matches the predicate.\n */\nexport function waitForState(observable: IObservable): Promise;\nexport function waitForState(observable: IObservable, predicate: (state: T) => state is TState, isError?: (state: T) => boolean | unknown | undefined, cancellationToken?: CancellationToken): Promise;\nexport function waitForState(observable: IObservable, predicate: (state: T) => boolean, isError?: (state: T) => boolean | unknown | undefined, cancellationToken?: CancellationToken): Promise;\nexport function waitForState(observable: IObservable, predicate?: (state: T) => boolean, isError?: (state: T) => boolean | unknown | undefined, cancellationToken?: CancellationToken): Promise {\n\tif (!predicate) {\n\t\tpredicate = state => state !== null && state !== undefined;\n\t}\n\treturn new Promise((resolve, reject) => {\n\t\tlet isImmediateRun = true;\n\t\tlet shouldDispose = false;\n\t\tconst stateObs = observable.map(state => {\n\t\t\t/** @description waitForState.state */\n\t\t\treturn {\n\t\t\t\tisFinished: predicate(state),\n\t\t\t\terror: isError ? isError(state) : false,\n\t\t\t\tstate\n\t\t\t};\n\t\t});\n\t\tconst d = autorun(reader => {\n\t\t\t/** @description waitForState */\n\t\t\tconst { isFinished, error, state } = stateObs.read(reader);\n\t\t\tif (isFinished || error) {\n\t\t\t\tif (isImmediateRun) {\n\t\t\t\t\t// The variable `d` is not initialized yet\n\t\t\t\t\tshouldDispose = true;\n\t\t\t\t} else {\n\t\t\t\t\td.dispose();\n\t\t\t\t}\n\t\t\t\tif (error) {\n\t\t\t\t\treject(error === true ? state : error);\n\t\t\t\t} else {\n\t\t\t\t\tresolve(state);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\tif (cancellationToken) {\n\t\t\tconst dc = cancellationToken.onCancellationRequested(() => {\n\t\t\t\td.dispose();\n\t\t\t\tdc.dispose();\n\t\t\t\treject(new CancellationError());\n\t\t\t});\n\t\t\tif (cancellationToken.isCancellationRequested) {\n\t\t\t\td.dispose();\n\t\t\t\tdc.dispose();\n\t\t\t\treject(new CancellationError());\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tisImmediateRun = false;\n\t\tif (shouldDispose) {\n\t\t\td.dispose();\n\t\t}\n\t});\n}\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\nexport interface IRange {\n\tstart: number;\n\tend: number;\n}\n\nexport namespace Range {\n\n\t/**\n\t * Returns the intersection between two ranges as a range itself.\n\t * Returns `{ start: 0, end: 0 }` if the intersection is empty.\n\t */\n\texport function intersect(one: IRange, other: IRange): IRange {\n\t\tif (one.start >= other.end || other.start >= one.end) {\n\t\t\treturn { start: 0, end: 0 };\n\t\t}\n\n\t\tconst start = Math.max(one.start, other.start);\n\t\tconst end = Math.min(one.end, other.end);\n\n\t\tif (end - start <= 0) {\n\t\t\treturn { start: 0, end: 0 };\n\t\t}\n\n\t\treturn { start, end };\n\t}\n\n\texport function isEmpty(range: IRange): boolean {\n\t\treturn range.end - range.start <= 0;\n\t}\n\n\texport function intersects(one: IRange, other: IRange): boolean {\n\t\treturn !isEmpty(intersect(one, other));\n\t}\n\n\texport function relativeComplement(one: IRange, other: IRange): IRange[] {\n\t\tconst result: IRange[] = [];\n\t\tconst first = { start: one.start, end: Math.min(other.start, one.end) };\n\t\tconst second = { start: Math.max(other.end, one.start), end: one.end };\n\n\t\tif (!isEmpty(first)) {\n\t\t\tresult.push(first);\n\t\t}\n\n\t\tif (!isEmpty(second)) {\n\t\t\tresult.push(second);\n\t\t}\n\n\t\treturn result;\n\t}\n}\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\nimport { IRange, Range } from 'vs/base/common/range';\n\nexport interface IItem {\n\tsize: number;\n}\n\nexport interface IRangedGroup {\n\trange: IRange;\n\tsize: number;\n}\n\n/**\n * Returns the intersection between a ranged group and a range.\n * Returns `[]` if the intersection is empty.\n */\nexport function groupIntersect(range: IRange, groups: IRangedGroup[]): IRangedGroup[] {\n\tconst result: IRangedGroup[] = [];\n\n\tfor (const r of groups) {\n\t\tif (range.start >= r.range.end) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (range.end < r.range.start) {\n\t\t\tbreak;\n\t\t}\n\n\t\tconst intersection = Range.intersect(range, r.range);\n\n\t\tif (Range.isEmpty(intersection)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tresult.push({\n\t\t\trange: intersection,\n\t\t\tsize: r.size\n\t\t});\n\t}\n\n\treturn result;\n}\n\n/**\n * Shifts a range by that `much`.\n */\nexport function shift({ start, end }: IRange, much: number): IRange {\n\treturn { start: start + much, end: end + much };\n}\n\n/**\n * Consolidates a collection of ranged groups.\n *\n * Consolidation is the process of merging consecutive ranged groups\n * that share the same `size`.\n */\nexport function consolidate(groups: IRangedGroup[]): IRangedGroup[] {\n\tconst result: IRangedGroup[] = [];\n\tlet previousGroup: IRangedGroup | null = null;\n\n\tfor (const group of groups) {\n\t\tconst start = group.range.start;\n\t\tconst end = group.range.end;\n\t\tconst size = group.size;\n\n\t\tif (previousGroup && size === previousGroup.size) {\n\t\t\tpreviousGroup.range.end = end;\n\t\t\tcontinue;\n\t\t}\n\n\t\tpreviousGroup = { range: { start, end }, size };\n\t\tresult.push(previousGroup);\n\t}\n\n\treturn result;\n}\n\n/**\n * Concatenates several collections of ranged groups into a single\n * collection.\n */\nfunction concat(...groups: IRangedGroup[][]): IRangedGroup[] {\n\treturn consolidate(groups.reduce((r, g) => r.concat(g), []));\n}\n\nexport interface IRangeMap {\n\treadonly size: number;\n\tpaddingTop: number;\n\tsplice(index: number, deleteCount: number, items?: IItem[]): void;\n\tindexAt(position: number): number;\n\tindexAfter(position: number): number;\n\tpositionAt(index: number): number;\n}\n\nexport class RangeMap implements IRangeMap {\n\n\tprivate groups: IRangedGroup[] = [];\n\tprivate _size = 0;\n\tprivate _paddingTop = 0;\n\n\tget paddingTop() {\n\t\treturn this._paddingTop;\n\t}\n\n\tset paddingTop(paddingTop: number) {\n\t\tthis._size = this._size + paddingTop - this._paddingTop;\n\t\tthis._paddingTop = paddingTop;\n\t}\n\n\tconstructor(topPadding?: number) {\n\t\tthis._paddingTop = topPadding ?? 0;\n\t\tthis._size = this._paddingTop;\n\t}\n\n\tsplice(index: number, deleteCount: number, items: IItem[] = []): void {\n\t\tconst diff = items.length - deleteCount;\n\t\tconst before = groupIntersect({ start: 0, end: index }, this.groups);\n\t\tconst after = groupIntersect({ start: index + deleteCount, end: Number.POSITIVE_INFINITY }, this.groups)\n\t\t\t.map(g => ({ range: shift(g.range, diff), size: g.size }));\n\n\t\tconst middle = items.map((item, i) => ({\n\t\t\trange: { start: index + i, end: index + i + 1 },\n\t\t\tsize: item.size\n\t\t}));\n\n\t\tthis.groups = concat(before, middle, after);\n\t\tthis._size = this._paddingTop + this.groups.reduce((t, g) => t + (g.size * (g.range.end - g.range.start)), 0);\n\t}\n\n\t/**\n\t * Returns the number of items in the range map.\n\t */\n\tget count(): number {\n\t\tconst len = this.groups.length;\n\n\t\tif (!len) {\n\t\t\treturn 0;\n\t\t}\n\n\t\treturn this.groups[len - 1].range.end;\n\t}\n\n\t/**\n\t * Returns the sum of the sizes of all items in the range map.\n\t */\n\tget size(): number {\n\t\treturn this._size;\n\t}\n\n\t/**\n\t * Returns the index of the item at the given position.\n\t */\n\tindexAt(position: number): number {\n\t\tif (position < 0) {\n\t\t\treturn -1;\n\t\t}\n\n\t\tif (position < this._paddingTop) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tlet index = 0;\n\t\tlet size = this._paddingTop;\n\n\t\tfor (const group of this.groups) {\n\t\t\tconst count = group.range.end - group.range.start;\n\t\t\tconst newSize = size + (count * group.size);\n\n\t\t\tif (position < newSize) {\n\t\t\t\treturn index + Math.floor((position - size) / group.size);\n\t\t\t}\n\n\t\t\tindex += count;\n\t\t\tsize = newSize;\n\t\t}\n\n\t\treturn index;\n\t}\n\n\t/**\n\t * Returns the index of the item right after the item at the\n\t * index of the given position.\n\t */\n\tindexAfter(position: number): number {\n\t\treturn Math.min(this.indexAt(position) + 1, this.count);\n\t}\n\n\t/**\n\t * Returns the start position of the item at the given index.\n\t */\n\tpositionAt(index: number): number {\n\t\tif (index < 0) {\n\t\t\treturn -1;\n\t\t}\n\n\t\tlet position = 0;\n\t\tlet count = 0;\n\n\t\tfor (const group of this.groups) {\n\t\t\tconst groupCount = group.range.end - group.range.start;\n\t\t\tconst newCount = count + groupCount;\n\n\t\t\tif (index < newCount) {\n\t\t\t\treturn this._paddingTop + position + ((index - count) * group.size);\n\t\t\t}\n\n\t\t\tposition += groupCount * group.size;\n\t\t\tcount = newCount;\n\t\t}\n\n\t\treturn -1;\n\t}\n}\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// fake definition so that the valid layers check won't trip on this\ndeclare const globalThis: { performance?: { now(): number } };\n\nconst hasPerformanceNow = (globalThis.performance && typeof globalThis.performance.now === 'function');\n\nexport class StopWatch {\n\n\tprivate _startTime: number;\n\tprivate _stopTime: number;\n\n\tprivate readonly _now: () => number;\n\n\tpublic static create(highResolution?: boolean): StopWatch {\n\t\treturn new StopWatch(highResolution);\n\t}\n\n\tconstructor(highResolution?: boolean) {\n\t\tthis._now = hasPerformanceNow && highResolution === false ? Date.now : globalThis.performance!.now.bind(globalThis.performance);\n\t\tthis._startTime = this._now();\n\t\tthis._stopTime = -1;\n\t}\n\n\tpublic stop(): void {\n\t\tthis._stopTime = this._now();\n\t}\n\n\tpublic reset(): void {\n\t\tthis._startTime = this._now();\n\t\tthis._stopTime = -1;\n\t}\n\n\tpublic elapsed(): number {\n\t\tif (this._stopTime !== -1) {\n\t\t\treturn this._stopTime - this._startTime;\n\t\t}\n\t\treturn this._now() - this._startTime;\n\t}\n}\n","\nimport { onUnexpectedError } from 'vs/base/common/errors';\nimport { createSingleCallFunction } from 'vs/base/common/functional';\nimport { combinedDisposable, Disposable, DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle';\nimport { LinkedList } from 'vs/base/common/linkedList';\nimport { IObservable, IObserver } from 'vs/base/common/observable';\nimport { StopWatch } from 'vs/base/common/stopwatch';\nimport { MicrotaskDelay } from 'vs/base/common/symbols';\n\n\n// -----------------------------------------------------------------------------------------------------------------------\n// Uncomment the next line to print warnings whenever a listener is GC'ed without having been disposed. This is a LEAK.\n// -----------------------------------------------------------------------------------------------------------------------\nconst _enableListenerGCedWarning = false\n\t// || Boolean(\"TRUE\") // causes a linter warning so that it cannot be pushed\n\t;\n\n// -----------------------------------------------------------------------------------------------------------------------\n// Uncomment the next line to print warnings whenever an emitter with listeners is disposed. That is a sign of code smell.\n// -----------------------------------------------------------------------------------------------------------------------\nconst _enableDisposeWithListenerWarning = false\n\t// || Boolean(\"TRUE\") // causes a linter warning so that it cannot be pushed\n\t;\n\n\n// -----------------------------------------------------------------------------------------------------------------------\n// Uncomment the next line to print warnings whenever a snapshotted event is used repeatedly without cleanup.\n// See https://github.com/microsoft/vscode/issues/142851\n// -----------------------------------------------------------------------------------------------------------------------\nconst _enableSnapshotPotentialLeakWarning = false\n\t// || Boolean(\"TRUE\") // causes a linter warning so that it cannot be pushed\n\t;\n\n/**\n * An event with zero or one parameters that can be subscribed to. The event is a function itself.\n */\nexport interface Event {\n\t(listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[] | DisposableStore): IDisposable;\n}\n\nexport namespace Event {\n\texport const None: Event = () => Disposable.None;\n\n\tfunction _addLeakageTraceLogic(options: EmitterOptions) {\n\t\tif (_enableSnapshotPotentialLeakWarning) {\n\t\t\tconst { onDidAddListener: origListenerDidAdd } = options;\n\t\t\tconst stack = Stacktrace.create();\n\t\t\tlet count = 0;\n\t\t\toptions.onDidAddListener = () => {\n\t\t\t\tif (++count === 2) {\n\t\t\t\t\tconsole.warn('snapshotted emitter LIKELY used public and SHOULD HAVE BEEN created with DisposableStore. snapshotted here');\n\t\t\t\t\tstack.print();\n\t\t\t\t}\n\t\t\t\torigListenerDidAdd?.();\n\t\t\t};\n\t\t}\n\t}\n\n\t/**\n\t * Given an event, returns another event which debounces calls and defers the listeners to a later task via a shared\n\t * `setTimeout`. The event is converted into a signal (`Event`) to avoid additional object creation as a\n\t * result of merging events and to try prevent race conditions that could arise when using related deferred and\n\t * non-deferred events.\n\t *\n\t * This is useful for deferring non-critical work (eg. general UI updates) to ensure it does not block critical work\n\t * (eg. latency of keypress to text rendered).\n\t *\n\t * *NOTE* that this function returns an `Event` and it MUST be called with a `DisposableStore` whenever the returned\n\t * event is accessible to \"third parties\", e.g the event is a public property. Otherwise a leaked listener on the\n\t * returned event causes this utility to leak a listener on the original event.\n\t *\n\t * @param event The event source for the new event.\n\t * @param disposable A disposable store to add the new EventEmitter to.\n\t */\n\texport function defer(event: Event, disposable?: DisposableStore): Event {\n\t\treturn debounce(event, () => void 0, 0, undefined, true, undefined, disposable);\n\t}\n\n\t/**\n\t * Given an event, returns another event which only fires once.\n\t *\n\t * @param event The event source for the new event.\n\t */\n\texport function once(event: Event): Event {\n\t\treturn (listener, thisArgs = null, disposables?) => {\n\t\t\t// we need this, in case the event fires during the listener call\n\t\t\tlet didFire = false;\n\t\t\tlet result: IDisposable | undefined = undefined;\n\t\t\tresult = event(e => {\n\t\t\t\tif (didFire) {\n\t\t\t\t\treturn;\n\t\t\t\t} else if (result) {\n\t\t\t\t\tresult.dispose();\n\t\t\t\t} else {\n\t\t\t\t\tdidFire = true;\n\t\t\t\t}\n\n\t\t\t\treturn listener.call(thisArgs, e);\n\t\t\t}, null, disposables);\n\n\t\t\tif (didFire) {\n\t\t\t\tresult.dispose();\n\t\t\t}\n\n\t\t\treturn result;\n\t\t};\n\t}\n\n\t/**\n\t * Maps an event of one type into an event of another type using a mapping function, similar to how\n\t * `Array.prototype.map` works.\n\t *\n\t * *NOTE* that this function returns an `Event` and it MUST be called with a `DisposableStore` whenever the returned\n\t * event is accessible to \"third parties\", e.g the event is a public property. Otherwise a leaked listener on the\n\t * returned event causes this utility to leak a listener on the original event.\n\t *\n\t * @param event The event source for the new event.\n\t * @param map The mapping function.\n\t * @param disposable A disposable store to add the new EventEmitter to.\n\t */\n\texport function map(event: Event, map: (i: I) => O, disposable?: DisposableStore): Event {\n\t\treturn snapshot((listener, thisArgs = null, disposables?) => event(i => listener.call(thisArgs, map(i)), null, disposables), disposable);\n\t}\n\n\t/**\n\t * Wraps an event in another event that performs some function on the event object before firing.\n\t *\n\t * *NOTE* that this function returns an `Event` and it MUST be called with a `DisposableStore` whenever the returned\n\t * event is accessible to \"third parties\", e.g the event is a public property. Otherwise a leaked listener on the\n\t * returned event causes this utility to leak a listener on the original event.\n\t *\n\t * @param event The event source for the new event.\n\t * @param each The function to perform on the event object.\n\t * @param disposable A disposable store to add the new EventEmitter to.\n\t */\n\texport function forEach(event: Event, each: (i: I) => void, disposable?: DisposableStore): Event {\n\t\treturn snapshot((listener, thisArgs = null, disposables?) => event(i => { each(i); listener.call(thisArgs, i); }, null, disposables), disposable);\n\t}\n\n\t/**\n\t * Wraps an event in another event that fires only when some condition is met.\n\t *\n\t * *NOTE* that this function returns an `Event` and it MUST be called with a `DisposableStore` whenever the returned\n\t * event is accessible to \"third parties\", e.g the event is a public property. Otherwise a leaked listener on the\n\t * returned event causes this utility to leak a listener on the original event.\n\t *\n\t * @param event The event source for the new event.\n\t * @param filter The filter function that defines the condition. The event will fire for the object if this function\n\t * returns true.\n\t * @param disposable A disposable store to add the new EventEmitter to.\n\t */\n\texport function filter(event: Event, filter: (e: T | U) => e is T, disposable?: DisposableStore): Event;\n\texport function filter(event: Event, filter: (e: T) => boolean, disposable?: DisposableStore): Event;\n\texport function filter(event: Event, filter: (e: T | R) => e is R, disposable?: DisposableStore): Event;\n\texport function filter(event: Event, filter: (e: T) => boolean, disposable?: DisposableStore): Event {\n\t\treturn snapshot((listener, thisArgs = null, disposables?) => event(e => filter(e) && listener.call(thisArgs, e), null, disposables), disposable);\n\t}\n\n\t/**\n\t * Given an event, returns the same event but typed as `Event`.\n\t */\n\texport function signal(event: Event): Event {\n\t\treturn event as Event as Event;\n\t}\n\n\t/**\n\t * Given a collection of events, returns a single event which emits whenever any of the provided events emit.\n\t */\n\texport function any(...events: Event[]): Event;\n\texport function any(...events: Event[]): Event;\n\texport function any(...events: Event[]): Event {\n\t\treturn (listener, thisArgs = null, disposables?) => {\n\t\t\tconst disposable = combinedDisposable(...events.map(event => event(e => listener.call(thisArgs, e))));\n\t\t\treturn addAndReturnDisposable(disposable, disposables);\n\t\t};\n\t}\n\n\t/**\n\t * *NOTE* that this function returns an `Event` and it MUST be called with a `DisposableStore` whenever the returned\n\t * event is accessible to \"third parties\", e.g the event is a public property. Otherwise a leaked listener on the\n\t * returned event causes this utility to leak a listener on the original event.\n\t */\n\texport function reduce(event: Event, merge: (last: O | undefined, event: I) => O, initial?: O, disposable?: DisposableStore): Event {\n\t\tlet output: O | undefined = initial;\n\n\t\treturn map(event, e => {\n\t\t\toutput = merge(output, e);\n\t\t\treturn output;\n\t\t}, disposable);\n\t}\n\n\tfunction snapshot(event: Event, disposable: DisposableStore | undefined): Event {\n\t\tlet listener: IDisposable | undefined;\n\n\t\tconst options: EmitterOptions | undefined = {\n\t\t\tonWillAddFirstListener() {\n\t\t\t\tlistener = event(emitter.fire, emitter);\n\t\t\t},\n\t\t\tonDidRemoveLastListener() {\n\t\t\t\tlistener?.dispose();\n\t\t\t}\n\t\t};\n\n\t\tif (!disposable) {\n\t\t\t_addLeakageTraceLogic(options);\n\t\t}\n\n\t\tconst emitter = new Emitter(options);\n\n\t\tdisposable?.add(emitter);\n\n\t\treturn emitter.event;\n\t}\n\n\t/**\n\t * Adds the IDisposable to the store if it's set, and returns it. Useful to\n\t * Event function implementation.\n\t */\n\tfunction addAndReturnDisposable(d: T, store: DisposableStore | IDisposable[] | undefined): T {\n\t\tif (store instanceof Array) {\n\t\t\tstore.push(d);\n\t\t} else if (store) {\n\t\t\tstore.add(d);\n\t\t}\n\t\treturn d;\n\t}\n\n\t/**\n\t * Given an event, creates a new emitter that event that will debounce events based on {@link delay} and give an\n\t * array event object of all events that fired.\n\t *\n\t * *NOTE* that this function returns an `Event` and it MUST be called with a `DisposableStore` whenever the returned\n\t * event is accessible to \"third parties\", e.g the event is a public property. Otherwise a leaked listener on the\n\t * returned event causes this utility to leak a listener on the original event.\n\t *\n\t * @param event The original event to debounce.\n\t * @param merge A function that reduces all events into a single event.\n\t * @param delay The number of milliseconds to debounce.\n\t * @param leading Whether to fire a leading event without debouncing.\n\t * @param flushOnListenerRemove Whether to fire all debounced events when a listener is removed. If this is not\n\t * specified, some events could go missing. Use this if it's important that all events are processed, even if the\n\t * listener gets disposed before the debounced event fires.\n\t * @param leakWarningThreshold See {@link EmitterOptions.leakWarningThreshold}.\n\t * @param disposable A disposable store to register the debounce emitter to.\n\t */\n\texport function debounce(event: Event, merge: (last: T | undefined, event: T) => T, delay?: number | typeof MicrotaskDelay, leading?: boolean, flushOnListenerRemove?: boolean, leakWarningThreshold?: number, disposable?: DisposableStore): Event;\n\texport function debounce(event: Event, merge: (last: O | undefined, event: I) => O, delay?: number | typeof MicrotaskDelay, leading?: boolean, flushOnListenerRemove?: boolean, leakWarningThreshold?: number, disposable?: DisposableStore): Event;\n\texport function debounce(event: Event, merge: (last: O | undefined, event: I) => O, delay: number | typeof MicrotaskDelay = 100, leading = false, flushOnListenerRemove = false, leakWarningThreshold?: number, disposable?: DisposableStore): Event {\n\t\tlet subscription: IDisposable;\n\t\tlet output: O | undefined = undefined;\n\t\tlet handle: any = undefined;\n\t\tlet numDebouncedCalls = 0;\n\t\tlet doFire: (() => void) | undefined;\n\n\t\tconst options: EmitterOptions | undefined = {\n\t\t\tleakWarningThreshold,\n\t\t\tonWillAddFirstListener() {\n\t\t\t\tsubscription = event(cur => {\n\t\t\t\t\tnumDebouncedCalls++;\n\t\t\t\t\toutput = merge(output, cur);\n\n\t\t\t\t\tif (leading && !handle) {\n\t\t\t\t\t\temitter.fire(output);\n\t\t\t\t\t\toutput = undefined;\n\t\t\t\t\t}\n\n\t\t\t\t\tdoFire = () => {\n\t\t\t\t\t\tconst _output = output;\n\t\t\t\t\t\toutput = undefined;\n\t\t\t\t\t\thandle = undefined;\n\t\t\t\t\t\tif (!leading || numDebouncedCalls > 1) {\n\t\t\t\t\t\t\temitter.fire(_output!);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tnumDebouncedCalls = 0;\n\t\t\t\t\t};\n\n\t\t\t\t\tif (typeof delay === 'number') {\n\t\t\t\t\t\tclearTimeout(handle);\n\t\t\t\t\t\thandle = setTimeout(doFire, delay);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif (handle === undefined) {\n\t\t\t\t\t\t\thandle = 0;\n\t\t\t\t\t\t\tqueueMicrotask(doFire);\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\tonWillRemoveListener() {\n\t\t\t\tif (flushOnListenerRemove && numDebouncedCalls > 0) {\n\t\t\t\t\tdoFire?.();\n\t\t\t\t}\n\t\t\t},\n\t\t\tonDidRemoveLastListener() {\n\t\t\t\tdoFire = undefined;\n\t\t\t\tsubscription.dispose();\n\t\t\t}\n\t\t};\n\n\t\tif (!disposable) {\n\t\t\t_addLeakageTraceLogic(options);\n\t\t}\n\n\t\tconst emitter = new Emitter(options);\n\n\t\tdisposable?.add(emitter);\n\n\t\treturn emitter.event;\n\t}\n\n\t/**\n\t * Debounces an event, firing after some delay (default=0) with an array of all event original objects.\n\t *\n\t * *NOTE* that this function returns an `Event` and it MUST be called with a `DisposableStore` whenever the returned\n\t * event is accessible to \"third parties\", e.g the event is a public property. Otherwise a leaked listener on the\n\t * returned event causes this utility to leak a listener on the original event.\n\t */\n\texport function accumulate(event: Event, delay: number = 0, disposable?: DisposableStore): Event {\n\t\treturn Event.debounce(event, (last, e) => {\n\t\t\tif (!last) {\n\t\t\t\treturn [e];\n\t\t\t}\n\t\t\tlast.push(e);\n\t\t\treturn last;\n\t\t}, delay, undefined, true, undefined, disposable);\n\t}\n\n\t/**\n\t * Filters an event such that some condition is _not_ met more than once in a row, effectively ensuring duplicate\n\t * event objects from different sources do not fire the same event object.\n\t *\n\t * *NOTE* that this function returns an `Event` and it MUST be called with a `DisposableStore` whenever the returned\n\t * event is accessible to \"third parties\", e.g the event is a public property. Otherwise a leaked listener on the\n\t * returned event causes this utility to leak a listener on the original event.\n\t *\n\t * @param event The event source for the new event.\n\t * @param equals The equality condition.\n\t * @param disposable A disposable store to add the new EventEmitter to.\n\t *\n\t * @example\n\t * ```\n\t * // Fire only one time when a single window is opened or focused\n\t * Event.latch(Event.any(onDidOpenWindow, onDidFocusWindow))\n\t * ```\n\t */\n\texport function latch(event: Event, equals: (a: T, b: T) => boolean = (a, b) => a === b, disposable?: DisposableStore): Event {\n\t\tlet firstCall = true;\n\t\tlet cache: T;\n\n\t\treturn filter(event, value => {\n\t\t\tconst shouldEmit = firstCall || !equals(value, cache);\n\t\t\tfirstCall = false;\n\t\t\tcache = value;\n\t\t\treturn shouldEmit;\n\t\t}, disposable);\n\t}\n\n\t/**\n\t * Splits an event whose parameter is a union type into 2 separate events for each type in the union.\n\t *\n\t * *NOTE* that this function returns an `Event` and it MUST be called with a `DisposableStore` whenever the returned\n\t * event is accessible to \"third parties\", e.g the event is a public property. Otherwise a leaked listener on the\n\t * returned event causes this utility to leak a listener on the original event.\n\t *\n\t * @example\n\t * ```\n\t * const event = new EventEmitter().event;\n\t * const [numberEvent, undefinedEvent] = Event.split(event, isUndefined);\n\t * ```\n\t *\n\t * @param event The event source for the new event.\n\t * @param isT A function that determines what event is of the first type.\n\t * @param disposable A disposable store to add the new EventEmitter to.\n\t */\n\texport function split(event: Event, isT: (e: T | U) => e is T, disposable?: DisposableStore): [Event, Event] {\n\t\treturn [\n\t\t\tEvent.filter(event, isT, disposable),\n\t\t\tEvent.filter(event, e => !isT(e), disposable) as Event,\n\t\t];\n\t}\n\n\t/**\n\t * Buffers an event until it has a listener attached.\n\t *\n\t * *NOTE* that this function returns an `Event` and it MUST be called with a `DisposableStore` whenever the returned\n\t * event is accessible to \"third parties\", e.g the event is a public property. Otherwise a leaked listener on the\n\t * returned event causes this utility to leak a listener on the original event.\n\t *\n\t * @param event The event source for the new event.\n\t * @param flushAfterTimeout Determines whether to flush the buffer after a timeout immediately or after a\n\t * `setTimeout` when the first event listener is added.\n\t * @param _buffer Internal: A source event array used for tests.\n\t *\n\t * @example\n\t * ```\n\t * // Start accumulating events, when the first listener is attached, flush\n\t * // the event after a timeout such that multiple listeners attached before\n\t * // the timeout would receive the event\n\t * this.onInstallExtension = Event.buffer(service.onInstallExtension, true);\n\t * ```\n\t */\n\texport function buffer(event: Event, flushAfterTimeout = false, _buffer: T[] = [], disposable?: DisposableStore): Event {\n\t\tlet buffer: T[] | null = _buffer.slice();\n\n\t\tlet listener: IDisposable | null = event(e => {\n\t\t\tif (buffer) {\n\t\t\t\tbuffer.push(e);\n\t\t\t} else {\n\t\t\t\temitter.fire(e);\n\t\t\t}\n\t\t});\n\n\t\tif (disposable) {\n\t\t\tdisposable.add(listener);\n\t\t}\n\n\t\tconst flush = () => {\n\t\t\tbuffer?.forEach(e => emitter.fire(e));\n\t\t\tbuffer = null;\n\t\t};\n\n\t\tconst emitter = new Emitter({\n\t\t\tonWillAddFirstListener() {\n\t\t\t\tif (!listener) {\n\t\t\t\t\tlistener = event(e => emitter.fire(e));\n\t\t\t\t\tif (disposable) {\n\t\t\t\t\t\tdisposable.add(listener);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tonDidAddFirstListener() {\n\t\t\t\tif (buffer) {\n\t\t\t\t\tif (flushAfterTimeout) {\n\t\t\t\t\t\tsetTimeout(flush);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tflush();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tonDidRemoveLastListener() {\n\t\t\t\tif (listener) {\n\t\t\t\t\tlistener.dispose();\n\t\t\t\t}\n\t\t\t\tlistener = null;\n\t\t\t}\n\t\t});\n\n\t\tif (disposable) {\n\t\t\tdisposable.add(emitter);\n\t\t}\n\n\t\treturn emitter.event;\n\t}\n\t/**\n\t * Wraps the event in an {@link IChainableEvent}, allowing a more functional programming style.\n\t *\n\t * @example\n\t * ```\n\t * // Normal\n\t * const onEnterPressNormal = Event.filter(\n\t * Event.map(onKeyPress.event, e => new StandardKeyboardEvent(e)),\n\t * e.keyCode === KeyCode.Enter\n\t * ).event;\n\t *\n\t * // Using chain\n\t * const onEnterPressChain = Event.chain(onKeyPress.event, $ => $\n\t * .map(e => new StandardKeyboardEvent(e))\n\t * .filter(e => e.keyCode === KeyCode.Enter)\n\t * );\n\t * ```\n\t */\n\texport function chain(event: Event, sythensize: ($: IChainableSythensis) => IChainableSythensis): Event {\n\t\tconst fn: Event = (listener, thisArgs, disposables) => {\n\t\t\tconst cs = sythensize(new ChainableSynthesis()) as ChainableSynthesis;\n\t\t\treturn event(function (value) {\n\t\t\t\tconst result = cs.evaluate(value);\n\t\t\t\tif (result !== HaltChainable) {\n\t\t\t\t\tlistener.call(thisArgs, result);\n\t\t\t\t}\n\t\t\t}, undefined, disposables);\n\t\t};\n\n\t\treturn fn;\n\t}\n\n\tconst HaltChainable = Symbol('HaltChainable');\n\n\tclass ChainableSynthesis implements IChainableSythensis {\n\t\tprivate readonly steps: ((input: any) => any)[] = [];\n\n\t\tmap(fn: (i: any) => O): this {\n\t\t\tthis.steps.push(fn);\n\t\t\treturn this;\n\t\t}\n\n\t\tforEach(fn: (i: any) => void): this {\n\t\t\tthis.steps.push(v => {\n\t\t\t\tfn(v);\n\t\t\t\treturn v;\n\t\t\t});\n\t\t\treturn this;\n\t\t}\n\n\t\tfilter(fn: (e: any) => boolean): this {\n\t\t\tthis.steps.push(v => fn(v) ? v : HaltChainable);\n\t\t\treturn this;\n\t\t}\n\n\t\treduce(merge: (last: R | undefined, event: any) => R, initial?: R | undefined): this {\n\t\t\tlet last = initial;\n\t\t\tthis.steps.push(v => {\n\t\t\t\tlast = merge(last, v);\n\t\t\t\treturn last;\n\t\t\t});\n\t\t\treturn this;\n\t\t}\n\n\t\tlatch(equals: (a: any, b: any) => boolean = (a, b) => a === b): ChainableSynthesis {\n\t\t\tlet firstCall = true;\n\t\t\tlet cache: any;\n\t\t\tthis.steps.push(value => {\n\t\t\t\tconst shouldEmit = firstCall || !equals(value, cache);\n\t\t\t\tfirstCall = false;\n\t\t\t\tcache = value;\n\t\t\t\treturn shouldEmit ? value : HaltChainable;\n\t\t\t});\n\n\t\t\treturn this;\n\t\t}\n\n\t\tpublic evaluate(value: any) {\n\t\t\tfor (const step of this.steps) {\n\t\t\t\tvalue = step(value);\n\t\t\t\tif (value === HaltChainable) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn value;\n\t\t}\n\t}\n\n\texport interface IChainableSythensis {\n\t\tmap(fn: (i: T) => O): IChainableSythensis;\n\t\tforEach(fn: (i: T) => void): IChainableSythensis;\n\t\tfilter(fn: (e: T) => e is R): IChainableSythensis;\n\t\tfilter(fn: (e: T) => boolean): IChainableSythensis;\n\t\treduce(merge: (last: R, event: T) => R, initial: R): IChainableSythensis;\n\t\treduce(merge: (last: R | undefined, event: T) => R): IChainableSythensis;\n\t\tlatch(equals?: (a: T, b: T) => boolean): IChainableSythensis;\n\t}\n\n\texport interface NodeEventEmitter {\n\t\ton(event: string | symbol, listener: Function): unknown;\n\t\tremoveListener(event: string | symbol, listener: Function): unknown;\n\t}\n\n\t/**\n\t * Creates an {@link Event} from a node event emitter.\n\t */\n\texport function fromNodeEventEmitter(emitter: NodeEventEmitter, eventName: string, map: (...args: any[]) => T = id => id): Event {\n\t\tconst fn = (...args: any[]) => result.fire(map(...args));\n\t\tconst onFirstListenerAdd = () => emitter.on(eventName, fn);\n\t\tconst onLastListenerRemove = () => emitter.removeListener(eventName, fn);\n\t\tconst result = new Emitter({ onWillAddFirstListener: onFirstListenerAdd, onDidRemoveLastListener: onLastListenerRemove });\n\n\t\treturn result.event;\n\t}\n\n\texport interface DOMEventEmitter {\n\t\taddEventListener(event: string | symbol, listener: Function): void;\n\t\tremoveEventListener(event: string | symbol, listener: Function): void;\n\t}\n\n\t/**\n\t * Creates an {@link Event} from a DOM event emitter.\n\t */\n\texport function fromDOMEventEmitter(emitter: DOMEventEmitter, eventName: string, map: (...args: any[]) => T = id => id): Event {\n\t\tconst fn = (...args: any[]) => result.fire(map(...args));\n\t\tconst onFirstListenerAdd = () => emitter.addEventListener(eventName, fn);\n\t\tconst onLastListenerRemove = () => emitter.removeEventListener(eventName, fn);\n\t\tconst result = new Emitter({ onWillAddFirstListener: onFirstListenerAdd, onDidRemoveLastListener: onLastListenerRemove });\n\n\t\treturn result.event;\n\t}\n\n\t/**\n\t * Creates a promise out of an event, using the {@link Event.once} helper.\n\t */\n\texport function toPromise(event: Event): Promise {\n\t\treturn new Promise(resolve => once(event)(resolve));\n\t}\n\n\t/**\n\t * Creates an event out of a promise that fires once when the promise is\n\t * resolved with the result of the promise or `undefined`.\n\t */\n\texport function fromPromise(promise: Promise): Event {\n\t\tconst result = new Emitter();\n\n\t\tpromise.then(res => {\n\t\t\tresult.fire(res);\n\t\t}, () => {\n\t\t\tresult.fire(undefined);\n\t\t}).finally(() => {\n\t\t\tresult.dispose();\n\t\t});\n\n\t\treturn result.event;\n\t}\n\n\t/**\n\t * Adds a listener to an event and calls the listener immediately with undefined as the event object.\n\t *\n\t * @example\n\t * ```\n\t * // Initialize the UI and update it when dataChangeEvent fires\n\t * runAndSubscribe(dataChangeEvent, () => this._updateUI());\n\t * ```\n\t */\n\texport function runAndSubscribe(event: Event, handler: (e: T) => any, initial: T): IDisposable;\n\texport function runAndSubscribe(event: Event, handler: (e: T | undefined) => any): IDisposable;\n\texport function runAndSubscribe(event: Event, handler: (e: T | undefined) => any, initial?: T): IDisposable {\n\t\thandler(initial);\n\t\treturn event(e => handler(e));\n\t}\n\n\tclass EmitterObserver implements IObserver {\n\n\t\treadonly emitter: Emitter;\n\n\t\tprivate _counter = 0;\n\t\tprivate _hasChanged = false;\n\n\t\tconstructor(readonly _observable: IObservable, store: DisposableStore | undefined) {\n\t\t\tconst options: EmitterOptions = {\n\t\t\t\tonWillAddFirstListener: () => {\n\t\t\t\t\t_observable.addObserver(this);\n\t\t\t\t},\n\t\t\t\tonDidRemoveLastListener: () => {\n\t\t\t\t\t_observable.removeObserver(this);\n\t\t\t\t}\n\t\t\t};\n\t\t\tif (!store) {\n\t\t\t\t_addLeakageTraceLogic(options);\n\t\t\t}\n\t\t\tthis.emitter = new Emitter(options);\n\t\t\tif (store) {\n\t\t\t\tstore.add(this.emitter);\n\t\t\t}\n\t\t}\n\n\t\tbeginUpdate(_observable: IObservable): void {\n\t\t\t// assert(_observable === this.obs);\n\t\t\tthis._counter++;\n\t\t}\n\n\t\thandlePossibleChange(_observable: IObservable): void {\n\t\t\t// assert(_observable === this.obs);\n\t\t}\n\n\t\thandleChange(_observable: IObservable, _change: TChange): void {\n\t\t\t// assert(_observable === this.obs);\n\t\t\tthis._hasChanged = true;\n\t\t}\n\n\t\tendUpdate(_observable: IObservable): void {\n\t\t\t// assert(_observable === this.obs);\n\t\t\tthis._counter--;\n\t\t\tif (this._counter === 0) {\n\t\t\t\tthis._observable.reportChanges();\n\t\t\t\tif (this._hasChanged) {\n\t\t\t\t\tthis._hasChanged = false;\n\t\t\t\t\tthis.emitter.fire(this._observable.get());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Creates an event emitter that is fired when the observable changes.\n\t * Each listeners subscribes to the emitter.\n\t */\n\texport function fromObservable(obs: IObservable, store?: DisposableStore): Event {\n\t\tconst observer = new EmitterObserver(obs, store);\n\t\treturn observer.emitter.event;\n\t}\n\n\t/**\n\t * Each listener is attached to the observable directly.\n\t */\n\texport function fromObservableLight(observable: IObservable): Event {\n\t\treturn (listener, thisArgs, disposables) => {\n\t\t\tlet count = 0;\n\t\t\tlet didChange = false;\n\t\t\tconst observer: IObserver = {\n\t\t\t\tbeginUpdate() {\n\t\t\t\t\tcount++;\n\t\t\t\t},\n\t\t\t\tendUpdate() {\n\t\t\t\t\tcount--;\n\t\t\t\t\tif (count === 0) {\n\t\t\t\t\t\tobservable.reportChanges();\n\t\t\t\t\t\tif (didChange) {\n\t\t\t\t\t\t\tdidChange = false;\n\t\t\t\t\t\t\tlistener.call(thisArgs);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\thandlePossibleChange() {\n\t\t\t\t\t// noop\n\t\t\t\t},\n\t\t\t\thandleChange() {\n\t\t\t\t\tdidChange = true;\n\t\t\t\t}\n\t\t\t};\n\t\t\tobservable.addObserver(observer);\n\t\t\tobservable.reportChanges();\n\t\t\tconst disposable = {\n\t\t\t\tdispose() {\n\t\t\t\t\tobservable.removeObserver(observer);\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tif (disposables instanceof DisposableStore) {\n\t\t\t\tdisposables.add(disposable);\n\t\t\t} else if (Array.isArray(disposables)) {\n\t\t\t\tdisposables.push(disposable);\n\t\t\t}\n\n\t\t\treturn disposable;\n\t\t};\n\t}\n}\n\nexport interface EmitterOptions {\n\t/**\n\t * Optional function that's called *before* the very first listener is added\n\t */\n\tonWillAddFirstListener?: Function;\n\t/**\n\t * Optional function that's called *after* the very first listener is added\n\t */\n\tonDidAddFirstListener?: Function;\n\t/**\n\t * Optional function that's called after a listener is added\n\t */\n\tonDidAddListener?: Function;\n\t/**\n\t * Optional function that's called *after* remove the very last listener\n\t */\n\tonDidRemoveLastListener?: Function;\n\t/**\n\t * Optional function that's called *before* a listener is removed\n\t */\n\tonWillRemoveListener?: Function;\n\t/**\n\t * Optional function that's called when a listener throws an error. Defaults to\n\t * {@link onUnexpectedError}\n\t */\n\tonListenerError?: (e: any) => void;\n\t/**\n\t * Number of listeners that are allowed before assuming a leak. Default to\n\t * a globally configured value\n\t *\n\t * @see setGlobalLeakWarningThreshold\n\t */\n\tleakWarningThreshold?: number;\n\t/**\n\t * Pass in a delivery queue, which is useful for ensuring\n\t * in order event delivery across multiple emitters.\n\t */\n\tdeliveryQueue?: EventDeliveryQueue;\n\n\t/** ONLY enable this during development */\n\t_profName?: string;\n}\n\n\nexport class EventProfiling {\n\n\tstatic readonly all = new Set();\n\n\tprivate static _idPool = 0;\n\n\treadonly name: string;\n\tpublic listenerCount: number = 0;\n\tpublic invocationCount = 0;\n\tpublic elapsedOverall = 0;\n\tpublic durations: number[] = [];\n\n\tprivate _stopWatch?: StopWatch;\n\n\tconstructor(name: string) {\n\t\tthis.name = `${name}_${EventProfiling._idPool++}`;\n\t\tEventProfiling.all.add(this);\n\t}\n\n\tstart(listenerCount: number): void {\n\t\tthis._stopWatch = new StopWatch();\n\t\tthis.listenerCount = listenerCount;\n\t}\n\n\tstop(): void {\n\t\tif (this._stopWatch) {\n\t\t\tconst elapsed = this._stopWatch.elapsed();\n\t\t\tthis.durations.push(elapsed);\n\t\t\tthis.elapsedOverall += elapsed;\n\t\t\tthis.invocationCount += 1;\n\t\t\tthis._stopWatch = undefined;\n\t\t}\n\t}\n}\n\nlet _globalLeakWarningThreshold = -1;\n\nclass LeakageMonitor {\n\n\tprivate _stacks: Map | undefined;\n\tprivate _warnCountdown: number = 0;\n\n\tconstructor(\n\t\tprivate readonly _errorHandler: (err: Error) => void,\n\t\treadonly threshold: number,\n\t\treadonly name: string = Math.random().toString(18).slice(2, 5),\n\t) { }\n\n\tdispose(): void {\n\t\tthis._stacks?.clear();\n\t}\n\n\tcheck(stack: Stacktrace, listenerCount: number): undefined | (() => void) {\n\n\t\tconst threshold = this.threshold;\n\t\tif (threshold <= 0 || listenerCount < threshold) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (!this._stacks) {\n\t\t\tthis._stacks = new Map();\n\t\t}\n\t\tconst count = (this._stacks.get(stack.value) || 0);\n\t\tthis._stacks.set(stack.value, count + 1);\n\t\tthis._warnCountdown -= 1;\n\n\t\tif (this._warnCountdown <= 0) {\n\t\t\t// only warn on first exceed and then every time the limit\n\t\t\t// is exceeded by 50% again\n\t\t\tthis._warnCountdown = threshold * 0.5;\n\n\t\t\tconst [topStack, topCount] = this.getMostFrequentStack()!;\n\t\t\tconst message = `[${this.name}] potential listener LEAK detected, having ${listenerCount} listeners already. MOST frequent listener (${topCount}):`;\n\t\t\tconsole.warn(message);\n\t\t\tconsole.warn(topStack!);\n\n\t\t\tconst error = new ListenerLeakError(message, topStack);\n\t\t\tthis._errorHandler(error);\n\t\t}\n\n\t\treturn () => {\n\t\t\tconst count = (this._stacks!.get(stack.value) || 0);\n\t\t\tthis._stacks!.set(stack.value, count - 1);\n\t\t};\n\t}\n\n\tgetMostFrequentStack(): [string, number] | undefined {\n\t\tif (!this._stacks) {\n\t\t\treturn undefined;\n\t\t}\n\t\tlet topStack: [string, number] | undefined;\n\t\tlet topCount: number = 0;\n\t\tfor (const [stack, count] of this._stacks) {\n\t\t\tif (!topStack || topCount < count) {\n\t\t\t\ttopStack = [stack, count];\n\t\t\t\ttopCount = count;\n\t\t\t}\n\t\t}\n\t\treturn topStack;\n\t}\n}\n\nclass Stacktrace {\n\n\tstatic create() {\n\t\tconst err = new Error();\n\t\treturn new Stacktrace(err.stack ?? '');\n\t}\n\n\tprivate constructor(readonly value: string) { }\n\n\tprint() {\n\t\tconsole.warn(this.value.split('\\n').slice(2).join('\\n'));\n\t}\n}\n\n// error that is logged when going over the configured listener threshold\nexport class ListenerLeakError extends Error {\n\tconstructor(message: string, stack: string) {\n\t\tsuper(message);\n\t\tthis.name = 'ListenerLeakError';\n\t\tthis.stack = stack;\n\t}\n}\n\n// SEVERE error that is logged when having gone way over the configured listener\n// threshold so that the emitter refuses to accept more listeners\nexport class ListenerRefusalError extends Error {\n\tconstructor(message: string, stack: string) {\n\t\tsuper(message);\n\t\tthis.name = 'ListenerRefusalError';\n\t\tthis.stack = stack;\n\t}\n}\nclass UniqueContainer {\n\tstack?: Stacktrace;\n\tconstructor(public readonly value: T) { }\n}\nconst compactionThreshold = 2;\n\ntype ListenerContainer = UniqueContainer<(data: T) => void>;\ntype ListenerOrListeners = (ListenerContainer | undefined)[] | ListenerContainer;\n\nconst forEachListener = (listeners: ListenerOrListeners, fn: (c: ListenerContainer) => void) => {\n\tif (listeners instanceof UniqueContainer) {\n\t\tfn(listeners);\n\t} else {\n\t\tfor (let i = 0; i < listeners.length; i++) {\n\t\t\tconst l = listeners[i];\n\t\t\tif (l) {\n\t\t\t\tfn(l);\n\t\t\t}\n\t\t}\n\t}\n};\n\n\nconst _listenerFinalizers = _enableListenerGCedWarning\n\t? new FinalizationRegistry(heldValue => {\n\t\tif (typeof heldValue === 'string') {\n\t\t\tconsole.warn('[LEAKING LISTENER] GC\\'ed a listener that was NOT yet disposed. This is where is was created:');\n\t\t\tconsole.warn(heldValue);\n\t\t}\n\t})\n\t: undefined;\n\n/**\n * The Emitter can be used to expose an Event to the public\n * to fire it from the insides.\n * Sample:\n\tclass Document {\n\n\t\tprivate readonly _onDidChange = new Emitter<(value:string)=>any>();\n\n\t\tpublic onDidChange = this._onDidChange.event;\n\n\t\t// getter-style\n\t\t// get onDidChange(): Event<(value:string)=>any> {\n\t\t// \treturn this._onDidChange.event;\n\t\t// }\n\n\t\tprivate _doIt() {\n\t\t\t//...\n\t\t\tthis._onDidChange.fire(value);\n\t\t}\n\t}\n */\nexport class Emitter {\n\n\tprivate readonly _options?: EmitterOptions;\n\tprivate readonly _leakageMon?: LeakageMonitor;\n\tprivate readonly _perfMon?: EventProfiling;\n\tprivate _disposed?: true;\n\tprivate _event?: Event;\n\n\t/**\n\t * A listener, or list of listeners. A single listener is the most common\n\t * for event emitters (#185789), so we optimize that special case to avoid\n\t * wrapping it in an array (just like Node.js itself.)\n\t *\n\t * A list of listeners never 'downgrades' back to a plain function if\n\t * listeners are removed, for two reasons:\n\t *\n\t * 1. That's complicated (especially with the deliveryQueue)\n\t * 2. A listener with >1 listener is likely to have >1 listener again at\n\t * some point, and swapping between arrays and functions may[citation needed]\n\t * introduce unnecessary work and garbage.\n\t *\n\t * The array listeners can be 'sparse', to avoid reallocating the array\n\t * whenever any listener is added or removed. If more than `1 / compactionThreshold`\n\t * of the array is empty, only then is it resized.\n\t */\n\tprotected _listeners?: ListenerOrListeners;\n\n\t/**\n\t * Always to be defined if _listeners is an array. It's no longer a true\n\t * queue, but holds the dispatching 'state'. If `fire()` is called on an\n\t * emitter, any work left in the _deliveryQueue is finished first.\n\t */\n\tprivate _deliveryQueue?: EventDeliveryQueuePrivate;\n\tprotected _size = 0;\n\n\tconstructor(options?: EmitterOptions) {\n\t\tthis._options = options;\n\t\tthis._leakageMon = (_globalLeakWarningThreshold > 0 || this._options?.leakWarningThreshold)\n\t\t\t? new LeakageMonitor(options?.onListenerError ?? onUnexpectedError, this._options?.leakWarningThreshold ?? _globalLeakWarningThreshold) :\n\t\t\tundefined;\n\t\tthis._perfMon = this._options?._profName ? new EventProfiling(this._options._profName) : undefined;\n\t\tthis._deliveryQueue = this._options?.deliveryQueue as EventDeliveryQueuePrivate | undefined;\n\t}\n\n\tdispose() {\n\t\tif (!this._disposed) {\n\t\t\tthis._disposed = true;\n\n\t\t\t// It is bad to have listeners at the time of disposing an emitter, it is worst to have listeners keep the emitter\n\t\t\t// alive via the reference that's embedded in their disposables. Therefore we loop over all remaining listeners and\n\t\t\t// unset their subscriptions/disposables. Looping and blaming remaining listeners is done on next tick because the\n\t\t\t// the following programming pattern is very popular:\n\t\t\t//\n\t\t\t// const someModel = this._disposables.add(new ModelObject()); // (1) create and register model\n\t\t\t// this._disposables.add(someModel.onDidChange(() => { ... }); // (2) subscribe and register model-event listener\n\t\t\t// ...later...\n\t\t\t// this._disposables.dispose(); disposes (1) then (2): don't warn after (1) but after the \"overall dispose\" is done\n\n\t\t\tif (this._deliveryQueue?.current === this) {\n\t\t\t\tthis._deliveryQueue.reset();\n\t\t\t}\n\t\t\tif (this._listeners) {\n\t\t\t\tif (_enableDisposeWithListenerWarning) {\n\t\t\t\t\tconst listeners = this._listeners;\n\t\t\t\t\tqueueMicrotask(() => {\n\t\t\t\t\t\tforEachListener(listeners, l => l.stack?.print());\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tthis._listeners = undefined;\n\t\t\t\tthis._size = 0;\n\t\t\t}\n\t\t\tthis._options?.onDidRemoveLastListener?.();\n\t\t\tthis._leakageMon?.dispose();\n\t\t}\n\t}\n\n\t/**\n\t * For the public to allow to subscribe\n\t * to events from this Emitter\n\t */\n\tget event(): Event {\n\t\tthis._event ??= (callback: (e: T) => any, thisArgs?: any, disposables?: IDisposable[] | DisposableStore) => {\n\t\t\tif (this._leakageMon && this._size > this._leakageMon.threshold ** 2) {\n\t\t\t\tconst message = `[${this._leakageMon.name}] REFUSES to accept new listeners because it exceeded its threshold by far (${this._size} vs ${this._leakageMon.threshold})`;\n\t\t\t\tconsole.warn(message);\n\n\t\t\t\tconst tuple = this._leakageMon.getMostFrequentStack() ?? ['UNKNOWN stack', -1];\n\t\t\t\tconst error = new ListenerRefusalError(`${message}. HINT: Stack shows most frequent listener (${tuple[1]}-times)`, tuple[0]);\n\t\t\t\tconst errorHandler = this._options?.onListenerError || onUnexpectedError;\n\t\t\t\terrorHandler(error);\n\n\t\t\t\treturn Disposable.None;\n\t\t\t}\n\n\t\t\tif (this._disposed) {\n\t\t\t\t// todo: should we warn if a listener is added to a disposed emitter? This happens often\n\t\t\t\treturn Disposable.None;\n\t\t\t}\n\n\t\t\tif (thisArgs) {\n\t\t\t\tcallback = callback.bind(thisArgs);\n\t\t\t}\n\n\t\t\tconst contained = new UniqueContainer(callback);\n\n\t\t\tlet removeMonitor: Function | undefined;\n\t\t\tlet stack: Stacktrace | undefined;\n\t\t\tif (this._leakageMon && this._size >= Math.ceil(this._leakageMon.threshold * 0.2)) {\n\t\t\t\t// check and record this emitter for potential leakage\n\t\t\t\tcontained.stack = Stacktrace.create();\n\t\t\t\tremoveMonitor = this._leakageMon.check(contained.stack, this._size + 1);\n\t\t\t}\n\n\t\t\tif (_enableDisposeWithListenerWarning) {\n\t\t\t\tcontained.stack = stack ?? Stacktrace.create();\n\t\t\t}\n\n\t\t\tif (!this._listeners) {\n\t\t\t\tthis._options?.onWillAddFirstListener?.(this);\n\t\t\t\tthis._listeners = contained;\n\t\t\t\tthis._options?.onDidAddFirstListener?.(this);\n\t\t\t} else if (this._listeners instanceof UniqueContainer) {\n\t\t\t\tthis._deliveryQueue ??= new EventDeliveryQueuePrivate();\n\t\t\t\tthis._listeners = [this._listeners, contained];\n\t\t\t} else {\n\t\t\t\tthis._listeners.push(contained);\n\t\t\t}\n\n\t\t\tthis._size++;\n\n\n\t\t\tconst result = toDisposable(() => {\n\t\t\t\t_listenerFinalizers?.unregister(result);\n\t\t\t\tremoveMonitor?.();\n\t\t\t\tthis._removeListener(contained);\n\t\t\t});\n\t\t\tif (disposables instanceof DisposableStore) {\n\t\t\t\tdisposables.add(result);\n\t\t\t} else if (Array.isArray(disposables)) {\n\t\t\t\tdisposables.push(result);\n\t\t\t}\n\n\t\t\tif (_listenerFinalizers) {\n\t\t\t\tconst stack = new Error().stack!.split('\\n').slice(2).join('\\n').trim();\n\t\t\t\t_listenerFinalizers.register(result, stack, result);\n\t\t\t}\n\n\t\t\treturn result;\n\t\t};\n\n\t\treturn this._event;\n\t}\n\n\tprivate _removeListener(listener: ListenerContainer) {\n\t\tthis._options?.onWillRemoveListener?.(this);\n\n\t\tif (!this._listeners) {\n\t\t\treturn; // expected if a listener gets disposed\n\t\t}\n\n\t\tif (this._size === 1) {\n\t\t\tthis._listeners = undefined;\n\t\t\tthis._options?.onDidRemoveLastListener?.(this);\n\t\t\tthis._size = 0;\n\t\t\treturn;\n\t\t}\n\n\t\t// size > 1 which requires that listeners be a list:\n\t\tconst listeners = this._listeners as (ListenerContainer | undefined)[];\n\n\t\tconst index = listeners.indexOf(listener);\n\t\tif (index === -1) {\n\t\t\tconsole.log('disposed?', this._disposed);\n\t\t\tconsole.log('size?', this._size);\n\t\t\tconsole.log('arr?', JSON.stringify(this._listeners));\n\t\t\tthrow new Error('Attempted to dispose unknown listener');\n\t\t}\n\n\t\tthis._size--;\n\t\tlisteners[index] = undefined;\n\n\t\tconst adjustDeliveryQueue = this._deliveryQueue!.current === this;\n\t\tif (this._size * compactionThreshold <= listeners.length) {\n\t\t\tlet n = 0;\n\t\t\tfor (let i = 0; i < listeners.length; i++) {\n\t\t\t\tif (listeners[i]) {\n\t\t\t\t\tlisteners[n++] = listeners[i];\n\t\t\t\t} else if (adjustDeliveryQueue) {\n\t\t\t\t\tthis._deliveryQueue!.end--;\n\t\t\t\t\tif (n < this._deliveryQueue!.i) {\n\t\t\t\t\t\tthis._deliveryQueue!.i--;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tlisteners.length = n;\n\t\t}\n\t}\n\n\tprivate _deliver(listener: undefined | UniqueContainer<(value: T) => void>, value: T) {\n\t\tif (!listener) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst errorHandler = this._options?.onListenerError || onUnexpectedError;\n\t\tif (!errorHandler) {\n\t\t\tlistener.value(value);\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tlistener.value(value);\n\t\t} catch (e) {\n\t\t\terrorHandler(e);\n\t\t}\n\t}\n\n\t/** Delivers items in the queue. Assumes the queue is ready to go. */\n\tprivate _deliverQueue(dq: EventDeliveryQueuePrivate) {\n\t\tconst listeners = dq.current!._listeners! as (ListenerContainer | undefined)[];\n\t\twhile (dq.i < dq.end) {\n\t\t\t// important: dq.i is incremented before calling deliver() because it might reenter deliverQueue()\n\t\t\tthis._deliver(listeners[dq.i++], dq.value as T);\n\t\t}\n\t\tdq.reset();\n\t}\n\n\t/**\n\t * To be kept private to fire an event to\n\t * subscribers\n\t */\n\tfire(event: T): void {\n\t\tif (this._deliveryQueue?.current) {\n\t\t\tthis._deliverQueue(this._deliveryQueue);\n\t\t\tthis._perfMon?.stop(); // last fire() will have starting perfmon, stop it before starting the next dispatch\n\t\t}\n\n\t\tthis._perfMon?.start(this._size);\n\n\t\tif (!this._listeners) {\n\t\t\t// no-op\n\t\t} else if (this._listeners instanceof UniqueContainer) {\n\t\t\tthis._deliver(this._listeners, event);\n\t\t} else {\n\t\t\tconst dq = this._deliveryQueue!;\n\t\t\tdq.enqueue(this, event, this._listeners.length);\n\t\t\tthis._deliverQueue(dq);\n\t\t}\n\n\t\tthis._perfMon?.stop();\n\t}\n\n\thasListeners(): boolean {\n\t\treturn this._size > 0;\n\t}\n}\n\nexport interface EventDeliveryQueue {\n}\n\nexport const createEventDeliveryQueue = (): EventDeliveryQueue => new EventDeliveryQueuePrivate();\n\nclass EventDeliveryQueuePrivate implements EventDeliveryQueue {\n\n\t/**\n\t * Index in current's listener list.\n\t */\n\tpublic i = -1;\n\n\t/**\n\t * The last index in the listener's list to deliver.\n\t */\n\tpublic end = 0;\n\n\t/**\n\t * Emitter currently being dispatched on. Emitter._listeners is always an array.\n\t */\n\tpublic current?: Emitter;\n\t/**\n\t * Currently emitting value. Defined whenever `current` is.\n\t */\n\tpublic value?: unknown;\n\n\tpublic enqueue(emitter: Emitter, value: T, end: number) {\n\t\tthis.i = 0;\n\t\tthis.end = end;\n\t\tthis.current = emitter;\n\t\tthis.value = value;\n\t}\n\n\tpublic reset() {\n\t\tthis.i = this.end; // force any current emission loop to stop, mainly for during dispose\n\t\tthis.current = undefined;\n\t\tthis.value = undefined;\n\t}\n}\n\n\nexport class PauseableEmitter extends Emitter {\n\n\tprivate _isPaused = 0;\n\tprotected _eventQueue = new LinkedList();\n\tprivate _mergeFn?: (input: T[]) => T;\n\n\tconstructor(options?: EmitterOptions & { merge?: (input: T[]) => T }) {\n\t\tsuper(options);\n\t\tthis._mergeFn = options?.merge;\n\t}\n\n\tpause(): void {\n\t\tthis._isPaused++;\n\t}\n\n\tresume(): void {\n\t\tif (this._isPaused !== 0 && --this._isPaused === 0) {\n\t\t\tif (this._mergeFn) {\n\t\t\t\t// use the merge function to create a single composite\n\t\t\t\t// event. make a copy in case firing pauses this emitter\n\t\t\t\tif (this._eventQueue.size > 0) {\n\t\t\t\t\tconst events = Array.from(this._eventQueue);\n\t\t\t\t\tthis._eventQueue.clear();\n\t\t\t\t\tsuper.fire(this._mergeFn(events));\n\t\t\t\t}\n\n\t\t\t} else {\n\t\t\t\t// no merging, fire each event individually and test\n\t\t\t\t// that this emitter isn't paused halfway through\n\t\t\t\twhile (!this._isPaused && this._eventQueue.size !== 0) {\n\t\t\t\t\tsuper.fire(this._eventQueue.shift()!);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\toverride fire(event: T): void {\n\t\tif (this._size) {\n\t\t\tif (this._isPaused !== 0) {\n\t\t\t\tthis._eventQueue.push(event);\n\t\t\t} else {\n\t\t\t\tsuper.fire(event);\n\t\t\t}\n\t\t}\n\t}\n}\n\nexport class DebounceEmitter extends PauseableEmitter {\n\n\tprivate readonly _delay: number;\n\tprivate _handle: any | undefined;\n\n\tconstructor(options: EmitterOptions & { merge: (input: T[]) => T; delay?: number }) {\n\t\tsuper(options);\n\t\tthis._delay = options.delay ?? 100;\n\t}\n\n\toverride fire(event: T): void {\n\t\tif (!this._handle) {\n\t\t\tthis.pause();\n\t\t\tthis._handle = setTimeout(() => {\n\t\t\t\tthis._handle = undefined;\n\t\t\t\tthis.resume();\n\t\t\t}, this._delay);\n\t\t}\n\t\tsuper.fire(event);\n\t}\n}\n\n/**\n * An emitter which queue all events and then process them at the\n * end of the event loop.\n */\nexport class MicrotaskEmitter extends Emitter {\n\tprivate _queuedEvents: T[] = [];\n\tprivate _mergeFn?: (input: T[]) => T;\n\n\tconstructor(options?: EmitterOptions & { merge?: (input: T[]) => T }) {\n\t\tsuper(options);\n\t\tthis._mergeFn = options?.merge;\n\t}\n\toverride fire(event: T): void {\n\n\t\tif (!this.hasListeners()) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._queuedEvents.push(event);\n\t\tif (this._queuedEvents.length === 1) {\n\t\t\tqueueMicrotask(() => {\n\t\t\t\tif (this._mergeFn) {\n\t\t\t\t\tsuper.fire(this._mergeFn(this._queuedEvents));\n\t\t\t\t} else {\n\t\t\t\t\tthis._queuedEvents.forEach(e => super.fire(e));\n\t\t\t\t}\n\t\t\t\tthis._queuedEvents = [];\n\t\t\t});\n\t\t}\n\t}\n}\n\n/**\n * An event emitter that multiplexes many events into a single event.\n *\n * @example Listen to the `onData` event of all `Thing`s, dynamically adding and removing `Thing`s\n * to the multiplexer as needed.\n *\n * ```typescript\n * const anythingDataMultiplexer = new EventMultiplexer<{ data: string }>();\n *\n * const thingListeners = DisposableMap();\n *\n * thingService.onDidAddThing(thing => {\n * thingListeners.set(thing, anythingDataMultiplexer.add(thing.onData);\n * });\n * thingService.onDidRemoveThing(thing => {\n * thingListeners.deleteAndDispose(thing);\n * });\n *\n * anythingDataMultiplexer.event(e => {\n * console.log('Something fired data ' + e.data)\n * });\n * ```\n */\nexport class EventMultiplexer implements IDisposable {\n\n\tprivate readonly emitter: Emitter;\n\tprivate hasListeners = false;\n\tprivate events: { event: Event; listener: IDisposable | null }[] = [];\n\n\tconstructor() {\n\t\tthis.emitter = new Emitter({\n\t\t\tonWillAddFirstListener: () => this.onFirstListenerAdd(),\n\t\t\tonDidRemoveLastListener: () => this.onLastListenerRemove()\n\t\t});\n\t}\n\n\tget event(): Event {\n\t\treturn this.emitter.event;\n\t}\n\n\tadd(event: Event): IDisposable {\n\t\tconst e = { event: event, listener: null };\n\t\tthis.events.push(e);\n\n\t\tif (this.hasListeners) {\n\t\t\tthis.hook(e);\n\t\t}\n\n\t\tconst dispose = () => {\n\t\t\tif (this.hasListeners) {\n\t\t\t\tthis.unhook(e);\n\t\t\t}\n\n\t\t\tconst idx = this.events.indexOf(e);\n\t\t\tthis.events.splice(idx, 1);\n\t\t};\n\n\t\treturn toDisposable(createSingleCallFunction(dispose));\n\t}\n\n\tprivate onFirstListenerAdd(): void {\n\t\tthis.hasListeners = true;\n\t\tthis.events.forEach(e => this.hook(e));\n\t}\n\n\tprivate onLastListenerRemove(): void {\n\t\tthis.hasListeners = false;\n\t\tthis.events.forEach(e => this.unhook(e));\n\t}\n\n\tprivate hook(e: { event: Event; listener: IDisposable | null }): void {\n\t\te.listener = e.event(r => this.emitter.fire(r));\n\t}\n\n\tprivate unhook(e: { event: Event; listener: IDisposable | null }): void {\n\t\te.listener?.dispose();\n\t\te.listener = null;\n\t}\n\n\tdispose(): void {\n\t\tthis.emitter.dispose();\n\n\t\tfor (const e of this.events) {\n\t\t\te.listener?.dispose();\n\t\t}\n\t\tthis.events = [];\n\t}\n}\n\n/**\n * The EventBufferer is useful in situations in which you want\n * to delay firing your events during some code.\n * You can wrap that code and be sure that the event will not\n * be fired during that wrap.\n *\n * ```\n * const emitter: Emitter;\n * const delayer = new EventDelayer();\n * const delayedEvent = delayer.wrapEvent(emitter.event);\n *\n * delayedEvent(console.log);\n *\n * delayer.bufferEvents(() => {\n * emitter.fire(); // event will not be fired yet\n * });\n *\n * // event will only be fired at this point\n * ```\n */\nexport class EventBufferer {\n\n\tprivate data: { buffers: Function[] }[] = [];\n\n\twrapEvent(event: Event): Event;\n\twrapEvent(event: Event, reduce: (last: T | undefined, event: T) => T): Event;\n\twrapEvent(event: Event, reduce: (last: O | undefined, event: T) => O, initial: O): Event;\n\twrapEvent(event: Event, reduce?: (last: T | O | undefined, event: T) => T | O, initial?: O): Event {\n\t\treturn (listener, thisArgs?, disposables?) => {\n\t\t\treturn event(i => {\n\t\t\t\tconst data = this.data[this.data.length - 1];\n\n\t\t\t\t// Non-reduce scenario\n\t\t\t\tif (!reduce) {\n\t\t\t\t\t// Buffering case\n\t\t\t\t\tif (data) {\n\t\t\t\t\t\tdata.buffers.push(() => listener.call(thisArgs, i));\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Not buffering case\n\t\t\t\t\t\tlistener.call(thisArgs, i);\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Reduce scenario\n\t\t\t\tconst reduceData = data as typeof data & {\n\t\t\t\t\t/**\n\t\t\t\t\t * The accumulated items that will be reduced.\n\t\t\t\t\t */\n\t\t\t\t\titems?: T[];\n\t\t\t\t\t/**\n\t\t\t\t\t * The reduced result cached to be shared with other listeners.\n\t\t\t\t\t */\n\t\t\t\t\treducedResult?: T | O;\n\t\t\t\t};\n\n\t\t\t\t// Not buffering case\n\t\t\t\tif (!reduceData) {\n\t\t\t\t\t// TODO: Is there a way to cache this reduce call for all listeners?\n\t\t\t\t\tlistener.call(thisArgs, reduce(initial, i));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Buffering case\n\t\t\t\treduceData.items ??= [];\n\t\t\t\treduceData.items.push(i);\n\t\t\t\tif (reduceData.buffers.length === 0) {\n\t\t\t\t\t// Include a single buffered function that will reduce all events when we're done buffering events\n\t\t\t\t\tdata.buffers.push(() => {\n\t\t\t\t\t\t// cache the reduced result so that the value can be shared across all listeners\n\t\t\t\t\t\treduceData.reducedResult ??= initial\n\t\t\t\t\t\t\t? reduceData.items!.reduce(reduce as (last: O | undefined, event: T) => O, initial)\n\t\t\t\t\t\t\t: reduceData.items!.reduce(reduce as (last: T | undefined, event: T) => T);\n\t\t\t\t\t\tlistener.call(thisArgs, reduceData.reducedResult);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}, undefined, disposables);\n\t\t};\n\t}\n\n\tbufferEvents(fn: () => R): R {\n\t\tconst data = { buffers: new Array() };\n\t\tthis.data.push(data);\n\t\tconst r = fn();\n\t\tthis.data.pop();\n\t\tdata.buffers.forEach(flush => flush());\n\t\treturn r;\n\t}\n}\n\n/**\n * A Relay is an event forwarder which functions as a replugabble event pipe.\n * Once created, you can connect an input event to it and it will simply forward\n * events from that input event through its own `event` property. The `input`\n * can be changed at any point in time.\n */\nexport class Relay implements IDisposable {\n\n\tprivate listening = false;\n\tprivate inputEvent: Event = Event.None;\n\tprivate inputEventListener: IDisposable = Disposable.None;\n\n\tprivate readonly emitter = new Emitter({\n\t\tonDidAddFirstListener: () => {\n\t\t\tthis.listening = true;\n\t\t\tthis.inputEventListener = this.inputEvent(this.emitter.fire, this.emitter);\n\t\t},\n\t\tonDidRemoveLastListener: () => {\n\t\t\tthis.listening = false;\n\t\t\tthis.inputEventListener.dispose();\n\t\t}\n\t});\n\n\treadonly event: Event = this.emitter.event;\n\n\tset input(event: Event) {\n\t\tthis.inputEvent = event;\n\n\t\tif (this.listening) {\n\t\t\tthis.inputEventListener.dispose();\n\t\t\tthis.inputEventListener = event(this.emitter.fire, this.emitter);\n\t\t}\n\t}\n\n\tdispose() {\n\t\tthis.inputEventListener.dispose();\n\t\tthis.emitter.dispose();\n\t}\n}\n\nexport interface IValueWithChangeEvent {\n\treadonly onDidChange: Event;\n\tget value(): T;\n}\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\nimport { GestureEvent } from 'vs/base/browser/touch';\nimport { Emitter, Event as BaseEvent } from 'vs/base/common/event';\nimport { IDisposable } from 'vs/base/common/lifecycle';\n\nexport type EventHandler = HTMLElement | HTMLDocument | Window;\n\nexport interface DOMEventMap extends HTMLElementEventMap, DocumentEventMap, WindowEventMap {\n\t'-monaco-gesturetap': GestureEvent;\n\t'-monaco-gesturechange': GestureEvent;\n\t'-monaco-gesturestart': GestureEvent;\n\t'-monaco-gesturesend': GestureEvent;\n\t'-monaco-gesturecontextmenu': GestureEvent;\n\t'compositionstart': CompositionEvent;\n\t'compositionupdate': CompositionEvent;\n\t'compositionend': CompositionEvent;\n}\n\nexport class DomEmitter implements IDisposable {\n\n\tprivate emitter: Emitter;\n\n\tget event(): BaseEvent {\n\t\treturn this.emitter.event;\n\t}\n\n\tconstructor(element: Window & typeof globalThis, type: WindowEventMap, useCapture?: boolean);\n\tconstructor(element: Document, type: DocumentEventMap, useCapture?: boolean);\n\tconstructor(element: EventHandler, type: K, useCapture?: boolean);\n\tconstructor(element: EventHandler, type: K, useCapture?: boolean) {\n\t\tconst fn = (e: Event) => this.emitter.fire(e as DOMEventMap[K]);\n\t\tthis.emitter = new Emitter({\n\t\t\tonWillAddFirstListener: () => element.addEventListener(type, fn, useCapture),\n\t\t\tonDidRemoveLastListener: () => element.removeEventListener(type, fn, useCapture)\n\t\t});\n\t}\n\n\tdispose(): void {\n\t\tthis.emitter.dispose();\n\t}\n}\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\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { DisposableStore, IDisposable } from 'vs/base/common/lifecycle';\n\nexport interface CancellationToken {\n\n\t/**\n\t * A flag signalling is cancellation has been requested.\n\t */\n\treadonly isCancellationRequested: boolean;\n\n\t/**\n\t * An event which fires when cancellation is requested. This event\n\t * only ever fires `once` as cancellation can only happen once. Listeners\n\t * that are registered after cancellation will be called (next event loop run),\n\t * but also only once.\n\t *\n\t * @event\n\t */\n\treadonly onCancellationRequested: (listener: (e: any) => any, thisArgs?: any, disposables?: IDisposable[]) => IDisposable;\n}\n\nconst shortcutEvent: Event = Object.freeze(function (callback, context?): IDisposable {\n\tconst handle = setTimeout(callback.bind(context), 0);\n\treturn { dispose() { clearTimeout(handle); } };\n});\n\nexport namespace CancellationToken {\n\n\texport function isCancellationToken(thing: unknown): thing is CancellationToken {\n\t\tif (thing === CancellationToken.None || thing === CancellationToken.Cancelled) {\n\t\t\treturn true;\n\t\t}\n\t\tif (thing instanceof MutableToken) {\n\t\t\treturn true;\n\t\t}\n\t\tif (!thing || typeof thing !== 'object') {\n\t\t\treturn false;\n\t\t}\n\t\treturn typeof (thing as CancellationToken).isCancellationRequested === 'boolean'\n\t\t\t&& typeof (thing as CancellationToken).onCancellationRequested === 'function';\n\t}\n\n\n\texport const None = Object.freeze({\n\t\tisCancellationRequested: false,\n\t\tonCancellationRequested: Event.None\n\t});\n\n\texport const Cancelled = Object.freeze({\n\t\tisCancellationRequested: true,\n\t\tonCancellationRequested: shortcutEvent\n\t});\n}\n\nclass MutableToken implements CancellationToken {\n\n\tprivate _isCancelled: boolean = false;\n\tprivate _emitter: Emitter | null = null;\n\n\tpublic cancel() {\n\t\tif (!this._isCancelled) {\n\t\t\tthis._isCancelled = true;\n\t\t\tif (this._emitter) {\n\t\t\t\tthis._emitter.fire(undefined);\n\t\t\t\tthis.dispose();\n\t\t\t}\n\t\t}\n\t}\n\n\tget isCancellationRequested(): boolean {\n\t\treturn this._isCancelled;\n\t}\n\n\tget onCancellationRequested(): Event {\n\t\tif (this._isCancelled) {\n\t\t\treturn shortcutEvent;\n\t\t}\n\t\tif (!this._emitter) {\n\t\t\tthis._emitter = new Emitter();\n\t\t}\n\t\treturn this._emitter.event;\n\t}\n\n\tpublic dispose(): void {\n\t\tif (this._emitter) {\n\t\t\tthis._emitter.dispose();\n\t\t\tthis._emitter = null;\n\t\t}\n\t}\n}\n\nexport class CancellationTokenSource {\n\n\tprivate _token?: CancellationToken = undefined;\n\tprivate _parentListener?: IDisposable = undefined;\n\n\tconstructor(parent?: CancellationToken) {\n\t\tthis._parentListener = parent && parent.onCancellationRequested(this.cancel, this);\n\t}\n\n\tget token(): CancellationToken {\n\t\tif (!this._token) {\n\t\t\t// be lazy and create the token only when\n\t\t\t// actually needed\n\t\t\tthis._token = new MutableToken();\n\t\t}\n\t\treturn this._token;\n\t}\n\n\tcancel(): void {\n\t\tif (!this._token) {\n\t\t\t// save an object by returning the default\n\t\t\t// cancelled token when cancellation happens\n\t\t\t// before someone asks for the token\n\t\t\tthis._token = CancellationToken.Cancelled;\n\n\t\t} else if (this._token instanceof MutableToken) {\n\t\t\t// actually cancel\n\t\t\tthis._token.cancel();\n\t\t}\n\t}\n\n\tdispose(cancel: boolean = false): void {\n\t\tif (cancel) {\n\t\t\tthis.cancel();\n\t\t}\n\t\tthis._parentListener?.dispose();\n\t\tif (!this._token) {\n\t\t\t// ensure to initialize with an empty token if we had none\n\t\t\tthis._token = CancellationToken.None;\n\n\t\t} else if (this._token instanceof MutableToken) {\n\t\t\t// actually dispose\n\t\t\tthis._token.dispose();\n\t\t}\n\t}\n}\n\nexport function cancelOnDispose(store: DisposableStore): CancellationToken {\n\tconst source = new CancellationTokenSource();\n\tstore.add({ dispose() { source.cancel(); } });\n\treturn source.token;\n}\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\nimport { Emitter } from 'vs/base/common/event';\n\nexport class IMEImpl {\n\n\tprivate readonly _onDidChange = new Emitter();\n\tpublic readonly onDidChange = this._onDidChange.event;\n\n\tprivate _enabled = true;\n\n\tpublic get enabled() {\n\t\treturn this._enabled;\n\t}\n\n\t/**\n\t * Enable IME\n\t */\n\tpublic enable(): void {\n\t\tthis._enabled = true;\n\t\tthis._onDidChange.fire();\n\t}\n\n\t/**\n\t * Disable IME\n\t */\n\tpublic disable(): void {\n\t\tthis._enabled = false;\n\t\tthis._onDidChange.fire();\n\t}\n}\n\nexport const IME = new IMEImpl();\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\nimport { Event } from 'vs/base/common/event';\nimport { DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle';\nimport { BaseObservable, ConvenientObservable, IObservable, IObserver, IReader, ITransaction, _setKeepObserved, _setRecomputeInitiallyAndOnChange, subtransaction, transaction } from 'vs/base/common/observableInternal/base';\nimport { DebugNameData, Owner, getFunctionName } from 'vs/base/common/observableInternal/debugName';\nimport { derived, derivedOpts } from 'vs/base/common/observableInternal/derived';\nimport { getLogger } from 'vs/base/common/observableInternal/logging';\nimport { IValueWithChangeEvent } from '../event';\n\n/**\n * Represents an efficient observable whose value never changes.\n */\nexport function constObservable(value: T): IObservable {\n\treturn new ConstObservable(value);\n}\n\nclass ConstObservable extends ConvenientObservable {\n\tconstructor(private readonly value: T) {\n\t\tsuper();\n\t}\n\n\tpublic override get debugName(): string {\n\t\treturn this.toString();\n\t}\n\n\tpublic get(): T {\n\t\treturn this.value;\n\t}\n\tpublic addObserver(observer: IObserver): void {\n\t\t// NO OP\n\t}\n\tpublic removeObserver(observer: IObserver): void {\n\t\t// NO OP\n\t}\n\n\toverride toString(): string {\n\t\treturn `Const: ${this.value}`;\n\t}\n}\n\nexport function observableFromEvent(\n\tevent: Event,\n\tgetValue: (args: TArgs | undefined) => T\n): IObservable {\n\treturn new FromEventObservable(event, getValue);\n}\n\nexport class FromEventObservable extends BaseObservable {\n\tpublic static globalTransaction: ITransaction | undefined;\n\n\tprivate value: T | undefined;\n\tprivate hasValue = false;\n\tprivate subscription: IDisposable | undefined;\n\n\tconstructor(\n\t\tprivate readonly event: Event,\n\t\tpublic readonly _getValue: (args: TArgs | undefined) => T\n\t) {\n\t\tsuper();\n\t}\n\n\tprivate getDebugName(): string | undefined {\n\t\treturn getFunctionName(this._getValue);\n\t}\n\n\tpublic get debugName(): string {\n\t\tconst name = this.getDebugName();\n\t\treturn 'From Event' + (name ? `: ${name}` : '');\n\t}\n\n\tprotected override onFirstObserverAdded(): void {\n\t\tthis.subscription = this.event(this.handleEvent);\n\t}\n\n\tprivate readonly handleEvent = (args: TArgs | undefined) => {\n\t\tconst newValue = this._getValue(args);\n\t\tconst oldValue = this.value;\n\n\t\tconst didChange = !this.hasValue || oldValue !== newValue;\n\t\tlet didRunTransaction = false;\n\n\t\tif (didChange) {\n\t\t\tthis.value = newValue;\n\n\t\t\tif (this.hasValue) {\n\t\t\t\tdidRunTransaction = true;\n\t\t\t\tsubtransaction(\n\t\t\t\t\tFromEventObservable.globalTransaction,\n\t\t\t\t\t(tx) => {\n\t\t\t\t\t\tgetLogger()?.handleFromEventObservableTriggered(this, { oldValue, newValue, change: undefined, didChange, hadValue: this.hasValue });\n\n\t\t\t\t\t\tfor (const o of this.observers) {\n\t\t\t\t\t\t\ttx.updateObserver(o, this);\n\t\t\t\t\t\t\to.handleChange(this, undefined);\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t() => {\n\t\t\t\t\t\tconst name = this.getDebugName();\n\t\t\t\t\t\treturn 'Event fired' + (name ? `: ${name}` : '');\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t}\n\t\t\tthis.hasValue = true;\n\t\t}\n\n\t\tif (!didRunTransaction) {\n\t\t\tgetLogger()?.handleFromEventObservableTriggered(this, { oldValue, newValue, change: undefined, didChange, hadValue: this.hasValue });\n\t\t}\n\t};\n\n\tprotected override onLastObserverRemoved(): void {\n\t\tthis.subscription!.dispose();\n\t\tthis.subscription = undefined;\n\t\tthis.hasValue = false;\n\t\tthis.value = undefined;\n\t}\n\n\tpublic get(): T {\n\t\tif (this.subscription) {\n\t\t\tif (!this.hasValue) {\n\t\t\t\tthis.handleEvent(undefined);\n\t\t\t}\n\t\t\treturn this.value!;\n\t\t} else {\n\t\t\t// no cache, as there are no subscribers to keep it updated\n\t\t\tconst value = this._getValue(undefined);\n\t\t\treturn value;\n\t\t}\n\t}\n}\n\nexport namespace observableFromEvent {\n\texport const Observer = FromEventObservable;\n\n\texport function batchEventsGlobally(tx: ITransaction, fn: () => void): void {\n\t\tlet didSet = false;\n\t\tif (FromEventObservable.globalTransaction === undefined) {\n\t\t\tFromEventObservable.globalTransaction = tx;\n\t\t\tdidSet = true;\n\t\t}\n\t\ttry {\n\t\t\tfn();\n\t\t} finally {\n\t\t\tif (didSet) {\n\t\t\t\tFromEventObservable.globalTransaction = undefined;\n\t\t\t}\n\t\t}\n\t}\n}\n\nexport function observableSignalFromEvent(\n\tdebugName: string,\n\tevent: Event\n): IObservable {\n\treturn new FromEventObservableSignal(debugName, event);\n}\n\nclass FromEventObservableSignal extends BaseObservable {\n\tprivate subscription: IDisposable | undefined;\n\n\tconstructor(\n\t\tpublic readonly debugName: string,\n\t\tprivate readonly event: Event,\n\t) {\n\t\tsuper();\n\t}\n\n\tprotected override onFirstObserverAdded(): void {\n\t\tthis.subscription = this.event(this.handleEvent);\n\t}\n\n\tprivate readonly handleEvent = () => {\n\t\ttransaction(\n\t\t\t(tx) => {\n\t\t\t\tfor (const o of this.observers) {\n\t\t\t\t\ttx.updateObserver(o, this);\n\t\t\t\t\to.handleChange(this, undefined);\n\t\t\t\t}\n\t\t\t},\n\t\t\t() => this.debugName\n\t\t);\n\t};\n\n\tprotected override onLastObserverRemoved(): void {\n\t\tthis.subscription!.dispose();\n\t\tthis.subscription = undefined;\n\t}\n\n\tpublic override get(): void {\n\t\t// NO OP\n\t}\n}\n\n/**\n * Creates a signal that can be triggered to invalidate observers.\n * Signals don't have a value - when they are triggered they indicate a change.\n * However, signals can carry a delta that is passed to observers.\n */\nexport function observableSignal(debugName: string): IObservableSignal;\nexport function observableSignal(owner: object): IObservableSignal;\nexport function observableSignal(debugNameOrOwner: string | object): IObservableSignal {\n\tif (typeof debugNameOrOwner === 'string') {\n\t\treturn new ObservableSignal(debugNameOrOwner);\n\t} else {\n\t\treturn new ObservableSignal(undefined, debugNameOrOwner);\n\t}\n}\n\nexport interface IObservableSignal extends IObservable {\n\ttrigger(tx: ITransaction | undefined, change: TChange): void;\n}\n\nclass ObservableSignal extends BaseObservable implements IObservableSignal {\n\tpublic get debugName() {\n\t\treturn new DebugNameData(this._owner, this._debugName, undefined).getDebugName(this) ?? 'Observable Signal';\n\t}\n\n\tconstructor(\n\t\tprivate readonly _debugName: string | undefined,\n\t\tprivate readonly _owner?: object,\n\t) {\n\t\tsuper();\n\t}\n\n\tpublic trigger(tx: ITransaction | undefined, change: TChange): void {\n\t\tif (!tx) {\n\t\t\ttransaction(tx => {\n\t\t\t\tthis.trigger(tx, change);\n\t\t\t}, () => `Trigger signal ${this.debugName}`);\n\t\t\treturn;\n\t\t}\n\n\t\tfor (const o of this.observers) {\n\t\t\ttx.updateObserver(o, this);\n\t\t\to.handleChange(this, change);\n\t\t}\n\t}\n\n\tpublic override get(): void {\n\t\t// NO OP\n\t}\n}\n\n/**\n * This makes sure the observable is being observed and keeps its cache alive.\n */\nexport function keepObserved(observable: IObservable): IDisposable {\n\tconst o = new KeepAliveObserver(false, undefined);\n\tobservable.addObserver(o);\n\treturn toDisposable(() => {\n\t\tobservable.removeObserver(o);\n\t});\n}\n\n_setKeepObserved(keepObserved);\n\n/**\n * This converts the given observable into an autorun.\n */\nexport function recomputeInitiallyAndOnChange(observable: IObservable, handleValue?: (value: T) => void): IDisposable {\n\tconst o = new KeepAliveObserver(true, handleValue);\n\tobservable.addObserver(o);\n\tif (handleValue) {\n\t\thandleValue(observable.get());\n\t} else {\n\t\tobservable.reportChanges();\n\t}\n\n\treturn toDisposable(() => {\n\t\tobservable.removeObserver(o);\n\t});\n}\n\n_setRecomputeInitiallyAndOnChange(recomputeInitiallyAndOnChange);\n\nexport class KeepAliveObserver implements IObserver {\n\tprivate _counter = 0;\n\n\tconstructor(\n\t\tprivate readonly _forceRecompute: boolean,\n\t\tprivate readonly _handleValue: ((value: any) => void) | undefined,\n\t) { }\n\n\tbeginUpdate(observable: IObservable): void {\n\t\tthis._counter++;\n\t}\n\n\tendUpdate(observable: IObservable): void {\n\t\tthis._counter--;\n\t\tif (this._counter === 0 && this._forceRecompute) {\n\t\t\tif (this._handleValue) {\n\t\t\t\tthis._handleValue(observable.get());\n\t\t\t} else {\n\t\t\t\tobservable.reportChanges();\n\t\t\t}\n\t\t}\n\t}\n\n\thandlePossibleChange(observable: IObservable): void {\n\t\t// NO OP\n\t}\n\n\thandleChange(observable: IObservable, change: TChange): void {\n\t\t// NO OP\n\t}\n}\n\nexport function derivedObservableWithCache(owner: Owner, computeFn: (reader: IReader, lastValue: T | undefined) => T): IObservable {\n\tlet lastValue: T | undefined = undefined;\n\tconst observable = derived(owner, reader => {\n\t\tlastValue = computeFn(reader, lastValue);\n\t\treturn lastValue;\n\t});\n\treturn observable;\n}\n\nexport function derivedObservableWithWritableCache(owner: object, computeFn: (reader: IReader, lastValue: T | undefined) => T): IObservable\n\t& { clearCache(transaction: ITransaction): void; setCache(newValue: T | undefined, tx: ITransaction | undefined): void } {\n\tlet lastValue: T | undefined = undefined;\n\tconst onChange = observableSignal('derivedObservableWithWritableCache');\n\tconst observable = derived(owner, reader => {\n\t\tonChange.read(reader);\n\t\tlastValue = computeFn(reader, lastValue);\n\t\treturn lastValue;\n\t});\n\treturn Object.assign(observable, {\n\t\tclearCache: (tx: ITransaction) => {\n\t\t\tlastValue = undefined;\n\t\t\tonChange.trigger(tx);\n\t\t},\n\t\tsetCache: (newValue: T | undefined, tx: ITransaction | undefined) => {\n\t\t\tlastValue = newValue;\n\t\t\tonChange.trigger(tx);\n\t\t}\n\t});\n}\n\n/**\n * When the items array changes, referential equal items are not mapped again.\n */\nexport function mapObservableArrayCached(owner: Owner, items: IObservable, map: (input: TIn, store: DisposableStore) => TOut, keySelector?: (input: TIn) => TKey): IObservable {\n\tlet m = new ArrayMap(map, keySelector);\n\tconst self = derivedOpts({\n\t\tdebugReferenceFn: map,\n\t\towner,\n\t\tonLastObserverRemoved: () => {\n\t\t\tm.dispose();\n\t\t\tm = new ArrayMap(map);\n\t\t}\n\t}, (reader) => {\n\t\tm.setItems(items.read(reader));\n\t\treturn m.getItems();\n\t});\n\treturn self;\n}\n\nclass ArrayMap implements IDisposable {\n\tprivate readonly _cache = new Map();\n\tprivate _items: TOut[] = [];\n\tconstructor(\n\t\tprivate readonly _map: (input: TIn, store: DisposableStore) => TOut,\n\t\tprivate readonly _keySelector?: (input: TIn) => TKey,\n\t) {\n\t}\n\n\tpublic dispose(): void {\n\t\tthis._cache.forEach(entry => entry.store.dispose());\n\t\tthis._cache.clear();\n\t}\n\n\tpublic setItems(items: readonly TIn[]): void {\n\t\tconst newItems: TOut[] = [];\n\t\tconst itemsToRemove = new Set(this._cache.keys());\n\n\t\tfor (const item of items) {\n\t\t\tconst key = this._keySelector ? this._keySelector(item) : item as unknown as TKey;\n\n\t\t\tlet entry = this._cache.get(key);\n\t\t\tif (!entry) {\n\t\t\t\tconst store = new DisposableStore();\n\t\t\t\tconst out = this._map(item, store);\n\t\t\t\tentry = { out, store };\n\t\t\t\tthis._cache.set(key, entry);\n\t\t\t} else {\n\t\t\t\titemsToRemove.delete(key);\n\t\t\t}\n\t\t\tnewItems.push(entry.out);\n\t\t}\n\n\t\tfor (const item of itemsToRemove) {\n\t\t\tconst entry = this._cache.get(item)!;\n\t\t\tentry.store.dispose();\n\t\t\tthis._cache.delete(item);\n\t\t}\n\n\t\tthis._items = newItems;\n\t}\n\n\tpublic getItems(): TOut[] {\n\t\treturn this._items;\n\t}\n}\n\nexport class ValueWithChangeEventFromObservable implements IValueWithChangeEvent {\n\tconstructor(public readonly observable: IObservable) {\n\t}\n\n\tget onDidChange(): Event {\n\t\treturn Event.fromObservableLight(this.observable);\n\t}\n\n\tget value(): T {\n\t\treturn this.observable.get();\n\t}\n}\n\nexport function observableFromValueWithChangeEvent(_owner: Owner, value: IValueWithChangeEvent): IObservable {\n\tif (value instanceof ValueWithChangeEventFromObservable) {\n\t\treturn value.observable;\n\t}\n\treturn observableFromEvent(value.onDidChange, () => value.value);\n}\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 facade for the observable implementation. Only import from here!\n\nexport {\n\tIObservable,\n\tIObserver,\n\tIReader,\n\tISettable,\n\tISettableObservable,\n\tITransaction,\n\tIChangeContext } from 'vs/base/common/observableInternal/base';\n\nexport {\n\tobservableValue,\n\tdisposableObservableValue,\n\ttransaction,\n\tsubtransaction } from 'vs/base/common/observableInternal/base';\nexport {\n\tderived,\n\tderivedOpts,\n\tderivedHandleChanges,\n\tderivedWithStore } from 'vs/base/common/observableInternal/derived';\nexport {\n\tautorun,\n\tautorunHandleChanges,\n\tautorunWithStore,\n\tautorunOpts } from 'vs/base/common/observableInternal/autorun';\nexport {\n\tIObservableSignal } from 'vs/base/common/observableInternal/utils';\nexport {\n\tconstObservable,\n\tderivedObservableWithCache,\n\tderivedObservableWithWritableCache,\n\tkeepObserved,\n\trecomputeInitiallyAndOnChange,\n\tobservableFromEvent,\n\tobservableSignal,\n\tobservableSignalFromEvent } from 'vs/base/common/observableInternal/utils';\nexport {\n\twaitForState } from 'vs/base/common/observableInternal/promise';\n\nimport { ConsoleObservableLogger, setLogger } from 'vs/base/common/observableInternal/logging';\n\n// Remove \"//\" in the next line to enable logging\nconst enableLogging = false\n\t// || Boolean(\"true\") // done \"weirdly\" so that a lint warning prevents you from pushing this\n\t;\n\nif (enableLogging) {\n\tsetLogger(new ConsoleObservableLogger());\n}\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\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { Disposable, IDisposable } from 'vs/base/common/lifecycle';\n\nexport const enum ScrollbarVisibility {\n\tAuto = 1,\n\tHidden = 2,\n\tVisible = 3\n}\n\nexport interface ScrollEvent {\n\tinSmoothScrolling: boolean;\n\n\toldWidth: number;\n\toldScrollWidth: number;\n\toldScrollLeft: number;\n\n\twidth: number;\n\tscrollWidth: number;\n\tscrollLeft: number;\n\n\toldHeight: number;\n\toldScrollHeight: number;\n\toldScrollTop: number;\n\n\theight: number;\n\tscrollHeight: number;\n\tscrollTop: number;\n\n\twidthChanged: boolean;\n\tscrollWidthChanged: boolean;\n\tscrollLeftChanged: boolean;\n\n\theightChanged: boolean;\n\tscrollHeightChanged: boolean;\n\tscrollTopChanged: boolean;\n}\n\nexport class ScrollState implements IScrollDimensions, IScrollPosition {\n\t_scrollStateBrand: void = undefined;\n\n\tpublic readonly rawScrollLeft: number;\n\tpublic readonly rawScrollTop: number;\n\n\tpublic readonly width: number;\n\tpublic readonly scrollWidth: number;\n\tpublic readonly scrollLeft: number;\n\tpublic readonly height: number;\n\tpublic readonly scrollHeight: number;\n\tpublic readonly scrollTop: number;\n\n\tconstructor(\n\t\tprivate readonly _forceIntegerValues: boolean,\n\t\twidth: number,\n\t\tscrollWidth: number,\n\t\tscrollLeft: number,\n\t\theight: number,\n\t\tscrollHeight: number,\n\t\tscrollTop: number\n\t) {\n\t\tif (this._forceIntegerValues) {\n\t\t\twidth = width | 0;\n\t\t\tscrollWidth = scrollWidth | 0;\n\t\t\tscrollLeft = scrollLeft | 0;\n\t\t\theight = height | 0;\n\t\t\tscrollHeight = scrollHeight | 0;\n\t\t\tscrollTop = scrollTop | 0;\n\t\t}\n\n\t\tthis.rawScrollLeft = scrollLeft; // before validation\n\t\tthis.rawScrollTop = scrollTop; // before validation\n\n\t\tif (width < 0) {\n\t\t\twidth = 0;\n\t\t}\n\t\tif (scrollLeft + width > scrollWidth) {\n\t\t\tscrollLeft = scrollWidth - width;\n\t\t}\n\t\tif (scrollLeft < 0) {\n\t\t\tscrollLeft = 0;\n\t\t}\n\n\t\tif (height < 0) {\n\t\t\theight = 0;\n\t\t}\n\t\tif (scrollTop + height > scrollHeight) {\n\t\t\tscrollTop = scrollHeight - height;\n\t\t}\n\t\tif (scrollTop < 0) {\n\t\t\tscrollTop = 0;\n\t\t}\n\n\t\tthis.width = width;\n\t\tthis.scrollWidth = scrollWidth;\n\t\tthis.scrollLeft = scrollLeft;\n\t\tthis.height = height;\n\t\tthis.scrollHeight = scrollHeight;\n\t\tthis.scrollTop = scrollTop;\n\t}\n\n\tpublic equals(other: ScrollState): boolean {\n\t\treturn (\n\t\t\tthis.rawScrollLeft === other.rawScrollLeft\n\t\t\t&& this.rawScrollTop === other.rawScrollTop\n\t\t\t&& this.width === other.width\n\t\t\t&& this.scrollWidth === other.scrollWidth\n\t\t\t&& this.scrollLeft === other.scrollLeft\n\t\t\t&& this.height === other.height\n\t\t\t&& this.scrollHeight === other.scrollHeight\n\t\t\t&& this.scrollTop === other.scrollTop\n\t\t);\n\t}\n\n\tpublic withScrollDimensions(update: INewScrollDimensions, useRawScrollPositions: boolean): ScrollState {\n\t\treturn new ScrollState(\n\t\t\tthis._forceIntegerValues,\n\t\t\t(typeof update.width !== 'undefined' ? update.width : this.width),\n\t\t\t(typeof update.scrollWidth !== 'undefined' ? update.scrollWidth : this.scrollWidth),\n\t\t\tuseRawScrollPositions ? this.rawScrollLeft : this.scrollLeft,\n\t\t\t(typeof update.height !== 'undefined' ? update.height : this.height),\n\t\t\t(typeof update.scrollHeight !== 'undefined' ? update.scrollHeight : this.scrollHeight),\n\t\t\tuseRawScrollPositions ? this.rawScrollTop : this.scrollTop\n\t\t);\n\t}\n\n\tpublic withScrollPosition(update: INewScrollPosition): ScrollState {\n\t\treturn new ScrollState(\n\t\t\tthis._forceIntegerValues,\n\t\t\tthis.width,\n\t\t\tthis.scrollWidth,\n\t\t\t(typeof update.scrollLeft !== 'undefined' ? update.scrollLeft : this.rawScrollLeft),\n\t\t\tthis.height,\n\t\t\tthis.scrollHeight,\n\t\t\t(typeof update.scrollTop !== 'undefined' ? update.scrollTop : this.rawScrollTop)\n\t\t);\n\t}\n\n\tpublic createScrollEvent(previous: ScrollState, inSmoothScrolling: boolean): ScrollEvent {\n\t\tconst widthChanged = (this.width !== previous.width);\n\t\tconst scrollWidthChanged = (this.scrollWidth !== previous.scrollWidth);\n\t\tconst scrollLeftChanged = (this.scrollLeft !== previous.scrollLeft);\n\n\t\tconst heightChanged = (this.height !== previous.height);\n\t\tconst scrollHeightChanged = (this.scrollHeight !== previous.scrollHeight);\n\t\tconst scrollTopChanged = (this.scrollTop !== previous.scrollTop);\n\n\t\treturn {\n\t\t\tinSmoothScrolling: inSmoothScrolling,\n\t\t\toldWidth: previous.width,\n\t\t\toldScrollWidth: previous.scrollWidth,\n\t\t\toldScrollLeft: previous.scrollLeft,\n\n\t\t\twidth: this.width,\n\t\t\tscrollWidth: this.scrollWidth,\n\t\t\tscrollLeft: this.scrollLeft,\n\n\t\t\toldHeight: previous.height,\n\t\t\toldScrollHeight: previous.scrollHeight,\n\t\t\toldScrollTop: previous.scrollTop,\n\n\t\t\theight: this.height,\n\t\t\tscrollHeight: this.scrollHeight,\n\t\t\tscrollTop: this.scrollTop,\n\n\t\t\twidthChanged: widthChanged,\n\t\t\tscrollWidthChanged: scrollWidthChanged,\n\t\t\tscrollLeftChanged: scrollLeftChanged,\n\n\t\t\theightChanged: heightChanged,\n\t\t\tscrollHeightChanged: scrollHeightChanged,\n\t\t\tscrollTopChanged: scrollTopChanged,\n\t\t};\n\t}\n\n}\n\nexport interface IScrollDimensions {\n\treadonly width: number;\n\treadonly scrollWidth: number;\n\treadonly height: number;\n\treadonly scrollHeight: number;\n}\nexport interface INewScrollDimensions {\n\twidth?: number;\n\tscrollWidth?: number;\n\theight?: number;\n\tscrollHeight?: number;\n}\n\nexport interface IScrollPosition {\n\treadonly scrollLeft: number;\n\treadonly scrollTop: number;\n}\nexport interface ISmoothScrollPosition {\n\treadonly scrollLeft: number;\n\treadonly scrollTop: number;\n\n\treadonly width: number;\n\treadonly height: number;\n}\nexport interface INewScrollPosition {\n\tscrollLeft?: number;\n\tscrollTop?: number;\n}\n\nexport interface IScrollableOptions {\n\t/**\n\t * Define if the scroll values should always be integers.\n\t */\n\tforceIntegerValues: boolean;\n\t/**\n\t * Set the duration (ms) used for smooth scroll animations.\n\t */\n\tsmoothScrollDuration: number;\n\t/**\n\t * A function to schedule an update at the next frame (used for smooth scroll animations).\n\t */\n\tscheduleAtNextAnimationFrame: (callback: () => void) => IDisposable;\n}\n\nexport class Scrollable extends Disposable {\n\n\t_scrollableBrand: void = undefined;\n\n\tprivate _smoothScrollDuration: number;\n\tprivate readonly _scheduleAtNextAnimationFrame: (callback: () => void) => IDisposable;\n\tprivate _state: ScrollState;\n\tprivate _smoothScrolling: SmoothScrollingOperation | null;\n\n\tprivate _onScroll = this._register(new Emitter());\n\tpublic readonly onScroll: Event = this._onScroll.event;\n\n\tconstructor(options: IScrollableOptions) {\n\t\tsuper();\n\n\t\tthis._smoothScrollDuration = options.smoothScrollDuration;\n\t\tthis._scheduleAtNextAnimationFrame = options.scheduleAtNextAnimationFrame;\n\t\tthis._state = new ScrollState(options.forceIntegerValues, 0, 0, 0, 0, 0, 0);\n\t\tthis._smoothScrolling = null;\n\t}\n\n\tpublic override dispose(): void {\n\t\tif (this._smoothScrolling) {\n\t\t\tthis._smoothScrolling.dispose();\n\t\t\tthis._smoothScrolling = null;\n\t\t}\n\t\tsuper.dispose();\n\t}\n\n\tpublic setSmoothScrollDuration(smoothScrollDuration: number): void {\n\t\tthis._smoothScrollDuration = smoothScrollDuration;\n\t}\n\n\tpublic validateScrollPosition(scrollPosition: INewScrollPosition): IScrollPosition {\n\t\treturn this._state.withScrollPosition(scrollPosition);\n\t}\n\n\tpublic getScrollDimensions(): IScrollDimensions {\n\t\treturn this._state;\n\t}\n\n\tpublic setScrollDimensions(dimensions: INewScrollDimensions, useRawScrollPositions: boolean): void {\n\t\tconst newState = this._state.withScrollDimensions(dimensions, useRawScrollPositions);\n\t\tthis._setState(newState, Boolean(this._smoothScrolling));\n\n\t\t// Validate outstanding animated scroll position target\n\t\tthis._smoothScrolling?.acceptScrollDimensions(this._state);\n\t}\n\n\t/**\n\t * Returns the final scroll position that the instance will have once the smooth scroll animation concludes.\n\t * If no scroll animation is occurring, it will return the current scroll position instead.\n\t */\n\tpublic getFutureScrollPosition(): IScrollPosition {\n\t\tif (this._smoothScrolling) {\n\t\t\treturn this._smoothScrolling.to;\n\t\t}\n\t\treturn this._state;\n\t}\n\n\t/**\n\t * Returns the current scroll position.\n\t * Note: This result might be an intermediate scroll position, as there might be an ongoing smooth scroll animation.\n\t */\n\tpublic getCurrentScrollPosition(): IScrollPosition {\n\t\treturn this._state;\n\t}\n\n\tpublic setScrollPositionNow(update: INewScrollPosition): void {\n\t\t// no smooth scrolling requested\n\t\tconst newState = this._state.withScrollPosition(update);\n\n\t\t// Terminate any outstanding smooth scrolling\n\t\tif (this._smoothScrolling) {\n\t\t\tthis._smoothScrolling.dispose();\n\t\t\tthis._smoothScrolling = null;\n\t\t}\n\n\t\tthis._setState(newState, false);\n\t}\n\n\tpublic setScrollPositionSmooth(update: INewScrollPosition, reuseAnimation?: boolean): void {\n\t\tif (this._smoothScrollDuration === 0) {\n\t\t\t// Smooth scrolling not supported.\n\t\t\treturn this.setScrollPositionNow(update);\n\t\t}\n\n\t\tif (this._smoothScrolling) {\n\t\t\t// Combine our pending scrollLeft/scrollTop with incoming scrollLeft/scrollTop\n\t\t\tupdate = {\n\t\t\t\tscrollLeft: (typeof update.scrollLeft === 'undefined' ? this._smoothScrolling.to.scrollLeft : update.scrollLeft),\n\t\t\t\tscrollTop: (typeof update.scrollTop === 'undefined' ? this._smoothScrolling.to.scrollTop : update.scrollTop)\n\t\t\t};\n\n\t\t\t// Validate `update`\n\t\t\tconst validTarget = this._state.withScrollPosition(update);\n\n\t\t\tif (this._smoothScrolling.to.scrollLeft === validTarget.scrollLeft && this._smoothScrolling.to.scrollTop === validTarget.scrollTop) {\n\t\t\t\t// No need to interrupt or extend the current animation since we're going to the same place\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tlet newSmoothScrolling: SmoothScrollingOperation;\n\t\t\tif (reuseAnimation) {\n\t\t\t\tnewSmoothScrolling = new SmoothScrollingOperation(this._smoothScrolling.from, validTarget, this._smoothScrolling.startTime, this._smoothScrolling.duration);\n\t\t\t} else {\n\t\t\t\tnewSmoothScrolling = this._smoothScrolling.combine(this._state, validTarget, this._smoothScrollDuration);\n\t\t\t}\n\t\t\tthis._smoothScrolling.dispose();\n\t\t\tthis._smoothScrolling = newSmoothScrolling;\n\t\t} else {\n\t\t\t// Validate `update`\n\t\t\tconst validTarget = this._state.withScrollPosition(update);\n\n\t\t\tthis._smoothScrolling = SmoothScrollingOperation.start(this._state, validTarget, this._smoothScrollDuration);\n\t\t}\n\n\t\t// Begin smooth scrolling animation\n\t\tthis._smoothScrolling.animationFrameDisposable = this._scheduleAtNextAnimationFrame(() => {\n\t\t\tif (!this._smoothScrolling) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis._smoothScrolling.animationFrameDisposable = null;\n\t\t\tthis._performSmoothScrolling();\n\t\t});\n\t}\n\n\tpublic hasPendingScrollAnimation(): boolean {\n\t\treturn Boolean(this._smoothScrolling);\n\t}\n\n\tprivate _performSmoothScrolling(): void {\n\t\tif (!this._smoothScrolling) {\n\t\t\treturn;\n\t\t}\n\t\tconst update = this._smoothScrolling.tick();\n\t\tconst newState = this._state.withScrollPosition(update);\n\n\t\tthis._setState(newState, true);\n\n\t\tif (!this._smoothScrolling) {\n\t\t\t// Looks like someone canceled the smooth scrolling\n\t\t\t// from the scroll event handler\n\t\t\treturn;\n\t\t}\n\n\t\tif (update.isDone) {\n\t\t\tthis._smoothScrolling.dispose();\n\t\t\tthis._smoothScrolling = null;\n\t\t\treturn;\n\t\t}\n\n\t\t// Continue smooth scrolling animation\n\t\tthis._smoothScrolling.animationFrameDisposable = this._scheduleAtNextAnimationFrame(() => {\n\t\t\tif (!this._smoothScrolling) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis._smoothScrolling.animationFrameDisposable = null;\n\t\t\tthis._performSmoothScrolling();\n\t\t});\n\t}\n\n\tprivate _setState(newState: ScrollState, inSmoothScrolling: boolean): void {\n\t\tconst oldState = this._state;\n\t\tif (oldState.equals(newState)) {\n\t\t\t// no change\n\t\t\treturn;\n\t\t}\n\t\tthis._state = newState;\n\t\tthis._onScroll.fire(this._state.createScrollEvent(oldState, inSmoothScrolling));\n\t}\n}\n\nexport class SmoothScrollingUpdate {\n\n\tpublic readonly scrollLeft: number;\n\tpublic readonly scrollTop: number;\n\tpublic readonly isDone: boolean;\n\n\tconstructor(scrollLeft: number, scrollTop: number, isDone: boolean) {\n\t\tthis.scrollLeft = scrollLeft;\n\t\tthis.scrollTop = scrollTop;\n\t\tthis.isDone = isDone;\n\t}\n\n}\n\ninterface IAnimation {\n\t(completion: number): number;\n}\n\nfunction createEaseOutCubic(from: number, to: number): IAnimation {\n\tconst delta = to - from;\n\treturn function (completion: number): number {\n\t\treturn from + delta * easeOutCubic(completion);\n\t};\n}\n\nfunction createComposed(a: IAnimation, b: IAnimation, cut: number): IAnimation {\n\treturn function (completion: number): number {\n\t\tif (completion < cut) {\n\t\t\treturn a(completion / cut);\n\t\t}\n\t\treturn b((completion - cut) / (1 - cut));\n\t};\n}\n\nexport class SmoothScrollingOperation {\n\n\tpublic readonly from: ISmoothScrollPosition;\n\tpublic to: ISmoothScrollPosition;\n\tpublic readonly duration: number;\n\tpublic readonly startTime: number;\n\tpublic animationFrameDisposable: IDisposable | null;\n\n\tprivate scrollLeft!: IAnimation;\n\tprivate scrollTop!: IAnimation;\n\n\tconstructor(from: ISmoothScrollPosition, to: ISmoothScrollPosition, startTime: number, duration: number) {\n\t\tthis.from = from;\n\t\tthis.to = to;\n\t\tthis.duration = duration;\n\t\tthis.startTime = startTime;\n\n\t\tthis.animationFrameDisposable = null;\n\n\t\tthis._initAnimations();\n\t}\n\n\tprivate _initAnimations(): void {\n\t\tthis.scrollLeft = this._initAnimation(this.from.scrollLeft, this.to.scrollLeft, this.to.width);\n\t\tthis.scrollTop = this._initAnimation(this.from.scrollTop, this.to.scrollTop, this.to.height);\n\t}\n\n\tprivate _initAnimation(from: number, to: number, viewportSize: number): IAnimation {\n\t\tconst delta = Math.abs(from - to);\n\t\tif (delta > 2.5 * viewportSize) {\n\t\t\tlet stop1: number, stop2: number;\n\t\t\tif (from < to) {\n\t\t\t\t// scroll to 75% of the viewportSize\n\t\t\t\tstop1 = from + 0.75 * viewportSize;\n\t\t\t\tstop2 = to - 0.75 * viewportSize;\n\t\t\t} else {\n\t\t\t\tstop1 = from - 0.75 * viewportSize;\n\t\t\t\tstop2 = to + 0.75 * viewportSize;\n\t\t\t}\n\t\t\treturn createComposed(createEaseOutCubic(from, stop1), createEaseOutCubic(stop2, to), 0.33);\n\t\t}\n\t\treturn createEaseOutCubic(from, to);\n\t}\n\n\tpublic dispose(): void {\n\t\tif (this.animationFrameDisposable !== null) {\n\t\t\tthis.animationFrameDisposable.dispose();\n\t\t\tthis.animationFrameDisposable = null;\n\t\t}\n\t}\n\n\tpublic acceptScrollDimensions(state: ScrollState): void {\n\t\tthis.to = state.withScrollPosition(this.to);\n\t\tthis._initAnimations();\n\t}\n\n\tpublic tick(): SmoothScrollingUpdate {\n\t\treturn this._tick(Date.now());\n\t}\n\n\tprotected _tick(now: number): SmoothScrollingUpdate {\n\t\tconst completion = (now - this.startTime) / this.duration;\n\n\t\tif (completion < 1) {\n\t\t\tconst newScrollLeft = this.scrollLeft(completion);\n\t\t\tconst newScrollTop = this.scrollTop(completion);\n\t\t\treturn new SmoothScrollingUpdate(newScrollLeft, newScrollTop, false);\n\t\t}\n\n\t\treturn new SmoothScrollingUpdate(this.to.scrollLeft, this.to.scrollTop, true);\n\t}\n\n\tpublic combine(from: ISmoothScrollPosition, to: ISmoothScrollPosition, duration: number): SmoothScrollingOperation {\n\t\treturn SmoothScrollingOperation.start(from, to, duration);\n\t}\n\n\tpublic static start(from: ISmoothScrollPosition, to: ISmoothScrollPosition, duration: number): SmoothScrollingOperation {\n\t\t// +10 / -10 : pretend the animation already started for a quicker response to a scroll request\n\t\tduration = duration + 10;\n\t\tconst startTime = Date.now() - 10;\n\n\t\treturn new SmoothScrollingOperation(from, to, startTime, duration);\n\t}\n}\n\nfunction easeInCubic(t: number) {\n\treturn Math.pow(t, 3);\n}\n\nfunction easeOutCubic(t: number) {\n\treturn 1 - easeInCubic(1 - t);\n}\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\nimport { LRUCachedFunction } from 'vs/base/common/cache';\nimport { CharCode } from 'vs/base/common/charCode';\nimport { Lazy } from 'vs/base/common/lazy';\nimport { Constants } from 'vs/base/common/uint';\n\nexport function isFalsyOrWhitespace(str: string | undefined): boolean {\n\tif (!str || typeof str !== 'string') {\n\t\treturn true;\n\t}\n\treturn str.trim().length === 0;\n}\n\nconst _formatRegexp = /{(\\d+)}/g;\n\n/**\n * Helper to produce a string with a variable number of arguments. Insert variable segments\n * into the string using the {n} notation where N is the index of the argument following the string.\n * @param value string to which formatting is applied\n * @param args replacements for {n}-entries\n */\nexport function format(value: string, ...args: any[]): string {\n\tif (args.length === 0) {\n\t\treturn value;\n\t}\n\treturn value.replace(_formatRegexp, function (match, group) {\n\t\tconst idx = parseInt(group, 10);\n\t\treturn isNaN(idx) || idx < 0 || idx >= args.length ?\n\t\t\tmatch :\n\t\t\targs[idx];\n\t});\n}\n\n/**\n * Encodes the given value so that it can be used as literal value in html attributes.\n *\n * In other words, computes `$val`, such that `attr` in `
    ` has the runtime value `value`.\n * This prevents XSS injection.\n */\nexport function htmlAttributeEncodeValue(value: string): string {\n\treturn value.replace(/[<>\"'&]/g, ch => {\n\t\tswitch (ch) {\n\t\t\tcase '<': return '<';\n\t\t\tcase '>': return '>';\n\t\t\tcase '\"': return '"';\n\t\t\tcase '\\'': return ''';\n\t\t\tcase '&': return '&';\n\t\t}\n\t\treturn ch;\n\t});\n}\n\n/**\n * Converts HTML characters inside the string to use entities instead. Makes the string safe from\n * being used e.g. in HTMLElement.innerHTML.\n */\nexport function escape(html: string): string {\n\treturn html.replace(/[<>&]/g, function (match) {\n\t\tswitch (match) {\n\t\t\tcase '<': return '<';\n\t\t\tcase '>': return '>';\n\t\t\tcase '&': return '&';\n\t\t\tdefault: return match;\n\t\t}\n\t});\n}\n\n/**\n * Escapes regular expression characters in a given string\n */\nexport function escapeRegExpCharacters(value: string): string {\n\treturn value.replace(/[\\\\\\{\\}\\*\\+\\?\\|\\^\\$\\.\\[\\]\\(\\)]/g, '\\\\$&');\n}\n\n/**\n * Removes all occurrences of needle from the beginning and end of haystack.\n * @param haystack string to trim\n * @param needle the thing to trim (default is a blank)\n */\nexport function trim(haystack: string, needle: string = ' '): string {\n\tconst trimmed = ltrim(haystack, needle);\n\treturn rtrim(trimmed, needle);\n}\n\n/**\n * Removes all occurrences of needle from the beginning of haystack.\n * @param haystack string to trim\n * @param needle the thing to trim\n */\nexport function ltrim(haystack: string, needle: string): string {\n\tif (!haystack || !needle) {\n\t\treturn haystack;\n\t}\n\n\tconst needleLen = needle.length;\n\tif (needleLen === 0 || haystack.length === 0) {\n\t\treturn haystack;\n\t}\n\n\tlet offset = 0;\n\n\twhile (haystack.indexOf(needle, offset) === offset) {\n\t\toffset = offset + needleLen;\n\t}\n\treturn haystack.substring(offset);\n}\n\n/**\n * Removes all occurrences of needle from the end of haystack.\n * @param haystack string to trim\n * @param needle the thing to trim\n */\nexport function rtrim(haystack: string, needle: string): string {\n\tif (!haystack || !needle) {\n\t\treturn haystack;\n\t}\n\n\tconst needleLen = needle.length,\n\t\thaystackLen = haystack.length;\n\n\tif (needleLen === 0 || haystackLen === 0) {\n\t\treturn haystack;\n\t}\n\n\tlet offset = haystackLen,\n\t\tidx = -1;\n\n\twhile (true) {\n\t\tidx = haystack.lastIndexOf(needle, offset - 1);\n\t\tif (idx === -1 || idx + needleLen !== offset) {\n\t\t\tbreak;\n\t\t}\n\t\tif (idx === 0) {\n\t\t\treturn '';\n\t\t}\n\t\toffset = idx;\n\t}\n\n\treturn haystack.substring(0, offset);\n}\n\nexport function convertSimple2RegExpPattern(pattern: string): string {\n\treturn pattern.replace(/[\\-\\\\\\{\\}\\+\\?\\|\\^\\$\\.\\,\\[\\]\\(\\)\\#\\s]/g, '\\\\$&').replace(/[\\*]/g, '.*');\n}\n\nexport function stripWildcards(pattern: string): string {\n\treturn pattern.replace(/\\*/g, '');\n}\n\nexport interface RegExpOptions {\n\tmatchCase?: boolean;\n\twholeWord?: boolean;\n\tmultiline?: boolean;\n\tglobal?: boolean;\n\tunicode?: boolean;\n}\n\nexport function createRegExp(searchString: string, isRegex: boolean, options: RegExpOptions = {}): RegExp {\n\tif (!searchString) {\n\t\tthrow new Error('Cannot create regex from empty string');\n\t}\n\tif (!isRegex) {\n\t\tsearchString = escapeRegExpCharacters(searchString);\n\t}\n\tif (options.wholeWord) {\n\t\tif (!/\\B/.test(searchString.charAt(0))) {\n\t\t\tsearchString = '\\\\b' + searchString;\n\t\t}\n\t\tif (!/\\B/.test(searchString.charAt(searchString.length - 1))) {\n\t\t\tsearchString = searchString + '\\\\b';\n\t\t}\n\t}\n\tlet modifiers = '';\n\tif (options.global) {\n\t\tmodifiers += 'g';\n\t}\n\tif (!options.matchCase) {\n\t\tmodifiers += 'i';\n\t}\n\tif (options.multiline) {\n\t\tmodifiers += 'm';\n\t}\n\tif (options.unicode) {\n\t\tmodifiers += 'u';\n\t}\n\n\treturn new RegExp(searchString, modifiers);\n}\n\nexport function regExpLeadsToEndlessLoop(regexp: RegExp): boolean {\n\t// Exit early if it's one of these special cases which are meant to match\n\t// against an empty string\n\tif (regexp.source === '^' || regexp.source === '^$' || regexp.source === '$' || regexp.source === '^\\\\s*$') {\n\t\treturn false;\n\t}\n\n\t// We check against an empty string. If the regular expression doesn't advance\n\t// (e.g. ends in an endless loop) it will match an empty string.\n\tconst match = regexp.exec('');\n\treturn !!(match && regexp.lastIndex === 0);\n}\n\nexport function splitLines(str: string): string[] {\n\treturn str.split(/\\r\\n|\\r|\\n/);\n}\n\nexport function splitLinesIncludeSeparators(str: string): string[] {\n\tconst linesWithSeparators: string[] = [];\n\tconst splitLinesAndSeparators = str.split(/(\\r\\n|\\r|\\n)/);\n\tfor (let i = 0; i < Math.ceil(splitLinesAndSeparators.length / 2); i++) {\n\t\tlinesWithSeparators.push(splitLinesAndSeparators[2 * i] + (splitLinesAndSeparators[2 * i + 1] ?? ''));\n\t}\n\treturn linesWithSeparators;\n}\n\n/**\n * Returns first index of the string that is not whitespace.\n * If string is empty or contains only whitespaces, returns -1\n */\nexport function firstNonWhitespaceIndex(str: string): number {\n\tfor (let i = 0, len = str.length; i < len; i++) {\n\t\tconst chCode = str.charCodeAt(i);\n\t\tif (chCode !== CharCode.Space && chCode !== CharCode.Tab) {\n\t\t\treturn i;\n\t\t}\n\t}\n\treturn -1;\n}\n\n/**\n * Returns the leading whitespace of the string.\n * If the string contains only whitespaces, returns entire string\n */\nexport function getLeadingWhitespace(str: string, start: number = 0, end: number = str.length): string {\n\tfor (let i = start; i < end; i++) {\n\t\tconst chCode = str.charCodeAt(i);\n\t\tif (chCode !== CharCode.Space && chCode !== CharCode.Tab) {\n\t\t\treturn str.substring(start, i);\n\t\t}\n\t}\n\treturn str.substring(start, end);\n}\n\n/**\n * Returns last index of the string that is not whitespace.\n * If string is empty or contains only whitespaces, returns -1\n */\nexport function lastNonWhitespaceIndex(str: string, startIndex: number = str.length - 1): number {\n\tfor (let i = startIndex; i >= 0; i--) {\n\t\tconst chCode = str.charCodeAt(i);\n\t\tif (chCode !== CharCode.Space && chCode !== CharCode.Tab) {\n\t\t\treturn i;\n\t\t}\n\t}\n\treturn -1;\n}\n\nexport function compare(a: string, b: string): number {\n\tif (a < b) {\n\t\treturn -1;\n\t} else if (a > b) {\n\t\treturn 1;\n\t} else {\n\t\treturn 0;\n\t}\n}\n\nexport function compareSubstring(a: string, b: string, aStart: number = 0, aEnd: number = a.length, bStart: number = 0, bEnd: number = b.length): number {\n\tfor (; aStart < aEnd && bStart < bEnd; aStart++, bStart++) {\n\t\tconst codeA = a.charCodeAt(aStart);\n\t\tconst codeB = b.charCodeAt(bStart);\n\t\tif (codeA < codeB) {\n\t\t\treturn -1;\n\t\t} else if (codeA > codeB) {\n\t\t\treturn 1;\n\t\t}\n\t}\n\tconst aLen = aEnd - aStart;\n\tconst bLen = bEnd - bStart;\n\tif (aLen < bLen) {\n\t\treturn -1;\n\t} else if (aLen > bLen) {\n\t\treturn 1;\n\t}\n\treturn 0;\n}\n\nexport function compareIgnoreCase(a: string, b: string): number {\n\treturn compareSubstringIgnoreCase(a, b, 0, a.length, 0, b.length);\n}\n\nexport function compareSubstringIgnoreCase(a: string, b: string, aStart: number = 0, aEnd: number = a.length, bStart: number = 0, bEnd: number = b.length): number {\n\n\tfor (; aStart < aEnd && bStart < bEnd; aStart++, bStart++) {\n\n\t\tlet codeA = a.charCodeAt(aStart);\n\t\tlet codeB = b.charCodeAt(bStart);\n\n\t\tif (codeA === codeB) {\n\t\t\t// equal\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (codeA >= 128 || codeB >= 128) {\n\t\t\t// not ASCII letters -> fallback to lower-casing strings\n\t\t\treturn compareSubstring(a.toLowerCase(), b.toLowerCase(), aStart, aEnd, bStart, bEnd);\n\t\t}\n\n\t\t// mapper lower-case ascii letter onto upper-case varinats\n\t\t// [97-122] (lower ascii) --> [65-90] (upper ascii)\n\t\tif (isLowerAsciiLetter(codeA)) {\n\t\t\tcodeA -= 32;\n\t\t}\n\t\tif (isLowerAsciiLetter(codeB)) {\n\t\t\tcodeB -= 32;\n\t\t}\n\n\t\t// compare both code points\n\t\tconst diff = codeA - codeB;\n\t\tif (diff === 0) {\n\t\t\tcontinue;\n\t\t}\n\n\t\treturn diff;\n\t}\n\n\tconst aLen = aEnd - aStart;\n\tconst bLen = bEnd - bStart;\n\n\tif (aLen < bLen) {\n\t\treturn -1;\n\t} else if (aLen > bLen) {\n\t\treturn 1;\n\t}\n\n\treturn 0;\n}\n\nexport function isAsciiDigit(code: number): boolean {\n\treturn code >= CharCode.Digit0 && code <= CharCode.Digit9;\n}\n\nexport function isLowerAsciiLetter(code: number): boolean {\n\treturn code >= CharCode.a && code <= CharCode.z;\n}\n\nexport function isUpperAsciiLetter(code: number): boolean {\n\treturn code >= CharCode.A && code <= CharCode.Z;\n}\n\nexport function equalsIgnoreCase(a: string, b: string): boolean {\n\treturn a.length === b.length && compareSubstringIgnoreCase(a, b) === 0;\n}\n\nexport function startsWithIgnoreCase(str: string, candidate: string): boolean {\n\tconst candidateLength = candidate.length;\n\tif (candidate.length > str.length) {\n\t\treturn false;\n\t}\n\n\treturn compareSubstringIgnoreCase(str, candidate, 0, candidateLength) === 0;\n}\n\n/**\n * @returns the length of the common prefix of the two strings.\n */\nexport function commonPrefixLength(a: string, b: string): number {\n\n\tconst len = Math.min(a.length, b.length);\n\tlet i: number;\n\n\tfor (i = 0; i < len; i++) {\n\t\tif (a.charCodeAt(i) !== b.charCodeAt(i)) {\n\t\t\treturn i;\n\t\t}\n\t}\n\n\treturn len;\n}\n\n/**\n * @returns the length of the common suffix of the two strings.\n */\nexport function commonSuffixLength(a: string, b: string): number {\n\n\tconst len = Math.min(a.length, b.length);\n\tlet i: number;\n\n\tconst aLastIndex = a.length - 1;\n\tconst bLastIndex = b.length - 1;\n\n\tfor (i = 0; i < len; i++) {\n\t\tif (a.charCodeAt(aLastIndex - i) !== b.charCodeAt(bLastIndex - i)) {\n\t\t\treturn i;\n\t\t}\n\t}\n\n\treturn len;\n}\n\n/**\n * See http://en.wikipedia.org/wiki/Surrogate_pair\n */\nexport function isHighSurrogate(charCode: number): boolean {\n\treturn (0xD800 <= charCode && charCode <= 0xDBFF);\n}\n\n/**\n * See http://en.wikipedia.org/wiki/Surrogate_pair\n */\nexport function isLowSurrogate(charCode: number): boolean {\n\treturn (0xDC00 <= charCode && charCode <= 0xDFFF);\n}\n\n/**\n * See http://en.wikipedia.org/wiki/Surrogate_pair\n */\nexport function computeCodePoint(highSurrogate: number, lowSurrogate: number): number {\n\treturn ((highSurrogate - 0xD800) << 10) + (lowSurrogate - 0xDC00) + 0x10000;\n}\n\n/**\n * get the code point that begins at offset `offset`\n */\nexport function getNextCodePoint(str: string, len: number, offset: number): number {\n\tconst charCode = str.charCodeAt(offset);\n\tif (isHighSurrogate(charCode) && offset + 1 < len) {\n\t\tconst nextCharCode = str.charCodeAt(offset + 1);\n\t\tif (isLowSurrogate(nextCharCode)) {\n\t\t\treturn computeCodePoint(charCode, nextCharCode);\n\t\t}\n\t}\n\treturn charCode;\n}\n\n/**\n * get the code point that ends right before offset `offset`\n */\nfunction getPrevCodePoint(str: string, offset: number): number {\n\tconst charCode = str.charCodeAt(offset - 1);\n\tif (isLowSurrogate(charCode) && offset > 1) {\n\t\tconst prevCharCode = str.charCodeAt(offset - 2);\n\t\tif (isHighSurrogate(prevCharCode)) {\n\t\t\treturn computeCodePoint(prevCharCode, charCode);\n\t\t}\n\t}\n\treturn charCode;\n}\n\nexport class CodePointIterator {\n\n\tprivate readonly _str: string;\n\tprivate readonly _len: number;\n\tprivate _offset: number;\n\n\tpublic get offset(): number {\n\t\treturn this._offset;\n\t}\n\n\tconstructor(str: string, offset: number = 0) {\n\t\tthis._str = str;\n\t\tthis._len = str.length;\n\t\tthis._offset = offset;\n\t}\n\n\tpublic setOffset(offset: number): void {\n\t\tthis._offset = offset;\n\t}\n\n\tpublic prevCodePoint(): number {\n\t\tconst codePoint = getPrevCodePoint(this._str, this._offset);\n\t\tthis._offset -= (codePoint >= Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN ? 2 : 1);\n\t\treturn codePoint;\n\t}\n\n\tpublic nextCodePoint(): number {\n\t\tconst codePoint = getNextCodePoint(this._str, this._len, this._offset);\n\t\tthis._offset += (codePoint >= Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN ? 2 : 1);\n\t\treturn codePoint;\n\t}\n\n\tpublic eol(): boolean {\n\t\treturn (this._offset >= this._len);\n\t}\n}\n\nexport class GraphemeIterator {\n\n\tprivate readonly _iterator: CodePointIterator;\n\n\tpublic get offset(): number {\n\t\treturn this._iterator.offset;\n\t}\n\n\tconstructor(str: string, offset: number = 0) {\n\t\tthis._iterator = new CodePointIterator(str, offset);\n\t}\n\n\tpublic nextGraphemeLength(): number {\n\t\tconst graphemeBreakTree = GraphemeBreakTree.getInstance();\n\t\tconst iterator = this._iterator;\n\t\tconst initialOffset = iterator.offset;\n\n\t\tlet graphemeBreakType = graphemeBreakTree.getGraphemeBreakType(iterator.nextCodePoint());\n\t\twhile (!iterator.eol()) {\n\t\t\tconst offset = iterator.offset;\n\t\t\tconst nextGraphemeBreakType = graphemeBreakTree.getGraphemeBreakType(iterator.nextCodePoint());\n\t\t\tif (breakBetweenGraphemeBreakType(graphemeBreakType, nextGraphemeBreakType)) {\n\t\t\t\t// move iterator back\n\t\t\t\titerator.setOffset(offset);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tgraphemeBreakType = nextGraphemeBreakType;\n\t\t}\n\t\treturn (iterator.offset - initialOffset);\n\t}\n\n\tpublic prevGraphemeLength(): number {\n\t\tconst graphemeBreakTree = GraphemeBreakTree.getInstance();\n\t\tconst iterator = this._iterator;\n\t\tconst initialOffset = iterator.offset;\n\n\t\tlet graphemeBreakType = graphemeBreakTree.getGraphemeBreakType(iterator.prevCodePoint());\n\t\twhile (iterator.offset > 0) {\n\t\t\tconst offset = iterator.offset;\n\t\t\tconst prevGraphemeBreakType = graphemeBreakTree.getGraphemeBreakType(iterator.prevCodePoint());\n\t\t\tif (breakBetweenGraphemeBreakType(prevGraphemeBreakType, graphemeBreakType)) {\n\t\t\t\t// move iterator back\n\t\t\t\titerator.setOffset(offset);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tgraphemeBreakType = prevGraphemeBreakType;\n\t\t}\n\t\treturn (initialOffset - iterator.offset);\n\t}\n\n\tpublic eol(): boolean {\n\t\treturn this._iterator.eol();\n\t}\n}\n\nexport function nextCharLength(str: string, initialOffset: number): number {\n\tconst iterator = new GraphemeIterator(str, initialOffset);\n\treturn iterator.nextGraphemeLength();\n}\n\nexport function prevCharLength(str: string, initialOffset: number): number {\n\tconst iterator = new GraphemeIterator(str, initialOffset);\n\treturn iterator.prevGraphemeLength();\n}\n\nexport function getCharContainingOffset(str: string, offset: number): [number, number] {\n\tif (offset > 0 && isLowSurrogate(str.charCodeAt(offset))) {\n\t\toffset--;\n\t}\n\tconst endOffset = offset + nextCharLength(str, offset);\n\tconst startOffset = endOffset - prevCharLength(str, endOffset);\n\treturn [startOffset, endOffset];\n}\n\nlet CONTAINS_RTL: RegExp | undefined = undefined;\n\nfunction makeContainsRtl() {\n\t// Generated using https://github.com/alexdima/unicode-utils/blob/main/rtl-test.js\n\treturn /(?:[\\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\\u07FE-\\u0815\\u081A\\u0824\\u0828\\u0830-\\u0858\\u085E-\\u088E\\u08A0-\\u08C9\\u200F\\uFB1D\\uFB1F-\\uFB28\\uFB2A-\\uFD3D\\uFD50-\\uFDC7\\uFDF0-\\uFDFC\\uFE70-\\uFEFC]|\\uD802[\\uDC00-\\uDD1B\\uDD20-\\uDE00\\uDE10-\\uDE35\\uDE40-\\uDEE4\\uDEEB-\\uDF35\\uDF40-\\uDFFF]|\\uD803[\\uDC00-\\uDD23\\uDE80-\\uDEA9\\uDEAD-\\uDF45\\uDF51-\\uDF81\\uDF86-\\uDFF6]|\\uD83A[\\uDC00-\\uDCCF\\uDD00-\\uDD43\\uDD4B-\\uDFFF]|\\uD83B[\\uDC00-\\uDEBB])/;\n}\n\n/**\n * Returns true if `str` contains any Unicode character that is classified as \"R\" or \"AL\".\n */\nexport function containsRTL(str: string): boolean {\n\tif (!CONTAINS_RTL) {\n\t\tCONTAINS_RTL = makeContainsRtl();\n\t}\n\n\treturn CONTAINS_RTL.test(str);\n}\n\nconst IS_BASIC_ASCII = /^[\\t\\n\\r\\x20-\\x7E]*$/;\n/**\n * Returns true if `str` contains only basic ASCII characters in the range 32 - 126 (including 32 and 126) or \\n, \\r, \\t\n */\nexport function isBasicASCII(str: string): boolean {\n\treturn IS_BASIC_ASCII.test(str);\n}\n\nexport const UNUSUAL_LINE_TERMINATORS = /[\\u2028\\u2029]/; // LINE SEPARATOR (LS) or PARAGRAPH SEPARATOR (PS)\n/**\n * Returns true if `str` contains unusual line terminators, like LS or PS\n */\nexport function containsUnusualLineTerminators(str: string): boolean {\n\treturn UNUSUAL_LINE_TERMINATORS.test(str);\n}\n\nexport function isFullWidthCharacter(charCode: number): boolean {\n\t// Do a cheap trick to better support wrapping of wide characters, treat them as 2 columns\n\t// http://jrgraphix.net/research/unicode_blocks.php\n\t// 2E80 - 2EFF CJK Radicals Supplement\n\t// 2F00 - 2FDF Kangxi Radicals\n\t// 2FF0 - 2FFF Ideographic Description Characters\n\t// 3000 - 303F CJK Symbols and Punctuation\n\t// 3040 - 309F Hiragana\n\t// 30A0 - 30FF Katakana\n\t// 3100 - 312F Bopomofo\n\t// 3130 - 318F Hangul Compatibility Jamo\n\t// 3190 - 319F Kanbun\n\t// 31A0 - 31BF Bopomofo Extended\n\t// 31F0 - 31FF Katakana Phonetic Extensions\n\t// 3200 - 32FF Enclosed CJK Letters and Months\n\t// 3300 - 33FF CJK Compatibility\n\t// 3400 - 4DBF CJK Unified Ideographs Extension A\n\t// 4DC0 - 4DFF Yijing Hexagram Symbols\n\t// 4E00 - 9FFF CJK Unified Ideographs\n\t// A000 - A48F Yi Syllables\n\t// A490 - A4CF Yi Radicals\n\t// AC00 - D7AF Hangul Syllables\n\t// [IGNORE] D800 - DB7F High Surrogates\n\t// [IGNORE] DB80 - DBFF High Private Use Surrogates\n\t// [IGNORE] DC00 - DFFF Low Surrogates\n\t// [IGNORE] E000 - F8FF Private Use Area\n\t// F900 - FAFF CJK Compatibility Ideographs\n\t// [IGNORE] FB00 - FB4F Alphabetic Presentation Forms\n\t// [IGNORE] FB50 - FDFF Arabic Presentation Forms-A\n\t// [IGNORE] FE00 - FE0F Variation Selectors\n\t// [IGNORE] FE20 - FE2F Combining Half Marks\n\t// [IGNORE] FE30 - FE4F CJK Compatibility Forms\n\t// [IGNORE] FE50 - FE6F Small Form Variants\n\t// [IGNORE] FE70 - FEFF Arabic Presentation Forms-B\n\t// FF00 - FFEF Halfwidth and Fullwidth Forms\n\t// [https://en.wikipedia.org/wiki/Halfwidth_and_fullwidth_forms]\n\t// of which FF01 - FF5E fullwidth ASCII of 21 to 7E\n\t// [IGNORE] and FF65 - FFDC halfwidth of Katakana and Hangul\n\t// [IGNORE] FFF0 - FFFF Specials\n\treturn (\n\t\t(charCode >= 0x2E80 && charCode <= 0xD7AF)\n\t\t|| (charCode >= 0xF900 && charCode <= 0xFAFF)\n\t\t|| (charCode >= 0xFF01 && charCode <= 0xFF5E)\n\t);\n}\n\n/**\n * A fast function (therefore imprecise) to check if code points are emojis.\n * Generated using https://github.com/alexdima/unicode-utils/blob/main/emoji-test.js\n */\nexport function isEmojiImprecise(x: number): boolean {\n\treturn (\n\t\t(x >= 0x1F1E6 && x <= 0x1F1FF) || (x === 8986) || (x === 8987) || (x === 9200)\n\t\t|| (x === 9203) || (x >= 9728 && x <= 10175) || (x === 11088) || (x === 11093)\n\t\t|| (x >= 127744 && x <= 128591) || (x >= 128640 && x <= 128764)\n\t\t|| (x >= 128992 && x <= 129008) || (x >= 129280 && x <= 129535)\n\t\t|| (x >= 129648 && x <= 129782)\n\t);\n}\n\n\n// -- UTF-8 BOM\n\nexport const UTF8_BOM_CHARACTER = String.fromCharCode(CharCode.UTF8_BOM);\n\nexport function startsWithUTF8BOM(str: string): boolean {\n\treturn !!(str && str.length > 0 && str.charCodeAt(0) === CharCode.UTF8_BOM);\n}\n\nexport function containsUppercaseCharacter(target: string, ignoreEscapedChars = false): boolean {\n\tif (!target) {\n\t\treturn false;\n\t}\n\n\tif (ignoreEscapedChars) {\n\t\ttarget = target.replace(/\\\\./g, '');\n\t}\n\n\treturn target.toLowerCase() !== target;\n}\n\n/**\n * Produces 'a'-'z', followed by 'A'-'Z'... followed by 'a'-'z', etc.\n */\nexport function singleLetterHash(n: number): string {\n\tconst LETTERS_CNT = (CharCode.Z - CharCode.A + 1);\n\n\tn = n % (2 * LETTERS_CNT);\n\n\tif (n < LETTERS_CNT) {\n\t\treturn String.fromCharCode(CharCode.a + n);\n\t}\n\n\treturn String.fromCharCode(CharCode.A + n - LETTERS_CNT);\n}\n\nfunction breakBetweenGraphemeBreakType(breakTypeA: GraphemeBreakType, breakTypeB: GraphemeBreakType): boolean {\n\t// http://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundary_Rules\n\n\t// !!! Let's make the common case a bit faster\n\tif (breakTypeA === GraphemeBreakType.Other) {\n\t\t// see https://www.unicode.org/Public/13.0.0/ucd/auxiliary/GraphemeBreakTest-13.0.0d10.html#table\n\t\treturn (breakTypeB !== GraphemeBreakType.Extend && breakTypeB !== GraphemeBreakType.SpacingMark);\n\t}\n\n\t// Do not break between a CR and LF. Otherwise, break before and after controls.\n\t// GB3 CR × LF\n\t// GB4 (Control | CR | LF) ÷\n\t// GB5 ÷ (Control | CR | LF)\n\tif (breakTypeA === GraphemeBreakType.CR) {\n\t\tif (breakTypeB === GraphemeBreakType.LF) {\n\t\t\treturn false; // GB3\n\t\t}\n\t}\n\tif (breakTypeA === GraphemeBreakType.Control || breakTypeA === GraphemeBreakType.CR || breakTypeA === GraphemeBreakType.LF) {\n\t\treturn true; // GB4\n\t}\n\tif (breakTypeB === GraphemeBreakType.Control || breakTypeB === GraphemeBreakType.CR || breakTypeB === GraphemeBreakType.LF) {\n\t\treturn true; // GB5\n\t}\n\n\t// Do not break Hangul syllable sequences.\n\t// GB6 L × (L | V | LV | LVT)\n\t// GB7 (LV | V) × (V | T)\n\t// GB8 (LVT | T) × T\n\tif (breakTypeA === GraphemeBreakType.L) {\n\t\tif (breakTypeB === GraphemeBreakType.L || breakTypeB === GraphemeBreakType.V || breakTypeB === GraphemeBreakType.LV || breakTypeB === GraphemeBreakType.LVT) {\n\t\t\treturn false; // GB6\n\t\t}\n\t}\n\tif (breakTypeA === GraphemeBreakType.LV || breakTypeA === GraphemeBreakType.V) {\n\t\tif (breakTypeB === GraphemeBreakType.V || breakTypeB === GraphemeBreakType.T) {\n\t\t\treturn false; // GB7\n\t\t}\n\t}\n\tif (breakTypeA === GraphemeBreakType.LVT || breakTypeA === GraphemeBreakType.T) {\n\t\tif (breakTypeB === GraphemeBreakType.T) {\n\t\t\treturn false; // GB8\n\t\t}\n\t}\n\n\t// Do not break before extending characters or ZWJ.\n\t// GB9 × (Extend | ZWJ)\n\tif (breakTypeB === GraphemeBreakType.Extend || breakTypeB === GraphemeBreakType.ZWJ) {\n\t\treturn false; // GB9\n\t}\n\n\t// The GB9a and GB9b rules only apply to extended grapheme clusters:\n\t// Do not break before SpacingMarks, or after Prepend characters.\n\t// GB9a × SpacingMark\n\t// GB9b Prepend ×\n\tif (breakTypeB === GraphemeBreakType.SpacingMark) {\n\t\treturn false; // GB9a\n\t}\n\tif (breakTypeA === GraphemeBreakType.Prepend) {\n\t\treturn false; // GB9b\n\t}\n\n\t// Do not break within emoji modifier sequences or emoji zwj sequences.\n\t// GB11 \\p{Extended_Pictographic} Extend* ZWJ × \\p{Extended_Pictographic}\n\tif (breakTypeA === GraphemeBreakType.ZWJ && breakTypeB === GraphemeBreakType.Extended_Pictographic) {\n\t\t// Note: we are not implementing the rule entirely here to avoid introducing states\n\t\treturn false; // GB11\n\t}\n\n\t// GB12 sot (RI RI)* RI × RI\n\t// GB13 [^RI] (RI RI)* RI × RI\n\tif (breakTypeA === GraphemeBreakType.Regional_Indicator && breakTypeB === GraphemeBreakType.Regional_Indicator) {\n\t\t// Note: we are not implementing the rule entirely here to avoid introducing states\n\t\treturn false; // GB12 & GB13\n\t}\n\n\t// GB999 Any ÷ Any\n\treturn true;\n}\n\nexport const enum GraphemeBreakType {\n\tOther = 0,\n\tPrepend = 1,\n\tCR = 2,\n\tLF = 3,\n\tControl = 4,\n\tExtend = 5,\n\tRegional_Indicator = 6,\n\tSpacingMark = 7,\n\tL = 8,\n\tV = 9,\n\tT = 10,\n\tLV = 11,\n\tLVT = 12,\n\tZWJ = 13,\n\tExtended_Pictographic = 14\n}\n\nclass GraphemeBreakTree {\n\n\tprivate static _INSTANCE: GraphemeBreakTree | null = null;\n\tpublic static getInstance(): GraphemeBreakTree {\n\t\tif (!GraphemeBreakTree._INSTANCE) {\n\t\t\tGraphemeBreakTree._INSTANCE = new GraphemeBreakTree();\n\t\t}\n\t\treturn GraphemeBreakTree._INSTANCE;\n\t}\n\n\tprivate readonly _data: number[];\n\n\tconstructor() {\n\t\tthis._data = getGraphemeBreakRawData();\n\t}\n\n\tpublic getGraphemeBreakType(codePoint: number): GraphemeBreakType {\n\t\t// !!! Let's make 7bit ASCII a bit faster: 0..31\n\t\tif (codePoint < 32) {\n\t\t\tif (codePoint === CharCode.LineFeed) {\n\t\t\t\treturn GraphemeBreakType.LF;\n\t\t\t}\n\t\t\tif (codePoint === CharCode.CarriageReturn) {\n\t\t\t\treturn GraphemeBreakType.CR;\n\t\t\t}\n\t\t\treturn GraphemeBreakType.Control;\n\t\t}\n\t\t// !!! Let's make 7bit ASCII a bit faster: 32..126\n\t\tif (codePoint < 127) {\n\t\t\treturn GraphemeBreakType.Other;\n\t\t}\n\n\t\tconst data = this._data;\n\t\tconst nodeCount = data.length / 3;\n\t\tlet nodeIndex = 1;\n\t\twhile (nodeIndex <= nodeCount) {\n\t\t\tif (codePoint < data[3 * nodeIndex]) {\n\t\t\t\t// go left\n\t\t\t\tnodeIndex = 2 * nodeIndex;\n\t\t\t} else if (codePoint > data[3 * nodeIndex + 1]) {\n\t\t\t\t// go right\n\t\t\t\tnodeIndex = 2 * nodeIndex + 1;\n\t\t\t} else {\n\t\t\t\t// hit\n\t\t\t\treturn data[3 * nodeIndex + 2];\n\t\t\t}\n\t\t}\n\n\t\treturn GraphemeBreakType.Other;\n\t}\n}\n\nfunction getGraphemeBreakRawData(): number[] {\n\t// generated using https://github.com/alexdima/unicode-utils/blob/main/grapheme-break.js\n\treturn JSON.parse('[0,0,0,51229,51255,12,44061,44087,12,127462,127487,6,7083,7085,5,47645,47671,12,54813,54839,12,128678,128678,14,3270,3270,5,9919,9923,14,45853,45879,12,49437,49463,12,53021,53047,12,71216,71218,7,128398,128399,14,129360,129374,14,2519,2519,5,4448,4519,9,9742,9742,14,12336,12336,14,44957,44983,12,46749,46775,12,48541,48567,12,50333,50359,12,52125,52151,12,53917,53943,12,69888,69890,5,73018,73018,5,127990,127990,14,128558,128559,14,128759,128760,14,129653,129655,14,2027,2035,5,2891,2892,7,3761,3761,5,6683,6683,5,8293,8293,4,9825,9826,14,9999,9999,14,43452,43453,5,44509,44535,12,45405,45431,12,46301,46327,12,47197,47223,12,48093,48119,12,48989,49015,12,49885,49911,12,50781,50807,12,51677,51703,12,52573,52599,12,53469,53495,12,54365,54391,12,65279,65279,4,70471,70472,7,72145,72147,7,119173,119179,5,127799,127818,14,128240,128244,14,128512,128512,14,128652,128652,14,128721,128722,14,129292,129292,14,129445,129450,14,129734,129743,14,1476,1477,5,2366,2368,7,2750,2752,7,3076,3076,5,3415,3415,5,4141,4144,5,6109,6109,5,6964,6964,5,7394,7400,5,9197,9198,14,9770,9770,14,9877,9877,14,9968,9969,14,10084,10084,14,43052,43052,5,43713,43713,5,44285,44311,12,44733,44759,12,45181,45207,12,45629,45655,12,46077,46103,12,46525,46551,12,46973,46999,12,47421,47447,12,47869,47895,12,48317,48343,12,48765,48791,12,49213,49239,12,49661,49687,12,50109,50135,12,50557,50583,12,51005,51031,12,51453,51479,12,51901,51927,12,52349,52375,12,52797,52823,12,53245,53271,12,53693,53719,12,54141,54167,12,54589,54615,12,55037,55063,12,69506,69509,5,70191,70193,5,70841,70841,7,71463,71467,5,72330,72342,5,94031,94031,5,123628,123631,5,127763,127765,14,127941,127941,14,128043,128062,14,128302,128317,14,128465,128467,14,128539,128539,14,128640,128640,14,128662,128662,14,128703,128703,14,128745,128745,14,129004,129007,14,129329,129330,14,129402,129402,14,129483,129483,14,129686,129704,14,130048,131069,14,173,173,4,1757,1757,1,2200,2207,5,2434,2435,7,2631,2632,5,2817,2817,5,3008,3008,5,3201,3201,5,3387,3388,5,3542,3542,5,3902,3903,7,4190,4192,5,6002,6003,5,6439,6440,5,6765,6770,7,7019,7027,5,7154,7155,7,8205,8205,13,8505,8505,14,9654,9654,14,9757,9757,14,9792,9792,14,9852,9853,14,9890,9894,14,9937,9937,14,9981,9981,14,10035,10036,14,11035,11036,14,42654,42655,5,43346,43347,7,43587,43587,5,44006,44007,7,44173,44199,12,44397,44423,12,44621,44647,12,44845,44871,12,45069,45095,12,45293,45319,12,45517,45543,12,45741,45767,12,45965,45991,12,46189,46215,12,46413,46439,12,46637,46663,12,46861,46887,12,47085,47111,12,47309,47335,12,47533,47559,12,47757,47783,12,47981,48007,12,48205,48231,12,48429,48455,12,48653,48679,12,48877,48903,12,49101,49127,12,49325,49351,12,49549,49575,12,49773,49799,12,49997,50023,12,50221,50247,12,50445,50471,12,50669,50695,12,50893,50919,12,51117,51143,12,51341,51367,12,51565,51591,12,51789,51815,12,52013,52039,12,52237,52263,12,52461,52487,12,52685,52711,12,52909,52935,12,53133,53159,12,53357,53383,12,53581,53607,12,53805,53831,12,54029,54055,12,54253,54279,12,54477,54503,12,54701,54727,12,54925,54951,12,55149,55175,12,68101,68102,5,69762,69762,7,70067,70069,7,70371,70378,5,70720,70721,7,71087,71087,5,71341,71341,5,71995,71996,5,72249,72249,7,72850,72871,5,73109,73109,5,118576,118598,5,121505,121519,5,127245,127247,14,127568,127569,14,127777,127777,14,127872,127891,14,127956,127967,14,128015,128016,14,128110,128172,14,128259,128259,14,128367,128368,14,128424,128424,14,128488,128488,14,128530,128532,14,128550,128551,14,128566,128566,14,128647,128647,14,128656,128656,14,128667,128673,14,128691,128693,14,128715,128715,14,128728,128732,14,128752,128752,14,128765,128767,14,129096,129103,14,129311,129311,14,129344,129349,14,129394,129394,14,129413,129425,14,129466,129471,14,129511,129535,14,129664,129666,14,129719,129722,14,129760,129767,14,917536,917631,5,13,13,2,1160,1161,5,1564,1564,4,1807,1807,1,2085,2087,5,2307,2307,7,2382,2383,7,2497,2500,5,2563,2563,7,2677,2677,5,2763,2764,7,2879,2879,5,2914,2915,5,3021,3021,5,3142,3144,5,3263,3263,5,3285,3286,5,3398,3400,7,3530,3530,5,3633,3633,5,3864,3865,5,3974,3975,5,4155,4156,7,4229,4230,5,5909,5909,7,6078,6085,7,6277,6278,5,6451,6456,7,6744,6750,5,6846,6846,5,6972,6972,5,7074,7077,5,7146,7148,7,7222,7223,5,7416,7417,5,8234,8238,4,8417,8417,5,9000,9000,14,9203,9203,14,9730,9731,14,9748,9749,14,9762,9763,14,9776,9783,14,9800,9811,14,9831,9831,14,9872,9873,14,9882,9882,14,9900,9903,14,9929,9933,14,9941,9960,14,9974,9974,14,9989,9989,14,10006,10006,14,10062,10062,14,10160,10160,14,11647,11647,5,12953,12953,14,43019,43019,5,43232,43249,5,43443,43443,5,43567,43568,7,43696,43696,5,43765,43765,7,44013,44013,5,44117,44143,12,44229,44255,12,44341,44367,12,44453,44479,12,44565,44591,12,44677,44703,12,44789,44815,12,44901,44927,12,45013,45039,12,45125,45151,12,45237,45263,12,45349,45375,12,45461,45487,12,45573,45599,12,45685,45711,12,45797,45823,12,45909,45935,12,46021,46047,12,46133,46159,12,46245,46271,12,46357,46383,12,46469,46495,12,46581,46607,12,46693,46719,12,46805,46831,12,46917,46943,12,47029,47055,12,47141,47167,12,47253,47279,12,47365,47391,12,47477,47503,12,47589,47615,12,47701,47727,12,47813,47839,12,47925,47951,12,48037,48063,12,48149,48175,12,48261,48287,12,48373,48399,12,48485,48511,12,48597,48623,12,48709,48735,12,48821,48847,12,48933,48959,12,49045,49071,12,49157,49183,12,49269,49295,12,49381,49407,12,49493,49519,12,49605,49631,12,49717,49743,12,49829,49855,12,49941,49967,12,50053,50079,12,50165,50191,12,50277,50303,12,50389,50415,12,50501,50527,12,50613,50639,12,50725,50751,12,50837,50863,12,50949,50975,12,51061,51087,12,51173,51199,12,51285,51311,12,51397,51423,12,51509,51535,12,51621,51647,12,51733,51759,12,51845,51871,12,51957,51983,12,52069,52095,12,52181,52207,12,52293,52319,12,52405,52431,12,52517,52543,12,52629,52655,12,52741,52767,12,52853,52879,12,52965,52991,12,53077,53103,12,53189,53215,12,53301,53327,12,53413,53439,12,53525,53551,12,53637,53663,12,53749,53775,12,53861,53887,12,53973,53999,12,54085,54111,12,54197,54223,12,54309,54335,12,54421,54447,12,54533,54559,12,54645,54671,12,54757,54783,12,54869,54895,12,54981,55007,12,55093,55119,12,55243,55291,10,66045,66045,5,68325,68326,5,69688,69702,5,69817,69818,5,69957,69958,7,70089,70092,5,70198,70199,5,70462,70462,5,70502,70508,5,70750,70750,5,70846,70846,7,71100,71101,5,71230,71230,7,71351,71351,5,71737,71738,5,72000,72000,7,72160,72160,5,72273,72278,5,72752,72758,5,72882,72883,5,73031,73031,5,73461,73462,7,94192,94193,7,119149,119149,7,121403,121452,5,122915,122916,5,126980,126980,14,127358,127359,14,127535,127535,14,127759,127759,14,127771,127771,14,127792,127793,14,127825,127867,14,127897,127899,14,127945,127945,14,127985,127986,14,128000,128007,14,128021,128021,14,128066,128100,14,128184,128235,14,128249,128252,14,128266,128276,14,128335,128335,14,128379,128390,14,128407,128419,14,128444,128444,14,128481,128481,14,128499,128499,14,128526,128526,14,128536,128536,14,128543,128543,14,128556,128556,14,128564,128564,14,128577,128580,14,128643,128645,14,128649,128649,14,128654,128654,14,128660,128660,14,128664,128664,14,128675,128675,14,128686,128689,14,128695,128696,14,128705,128709,14,128717,128719,14,128725,128725,14,128736,128741,14,128747,128748,14,128755,128755,14,128762,128762,14,128981,128991,14,129009,129023,14,129160,129167,14,129296,129304,14,129320,129327,14,129340,129342,14,129356,129356,14,129388,129392,14,129399,129400,14,129404,129407,14,129432,129442,14,129454,129455,14,129473,129474,14,129485,129487,14,129648,129651,14,129659,129660,14,129671,129679,14,129709,129711,14,129728,129730,14,129751,129753,14,129776,129782,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,2274,2274,1,2363,2363,7,2377,2380,7,2402,2403,5,2494,2494,5,2507,2508,7,2558,2558,5,2622,2624,7,2641,2641,5,2691,2691,7,2759,2760,5,2786,2787,5,2876,2876,5,2881,2884,5,2901,2902,5,3006,3006,5,3014,3016,7,3072,3072,5,3134,3136,5,3157,3158,5,3260,3260,5,3266,3266,5,3274,3275,7,3328,3329,5,3391,3392,7,3405,3405,5,3457,3457,5,3536,3537,7,3551,3551,5,3636,3642,5,3764,3772,5,3895,3895,5,3967,3967,7,3993,4028,5,4146,4151,5,4182,4183,7,4226,4226,5,4253,4253,5,4957,4959,5,5940,5940,7,6070,6070,7,6087,6088,7,6158,6158,4,6432,6434,5,6448,6449,7,6679,6680,5,6742,6742,5,6754,6754,5,6783,6783,5,6912,6915,5,6966,6970,5,6978,6978,5,7042,7042,7,7080,7081,5,7143,7143,7,7150,7150,7,7212,7219,5,7380,7392,5,7412,7412,5,8203,8203,4,8232,8232,4,8265,8265,14,8400,8412,5,8421,8432,5,8617,8618,14,9167,9167,14,9200,9200,14,9410,9410,14,9723,9726,14,9733,9733,14,9745,9745,14,9752,9752,14,9760,9760,14,9766,9766,14,9774,9774,14,9786,9786,14,9794,9794,14,9823,9823,14,9828,9828,14,9833,9850,14,9855,9855,14,9875,9875,14,9880,9880,14,9885,9887,14,9896,9897,14,9906,9916,14,9926,9927,14,9935,9935,14,9939,9939,14,9962,9962,14,9972,9972,14,9978,9978,14,9986,9986,14,9997,9997,14,10002,10002,14,10017,10017,14,10055,10055,14,10071,10071,14,10133,10135,14,10548,10549,14,11093,11093,14,12330,12333,5,12441,12442,5,42608,42610,5,43010,43010,5,43045,43046,5,43188,43203,7,43302,43309,5,43392,43394,5,43446,43449,5,43493,43493,5,43571,43572,7,43597,43597,7,43703,43704,5,43756,43757,5,44003,44004,7,44009,44010,7,44033,44059,12,44089,44115,12,44145,44171,12,44201,44227,12,44257,44283,12,44313,44339,12,44369,44395,12,44425,44451,12,44481,44507,12,44537,44563,12,44593,44619,12,44649,44675,12,44705,44731,12,44761,44787,12,44817,44843,12,44873,44899,12,44929,44955,12,44985,45011,12,45041,45067,12,45097,45123,12,45153,45179,12,45209,45235,12,45265,45291,12,45321,45347,12,45377,45403,12,45433,45459,12,45489,45515,12,45545,45571,12,45601,45627,12,45657,45683,12,45713,45739,12,45769,45795,12,45825,45851,12,45881,45907,12,45937,45963,12,45993,46019,12,46049,46075,12,46105,46131,12,46161,46187,12,46217,46243,12,46273,46299,12,46329,46355,12,46385,46411,12,46441,46467,12,46497,46523,12,46553,46579,12,46609,46635,12,46665,46691,12,46721,46747,12,46777,46803,12,46833,46859,12,46889,46915,12,46945,46971,12,47001,47027,12,47057,47083,12,47113,47139,12,47169,47195,12,47225,47251,12,47281,47307,12,47337,47363,12,47393,47419,12,47449,47475,12,47505,47531,12,47561,47587,12,47617,47643,12,47673,47699,12,47729,47755,12,47785,47811,12,47841,47867,12,47897,47923,12,47953,47979,12,48009,48035,12,48065,48091,12,48121,48147,12,48177,48203,12,48233,48259,12,48289,48315,12,48345,48371,12,48401,48427,12,48457,48483,12,48513,48539,12,48569,48595,12,48625,48651,12,48681,48707,12,48737,48763,12,48793,48819,12,48849,48875,12,48905,48931,12,48961,48987,12,49017,49043,12,49073,49099,12,49129,49155,12,49185,49211,12,49241,49267,12,49297,49323,12,49353,49379,12,49409,49435,12,49465,49491,12,49521,49547,12,49577,49603,12,49633,49659,12,49689,49715,12,49745,49771,12,49801,49827,12,49857,49883,12,49913,49939,12,49969,49995,12,50025,50051,12,50081,50107,12,50137,50163,12,50193,50219,12,50249,50275,12,50305,50331,12,50361,50387,12,50417,50443,12,50473,50499,12,50529,50555,12,50585,50611,12,50641,50667,12,50697,50723,12,50753,50779,12,50809,50835,12,50865,50891,12,50921,50947,12,50977,51003,12,51033,51059,12,51089,51115,12,51145,51171,12,51201,51227,12,51257,51283,12,51313,51339,12,51369,51395,12,51425,51451,12,51481,51507,12,51537,51563,12,51593,51619,12,51649,51675,12,51705,51731,12,51761,51787,12,51817,51843,12,51873,51899,12,51929,51955,12,51985,52011,12,52041,52067,12,52097,52123,12,52153,52179,12,52209,52235,12,52265,52291,12,52321,52347,12,52377,52403,12,52433,52459,12,52489,52515,12,52545,52571,12,52601,52627,12,52657,52683,12,52713,52739,12,52769,52795,12,52825,52851,12,52881,52907,12,52937,52963,12,52993,53019,12,53049,53075,12,53105,53131,12,53161,53187,12,53217,53243,12,53273,53299,12,53329,53355,12,53385,53411,12,53441,53467,12,53497,53523,12,53553,53579,12,53609,53635,12,53665,53691,12,53721,53747,12,53777,53803,12,53833,53859,12,53889,53915,12,53945,53971,12,54001,54027,12,54057,54083,12,54113,54139,12,54169,54195,12,54225,54251,12,54281,54307,12,54337,54363,12,54393,54419,12,54449,54475,12,54505,54531,12,54561,54587,12,54617,54643,12,54673,54699,12,54729,54755,12,54785,54811,12,54841,54867,12,54897,54923,12,54953,54979,12,55009,55035,12,55065,55091,12,55121,55147,12,55177,55203,12,65024,65039,5,65520,65528,4,66422,66426,5,68152,68154,5,69291,69292,5,69633,69633,5,69747,69748,5,69811,69814,5,69826,69826,5,69932,69932,7,70016,70017,5,70079,70080,7,70095,70095,5,70196,70196,5,70367,70367,5,70402,70403,7,70464,70464,5,70487,70487,5,70709,70711,7,70725,70725,7,70833,70834,7,70843,70844,7,70849,70849,7,71090,71093,5,71103,71104,5,71227,71228,7,71339,71339,5,71344,71349,5,71458,71461,5,71727,71735,5,71985,71989,7,71998,71998,5,72002,72002,7,72154,72155,5,72193,72202,5,72251,72254,5,72281,72283,5,72344,72345,5,72766,72766,7,72874,72880,5,72885,72886,5,73023,73029,5,73104,73105,5,73111,73111,5,92912,92916,5,94095,94098,5,113824,113827,4,119142,119142,7,119155,119162,4,119362,119364,5,121476,121476,5,122888,122904,5,123184,123190,5,125252,125258,5,127183,127183,14,127340,127343,14,127377,127386,14,127491,127503,14,127548,127551,14,127744,127756,14,127761,127761,14,127769,127769,14,127773,127774,14,127780,127788,14,127796,127797,14,127820,127823,14,127869,127869,14,127894,127895,14,127902,127903,14,127943,127943,14,127947,127950,14,127972,127972,14,127988,127988,14,127992,127994,14,128009,128011,14,128019,128019,14,128023,128041,14,128064,128064,14,128102,128107,14,128174,128181,14,128238,128238,14,128246,128247,14,128254,128254,14,128264,128264,14,128278,128299,14,128329,128330,14,128348,128359,14,128371,128377,14,128392,128393,14,128401,128404,14,128421,128421,14,128433,128434,14,128450,128452,14,128476,128478,14,128483,128483,14,128495,128495,14,128506,128506,14,128519,128520,14,128528,128528,14,128534,128534,14,128538,128538,14,128540,128542,14,128544,128549,14,128552,128555,14,128557,128557,14,128560,128563,14,128565,128565,14,128567,128576,14,128581,128591,14,128641,128642,14,128646,128646,14,128648,128648,14,128650,128651,14,128653,128653,14,128655,128655,14,128657,128659,14,128661,128661,14,128663,128663,14,128665,128666,14,128674,128674,14,128676,128677,14,128679,128685,14,128690,128690,14,128694,128694,14,128697,128702,14,128704,128704,14,128710,128714,14,128716,128716,14,128720,128720,14,128723,128724,14,128726,128727,14,128733,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,129008,129008,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,129661,129663,14,129667,129670,14,129680,129685,14,129705,129708,14,129712,129718,14,129723,129727,14,129731,129733,14,129744,129750,14,129754,129759,14,129768,129775,14,129783,129791,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,2192,2193,1,2250,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,3132,3132,5,3137,3140,7,3146,3149,5,3170,3171,5,3202,3203,7,3262,3262,7,3264,3265,7,3267,3268,7,3271,3272,7,3276,3277,5,3298,3299,5,3330,3331,7,3390,3390,5,3393,3396,5,3402,3404,7,3406,3406,1,3426,3427,5,3458,3459,7,3535,3535,5,3538,3540,5,3544,3550,7,3570,3571,7,3635,3635,7,3655,3662,5,3763,3763,7,3784,3789,5,3893,3893,5,3897,3897,5,3953,3966,5,3968,3972,5,3981,3991,5,4038,4038,5,4145,4145,7,4153,4154,5,4157,4158,5,4184,4185,5,4209,4212,5,4228,4228,7,4237,4237,5,4352,4447,8,4520,4607,10,5906,5908,5,5938,5939,5,5970,5971,5,6068,6069,5,6071,6077,5,6086,6086,5,6089,6099,5,6155,6157,5,6159,6159,5,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,6862,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,7679,5,8204,8204,5,8206,8207,4,8233,8233,4,8252,8252,14,8288,8292,4,8294,8303,4,8413,8416,5,8418,8420,5,8482,8482,14,8596,8601,14,8986,8987,14,9096,9096,14,9193,9196,14,9199,9199,14,9201,9202,14,9208,9210,14,9642,9643,14,9664,9664,14,9728,9729,14,9732,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,9775,9775,14,9784,9785,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,9874,14,9876,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,9934,14,9936,9936,14,9938,9938,14,9940,9940,14,9961,9961,14,9963,9967,14,9970,9971,14,9973,9973,14,9975,9977,14,9979,9980,14,9982,9985,14,9987,9988,14,9992,9996,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,10083,14,10085,10087,14,10145,10145,14,10175,10175,14,11013,11015,14,11088,11088,14,11503,11505,5,11744,11775,5,12334,12335,5,12349,12349,14,12951,12951,14,42607,42607,5,42612,42621,5,42736,42737,5,43014,43014,5,43043,43044,7,43047,43047,7,43136,43137,7,43204,43205,5,43263,43263,5,43335,43345,5,43360,43388,8,43395,43395,7,43444,43445,7,43450,43451,7,43454,43456,7,43561,43566,5,43569,43570,5,43573,43574,5,43596,43596,5,43644,43644,5,43698,43700,5,43710,43711,5,43755,43755,7,43758,43759,7,43766,43766,5,44005,44005,5,44008,44008,5,44012,44012,7,44032,44032,11,44060,44060,11,44088,44088,11,44116,44116,11,44144,44144,11,44172,44172,11,44200,44200,11,44228,44228,11,44256,44256,11,44284,44284,11,44312,44312,11,44340,44340,11,44368,44368,11,44396,44396,11,44424,44424,11,44452,44452,11,44480,44480,11,44508,44508,11,44536,44536,11,44564,44564,11,44592,44592,11,44620,44620,11,44648,44648,11,44676,44676,11,44704,44704,11,44732,44732,11,44760,44760,11,44788,44788,11,44816,44816,11,44844,44844,11,44872,44872,11,44900,44900,11,44928,44928,11,44956,44956,11,44984,44984,11,45012,45012,11,45040,45040,11,45068,45068,11,45096,45096,11,45124,45124,11,45152,45152,11,45180,45180,11,45208,45208,11,45236,45236,11,45264,45264,11,45292,45292,11,45320,45320,11,45348,45348,11,45376,45376,11,45404,45404,11,45432,45432,11,45460,45460,11,45488,45488,11,45516,45516,11,45544,45544,11,45572,45572,11,45600,45600,11,45628,45628,11,45656,45656,11,45684,45684,11,45712,45712,11,45740,45740,11,45768,45768,11,45796,45796,11,45824,45824,11,45852,45852,11,45880,45880,11,45908,45908,11,45936,45936,11,45964,45964,11,45992,45992,11,46020,46020,11,46048,46048,11,46076,46076,11,46104,46104,11,46132,46132,11,46160,46160,11,46188,46188,11,46216,46216,11,46244,46244,11,46272,46272,11,46300,46300,11,46328,46328,11,46356,46356,11,46384,46384,11,46412,46412,11,46440,46440,11,46468,46468,11,46496,46496,11,46524,46524,11,46552,46552,11,46580,46580,11,46608,46608,11,46636,46636,11,46664,46664,11,46692,46692,11,46720,46720,11,46748,46748,11,46776,46776,11,46804,46804,11,46832,46832,11,46860,46860,11,46888,46888,11,46916,46916,11,46944,46944,11,46972,46972,11,47000,47000,11,47028,47028,11,47056,47056,11,47084,47084,11,47112,47112,11,47140,47140,11,47168,47168,11,47196,47196,11,47224,47224,11,47252,47252,11,47280,47280,11,47308,47308,11,47336,47336,11,47364,47364,11,47392,47392,11,47420,47420,11,47448,47448,11,47476,47476,11,47504,47504,11,47532,47532,11,47560,47560,11,47588,47588,11,47616,47616,11,47644,47644,11,47672,47672,11,47700,47700,11,47728,47728,11,47756,47756,11,47784,47784,11,47812,47812,11,47840,47840,11,47868,47868,11,47896,47896,11,47924,47924,11,47952,47952,11,47980,47980,11,48008,48008,11,48036,48036,11,48064,48064,11,48092,48092,11,48120,48120,11,48148,48148,11,48176,48176,11,48204,48204,11,48232,48232,11,48260,48260,11,48288,48288,11,48316,48316,11,48344,48344,11,48372,48372,11,48400,48400,11,48428,48428,11,48456,48456,11,48484,48484,11,48512,48512,11,48540,48540,11,48568,48568,11,48596,48596,11,48624,48624,11,48652,48652,11,48680,48680,11,48708,48708,11,48736,48736,11,48764,48764,11,48792,48792,11,48820,48820,11,48848,48848,11,48876,48876,11,48904,48904,11,48932,48932,11,48960,48960,11,48988,48988,11,49016,49016,11,49044,49044,11,49072,49072,11,49100,49100,11,49128,49128,11,49156,49156,11,49184,49184,11,49212,49212,11,49240,49240,11,49268,49268,11,49296,49296,11,49324,49324,11,49352,49352,11,49380,49380,11,49408,49408,11,49436,49436,11,49464,49464,11,49492,49492,11,49520,49520,11,49548,49548,11,49576,49576,11,49604,49604,11,49632,49632,11,49660,49660,11,49688,49688,11,49716,49716,11,49744,49744,11,49772,49772,11,49800,49800,11,49828,49828,11,49856,49856,11,49884,49884,11,49912,49912,11,49940,49940,11,49968,49968,11,49996,49996,11,50024,50024,11,50052,50052,11,50080,50080,11,50108,50108,11,50136,50136,11,50164,50164,11,50192,50192,11,50220,50220,11,50248,50248,11,50276,50276,11,50304,50304,11,50332,50332,11,50360,50360,11,50388,50388,11,50416,50416,11,50444,50444,11,50472,50472,11,50500,50500,11,50528,50528,11,50556,50556,11,50584,50584,11,50612,50612,11,50640,50640,11,50668,50668,11,50696,50696,11,50724,50724,11,50752,50752,11,50780,50780,11,50808,50808,11,50836,50836,11,50864,50864,11,50892,50892,11,50920,50920,11,50948,50948,11,50976,50976,11,51004,51004,11,51032,51032,11,51060,51060,11,51088,51088,11,51116,51116,11,51144,51144,11,51172,51172,11,51200,51200,11,51228,51228,11,51256,51256,11,51284,51284,11,51312,51312,11,51340,51340,11,51368,51368,11,51396,51396,11,51424,51424,11,51452,51452,11,51480,51480,11,51508,51508,11,51536,51536,11,51564,51564,11,51592,51592,11,51620,51620,11,51648,51648,11,51676,51676,11,51704,51704,11,51732,51732,11,51760,51760,11,51788,51788,11,51816,51816,11,51844,51844,11,51872,51872,11,51900,51900,11,51928,51928,11,51956,51956,11,51984,51984,11,52012,52012,11,52040,52040,11,52068,52068,11,52096,52096,11,52124,52124,11,52152,52152,11,52180,52180,11,52208,52208,11,52236,52236,11,52264,52264,11,52292,52292,11,52320,52320,11,52348,52348,11,52376,52376,11,52404,52404,11,52432,52432,11,52460,52460,11,52488,52488,11,52516,52516,11,52544,52544,11,52572,52572,11,52600,52600,11,52628,52628,11,52656,52656,11,52684,52684,11,52712,52712,11,52740,52740,11,52768,52768,11,52796,52796,11,52824,52824,11,52852,52852,11,52880,52880,11,52908,52908,11,52936,52936,11,52964,52964,11,52992,52992,11,53020,53020,11,53048,53048,11,53076,53076,11,53104,53104,11,53132,53132,11,53160,53160,11,53188,53188,11,53216,53216,11,53244,53244,11,53272,53272,11,53300,53300,11,53328,53328,11,53356,53356,11,53384,53384,11,53412,53412,11,53440,53440,11,53468,53468,11,53496,53496,11,53524,53524,11,53552,53552,11,53580,53580,11,53608,53608,11,53636,53636,11,53664,53664,11,53692,53692,11,53720,53720,11,53748,53748,11,53776,53776,11,53804,53804,11,53832,53832,11,53860,53860,11,53888,53888,11,53916,53916,11,53944,53944,11,53972,53972,11,54000,54000,11,54028,54028,11,54056,54056,11,54084,54084,11,54112,54112,11,54140,54140,11,54168,54168,11,54196,54196,11,54224,54224,11,54252,54252,11,54280,54280,11,54308,54308,11,54336,54336,11,54364,54364,11,54392,54392,11,54420,54420,11,54448,54448,11,54476,54476,11,54504,54504,11,54532,54532,11,54560,54560,11,54588,54588,11,54616,54616,11,54644,54644,11,54672,54672,11,54700,54700,11,54728,54728,11,54756,54756,11,54784,54784,11,54812,54812,11,54840,54840,11,54868,54868,11,54896,54896,11,54924,54924,11,54952,54952,11,54980,54980,11,55008,55008,11,55036,55036,11,55064,55064,11,55092,55092,11,55120,55120,11,55148,55148,11,55176,55176,11,55216,55238,9,64286,64286,5,65056,65071,5,65438,65439,5,65529,65531,4,66272,66272,5,68097,68099,5,68108,68111,5,68159,68159,5,68900,68903,5,69446,69456,5,69632,69632,7,69634,69634,7,69744,69744,5,69759,69761,5,69808,69810,7,69815,69816,7,69821,69821,1,69837,69837,1,69927,69931,5,69933,69940,5,70003,70003,5,70018,70018,7,70070,70078,5,70082,70083,1,70094,70094,7,70188,70190,7,70194,70195,7,70197,70197,7,70206,70206,5,70368,70370,7,70400,70401,5,70459,70460,5,70463,70463,7,70465,70468,7,70475,70477,7,70498,70499,7,70512,70516,5,70712,70719,5,70722,70724,5,70726,70726,5,70832,70832,5,70835,70840,5,70842,70842,5,70845,70845,5,70847,70848,5,70850,70851,5,71088,71089,7,71096,71099,7,71102,71102,7,71132,71133,5,71219,71226,5,71229,71229,5,71231,71232,5,71340,71340,7,71342,71343,7,71350,71350,7,71453,71455,5,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,118528,118573,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,123566,123566,5,125136,125142,5,126976,126979,14,126981,127182,14,127184,127231,14,127279,127279,14,127344,127345,14,127374,127374,14,127405,127461,14,127489,127490,14,127514,127514,14,127538,127546,14,127561,127567,14,127570,127743,14,127757,127758,14,127760,127760,14,127762,127762,14,127766,127768,14,127770,127770,14,127772,127772,14,127775,127776,14,127778,127779,14,127789,127791,14,127794,127795,14,127798,127798,14,127819,127819,14,127824,127824,14,127868,127868,14,127870,127871,14,127892,127893,14,127896,127896,14,127900,127901,14,127904,127940,14,127942,127942,14,127944,127944,14,127946,127946,14,127951,127955,14,127968,127971,14,127973,127984,14,127987,127987,14,127989,127989,14,127991,127991,14,127995,127999,5,128008,128008,14,128012,128014,14,128017,128018,14,128020,128020,14,128022,128022,14,128042,128042,14,128063,128063,14,128065,128065,14,128101,128101,14,128108,128109,14,128173,128173,14,128182,128183,14,128236,128237,14,128239,128239,14,128245,128245,14,128248,128248,14,128253,128253,14,128255,128258,14,128260,128263,14,128265,128265,14,128277,128277,14,128300,128301,14,128326,128328,14,128331,128334,14,128336,128347,14,128360,128366,14,128369,128370,14,128378,128378,14,128391,128391,14,128394,128397,14,128400,128400,14,128405,128406,14,128420,128420,14,128422,128423,14,128425,128432,14,128435,128443,14,128445,128449,14,128453,128464,14,128468,128475,14,128479,128480,14,128482,128482,14,128484,128487,14,128489,128494,14,128496,128498,14,128500,128505,14,128507,128511,14,128513,128518,14,128521,128525,14,128527,128527,14,128529,128529,14,128533,128533,14,128535,128535,14,128537,128537,14]');\n}\n\n//#endregion\n\n/**\n * Computes the offset after performing a left delete on the given string,\n * while considering unicode grapheme/emoji rules.\n*/\nexport function getLeftDeleteOffset(offset: number, str: string): number {\n\tif (offset === 0) {\n\t\treturn 0;\n\t}\n\n\t// Try to delete emoji part.\n\tconst emojiOffset = getOffsetBeforeLastEmojiComponent(offset, str);\n\tif (emojiOffset !== undefined) {\n\t\treturn emojiOffset;\n\t}\n\n\t// Otherwise, just skip a single code point.\n\tconst iterator = new CodePointIterator(str, offset);\n\titerator.prevCodePoint();\n\treturn iterator.offset;\n}\n\nfunction getOffsetBeforeLastEmojiComponent(initialOffset: number, str: string): number | undefined {\n\t// See https://www.unicode.org/reports/tr51/tr51-14.html#EBNF_and_Regex for the\n\t// structure of emojis.\n\tconst iterator = new CodePointIterator(str, initialOffset);\n\tlet codePoint = iterator.prevCodePoint();\n\n\t// Skip modifiers\n\twhile ((isEmojiModifier(codePoint) || codePoint === CodePoint.emojiVariantSelector || codePoint === CodePoint.enclosingKeyCap)) {\n\t\tif (iterator.offset === 0) {\n\t\t\t// Cannot skip modifier, no preceding emoji base.\n\t\t\treturn undefined;\n\t\t}\n\t\tcodePoint = iterator.prevCodePoint();\n\t}\n\n\t// Expect base emoji\n\tif (!isEmojiImprecise(codePoint)) {\n\t\t// Unexpected code point, not a valid emoji.\n\t\treturn undefined;\n\t}\n\n\tlet resultOffset = iterator.offset;\n\n\tif (resultOffset > 0) {\n\t\t// Skip optional ZWJ code points that combine multiple emojis.\n\t\t// In theory, we should check if that ZWJ actually combines multiple emojis\n\t\t// to prevent deleting ZWJs in situations we didn't account for.\n\t\tconst optionalZwjCodePoint = iterator.prevCodePoint();\n\t\tif (optionalZwjCodePoint === CodePoint.zwj) {\n\t\t\tresultOffset = iterator.offset;\n\t\t}\n\t}\n\n\treturn resultOffset;\n}\n\nfunction isEmojiModifier(codePoint: number): boolean {\n\treturn 0x1F3FB <= codePoint && codePoint <= 0x1F3FF;\n}\n\nconst enum CodePoint {\n\tzwj = 0x200D,\n\n\t/**\n\t * Variation Selector-16 (VS16)\n\t*/\n\temojiVariantSelector = 0xFE0F,\n\n\t/**\n\t * Combining Enclosing Keycap\n\t */\n\tenclosingKeyCap = 0x20E3,\n}\n\nexport const noBreakWhitespace = '\\xa0';\n\nexport class AmbiguousCharacters {\n\tprivate static readonly ambiguousCharacterData = new Lazy<\n\t\tRecord<\n\t\t\tstring | '_common' | '_default',\n\t\t\t/* code point -> ascii code point */ number[]\n\t\t>\n\t>(() => {\n\t\t// Generated using https://github.com/hediet/vscode-unicode-data\n\t\t// Stored as key1, value1, key2, value2, ...\n\t\treturn JSON.parse(\n\t\t\t'{\\\"_common\\\":[8232,32,8233,32,5760,32,8192,32,8193,32,8194,32,8195,32,8196,32,8197,32,8198,32,8200,32,8201,32,8202,32,8287,32,8199,32,8239,32,2042,95,65101,95,65102,95,65103,95,8208,45,8209,45,8210,45,65112,45,1748,45,8259,45,727,45,8722,45,10134,45,11450,45,1549,44,1643,44,8218,44,184,44,42233,44,894,59,2307,58,2691,58,1417,58,1795,58,1796,58,5868,58,65072,58,6147,58,6153,58,8282,58,1475,58,760,58,42889,58,8758,58,720,58,42237,58,451,33,11601,33,660,63,577,63,2429,63,5038,63,42731,63,119149,46,8228,46,1793,46,1794,46,42510,46,68176,46,1632,46,1776,46,42232,46,1373,96,65287,96,8219,96,8242,96,1370,96,1523,96,8175,96,65344,96,900,96,8189,96,8125,96,8127,96,8190,96,697,96,884,96,712,96,714,96,715,96,756,96,699,96,701,96,700,96,702,96,42892,96,1497,96,2036,96,2037,96,5194,96,5836,96,94033,96,94034,96,65339,91,10088,40,10098,40,12308,40,64830,40,65341,93,10089,41,10099,41,12309,41,64831,41,10100,123,119060,123,10101,125,65342,94,8270,42,1645,42,8727,42,66335,42,5941,47,8257,47,8725,47,8260,47,9585,47,10187,47,10744,47,119354,47,12755,47,12339,47,11462,47,20031,47,12035,47,65340,92,65128,92,8726,92,10189,92,10741,92,10745,92,119311,92,119355,92,12756,92,20022,92,12034,92,42872,38,708,94,710,94,5869,43,10133,43,66203,43,8249,60,10094,60,706,60,119350,60,5176,60,5810,60,5120,61,11840,61,12448,61,42239,61,8250,62,10095,62,707,62,119351,62,5171,62,94015,62,8275,126,732,126,8128,126,8764,126,65372,124,65293,45,120784,50,120794,50,120804,50,120814,50,120824,50,130034,50,42842,50,423,50,1000,50,42564,50,5311,50,42735,50,119302,51,120785,51,120795,51,120805,51,120815,51,120825,51,130035,51,42923,51,540,51,439,51,42858,51,11468,51,1248,51,94011,51,71882,51,120786,52,120796,52,120806,52,120816,52,120826,52,130036,52,5070,52,71855,52,120787,53,120797,53,120807,53,120817,53,120827,53,130037,53,444,53,71867,53,120788,54,120798,54,120808,54,120818,54,120828,54,130038,54,11474,54,5102,54,71893,54,119314,55,120789,55,120799,55,120809,55,120819,55,120829,55,130039,55,66770,55,71878,55,2819,56,2538,56,2666,56,125131,56,120790,56,120800,56,120810,56,120820,56,120830,56,130040,56,547,56,546,56,66330,56,2663,57,2920,57,2541,57,3437,57,120791,57,120801,57,120811,57,120821,57,120831,57,130041,57,42862,57,11466,57,71884,57,71852,57,71894,57,9082,97,65345,97,119834,97,119886,97,119938,97,119990,97,120042,97,120094,97,120146,97,120198,97,120250,97,120302,97,120354,97,120406,97,120458,97,593,97,945,97,120514,97,120572,97,120630,97,120688,97,120746,97,65313,65,119808,65,119860,65,119912,65,119964,65,120016,65,120068,65,120120,65,120172,65,120224,65,120276,65,120328,65,120380,65,120432,65,913,65,120488,65,120546,65,120604,65,120662,65,120720,65,5034,65,5573,65,42222,65,94016,65,66208,65,119835,98,119887,98,119939,98,119991,98,120043,98,120095,98,120147,98,120199,98,120251,98,120303,98,120355,98,120407,98,120459,98,388,98,5071,98,5234,98,5551,98,65314,66,8492,66,119809,66,119861,66,119913,66,120017,66,120069,66,120121,66,120173,66,120225,66,120277,66,120329,66,120381,66,120433,66,42932,66,914,66,120489,66,120547,66,120605,66,120663,66,120721,66,5108,66,5623,66,42192,66,66178,66,66209,66,66305,66,65347,99,8573,99,119836,99,119888,99,119940,99,119992,99,120044,99,120096,99,120148,99,120200,99,120252,99,120304,99,120356,99,120408,99,120460,99,7428,99,1010,99,11429,99,43951,99,66621,99,128844,67,71922,67,71913,67,65315,67,8557,67,8450,67,8493,67,119810,67,119862,67,119914,67,119966,67,120018,67,120174,67,120226,67,120278,67,120330,67,120382,67,120434,67,1017,67,11428,67,5087,67,42202,67,66210,67,66306,67,66581,67,66844,67,8574,100,8518,100,119837,100,119889,100,119941,100,119993,100,120045,100,120097,100,120149,100,120201,100,120253,100,120305,100,120357,100,120409,100,120461,100,1281,100,5095,100,5231,100,42194,100,8558,68,8517,68,119811,68,119863,68,119915,68,119967,68,120019,68,120071,68,120123,68,120175,68,120227,68,120279,68,120331,68,120383,68,120435,68,5024,68,5598,68,5610,68,42195,68,8494,101,65349,101,8495,101,8519,101,119838,101,119890,101,119942,101,120046,101,120098,101,120150,101,120202,101,120254,101,120306,101,120358,101,120410,101,120462,101,43826,101,1213,101,8959,69,65317,69,8496,69,119812,69,119864,69,119916,69,120020,69,120072,69,120124,69,120176,69,120228,69,120280,69,120332,69,120384,69,120436,69,917,69,120492,69,120550,69,120608,69,120666,69,120724,69,11577,69,5036,69,42224,69,71846,69,71854,69,66182,69,119839,102,119891,102,119943,102,119995,102,120047,102,120099,102,120151,102,120203,102,120255,102,120307,102,120359,102,120411,102,120463,102,43829,102,42905,102,383,102,7837,102,1412,102,119315,70,8497,70,119813,70,119865,70,119917,70,120021,70,120073,70,120125,70,120177,70,120229,70,120281,70,120333,70,120385,70,120437,70,42904,70,988,70,120778,70,5556,70,42205,70,71874,70,71842,70,66183,70,66213,70,66853,70,65351,103,8458,103,119840,103,119892,103,119944,103,120048,103,120100,103,120152,103,120204,103,120256,103,120308,103,120360,103,120412,103,120464,103,609,103,7555,103,397,103,1409,103,119814,71,119866,71,119918,71,119970,71,120022,71,120074,71,120126,71,120178,71,120230,71,120282,71,120334,71,120386,71,120438,71,1292,71,5056,71,5107,71,42198,71,65352,104,8462,104,119841,104,119945,104,119997,104,120049,104,120101,104,120153,104,120205,104,120257,104,120309,104,120361,104,120413,104,120465,104,1211,104,1392,104,5058,104,65320,72,8459,72,8460,72,8461,72,119815,72,119867,72,119919,72,120023,72,120179,72,120231,72,120283,72,120335,72,120387,72,120439,72,919,72,120494,72,120552,72,120610,72,120668,72,120726,72,11406,72,5051,72,5500,72,42215,72,66255,72,731,105,9075,105,65353,105,8560,105,8505,105,8520,105,119842,105,119894,105,119946,105,119998,105,120050,105,120102,105,120154,105,120206,105,120258,105,120310,105,120362,105,120414,105,120466,105,120484,105,618,105,617,105,953,105,8126,105,890,105,120522,105,120580,105,120638,105,120696,105,120754,105,1110,105,42567,105,1231,105,43893,105,5029,105,71875,105,65354,106,8521,106,119843,106,119895,106,119947,106,119999,106,120051,106,120103,106,120155,106,120207,106,120259,106,120311,106,120363,106,120415,106,120467,106,1011,106,1112,106,65322,74,119817,74,119869,74,119921,74,119973,74,120025,74,120077,74,120129,74,120181,74,120233,74,120285,74,120337,74,120389,74,120441,74,42930,74,895,74,1032,74,5035,74,5261,74,42201,74,119844,107,119896,107,119948,107,120000,107,120052,107,120104,107,120156,107,120208,107,120260,107,120312,107,120364,107,120416,107,120468,107,8490,75,65323,75,119818,75,119870,75,119922,75,119974,75,120026,75,120078,75,120130,75,120182,75,120234,75,120286,75,120338,75,120390,75,120442,75,922,75,120497,75,120555,75,120613,75,120671,75,120729,75,11412,75,5094,75,5845,75,42199,75,66840,75,1472,108,8739,73,9213,73,65512,73,1633,108,1777,73,66336,108,125127,108,120783,73,120793,73,120803,73,120813,73,120823,73,130033,73,65321,73,8544,73,8464,73,8465,73,119816,73,119868,73,119920,73,120024,73,120128,73,120180,73,120232,73,120284,73,120336,73,120388,73,120440,73,65356,108,8572,73,8467,108,119845,108,119897,108,119949,108,120001,108,120053,108,120105,73,120157,73,120209,73,120261,73,120313,73,120365,73,120417,73,120469,73,448,73,120496,73,120554,73,120612,73,120670,73,120728,73,11410,73,1030,73,1216,73,1493,108,1503,108,1575,108,126464,108,126592,108,65166,108,65165,108,1994,108,11599,73,5825,73,42226,73,93992,73,66186,124,66313,124,119338,76,8556,76,8466,76,119819,76,119871,76,119923,76,120027,76,120079,76,120131,76,120183,76,120235,76,120287,76,120339,76,120391,76,120443,76,11472,76,5086,76,5290,76,42209,76,93974,76,71843,76,71858,76,66587,76,66854,76,65325,77,8559,77,8499,77,119820,77,119872,77,119924,77,120028,77,120080,77,120132,77,120184,77,120236,77,120288,77,120340,77,120392,77,120444,77,924,77,120499,77,120557,77,120615,77,120673,77,120731,77,1018,77,11416,77,5047,77,5616,77,5846,77,42207,77,66224,77,66321,77,119847,110,119899,110,119951,110,120003,110,120055,110,120107,110,120159,110,120211,110,120263,110,120315,110,120367,110,120419,110,120471,110,1400,110,1404,110,65326,78,8469,78,119821,78,119873,78,119925,78,119977,78,120029,78,120081,78,120185,78,120237,78,120289,78,120341,78,120393,78,120445,78,925,78,120500,78,120558,78,120616,78,120674,78,120732,78,11418,78,42208,78,66835,78,3074,111,3202,111,3330,111,3458,111,2406,111,2662,111,2790,111,3046,111,3174,111,3302,111,3430,111,3664,111,3792,111,4160,111,1637,111,1781,111,65359,111,8500,111,119848,111,119900,111,119952,111,120056,111,120108,111,120160,111,120212,111,120264,111,120316,111,120368,111,120420,111,120472,111,7439,111,7441,111,43837,111,959,111,120528,111,120586,111,120644,111,120702,111,120760,111,963,111,120532,111,120590,111,120648,111,120706,111,120764,111,11423,111,4351,111,1413,111,1505,111,1607,111,126500,111,126564,111,126596,111,65259,111,65260,111,65258,111,65257,111,1726,111,64428,111,64429,111,64427,111,64426,111,1729,111,64424,111,64425,111,64423,111,64422,111,1749,111,3360,111,4125,111,66794,111,71880,111,71895,111,66604,111,1984,79,2534,79,2918,79,12295,79,70864,79,71904,79,120782,79,120792,79,120802,79,120812,79,120822,79,130032,79,65327,79,119822,79,119874,79,119926,79,119978,79,120030,79,120082,79,120134,79,120186,79,120238,79,120290,79,120342,79,120394,79,120446,79,927,79,120502,79,120560,79,120618,79,120676,79,120734,79,11422,79,1365,79,11604,79,4816,79,2848,79,66754,79,42227,79,71861,79,66194,79,66219,79,66564,79,66838,79,9076,112,65360,112,119849,112,119901,112,119953,112,120005,112,120057,112,120109,112,120161,112,120213,112,120265,112,120317,112,120369,112,120421,112,120473,112,961,112,120530,112,120544,112,120588,112,120602,112,120646,112,120660,112,120704,112,120718,112,120762,112,120776,112,11427,112,65328,80,8473,80,119823,80,119875,80,119927,80,119979,80,120031,80,120083,80,120187,80,120239,80,120291,80,120343,80,120395,80,120447,80,929,80,120504,80,120562,80,120620,80,120678,80,120736,80,11426,80,5090,80,5229,80,42193,80,66197,80,119850,113,119902,113,119954,113,120006,113,120058,113,120110,113,120162,113,120214,113,120266,113,120318,113,120370,113,120422,113,120474,113,1307,113,1379,113,1382,113,8474,81,119824,81,119876,81,119928,81,119980,81,120032,81,120084,81,120188,81,120240,81,120292,81,120344,81,120396,81,120448,81,11605,81,119851,114,119903,114,119955,114,120007,114,120059,114,120111,114,120163,114,120215,114,120267,114,120319,114,120371,114,120423,114,120475,114,43847,114,43848,114,7462,114,11397,114,43905,114,119318,82,8475,82,8476,82,8477,82,119825,82,119877,82,119929,82,120033,82,120189,82,120241,82,120293,82,120345,82,120397,82,120449,82,422,82,5025,82,5074,82,66740,82,5511,82,42211,82,94005,82,65363,115,119852,115,119904,115,119956,115,120008,115,120060,115,120112,115,120164,115,120216,115,120268,115,120320,115,120372,115,120424,115,120476,115,42801,115,445,115,1109,115,43946,115,71873,115,66632,115,65331,83,119826,83,119878,83,119930,83,119982,83,120034,83,120086,83,120138,83,120190,83,120242,83,120294,83,120346,83,120398,83,120450,83,1029,83,1359,83,5077,83,5082,83,42210,83,94010,83,66198,83,66592,83,119853,116,119905,116,119957,116,120009,116,120061,116,120113,116,120165,116,120217,116,120269,116,120321,116,120373,116,120425,116,120477,116,8868,84,10201,84,128872,84,65332,84,119827,84,119879,84,119931,84,119983,84,120035,84,120087,84,120139,84,120191,84,120243,84,120295,84,120347,84,120399,84,120451,84,932,84,120507,84,120565,84,120623,84,120681,84,120739,84,11430,84,5026,84,42196,84,93962,84,71868,84,66199,84,66225,84,66325,84,119854,117,119906,117,119958,117,120010,117,120062,117,120114,117,120166,117,120218,117,120270,117,120322,117,120374,117,120426,117,120478,117,42911,117,7452,117,43854,117,43858,117,651,117,965,117,120534,117,120592,117,120650,117,120708,117,120766,117,1405,117,66806,117,71896,117,8746,85,8899,85,119828,85,119880,85,119932,85,119984,85,120036,85,120088,85,120140,85,120192,85,120244,85,120296,85,120348,85,120400,85,120452,85,1357,85,4608,85,66766,85,5196,85,42228,85,94018,85,71864,85,8744,118,8897,118,65366,118,8564,118,119855,118,119907,118,119959,118,120011,118,120063,118,120115,118,120167,118,120219,118,120271,118,120323,118,120375,118,120427,118,120479,118,7456,118,957,118,120526,118,120584,118,120642,118,120700,118,120758,118,1141,118,1496,118,71430,118,43945,118,71872,118,119309,86,1639,86,1783,86,8548,86,119829,86,119881,86,119933,86,119985,86,120037,86,120089,86,120141,86,120193,86,120245,86,120297,86,120349,86,120401,86,120453,86,1140,86,11576,86,5081,86,5167,86,42719,86,42214,86,93960,86,71840,86,66845,86,623,119,119856,119,119908,119,119960,119,120012,119,120064,119,120116,119,120168,119,120220,119,120272,119,120324,119,120376,119,120428,119,120480,119,7457,119,1121,119,1309,119,1377,119,71434,119,71438,119,71439,119,43907,119,71919,87,71910,87,119830,87,119882,87,119934,87,119986,87,120038,87,120090,87,120142,87,120194,87,120246,87,120298,87,120350,87,120402,87,120454,87,1308,87,5043,87,5076,87,42218,87,5742,120,10539,120,10540,120,10799,120,65368,120,8569,120,119857,120,119909,120,119961,120,120013,120,120065,120,120117,120,120169,120,120221,120,120273,120,120325,120,120377,120,120429,120,120481,120,5441,120,5501,120,5741,88,9587,88,66338,88,71916,88,65336,88,8553,88,119831,88,119883,88,119935,88,119987,88,120039,88,120091,88,120143,88,120195,88,120247,88,120299,88,120351,88,120403,88,120455,88,42931,88,935,88,120510,88,120568,88,120626,88,120684,88,120742,88,11436,88,11613,88,5815,88,42219,88,66192,88,66228,88,66327,88,66855,88,611,121,7564,121,65369,121,119858,121,119910,121,119962,121,120014,121,120066,121,120118,121,120170,121,120222,121,120274,121,120326,121,120378,121,120430,121,120482,121,655,121,7935,121,43866,121,947,121,8509,121,120516,121,120574,121,120632,121,120690,121,120748,121,1199,121,4327,121,71900,121,65337,89,119832,89,119884,89,119936,89,119988,89,120040,89,120092,89,120144,89,120196,89,120248,89,120300,89,120352,89,120404,89,120456,89,933,89,978,89,120508,89,120566,89,120624,89,120682,89,120740,89,11432,89,1198,89,5033,89,5053,89,42220,89,94019,89,71844,89,66226,89,119859,122,119911,122,119963,122,120015,122,120067,122,120119,122,120171,122,120223,122,120275,122,120327,122,120379,122,120431,122,120483,122,7458,122,43923,122,71876,122,66293,90,71909,90,65338,90,8484,90,8488,90,119833,90,119885,90,119937,90,119989,90,120041,90,120197,90,120249,90,120301,90,120353,90,120405,90,120457,90,918,90,120493,90,120551,90,120609,90,120667,90,120725,90,5059,90,42204,90,71849,90,65282,34,65284,36,65285,37,65286,38,65290,42,65291,43,65294,46,65295,47,65296,48,65297,49,65298,50,65299,51,65300,52,65301,53,65302,54,65303,55,65304,56,65305,57,65308,60,65309,61,65310,62,65312,64,65316,68,65318,70,65319,71,65324,76,65329,81,65330,82,65333,85,65334,86,65335,87,65343,95,65346,98,65348,100,65350,102,65355,107,65357,109,65358,110,65361,113,65362,114,65364,116,65365,117,65367,119,65370,122,65371,123,65373,125,119846,109],\\\"_default\\\":[160,32,8211,45,65374,126,65306,58,65281,33,8216,96,8217,96,8245,96,180,96,12494,47,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,305,105,1050,75,921,73,1052,77,1086,111,1054,79,1009,112,1088,112,1056,80,1075,114,1058,84,215,120,1093,120,1061,88,1091,121,1059,89,65283,35,65288,40,65289,41,65292,44,65307,59,65311,63],\\\"cs\\\":[65374,126,65306,58,65281,33,8216,96,8217,96,8245,96,180,96,12494,47,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,305,105,1050,75,921,73,1052,77,1086,111,1054,79,1009,112,1088,112,1056,80,1075,114,1058,84,1093,120,1061,88,1091,121,1059,89,65283,35,65288,40,65289,41,65292,44,65307,59,65311,63],\\\"de\\\":[65374,126,65306,58,65281,33,8216,96,8217,96,8245,96,180,96,12494,47,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,305,105,1050,75,921,73,1052,77,1086,111,1054,79,1009,112,1088,112,1056,80,1075,114,1058,84,1093,120,1061,88,1091,121,1059,89,65283,35,65288,40,65289,41,65292,44,65307,59,65311,63],\\\"es\\\":[8211,45,65374,126,65306,58,65281,33,8245,96,180,96,12494,47,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,305,105,1050,75,1052,77,1086,111,1054,79,1009,112,1088,112,1056,80,1075,114,1058,84,215,120,1093,120,1061,88,1091,121,1059,89,65283,35,65288,40,65289,41,65292,44,65307,59,65311,63],\\\"fr\\\":[65374,126,65306,58,65281,33,8216,96,8245,96,12494,47,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,305,105,1050,75,921,73,1052,77,1086,111,1054,79,1009,112,1088,112,1056,80,1075,114,1058,84,215,120,1093,120,1061,88,1091,121,1059,89,65283,35,65288,40,65289,41,65292,44,65307,59,65311,63],\\\"it\\\":[160,32,8211,45,65374,126,65306,58,65281,33,8216,96,8245,96,180,96,12494,47,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,305,105,1050,75,921,73,1052,77,1086,111,1054,79,1009,112,1088,112,1056,80,1075,114,1058,84,215,120,1093,120,1061,88,1091,121,1059,89,65283,35,65288,40,65289,41,65292,44,65307,59,65311,63],\\\"ja\\\":[8211,45,65306,58,65281,33,8216,96,8217,96,8245,96,180,96,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,305,105,1050,75,921,73,1052,77,1086,111,1054,79,1009,112,1088,112,1056,80,1075,114,1058,84,215,120,1093,120,1061,88,1091,121,1059,89,65283,35,65292,44,65307,59],\\\"ko\\\":[8211,45,65374,126,65306,58,65281,33,8245,96,180,96,12494,47,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,305,105,1050,75,921,73,1052,77,1086,111,1054,79,1009,112,1088,112,1056,80,1075,114,1058,84,215,120,1093,120,1061,88,1091,121,1059,89,65283,35,65288,40,65289,41,65292,44,65307,59,65311,63],\\\"pl\\\":[65374,126,65306,58,65281,33,8216,96,8217,96,8245,96,180,96,12494,47,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,305,105,1050,75,921,73,1052,77,1086,111,1054,79,1009,112,1088,112,1056,80,1075,114,1058,84,215,120,1093,120,1061,88,1091,121,1059,89,65283,35,65288,40,65289,41,65292,44,65307,59,65311,63],\\\"pt-BR\\\":[65374,126,65306,58,65281,33,8216,96,8217,96,8245,96,180,96,12494,47,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,305,105,1050,75,921,73,1052,77,1086,111,1054,79,1009,112,1088,112,1056,80,1075,114,1058,84,215,120,1093,120,1061,88,1091,121,1059,89,65283,35,65288,40,65289,41,65292,44,65307,59,65311,63],\\\"qps-ploc\\\":[160,32,8211,45,65374,126,65306,58,65281,33,8216,96,8217,96,8245,96,180,96,12494,47,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,305,105,1050,75,921,73,1052,77,1086,111,1054,79,1088,112,1056,80,1075,114,1058,84,215,120,1093,120,1061,88,1091,121,1059,89,65283,35,65288,40,65289,41,65292,44,65307,59,65311,63],\\\"ru\\\":[65374,126,65306,58,65281,33,8216,96,8217,96,8245,96,180,96,12494,47,305,105,921,73,1009,112,215,120,65283,35,65288,40,65289,41,65292,44,65307,59,65311,63],\\\"tr\\\":[160,32,8211,45,65374,126,65306,58,65281,33,8245,96,180,96,12494,47,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,1050,75,921,73,1052,77,1086,111,1054,79,1009,112,1088,112,1056,80,1075,114,1058,84,215,120,1093,120,1061,88,1091,121,1059,89,65283,35,65288,40,65289,41,65292,44,65307,59,65311,63],\\\"zh-hans\\\":[65374,126,65306,58,65281,33,8245,96,180,96,12494,47,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,305,105,1050,75,921,73,1052,77,1086,111,1054,79,1009,112,1088,112,1056,80,1075,114,1058,84,215,120,1093,120,1061,88,1091,121,1059,89,65288,40,65289,41],\\\"zh-hant\\\":[8211,45,65374,126,180,96,12494,47,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,305,105,1050,75,921,73,1052,77,1086,111,1054,79,1009,112,1088,112,1056,80,1075,114,1058,84,215,120,1093,120,1061,88,1091,121,1059,89,65283,35,65307,59]}'\n\t\t);\n\t});\n\n\tprivate static readonly cache = new LRUCachedFunction<\n\t\tstring[],\n\t\tAmbiguousCharacters\n\t>({ getCacheKey: JSON.stringify }, (locales) => {\n\t\tfunction arrayToMap(arr: number[]): Map {\n\t\t\tconst result = new Map();\n\t\t\tfor (let i = 0; i < arr.length; i += 2) {\n\t\t\t\tresult.set(arr[i], arr[i + 1]);\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\n\t\tfunction mergeMaps(\n\t\t\tmap1: Map,\n\t\t\tmap2: Map\n\t\t): Map {\n\t\t\tconst result = new Map(map1);\n\t\t\tfor (const [key, value] of map2) {\n\t\t\t\tresult.set(key, value);\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\n\t\tfunction intersectMaps(\n\t\t\tmap1: Map | undefined,\n\t\t\tmap2: Map\n\t\t) {\n\t\t\tif (!map1) {\n\t\t\t\treturn map2;\n\t\t\t}\n\t\t\tconst result = new Map();\n\t\t\tfor (const [key, value] of map1) {\n\t\t\t\tif (map2.has(key)) {\n\t\t\t\t\tresult.set(key, value);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\n\t\tconst data = this.ambiguousCharacterData.value;\n\n\t\tlet filteredLocales = locales.filter(\n\t\t\t(l) => !l.startsWith('_') && l in data\n\t\t);\n\t\tif (filteredLocales.length === 0) {\n\t\t\tfilteredLocales = ['_default'];\n\t\t}\n\n\t\tlet languageSpecificMap: Map | undefined = undefined;\n\t\tfor (const locale of filteredLocales) {\n\t\t\tconst map = arrayToMap(data[locale]);\n\t\t\tlanguageSpecificMap = intersectMaps(languageSpecificMap, map);\n\t\t}\n\n\t\tconst commonMap = arrayToMap(data['_common']);\n\t\tconst map = mergeMaps(commonMap, languageSpecificMap!);\n\n\t\treturn new AmbiguousCharacters(map);\n\t});\n\n\tpublic static getInstance(locales: Set): AmbiguousCharacters {\n\t\treturn AmbiguousCharacters.cache.get(Array.from(locales));\n\t}\n\n\tprivate static _locales = new Lazy(() =>\n\t\tObject.keys(AmbiguousCharacters.ambiguousCharacterData.value).filter(\n\t\t\t(k) => !k.startsWith('_')\n\t\t)\n\t);\n\tpublic static getLocales(): string[] {\n\t\treturn AmbiguousCharacters._locales.value;\n\t}\n\n\tprivate constructor(\n\t\tprivate readonly confusableDictionary: Map\n\t) { }\n\n\tpublic isAmbiguous(codePoint: number): boolean {\n\t\treturn this.confusableDictionary.has(codePoint);\n\t}\n\n\t/**\n\t * Returns the non basic ASCII code point that the given code point can be confused,\n\t * or undefined if such code point does note exist.\n\t */\n\tpublic getPrimaryConfusable(codePoint: number): number | undefined {\n\t\treturn this.confusableDictionary.get(codePoint);\n\t}\n\n\tpublic getConfusableCodePoints(): ReadonlySet {\n\t\treturn new Set(this.confusableDictionary.keys());\n\t}\n}\n\nexport class InvisibleCharacters {\n\tprivate static getRawData(): number[] {\n\t\t// Generated using https://github.com/hediet/vscode-unicode-data\n\t\treturn JSON.parse('[9,10,11,12,13,32,127,160,173,847,1564,4447,4448,6068,6069,6155,6156,6157,6158,7355,7356,8192,8193,8194,8195,8196,8197,8198,8199,8200,8201,8202,8203,8204,8205,8206,8207,8234,8235,8236,8237,8238,8239,8287,8288,8289,8290,8291,8292,8293,8294,8295,8296,8297,8298,8299,8300,8301,8302,8303,10240,12288,12644,65024,65025,65026,65027,65028,65029,65030,65031,65032,65033,65034,65035,65036,65037,65038,65039,65279,65440,65520,65521,65522,65523,65524,65525,65526,65527,65528,65532,78844,119155,119156,119157,119158,119159,119160,119161,119162,917504,917505,917506,917507,917508,917509,917510,917511,917512,917513,917514,917515,917516,917517,917518,917519,917520,917521,917522,917523,917524,917525,917526,917527,917528,917529,917530,917531,917532,917533,917534,917535,917536,917537,917538,917539,917540,917541,917542,917543,917544,917545,917546,917547,917548,917549,917550,917551,917552,917553,917554,917555,917556,917557,917558,917559,917560,917561,917562,917563,917564,917565,917566,917567,917568,917569,917570,917571,917572,917573,917574,917575,917576,917577,917578,917579,917580,917581,917582,917583,917584,917585,917586,917587,917588,917589,917590,917591,917592,917593,917594,917595,917596,917597,917598,917599,917600,917601,917602,917603,917604,917605,917606,917607,917608,917609,917610,917611,917612,917613,917614,917615,917616,917617,917618,917619,917620,917621,917622,917623,917624,917625,917626,917627,917628,917629,917630,917631,917760,917761,917762,917763,917764,917765,917766,917767,917768,917769,917770,917771,917772,917773,917774,917775,917776,917777,917778,917779,917780,917781,917782,917783,917784,917785,917786,917787,917788,917789,917790,917791,917792,917793,917794,917795,917796,917797,917798,917799,917800,917801,917802,917803,917804,917805,917806,917807,917808,917809,917810,917811,917812,917813,917814,917815,917816,917817,917818,917819,917820,917821,917822,917823,917824,917825,917826,917827,917828,917829,917830,917831,917832,917833,917834,917835,917836,917837,917838,917839,917840,917841,917842,917843,917844,917845,917846,917847,917848,917849,917850,917851,917852,917853,917854,917855,917856,917857,917858,917859,917860,917861,917862,917863,917864,917865,917866,917867,917868,917869,917870,917871,917872,917873,917874,917875,917876,917877,917878,917879,917880,917881,917882,917883,917884,917885,917886,917887,917888,917889,917890,917891,917892,917893,917894,917895,917896,917897,917898,917899,917900,917901,917902,917903,917904,917905,917906,917907,917908,917909,917910,917911,917912,917913,917914,917915,917916,917917,917918,917919,917920,917921,917922,917923,917924,917925,917926,917927,917928,917929,917930,917931,917932,917933,917934,917935,917936,917937,917938,917939,917940,917941,917942,917943,917944,917945,917946,917947,917948,917949,917950,917951,917952,917953,917954,917955,917956,917957,917958,917959,917960,917961,917962,917963,917964,917965,917966,917967,917968,917969,917970,917971,917972,917973,917974,917975,917976,917977,917978,917979,917980,917981,917982,917983,917984,917985,917986,917987,917988,917989,917990,917991,917992,917993,917994,917995,917996,917997,917998,917999]');\n\t}\n\n\tprivate static _data: Set | undefined = undefined;\n\n\tprivate static getData() {\n\t\tif (!this._data) {\n\t\t\tthis._data = new Set(InvisibleCharacters.getRawData());\n\t\t}\n\t\treturn this._data;\n\t}\n\n\tpublic static isInvisibleCharacter(codePoint: number): boolean {\n\t\treturn InvisibleCharacters.getData().has(codePoint);\n\t}\n\n\tpublic static get codePoints(): ReadonlySet {\n\t\treturn InvisibleCharacters.getData();\n\t}\n}\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\nimport { CharCode } from 'vs/base/common/charCode';\nimport { LRUCache } from 'vs/base/common/map';\nimport { getKoreanAltChars } from 'vs/base/common/naturalLanguage/korean';\nimport * as strings from 'vs/base/common/strings';\n\nexport interface IFilter {\n\t// Returns null if word doesn't match.\n\t(word: string, wordToMatchAgainst: string): IMatch[] | null;\n}\n\nexport interface IMatch {\n\tstart: number;\n\tend: number;\n}\n\n// Combined filters\n\n/**\n * @returns A filter which combines the provided set\n * of filters with an or. The *first* filters that\n * matches defined the return value of the returned\n * filter.\n */\nexport function or(...filter: IFilter[]): IFilter {\n\treturn function (word: string, wordToMatchAgainst: string): IMatch[] | null {\n\t\tfor (let i = 0, len = filter.length; i < len; i++) {\n\t\t\tconst match = filter[i](word, wordToMatchAgainst);\n\t\t\tif (match) {\n\t\t\t\treturn match;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t};\n}\n\n// Prefix\n\nexport const matchesStrictPrefix: IFilter = _matchesPrefix.bind(undefined, false);\nexport const matchesPrefix: IFilter = _matchesPrefix.bind(undefined, true);\n\nfunction _matchesPrefix(ignoreCase: boolean, word: string, wordToMatchAgainst: string): IMatch[] | null {\n\tif (!wordToMatchAgainst || wordToMatchAgainst.length < word.length) {\n\t\treturn null;\n\t}\n\n\tlet matches: boolean;\n\tif (ignoreCase) {\n\t\tmatches = strings.startsWithIgnoreCase(wordToMatchAgainst, word);\n\t} else {\n\t\tmatches = wordToMatchAgainst.indexOf(word) === 0;\n\t}\n\n\tif (!matches) {\n\t\treturn null;\n\t}\n\n\treturn word.length > 0 ? [{ start: 0, end: word.length }] : [];\n}\n\n// Contiguous Substring\n\nexport function matchesContiguousSubString(word: string, wordToMatchAgainst: string): IMatch[] | null {\n\tconst index = wordToMatchAgainst.toLowerCase().indexOf(word.toLowerCase());\n\tif (index === -1) {\n\t\treturn null;\n\t}\n\n\treturn [{ start: index, end: index + word.length }];\n}\n\n// Substring\n\nexport function matchesSubString(word: string, wordToMatchAgainst: string): IMatch[] | null {\n\treturn _matchesSubString(word.toLowerCase(), wordToMatchAgainst.toLowerCase(), 0, 0);\n}\n\nfunction _matchesSubString(word: string, wordToMatchAgainst: string, i: number, j: number): IMatch[] | null {\n\tif (i === word.length) {\n\t\treturn [];\n\t} else if (j === wordToMatchAgainst.length) {\n\t\treturn null;\n\t} else {\n\t\tif (word[i] === wordToMatchAgainst[j]) {\n\t\t\tlet result: IMatch[] | null = null;\n\t\t\tif (result = _matchesSubString(word, wordToMatchAgainst, i + 1, j + 1)) {\n\t\t\t\treturn join({ start: j, end: j + 1 }, result);\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t\treturn _matchesSubString(word, wordToMatchAgainst, i, j + 1);\n\t}\n}\n\n// CamelCase\n\nfunction isLower(code: number): boolean {\n\treturn CharCode.a <= code && code <= CharCode.z;\n}\n\nexport function isUpper(code: number): boolean {\n\treturn CharCode.A <= code && code <= CharCode.Z;\n}\n\nfunction isNumber(code: number): boolean {\n\treturn CharCode.Digit0 <= code && code <= CharCode.Digit9;\n}\n\nfunction isWhitespace(code: number): boolean {\n\treturn (\n\t\tcode === CharCode.Space\n\t\t|| code === CharCode.Tab\n\t\t|| code === CharCode.LineFeed\n\t\t|| code === CharCode.CarriageReturn\n\t);\n}\n\nconst wordSeparators = new Set();\n// These are chosen as natural word separators based on writen text.\n// It is a subset of the word separators used by the monaco editor.\n'()[]{}<>`\\'\"-/;:,.?!'\n\t.split('')\n\t.forEach(s => wordSeparators.add(s.charCodeAt(0)));\n\nfunction isWordSeparator(code: number): boolean {\n\treturn isWhitespace(code) || wordSeparators.has(code);\n}\n\nfunction charactersMatch(codeA: number, codeB: number): boolean {\n\treturn (codeA === codeB) || (isWordSeparator(codeA) && isWordSeparator(codeB));\n}\n\nconst alternateCharsCache: Map | undefined> = new Map();\n/**\n * Gets alternative codes to the character code passed in. This comes in the\n * form of an array of character codes, all of which must match _in order_ to\n * successfully match.\n *\n * @param code The character code to check.\n */\nfunction getAlternateCodes(code: number): ArrayLike | undefined {\n\tif (alternateCharsCache.has(code)) {\n\t\treturn alternateCharsCache.get(code);\n\t}\n\n\t// NOTE: This function is written in such a way that it can be extended in\n\t// the future, but right now the return type takes into account it's only\n\t// supported by a single \"alt codes provider\".\n\t// `ArrayLike>` is a more appropriate type if changed.\n\tlet result: ArrayLike | undefined;\n\tconst codes = getKoreanAltChars(code);\n\tif (codes) {\n\t\tresult = codes;\n\t}\n\n\talternateCharsCache.set(code, result);\n\treturn result;\n}\n\nfunction isAlphanumeric(code: number): boolean {\n\treturn isLower(code) || isUpper(code) || isNumber(code);\n}\n\nfunction join(head: IMatch, tail: IMatch[]): IMatch[] {\n\tif (tail.length === 0) {\n\t\ttail = [head];\n\t} else if (head.end === tail[0].start) {\n\t\ttail[0].start = head.start;\n\t} else {\n\t\ttail.unshift(head);\n\t}\n\treturn tail;\n}\n\nfunction nextAnchor(camelCaseWord: string, start: number): number {\n\tfor (let i = start; i < camelCaseWord.length; i++) {\n\t\tconst c = camelCaseWord.charCodeAt(i);\n\t\tif (isUpper(c) || isNumber(c) || (i > 0 && !isAlphanumeric(camelCaseWord.charCodeAt(i - 1)))) {\n\t\t\treturn i;\n\t\t}\n\t}\n\treturn camelCaseWord.length;\n}\n\nfunction _matchesCamelCase(word: string, camelCaseWord: string, i: number, j: number): IMatch[] | null {\n\tif (i === word.length) {\n\t\treturn [];\n\t} else if (j === camelCaseWord.length) {\n\t\treturn null;\n\t} else if (word[i] !== camelCaseWord[j].toLowerCase()) {\n\t\treturn null;\n\t} else {\n\t\tlet result: IMatch[] | null = null;\n\t\tlet nextUpperIndex = j + 1;\n\t\tresult = _matchesCamelCase(word, camelCaseWord, i + 1, j + 1);\n\t\twhile (!result && (nextUpperIndex = nextAnchor(camelCaseWord, nextUpperIndex)) < camelCaseWord.length) {\n\t\t\tresult = _matchesCamelCase(word, camelCaseWord, i + 1, nextUpperIndex);\n\t\t\tnextUpperIndex++;\n\t\t}\n\t\treturn result === null ? null : join({ start: j, end: j + 1 }, result);\n\t}\n}\n\ninterface ICamelCaseAnalysis {\n\tupperPercent: number;\n\tlowerPercent: number;\n\talphaPercent: number;\n\tnumericPercent: number;\n}\n\n// Heuristic to avoid computing camel case matcher for words that don't\n// look like camelCaseWords.\nfunction analyzeCamelCaseWord(word: string): ICamelCaseAnalysis {\n\tlet upper = 0, lower = 0, alpha = 0, numeric = 0, code = 0;\n\n\tfor (let i = 0; i < word.length; i++) {\n\t\tcode = word.charCodeAt(i);\n\n\t\tif (isUpper(code)) { upper++; }\n\t\tif (isLower(code)) { lower++; }\n\t\tif (isAlphanumeric(code)) { alpha++; }\n\t\tif (isNumber(code)) { numeric++; }\n\t}\n\n\tconst upperPercent = upper / word.length;\n\tconst lowerPercent = lower / word.length;\n\tconst alphaPercent = alpha / word.length;\n\tconst numericPercent = numeric / word.length;\n\n\treturn { upperPercent, lowerPercent, alphaPercent, numericPercent };\n}\n\nfunction isUpperCaseWord(analysis: ICamelCaseAnalysis): boolean {\n\tconst { upperPercent, lowerPercent } = analysis;\n\treturn lowerPercent === 0 && upperPercent > 0.6;\n}\n\nfunction isCamelCaseWord(analysis: ICamelCaseAnalysis): boolean {\n\tconst { upperPercent, lowerPercent, alphaPercent, numericPercent } = analysis;\n\treturn lowerPercent > 0.2 && upperPercent < 0.8 && alphaPercent > 0.6 && numericPercent < 0.2;\n}\n\n// Heuristic to avoid computing camel case matcher for words that don't\n// look like camel case patterns.\nfunction isCamelCasePattern(word: string): boolean {\n\tlet upper = 0, lower = 0, code = 0, whitespace = 0;\n\n\tfor (let i = 0; i < word.length; i++) {\n\t\tcode = word.charCodeAt(i);\n\n\t\tif (isUpper(code)) { upper++; }\n\t\tif (isLower(code)) { lower++; }\n\t\tif (isWhitespace(code)) { whitespace++; }\n\t}\n\n\tif ((upper === 0 || lower === 0) && whitespace === 0) {\n\t\treturn word.length <= 30;\n\t} else {\n\t\treturn upper <= 5;\n\t}\n}\n\nexport function matchesCamelCase(word: string, camelCaseWord: string): IMatch[] | null {\n\tif (!camelCaseWord) {\n\t\treturn null;\n\t}\n\n\tcamelCaseWord = camelCaseWord.trim();\n\n\tif (camelCaseWord.length === 0) {\n\t\treturn null;\n\t}\n\n\tif (!isCamelCasePattern(word)) {\n\t\treturn null;\n\t}\n\n\t// TODO: Consider removing this check\n\tif (camelCaseWord.length > 60) {\n\t\tcamelCaseWord = camelCaseWord.substring(0, 60);\n\t}\n\n\tconst analysis = analyzeCamelCaseWord(camelCaseWord);\n\n\tif (!isCamelCaseWord(analysis)) {\n\t\tif (!isUpperCaseWord(analysis)) {\n\t\t\treturn null;\n\t\t}\n\n\t\tcamelCaseWord = camelCaseWord.toLowerCase();\n\t}\n\n\tlet result: IMatch[] | null = null;\n\tlet i = 0;\n\n\tword = word.toLowerCase();\n\twhile (i < camelCaseWord.length && (result = _matchesCamelCase(word, camelCaseWord, 0, i)) === null) {\n\t\ti = nextAnchor(camelCaseWord, i + 1);\n\t}\n\n\treturn result;\n}\n\n// Matches beginning of words supporting non-ASCII languages\n// If `contiguous` is true then matches word with beginnings of the words in the target. E.g. \"pul\" will match \"Git: Pull\"\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\"\n// Useful in cases where the target is words (e.g. command labels)\n\nexport function matchesWords(word: string, target: string, contiguous: boolean = false): IMatch[] | null {\n\tif (!target || target.length === 0) {\n\t\treturn null;\n\t}\n\n\tlet result: IMatch[] | null = null;\n\tlet targetIndex = 0;\n\n\tword = word.toLowerCase();\n\ttarget = target.toLowerCase();\n\twhile (targetIndex < target.length) {\n\t\tresult = _matchesWords(word, target, 0, targetIndex, contiguous);\n\t\tif (result !== null) {\n\t\t\tbreak;\n\t\t}\n\t\ttargetIndex = nextWord(target, targetIndex + 1);\n\t}\n\n\treturn result;\n}\n\nfunction _matchesWords(word: string, target: string, wordIndex: number, targetIndex: number, contiguous: boolean): IMatch[] | null {\n\tlet targetIndexOffset = 0;\n\n\tif (wordIndex === word.length) {\n\t\treturn [];\n\t} else if (targetIndex === target.length) {\n\t\treturn null;\n\t} else if (!charactersMatch(word.charCodeAt(wordIndex), target.charCodeAt(targetIndex))) {\n\t\t// Verify alternate characters before exiting\n\t\tconst altChars = getAlternateCodes(word.charCodeAt(wordIndex));\n\t\tif (!altChars) {\n\t\t\treturn null;\n\t\t}\n\t\tfor (let k = 0; k < altChars.length; k++) {\n\t\t\tif (!charactersMatch(altChars[k], target.charCodeAt(targetIndex + k))) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\t\ttargetIndexOffset += altChars.length - 1;\n\t}\n\n\tlet result: IMatch[] | null = null;\n\tlet nextWordIndex = targetIndex + targetIndexOffset + 1;\n\tresult = _matchesWords(word, target, wordIndex + 1, nextWordIndex, contiguous);\n\tif (!contiguous) {\n\t\twhile (!result && (nextWordIndex = nextWord(target, nextWordIndex)) < target.length) {\n\t\t\tresult = _matchesWords(word, target, wordIndex + 1, nextWordIndex, contiguous);\n\t\t\tnextWordIndex++;\n\t\t}\n\t}\n\n\tif (!result) {\n\t\treturn null;\n\t}\n\n\t// If the characters don't exactly match, then they must be word separators (see charactersMatch(...)).\n\t// We don't want to include this in the matches but we don't want to throw the target out all together so we return `result`.\n\tif (word.charCodeAt(wordIndex) !== target.charCodeAt(targetIndex)) {\n\t\t// Verify alternate characters before exiting\n\t\tconst altChars = getAlternateCodes(word.charCodeAt(wordIndex));\n\t\tif (!altChars) {\n\t\t\treturn result;\n\t\t}\n\t\tfor (let k = 0; k < altChars.length; k++) {\n\t\t\tif (altChars[k] !== target.charCodeAt(targetIndex + k)) {\n\t\t\t\treturn result;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn join({ start: targetIndex, end: targetIndex + targetIndexOffset + 1 }, result);\n}\n\nfunction nextWord(word: string, start: number): number {\n\tfor (let i = start; i < word.length; i++) {\n\t\tif (isWordSeparator(word.charCodeAt(i)) ||\n\t\t\t(i > 0 && isWordSeparator(word.charCodeAt(i - 1)))) {\n\t\t\treturn i;\n\t\t}\n\t}\n\treturn word.length;\n}\n\n// Fuzzy\n\nconst fuzzyContiguousFilter = or(matchesPrefix, matchesCamelCase, matchesContiguousSubString);\nconst fuzzySeparateFilter = or(matchesPrefix, matchesCamelCase, matchesSubString);\nconst fuzzyRegExpCache = new LRUCache(10000); // bounded to 10000 elements\n\nexport function matchesFuzzy(word: string, wordToMatchAgainst: string, enableSeparateSubstringMatching = false): IMatch[] | null {\n\tif (typeof word !== 'string' || typeof wordToMatchAgainst !== 'string') {\n\t\treturn null; // return early for invalid input\n\t}\n\n\t// Form RegExp for wildcard matches\n\tlet regexp = fuzzyRegExpCache.get(word);\n\tif (!regexp) {\n\t\tregexp = new RegExp(strings.convertSimple2RegExpPattern(word), 'i');\n\t\tfuzzyRegExpCache.set(word, regexp);\n\t}\n\n\t// RegExp Filter\n\tconst match = regexp.exec(wordToMatchAgainst);\n\tif (match) {\n\t\treturn [{ start: match.index, end: match.index + match[0].length }];\n\t}\n\n\t// Default Filter\n\treturn enableSeparateSubstringMatching ? fuzzySeparateFilter(word, wordToMatchAgainst) : fuzzyContiguousFilter(word, wordToMatchAgainst);\n}\n\n/**\n * Match pattern against word in a fuzzy way. As in IntelliSense and faster and more\n * powerful than `matchesFuzzy`\n */\nexport function matchesFuzzy2(pattern: string, word: string): IMatch[] | null {\n\tconst score = fuzzyScore(pattern, pattern.toLowerCase(), 0, word, word.toLowerCase(), 0, { firstMatchCanBeWeak: true, boostFullMatch: true });\n\treturn score ? createMatches(score) : null;\n}\n\nexport function anyScore(pattern: string, lowPattern: string, patternPos: number, word: string, lowWord: string, wordPos: number): FuzzyScore {\n\tconst max = Math.min(13, pattern.length);\n\tfor (; patternPos < max; patternPos++) {\n\t\tconst result = fuzzyScore(pattern, lowPattern, patternPos, word, lowWord, wordPos, { firstMatchCanBeWeak: true, boostFullMatch: true });\n\t\tif (result) {\n\t\t\treturn result;\n\t\t}\n\t}\n\treturn [0, wordPos];\n}\n\n//#region --- fuzzyScore ---\n\nexport function createMatches(score: undefined | FuzzyScore): IMatch[] {\n\tif (typeof score === 'undefined') {\n\t\treturn [];\n\t}\n\tconst res: IMatch[] = [];\n\tconst wordPos = score[1];\n\tfor (let i = score.length - 1; i > 1; i--) {\n\t\tconst pos = score[i] + wordPos;\n\t\tconst last = res[res.length - 1];\n\t\tif (last && last.end === pos) {\n\t\t\tlast.end = pos + 1;\n\t\t} else {\n\t\t\tres.push({ start: pos, end: pos + 1 });\n\t\t}\n\t}\n\treturn res;\n}\n\nconst _maxLen = 128;\n\nfunction initTable() {\n\tconst table: number[][] = [];\n\tconst row: number[] = [];\n\tfor (let i = 0; i <= _maxLen; i++) {\n\t\trow[i] = 0;\n\t}\n\tfor (let i = 0; i <= _maxLen; i++) {\n\t\ttable.push(row.slice(0));\n\t}\n\treturn table;\n}\n\nfunction initArr(maxLen: number) {\n\tconst row: number[] = [];\n\tfor (let i = 0; i <= maxLen; i++) {\n\t\trow[i] = 0;\n\t}\n\treturn row;\n}\n\nconst _minWordMatchPos = initArr(2 * _maxLen); // min word position for a certain pattern position\nconst _maxWordMatchPos = initArr(2 * _maxLen); // max word position for a certain pattern position\nconst _diag = initTable(); // the length of a contiguous diagonal match\nconst _table = initTable();\nconst _arrows = initTable();\nconst _debug = false;\n\nfunction printTable(table: number[][], pattern: string, patternLen: number, word: string, wordLen: number): string {\n\tfunction pad(s: string, n: number, pad = ' ') {\n\t\twhile (s.length < n) {\n\t\t\ts = pad + s;\n\t\t}\n\t\treturn s;\n\t}\n\tlet ret = ` | |${word.split('').map(c => pad(c, 3)).join('|')}\\n`;\n\n\tfor (let i = 0; i <= patternLen; i++) {\n\t\tif (i === 0) {\n\t\t\tret += ' |';\n\t\t} else {\n\t\t\tret += `${pattern[i - 1]}|`;\n\t\t}\n\t\tret += table[i].slice(0, wordLen + 1).map(n => pad(n.toString(), 3)).join('|') + '\\n';\n\t}\n\treturn ret;\n}\n\nfunction printTables(pattern: string, patternStart: number, word: string, wordStart: number): void {\n\tpattern = pattern.substr(patternStart);\n\tword = word.substr(wordStart);\n\tconsole.log(printTable(_table, pattern, pattern.length, word, word.length));\n\tconsole.log(printTable(_arrows, pattern, pattern.length, word, word.length));\n\tconsole.log(printTable(_diag, pattern, pattern.length, word, word.length));\n}\n\nfunction isSeparatorAtPos(value: string, index: number): boolean {\n\tif (index < 0 || index >= value.length) {\n\t\treturn false;\n\t}\n\tconst code = value.codePointAt(index);\n\tswitch (code) {\n\t\tcase CharCode.Underline:\n\t\tcase CharCode.Dash:\n\t\tcase CharCode.Period:\n\t\tcase CharCode.Space:\n\t\tcase CharCode.Slash:\n\t\tcase CharCode.Backslash:\n\t\tcase CharCode.SingleQuote:\n\t\tcase CharCode.DoubleQuote:\n\t\tcase CharCode.Colon:\n\t\tcase CharCode.DollarSign:\n\t\tcase CharCode.LessThan:\n\t\tcase CharCode.GreaterThan:\n\t\tcase CharCode.OpenParen:\n\t\tcase CharCode.CloseParen:\n\t\tcase CharCode.OpenSquareBracket:\n\t\tcase CharCode.CloseSquareBracket:\n\t\tcase CharCode.OpenCurlyBrace:\n\t\tcase CharCode.CloseCurlyBrace:\n\t\t\treturn true;\n\t\tcase undefined:\n\t\t\treturn false;\n\t\tdefault:\n\t\t\tif (strings.isEmojiImprecise(code)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn false;\n\t}\n}\n\nfunction isWhitespaceAtPos(value: string, index: number): boolean {\n\tif (index < 0 || index >= value.length) {\n\t\treturn false;\n\t}\n\tconst code = value.charCodeAt(index);\n\tswitch (code) {\n\t\tcase CharCode.Space:\n\t\tcase CharCode.Tab:\n\t\t\treturn true;\n\t\tdefault:\n\t\t\treturn false;\n\t}\n}\n\nfunction isUpperCaseAtPos(pos: number, word: string, wordLow: string): boolean {\n\treturn word[pos] !== wordLow[pos];\n}\n\nexport function isPatternInWord(patternLow: string, patternPos: number, patternLen: number, wordLow: string, wordPos: number, wordLen: number, fillMinWordPosArr = false): boolean {\n\twhile (patternPos < patternLen && wordPos < wordLen) {\n\t\tif (patternLow[patternPos] === wordLow[wordPos]) {\n\t\t\tif (fillMinWordPosArr) {\n\t\t\t\t// Remember the min word position for each pattern position\n\t\t\t\t_minWordMatchPos[patternPos] = wordPos;\n\t\t\t}\n\t\t\tpatternPos += 1;\n\t\t}\n\t\twordPos += 1;\n\t}\n\treturn patternPos === patternLen; // pattern must be exhausted\n}\n\nconst enum Arrow { Diag = 1, Left = 2, LeftLeft = 3 }\n\n/**\n * An array representing a fuzzy match.\n *\n * 0. the score\n * 1. the offset at which matching started\n * 2. ``\n * 3. ``\n * 4. `` etc\n */\nexport type FuzzyScore = [score: number, wordStart: number, ...matches: number[]];\n\nexport namespace FuzzyScore {\n\t/**\n\t * No matches and value `-100`\n\t */\n\texport const Default: FuzzyScore = ([-100, 0]);\n\n\texport function isDefault(score?: FuzzyScore): score is [-100, 0] {\n\t\treturn !score || (score.length === 2 && score[0] === -100 && score[1] === 0);\n\t}\n}\n\nexport abstract class FuzzyScoreOptions {\n\n\tstatic default = { boostFullMatch: true, firstMatchCanBeWeak: false };\n\n\tconstructor(\n\t\treadonly firstMatchCanBeWeak: boolean,\n\t\treadonly boostFullMatch: boolean,\n\t) { }\n}\n\nexport interface FuzzyScorer {\n\t(pattern: string, lowPattern: string, patternPos: number, word: string, lowWord: string, wordPos: number, options?: FuzzyScoreOptions): FuzzyScore | undefined;\n}\n\nexport function fuzzyScore(pattern: string, patternLow: string, patternStart: number, word: string, wordLow: string, wordStart: number, options: FuzzyScoreOptions = FuzzyScoreOptions.default): FuzzyScore | undefined {\n\n\tconst patternLen = pattern.length > _maxLen ? _maxLen : pattern.length;\n\tconst wordLen = word.length > _maxLen ? _maxLen : word.length;\n\n\tif (patternStart >= patternLen || wordStart >= wordLen || (patternLen - patternStart) > (wordLen - wordStart)) {\n\t\treturn undefined;\n\t}\n\n\t// Run a simple check if the characters of pattern occur\n\t// (in order) at all in word. If that isn't the case we\n\t// stop because no match will be possible\n\tif (!isPatternInWord(patternLow, patternStart, patternLen, wordLow, wordStart, wordLen, true)) {\n\t\treturn undefined;\n\t}\n\n\t// Find the max matching word position for each pattern position\n\t// NOTE: the min matching word position was filled in above, in the `isPatternInWord` call\n\t_fillInMaxWordMatchPos(patternLen, wordLen, patternStart, wordStart, patternLow, wordLow);\n\n\tlet row: number = 1;\n\tlet column: number = 1;\n\tlet patternPos = patternStart;\n\tlet wordPos = wordStart;\n\n\tconst hasStrongFirstMatch = [false];\n\n\t// There will be a match, fill in tables\n\tfor (row = 1, patternPos = patternStart; patternPos < patternLen; row++, patternPos++) {\n\n\t\t// Reduce search space to possible matching word positions and to possible access from next row\n\t\tconst minWordMatchPos = _minWordMatchPos[patternPos];\n\t\tconst maxWordMatchPos = _maxWordMatchPos[patternPos];\n\t\tconst nextMaxWordMatchPos = (patternPos + 1 < patternLen ? _maxWordMatchPos[patternPos + 1] : wordLen);\n\n\t\tfor (column = minWordMatchPos - wordStart + 1, wordPos = minWordMatchPos; wordPos < nextMaxWordMatchPos; column++, wordPos++) {\n\n\t\t\tlet score = Number.MIN_SAFE_INTEGER;\n\t\t\tlet canComeDiag = false;\n\n\t\t\tif (wordPos <= maxWordMatchPos) {\n\t\t\t\tscore = _doScore(\n\t\t\t\t\tpattern, patternLow, patternPos, patternStart,\n\t\t\t\t\tword, wordLow, wordPos, wordLen, wordStart,\n\t\t\t\t\t_diag[row - 1][column - 1] === 0,\n\t\t\t\t\thasStrongFirstMatch\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tlet diagScore = 0;\n\t\t\tif (score !== Number.MAX_SAFE_INTEGER) {\n\t\t\t\tcanComeDiag = true;\n\t\t\t\tdiagScore = score + _table[row - 1][column - 1];\n\t\t\t}\n\n\t\t\tconst canComeLeft = wordPos > minWordMatchPos;\n\t\t\tconst leftScore = canComeLeft ? _table[row][column - 1] + (_diag[row][column - 1] > 0 ? -5 : 0) : 0; // penalty for a gap start\n\n\t\t\tconst canComeLeftLeft = wordPos > minWordMatchPos + 1 && _diag[row][column - 1] > 0;\n\t\t\tconst leftLeftScore = canComeLeftLeft ? _table[row][column - 2] + (_diag[row][column - 2] > 0 ? -5 : 0) : 0; // penalty for a gap start\n\n\t\t\tif (canComeLeftLeft && (!canComeLeft || leftLeftScore >= leftScore) && (!canComeDiag || leftLeftScore >= diagScore)) {\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\n\t\t\t\t_table[row][column] = leftLeftScore;\n\t\t\t\t_arrows[row][column] = Arrow.LeftLeft;\n\t\t\t\t_diag[row][column] = 0;\n\t\t\t} else if (canComeLeft && (!canComeDiag || leftScore >= diagScore)) {\n\t\t\t\t// always prefer choosing left since that means a match is earlier in the word\n\t\t\t\t_table[row][column] = leftScore;\n\t\t\t\t_arrows[row][column] = Arrow.Left;\n\t\t\t\t_diag[row][column] = 0;\n\t\t\t} else if (canComeDiag) {\n\t\t\t\t_table[row][column] = diagScore;\n\t\t\t\t_arrows[row][column] = Arrow.Diag;\n\t\t\t\t_diag[row][column] = _diag[row - 1][column - 1] + 1;\n\t\t\t} else {\n\t\t\t\tthrow new Error(`not possible`);\n\t\t\t}\n\t\t}\n\t}\n\n\tif (_debug) {\n\t\tprintTables(pattern, patternStart, word, wordStart);\n\t}\n\n\tif (!hasStrongFirstMatch[0] && !options.firstMatchCanBeWeak) {\n\t\treturn undefined;\n\t}\n\n\trow--;\n\tcolumn--;\n\n\tconst result: FuzzyScore = [_table[row][column], wordStart];\n\n\tlet backwardsDiagLength = 0;\n\tlet maxMatchColumn = 0;\n\n\twhile (row >= 1) {\n\t\t// Find the column where we go diagonally up\n\t\tlet diagColumn = column;\n\t\tdo {\n\t\t\tconst arrow = _arrows[row][diagColumn];\n\t\t\tif (arrow === Arrow.LeftLeft) {\n\t\t\t\tdiagColumn = diagColumn - 2;\n\t\t\t} else if (arrow === Arrow.Left) {\n\t\t\t\tdiagColumn = diagColumn - 1;\n\t\t\t} else {\n\t\t\t\t// found the diagonal\n\t\t\t\tbreak;\n\t\t\t}\n\t\t} while (diagColumn >= 1);\n\n\t\t// Overturn the \"forwards\" decision if keeping the \"backwards\" diagonal would give a better match\n\t\tif (\n\t\t\tbackwardsDiagLength > 1 // only if we would have a contiguous match of 3 characters\n\t\t\t&& patternLow[patternStart + row - 1] === wordLow[wordStart + column - 1] // only if we can do a contiguous match diagonally\n\t\t\t&& !isUpperCaseAtPos(diagColumn + wordStart - 1, word, wordLow) // only if the forwards chose diagonal is not an uppercase\n\t\t\t&& backwardsDiagLength + 1 > _diag[row][diagColumn] // only if our contiguous match would be longer than the \"forwards\" contiguous match\n\t\t) {\n\t\t\tdiagColumn = column;\n\t\t}\n\n\t\tif (diagColumn === column) {\n\t\t\t// this is a contiguous match\n\t\t\tbackwardsDiagLength++;\n\t\t} else {\n\t\t\tbackwardsDiagLength = 1;\n\t\t}\n\n\t\tif (!maxMatchColumn) {\n\t\t\t// remember the last matched column\n\t\t\tmaxMatchColumn = diagColumn;\n\t\t}\n\n\t\trow--;\n\t\tcolumn = diagColumn - 1;\n\t\tresult.push(column);\n\t}\n\n\tif (wordLen - wordStart === patternLen && options.boostFullMatch) {\n\t\t// the word matches the pattern with all characters!\n\t\t// giving the score a total match boost (to come up ahead other words)\n\t\tresult[0] += 2;\n\t}\n\n\t// Add 1 penalty for each skipped character in the word\n\tconst skippedCharsCount = maxMatchColumn - patternLen;\n\tresult[0] -= skippedCharsCount;\n\n\treturn result;\n}\n\nfunction _fillInMaxWordMatchPos(patternLen: number, wordLen: number, patternStart: number, wordStart: number, patternLow: string, wordLow: string) {\n\tlet patternPos = patternLen - 1;\n\tlet wordPos = wordLen - 1;\n\twhile (patternPos >= patternStart && wordPos >= wordStart) {\n\t\tif (patternLow[patternPos] === wordLow[wordPos]) {\n\t\t\t_maxWordMatchPos[patternPos] = wordPos;\n\t\t\tpatternPos--;\n\t\t}\n\t\twordPos--;\n\t}\n}\n\nfunction _doScore(\n\tpattern: string, patternLow: string, patternPos: number, patternStart: number,\n\tword: string, wordLow: string, wordPos: number, wordLen: number, wordStart: number,\n\tnewMatchStart: boolean,\n\toutFirstMatchStrong: boolean[],\n): number {\n\tif (patternLow[patternPos] !== wordLow[wordPos]) {\n\t\treturn Number.MIN_SAFE_INTEGER;\n\t}\n\n\tlet score = 1;\n\tlet isGapLocation = false;\n\tif (wordPos === (patternPos - patternStart)) {\n\t\t// common prefix: `foobar <-> foobaz`\n\t\t// ^^^^^\n\t\tscore = pattern[patternPos] === word[wordPos] ? 7 : 5;\n\n\t} else if (isUpperCaseAtPos(wordPos, word, wordLow) && (wordPos === 0 || !isUpperCaseAtPos(wordPos - 1, word, wordLow))) {\n\t\t// hitting upper-case: `foo <-> forOthers`\n\t\t// ^^ ^\n\t\tscore = pattern[patternPos] === word[wordPos] ? 7 : 5;\n\t\tisGapLocation = true;\n\n\t} else if (isSeparatorAtPos(wordLow, wordPos) && (wordPos === 0 || !isSeparatorAtPos(wordLow, wordPos - 1))) {\n\t\t// hitting a separator: `. <-> foo.bar`\n\t\t// ^\n\t\tscore = 5;\n\n\t} else if (isSeparatorAtPos(wordLow, wordPos - 1) || isWhitespaceAtPos(wordLow, wordPos - 1)) {\n\t\t// post separator: `foo <-> bar_foo`\n\t\t// ^^^\n\t\tscore = 5;\n\t\tisGapLocation = true;\n\t}\n\n\tif (score > 1 && patternPos === patternStart) {\n\t\toutFirstMatchStrong[0] = true;\n\t}\n\n\tif (!isGapLocation) {\n\t\tisGapLocation = isUpperCaseAtPos(wordPos, word, wordLow) || isSeparatorAtPos(wordLow, wordPos - 1) || isWhitespaceAtPos(wordLow, wordPos - 1);\n\t}\n\n\t//\n\tif (patternPos === patternStart) { // first character in pattern\n\t\tif (wordPos > wordStart) {\n\t\t\t// the first pattern character would match a word character that is not at the word start\n\t\t\t// so introduce a penalty to account for the gap preceding this match\n\t\t\tscore -= isGapLocation ? 3 : 5;\n\t\t}\n\t} else {\n\t\tif (newMatchStart) {\n\t\t\t// this would be the beginning of a new match (i.e. there would be a gap before this location)\n\t\t\tscore += isGapLocation ? 2 : 0;\n\t\t} else {\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 preferred gap location\n\t\t\tscore += isGapLocation ? 0 : 1;\n\t\t}\n\t}\n\n\tif (wordPos + 1 === wordLen) {\n\t\t// we always penalize gaps, but this gives unfair advantages to a match that would match the last character in the word\n\t\t// so pretend there is a gap after the last character in the word to normalize things\n\t\tscore -= isGapLocation ? 3 : 5;\n\t}\n\n\treturn score;\n}\n\n//#endregion\n\n\n//#region --- graceful ---\n\nexport function fuzzyScoreGracefulAggressive(pattern: string, lowPattern: string, patternPos: number, word: string, lowWord: string, wordPos: number, options?: FuzzyScoreOptions): FuzzyScore | undefined {\n\treturn fuzzyScoreWithPermutations(pattern, lowPattern, patternPos, word, lowWord, wordPos, true, options);\n}\n\nfunction fuzzyScoreWithPermutations(pattern: string, lowPattern: string, patternPos: number, word: string, lowWord: string, wordPos: number, aggressive: boolean, options?: FuzzyScoreOptions): FuzzyScore | undefined {\n\tlet top = fuzzyScore(pattern, lowPattern, patternPos, word, lowWord, wordPos, options);\n\n\tif (top && !aggressive) {\n\t\t// when using the original pattern yield a result we`\n\t\t// return it unless we are aggressive and try to find\n\t\t// a better alignment, e.g. `cno` -> `^co^ns^ole` or `^c^o^nsole`.\n\t\treturn top;\n\t}\n\n\tif (pattern.length >= 3) {\n\t\t// When the pattern is long enough then try a few (max 7)\n\t\t// permutations of the pattern to find a better match. The\n\t\t// permutations only swap neighbouring characters, e.g\n\t\t// `cnoso` becomes `conso`, `cnsoo`, `cnoos`.\n\t\tconst tries = Math.min(7, pattern.length - 1);\n\t\tfor (let movingPatternPos = patternPos + 1; movingPatternPos < tries; movingPatternPos++) {\n\t\t\tconst newPattern = nextTypoPermutation(pattern, movingPatternPos);\n\t\t\tif (newPattern) {\n\t\t\t\tconst candidate = fuzzyScore(newPattern, newPattern.toLowerCase(), patternPos, word, lowWord, wordPos, options);\n\t\t\t\tif (candidate) {\n\t\t\t\t\tcandidate[0] -= 3; // permutation penalty\n\t\t\t\t\tif (!top || candidate[0] > top[0]) {\n\t\t\t\t\t\ttop = candidate;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn top;\n}\n\nfunction nextTypoPermutation(pattern: string, patternPos: number): string | undefined {\n\n\tif (patternPos + 1 >= pattern.length) {\n\t\treturn undefined;\n\t}\n\n\tconst swap1 = pattern[patternPos];\n\tconst swap2 = pattern[patternPos + 1];\n\n\tif (swap1 === swap2) {\n\t\treturn undefined;\n\t}\n\n\treturn pattern.slice(0, patternPos)\n\t\t+ swap2\n\t\t+ swap1\n\t\t+ pattern.slice(patternPos + 2);\n}\n\n//#endregion\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\nimport * as strings from 'vs/base/common/strings';\n\n/**\n * Return a hash value for an object.\n */\nexport function hash(obj: any): number {\n\treturn doHash(obj, 0);\n}\n\nexport function doHash(obj: any, hashVal: number): number {\n\tswitch (typeof obj) {\n\t\tcase 'object':\n\t\t\tif (obj === null) {\n\t\t\t\treturn numberHash(349, hashVal);\n\t\t\t} else if (Array.isArray(obj)) {\n\t\t\t\treturn arrayHash(obj, hashVal);\n\t\t\t}\n\t\t\treturn objectHash(obj, hashVal);\n\t\tcase 'string':\n\t\t\treturn stringHash(obj, hashVal);\n\t\tcase 'boolean':\n\t\t\treturn booleanHash(obj, hashVal);\n\t\tcase 'number':\n\t\t\treturn numberHash(obj, hashVal);\n\t\tcase 'undefined':\n\t\t\treturn numberHash(937, hashVal);\n\t\tdefault:\n\t\t\treturn numberHash(617, hashVal);\n\t}\n}\n\nexport function numberHash(val: number, initialHashVal: number): number {\n\treturn (((initialHashVal << 5) - initialHashVal) + val) | 0; // hashVal * 31 + ch, keep as int32\n}\n\nfunction booleanHash(b: boolean, initialHashVal: number): number {\n\treturn numberHash(b ? 433 : 863, initialHashVal);\n}\n\nexport function stringHash(s: string, hashVal: number) {\n\thashVal = numberHash(149417, hashVal);\n\tfor (let i = 0, length = s.length; i < length; i++) {\n\t\thashVal = numberHash(s.charCodeAt(i), hashVal);\n\t}\n\treturn hashVal;\n}\n\nfunction arrayHash(arr: any[], initialHashVal: number): number {\n\tinitialHashVal = numberHash(104579, initialHashVal);\n\treturn arr.reduce((hashVal, item) => doHash(item, hashVal), initialHashVal);\n}\n\nfunction objectHash(obj: any, initialHashVal: number): number {\n\tinitialHashVal = numberHash(181387, initialHashVal);\n\treturn Object.keys(obj).sort().reduce((hashVal, key) => {\n\t\thashVal = stringHash(key, hashVal);\n\t\treturn doHash(obj[key], hashVal);\n\t}, initialHashVal);\n}\n\nconst enum SHA1Constant {\n\tBLOCK_SIZE = 64, // 512 / 8\n\tUNICODE_REPLACEMENT = 0xFFFD,\n}\n\nfunction leftRotate(value: number, bits: number, totalBits: number = 32): number {\n\t// delta + bits = totalBits\n\tconst delta = totalBits - bits;\n\n\t// All ones, expect `delta` zeros aligned to the right\n\tconst mask = ~((1 << delta) - 1);\n\n\t// Join (value left-shifted `bits` bits) with (masked value right-shifted `delta` bits)\n\treturn ((value << bits) | ((mask & value) >>> delta)) >>> 0;\n}\n\nfunction fill(dest: Uint8Array, index: number = 0, count: number = dest.byteLength, value: number = 0): void {\n\tfor (let i = 0; i < count; i++) {\n\t\tdest[index + i] = value;\n\t}\n}\n\nfunction leftPad(value: string, length: number, char: string = '0'): string {\n\twhile (value.length < length) {\n\t\tvalue = char + value;\n\t}\n\treturn value;\n}\n\nexport function toHexString(buffer: ArrayBuffer): string;\nexport function toHexString(value: number, bitsize?: number): string;\nexport function toHexString(bufferOrValue: ArrayBuffer | number, bitsize: number = 32): string {\n\tif (bufferOrValue instanceof ArrayBuffer) {\n\t\treturn Array.from(new Uint8Array(bufferOrValue)).map(b => b.toString(16).padStart(2, '0')).join('');\n\t}\n\n\treturn leftPad((bufferOrValue >>> 0).toString(16), bitsize / 4);\n}\n\n/**\n * A SHA1 implementation that works with strings and does not allocate.\n */\nexport class StringSHA1 {\n\tprivate static _bigBlock32 = new DataView(new ArrayBuffer(320)); // 80 * 4 = 320\n\n\tprivate _h0 = 0x67452301;\n\tprivate _h1 = 0xEFCDAB89;\n\tprivate _h2 = 0x98BADCFE;\n\tprivate _h3 = 0x10325476;\n\tprivate _h4 = 0xC3D2E1F0;\n\n\tprivate readonly _buff: Uint8Array;\n\tprivate readonly _buffDV: DataView;\n\tprivate _buffLen: number;\n\tprivate _totalLen: number;\n\tprivate _leftoverHighSurrogate: number;\n\tprivate _finished: boolean;\n\n\tconstructor() {\n\t\tthis._buff = new Uint8Array(SHA1Constant.BLOCK_SIZE + 3 /* to fit any utf-8 */);\n\t\tthis._buffDV = new DataView(this._buff.buffer);\n\t\tthis._buffLen = 0;\n\t\tthis._totalLen = 0;\n\t\tthis._leftoverHighSurrogate = 0;\n\t\tthis._finished = false;\n\t}\n\n\tpublic update(str: string): void {\n\t\tconst strLen = str.length;\n\t\tif (strLen === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst buff = this._buff;\n\t\tlet buffLen = this._buffLen;\n\t\tlet leftoverHighSurrogate = this._leftoverHighSurrogate;\n\t\tlet charCode: number;\n\t\tlet offset: number;\n\n\t\tif (leftoverHighSurrogate !== 0) {\n\t\t\tcharCode = leftoverHighSurrogate;\n\t\t\toffset = -1;\n\t\t\tleftoverHighSurrogate = 0;\n\t\t} else {\n\t\t\tcharCode = str.charCodeAt(0);\n\t\t\toffset = 0;\n\t\t}\n\n\t\twhile (true) {\n\t\t\tlet codePoint = charCode;\n\t\t\tif (strings.isHighSurrogate(charCode)) {\n\t\t\t\tif (offset + 1 < strLen) {\n\t\t\t\t\tconst nextCharCode = str.charCodeAt(offset + 1);\n\t\t\t\t\tif (strings.isLowSurrogate(nextCharCode)) {\n\t\t\t\t\t\toffset++;\n\t\t\t\t\t\tcodePoint = strings.computeCodePoint(charCode, nextCharCode);\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// illegal => unicode replacement character\n\t\t\t\t\t\tcodePoint = SHA1Constant.UNICODE_REPLACEMENT;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// last character is a surrogate pair\n\t\t\t\t\tleftoverHighSurrogate = charCode;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} else if (strings.isLowSurrogate(charCode)) {\n\t\t\t\t// illegal => unicode replacement character\n\t\t\t\tcodePoint = SHA1Constant.UNICODE_REPLACEMENT;\n\t\t\t}\n\n\t\t\tbuffLen = this._push(buff, buffLen, codePoint);\n\t\t\toffset++;\n\t\t\tif (offset < strLen) {\n\t\t\t\tcharCode = str.charCodeAt(offset);\n\t\t\t} else {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tthis._buffLen = buffLen;\n\t\tthis._leftoverHighSurrogate = leftoverHighSurrogate;\n\t}\n\n\tprivate _push(buff: Uint8Array, buffLen: number, codePoint: number): number {\n\t\tif (codePoint < 0x0080) {\n\t\t\tbuff[buffLen++] = codePoint;\n\t\t} else if (codePoint < 0x0800) {\n\t\t\tbuff[buffLen++] = 0b11000000 | ((codePoint & 0b00000000000000000000011111000000) >>> 6);\n\t\t\tbuff[buffLen++] = 0b10000000 | ((codePoint & 0b00000000000000000000000000111111) >>> 0);\n\t\t} else if (codePoint < 0x10000) {\n\t\t\tbuff[buffLen++] = 0b11100000 | ((codePoint & 0b00000000000000001111000000000000) >>> 12);\n\t\t\tbuff[buffLen++] = 0b10000000 | ((codePoint & 0b00000000000000000000111111000000) >>> 6);\n\t\t\tbuff[buffLen++] = 0b10000000 | ((codePoint & 0b00000000000000000000000000111111) >>> 0);\n\t\t} else {\n\t\t\tbuff[buffLen++] = 0b11110000 | ((codePoint & 0b00000000000111000000000000000000) >>> 18);\n\t\t\tbuff[buffLen++] = 0b10000000 | ((codePoint & 0b00000000000000111111000000000000) >>> 12);\n\t\t\tbuff[buffLen++] = 0b10000000 | ((codePoint & 0b00000000000000000000111111000000) >>> 6);\n\t\t\tbuff[buffLen++] = 0b10000000 | ((codePoint & 0b00000000000000000000000000111111) >>> 0);\n\t\t}\n\n\t\tif (buffLen >= SHA1Constant.BLOCK_SIZE) {\n\t\t\tthis._step();\n\t\t\tbuffLen -= SHA1Constant.BLOCK_SIZE;\n\t\t\tthis._totalLen += SHA1Constant.BLOCK_SIZE;\n\t\t\t// take last 3 in case of UTF8 overflow\n\t\t\tbuff[0] = buff[SHA1Constant.BLOCK_SIZE + 0];\n\t\t\tbuff[1] = buff[SHA1Constant.BLOCK_SIZE + 1];\n\t\t\tbuff[2] = buff[SHA1Constant.BLOCK_SIZE + 2];\n\t\t}\n\n\t\treturn buffLen;\n\t}\n\n\tpublic digest(): string {\n\t\tif (!this._finished) {\n\t\t\tthis._finished = true;\n\t\t\tif (this._leftoverHighSurrogate) {\n\t\t\t\t// illegal => unicode replacement character\n\t\t\t\tthis._leftoverHighSurrogate = 0;\n\t\t\t\tthis._buffLen = this._push(this._buff, this._buffLen, SHA1Constant.UNICODE_REPLACEMENT);\n\t\t\t}\n\t\t\tthis._totalLen += this._buffLen;\n\t\t\tthis._wrapUp();\n\t\t}\n\n\t\treturn toHexString(this._h0) + toHexString(this._h1) + toHexString(this._h2) + toHexString(this._h3) + toHexString(this._h4);\n\t}\n\n\tprivate _wrapUp(): void {\n\t\tthis._buff[this._buffLen++] = 0x80;\n\t\tfill(this._buff, this._buffLen);\n\n\t\tif (this._buffLen > 56) {\n\t\t\tthis._step();\n\t\t\tfill(this._buff);\n\t\t}\n\n\t\t// this will fit because the mantissa can cover up to 52 bits\n\t\tconst ml = 8 * this._totalLen;\n\n\t\tthis._buffDV.setUint32(56, Math.floor(ml / 4294967296), false);\n\t\tthis._buffDV.setUint32(60, ml % 4294967296, false);\n\n\t\tthis._step();\n\t}\n\n\tprivate _step(): void {\n\t\tconst bigBlock32 = StringSHA1._bigBlock32;\n\t\tconst data = this._buffDV;\n\n\t\tfor (let j = 0; j < 64 /* 16*4 */; j += 4) {\n\t\t\tbigBlock32.setUint32(j, data.getUint32(j, false), false);\n\t\t}\n\n\t\tfor (let j = 64; j < 320 /* 80*4 */; j += 4) {\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);\n\t\t}\n\n\t\tlet a = this._h0;\n\t\tlet b = this._h1;\n\t\tlet c = this._h2;\n\t\tlet d = this._h3;\n\t\tlet e = this._h4;\n\n\t\tlet f: number, k: number;\n\t\tlet temp: number;\n\n\t\tfor (let j = 0; j < 80; j++) {\n\t\t\tif (j < 20) {\n\t\t\t\tf = (b & c) | ((~b) & d);\n\t\t\t\tk = 0x5A827999;\n\t\t\t} else if (j < 40) {\n\t\t\t\tf = b ^ c ^ d;\n\t\t\t\tk = 0x6ED9EBA1;\n\t\t\t} else if (j < 60) {\n\t\t\t\tf = (b & c) | (b & d) | (c & d);\n\t\t\t\tk = 0x8F1BBCDC;\n\t\t\t} else {\n\t\t\t\tf = b ^ c ^ d;\n\t\t\t\tk = 0xCA62C1D6;\n\t\t\t}\n\n\t\t\ttemp = (leftRotate(a, 5) + f + e + k + bigBlock32.getUint32(j * 4, false)) & 0xffffffff;\n\t\t\te = d;\n\t\t\td = c;\n\t\t\tc = leftRotate(b, 30);\n\t\t\tb = a;\n\t\t\ta = temp;\n\t\t}\n\n\t\tthis._h0 = (this._h0 + a) & 0xffffffff;\n\t\tthis._h1 = (this._h1 + b) & 0xffffffff;\n\t\tthis._h2 = (this._h2 + c) & 0xffffffff;\n\t\tthis._h3 = (this._h3 + d) & 0xffffffff;\n\t\tthis._h4 = (this._h4 + e) & 0xffffffff;\n\t}\n}\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\nimport { DiffChange } from 'vs/base/common/diff/diffChange';\nimport { stringHash } from 'vs/base/common/hash';\nimport { Constants } from 'vs/base/common/uint';\n\nexport class StringDiffSequence implements ISequence {\n\n\tconstructor(private source: string) { }\n\n\tgetElements(): Int32Array | number[] | string[] {\n\t\tconst source = this.source;\n\t\tconst characters = new Int32Array(source.length);\n\t\tfor (let i = 0, len = source.length; i < len; i++) {\n\t\t\tcharacters[i] = source.charCodeAt(i);\n\t\t}\n\t\treturn characters;\n\t}\n}\n\nexport function stringDiff(original: string, modified: string, pretty: boolean): IDiffChange[] {\n\treturn new LcsDiff(new StringDiffSequence(original), new StringDiffSequence(modified)).ComputeDiff(pretty).changes;\n}\n\nexport interface ISequence {\n\tgetElements(): Int32Array | number[] | string[];\n\tgetStrictElement?(index: number): string;\n}\n\nexport interface IDiffChange {\n\t/**\n\t * The position of the first element in the original sequence which\n\t * this change affects.\n\t */\n\toriginalStart: number;\n\n\t/**\n\t * The number of elements from the original sequence which were\n\t * affected.\n\t */\n\toriginalLength: number;\n\n\t/**\n\t * The position of the first element in the modified sequence which\n\t * this change affects.\n\t */\n\tmodifiedStart: number;\n\n\t/**\n\t * The number of elements from the modified sequence which were\n\t * affected (added).\n\t */\n\tmodifiedLength: number;\n}\n\nexport interface IContinueProcessingPredicate {\n\t(furthestOriginalIndex: number, matchLengthOfLongest: number): boolean;\n}\n\nexport interface IDiffResult {\n\tquitEarly: boolean;\n\tchanges: IDiffChange[];\n}\n\n//\n// The code below has been ported from a C# implementation in VS\n//\n\nclass Debug {\n\n\tpublic static Assert(condition: boolean, message: string): void {\n\t\tif (!condition) {\n\t\t\tthrow new Error(message);\n\t\t}\n\t}\n}\n\nclass MyArray {\n\t/**\n\t * Copies a range of elements from an Array starting at the specified source index and pastes\n\t * them to another Array starting at the specified destination index. The length and the indexes\n\t * are specified as 64-bit integers.\n\t * sourceArray:\n\t *\t\tThe Array that contains the data to copy.\n\t * sourceIndex:\n\t *\t\tA 64-bit integer that represents the index in the sourceArray at which copying begins.\n\t * destinationArray:\n\t *\t\tThe Array that receives the data.\n\t * destinationIndex:\n\t *\t\tA 64-bit integer that represents the index in the destinationArray at which storing begins.\n\t * length:\n\t *\t\tA 64-bit integer that represents the number of elements to copy.\n\t */\n\tpublic static Copy(sourceArray: any[], sourceIndex: number, destinationArray: any[], destinationIndex: number, length: number) {\n\t\tfor (let i = 0; i < length; i++) {\n\t\t\tdestinationArray[destinationIndex + i] = sourceArray[sourceIndex + i];\n\t\t}\n\t}\n\tpublic static Copy2(sourceArray: Int32Array, sourceIndex: number, destinationArray: Int32Array, destinationIndex: number, length: number) {\n\t\tfor (let i = 0; i < length; i++) {\n\t\t\tdestinationArray[destinationIndex + i] = sourceArray[sourceIndex + i];\n\t\t}\n\t}\n}\n\n//*****************************************************************************\n// LcsDiff.cs\n//\n// An implementation of the difference algorithm described in\n// \"An O(ND) Difference Algorithm and its variations\" by Eugene W. Myers\n//\n// Copyright (C) 2008 Microsoft Corporation @minifier_do_not_preserve\n//*****************************************************************************\n\n// Our total memory usage for storing history is (worst-case):\n// 2 * [(MaxDifferencesHistory + 1) * (MaxDifferencesHistory + 1) - 1] * sizeof(int)\n// 2 * [1448*1448 - 1] * 4 = 16773624 = 16MB\nconst enum LocalConstants {\n\tMaxDifferencesHistory = 1447\n}\n\n/**\n * A utility class which helps to create the set of DiffChanges from\n * a difference operation. This class accepts original DiffElements and\n * modified DiffElements that are involved in a particular change. The\n * MarkNextChange() method can be called to mark the separation between\n * distinct changes. At the end, the Changes property can be called to retrieve\n * the constructed changes.\n */\nclass DiffChangeHelper {\n\n\tprivate m_changes: DiffChange[];\n\tprivate m_originalStart: number;\n\tprivate m_modifiedStart: number;\n\tprivate m_originalCount: number;\n\tprivate m_modifiedCount: number;\n\n\t/**\n\t * Constructs a new DiffChangeHelper for the given DiffSequences.\n\t */\n\tconstructor() {\n\t\tthis.m_changes = [];\n\t\tthis.m_originalStart = Constants.MAX_SAFE_SMALL_INTEGER;\n\t\tthis.m_modifiedStart = Constants.MAX_SAFE_SMALL_INTEGER;\n\t\tthis.m_originalCount = 0;\n\t\tthis.m_modifiedCount = 0;\n\t}\n\n\t/**\n\t * Marks the beginning of the next change in the set of differences.\n\t */\n\tpublic MarkNextChange(): void {\n\t\t// Only add to the list if there is something to add\n\t\tif (this.m_originalCount > 0 || this.m_modifiedCount > 0) {\n\t\t\t// Add the new change to our list\n\t\t\tthis.m_changes.push(new DiffChange(this.m_originalStart, this.m_originalCount,\n\t\t\t\tthis.m_modifiedStart, this.m_modifiedCount));\n\t\t}\n\n\t\t// Reset for the next change\n\t\tthis.m_originalCount = 0;\n\t\tthis.m_modifiedCount = 0;\n\t\tthis.m_originalStart = Constants.MAX_SAFE_SMALL_INTEGER;\n\t\tthis.m_modifiedStart = Constants.MAX_SAFE_SMALL_INTEGER;\n\t}\n\n\t/**\n\t * Adds the original element at the given position to the elements\n\t * affected by the current change. The modified index gives context\n\t * to the change position with respect to the original sequence.\n\t * @param originalIndex The index of the original element to add.\n\t * @param modifiedIndex The index of the modified element that provides corresponding position in the modified sequence.\n\t */\n\tpublic AddOriginalElement(originalIndex: number, modifiedIndex: number) {\n\t\t// The 'true' start index is the smallest of the ones we've seen\n\t\tthis.m_originalStart = Math.min(this.m_originalStart, originalIndex);\n\t\tthis.m_modifiedStart = Math.min(this.m_modifiedStart, modifiedIndex);\n\n\t\tthis.m_originalCount++;\n\t}\n\n\t/**\n\t * Adds the modified element at the given position to the elements\n\t * affected by the current change. The original index gives context\n\t * to the change position with respect to the modified sequence.\n\t * @param originalIndex The index of the original element that provides corresponding position in the original sequence.\n\t * @param modifiedIndex The index of the modified element to add.\n\t */\n\tpublic AddModifiedElement(originalIndex: number, modifiedIndex: number): void {\n\t\t// The 'true' start index is the smallest of the ones we've seen\n\t\tthis.m_originalStart = Math.min(this.m_originalStart, originalIndex);\n\t\tthis.m_modifiedStart = Math.min(this.m_modifiedStart, modifiedIndex);\n\n\t\tthis.m_modifiedCount++;\n\t}\n\n\t/**\n\t * Retrieves all of the changes marked by the class.\n\t */\n\tpublic getChanges(): DiffChange[] {\n\t\tif (this.m_originalCount > 0 || this.m_modifiedCount > 0) {\n\t\t\t// Finish up on whatever is left\n\t\t\tthis.MarkNextChange();\n\t\t}\n\n\t\treturn this.m_changes;\n\t}\n\n\t/**\n\t * Retrieves all of the changes marked by the class in the reverse order\n\t */\n\tpublic getReverseChanges(): DiffChange[] {\n\t\tif (this.m_originalCount > 0 || this.m_modifiedCount > 0) {\n\t\t\t// Finish up on whatever is left\n\t\t\tthis.MarkNextChange();\n\t\t}\n\n\t\tthis.m_changes.reverse();\n\t\treturn this.m_changes;\n\t}\n\n}\n\n/**\n * An implementation of the difference algorithm described in\n * \"An O(ND) Difference Algorithm and its variations\" by Eugene W. Myers\n */\nexport class LcsDiff {\n\n\tprivate readonly ContinueProcessingPredicate: IContinueProcessingPredicate | null;\n\n\tprivate readonly _originalSequence: ISequence;\n\tprivate readonly _modifiedSequence: ISequence;\n\tprivate readonly _hasStrings: boolean;\n\tprivate readonly _originalStringElements: string[];\n\tprivate readonly _originalElementsOrHash: Int32Array;\n\tprivate readonly _modifiedStringElements: string[];\n\tprivate readonly _modifiedElementsOrHash: Int32Array;\n\n\tprivate m_forwardHistory: Int32Array[];\n\tprivate m_reverseHistory: Int32Array[];\n\n\t/**\n\t * Constructs the DiffFinder\n\t */\n\tconstructor(originalSequence: ISequence, modifiedSequence: ISequence, continueProcessingPredicate: IContinueProcessingPredicate | null = null) {\n\t\tthis.ContinueProcessingPredicate = continueProcessingPredicate;\n\n\t\tthis._originalSequence = originalSequence;\n\t\tthis._modifiedSequence = modifiedSequence;\n\n\t\tconst [originalStringElements, originalElementsOrHash, originalHasStrings] = LcsDiff._getElements(originalSequence);\n\t\tconst [modifiedStringElements, modifiedElementsOrHash, modifiedHasStrings] = LcsDiff._getElements(modifiedSequence);\n\n\t\tthis._hasStrings = (originalHasStrings && modifiedHasStrings);\n\t\tthis._originalStringElements = originalStringElements;\n\t\tthis._originalElementsOrHash = originalElementsOrHash;\n\t\tthis._modifiedStringElements = modifiedStringElements;\n\t\tthis._modifiedElementsOrHash = modifiedElementsOrHash;\n\n\t\tthis.m_forwardHistory = [];\n\t\tthis.m_reverseHistory = [];\n\t}\n\n\tprivate static _isStringArray(arr: Int32Array | number[] | string[]): arr is string[] {\n\t\treturn (arr.length > 0 && typeof arr[0] === 'string');\n\t}\n\n\tprivate static _getElements(sequence: ISequence): [string[], Int32Array, boolean] {\n\t\tconst elements = sequence.getElements();\n\n\t\tif (LcsDiff._isStringArray(elements)) {\n\t\t\tconst hashes = new Int32Array(elements.length);\n\t\t\tfor (let i = 0, len = elements.length; i < len; i++) {\n\t\t\t\thashes[i] = stringHash(elements[i], 0);\n\t\t\t}\n\t\t\treturn [elements, hashes, true];\n\t\t}\n\n\t\tif (elements instanceof Int32Array) {\n\t\t\treturn [[], elements, false];\n\t\t}\n\n\t\treturn [[], new Int32Array(elements), false];\n\t}\n\n\tprivate ElementsAreEqual(originalIndex: number, newIndex: number): boolean {\n\t\tif (this._originalElementsOrHash[originalIndex] !== this._modifiedElementsOrHash[newIndex]) {\n\t\t\treturn false;\n\t\t}\n\t\treturn (this._hasStrings ? this._originalStringElements[originalIndex] === this._modifiedStringElements[newIndex] : true);\n\t}\n\n\tprivate ElementsAreStrictEqual(originalIndex: number, newIndex: number): boolean {\n\t\tif (!this.ElementsAreEqual(originalIndex, newIndex)) {\n\t\t\treturn false;\n\t\t}\n\t\tconst originalElement = LcsDiff._getStrictElement(this._originalSequence, originalIndex);\n\t\tconst modifiedElement = LcsDiff._getStrictElement(this._modifiedSequence, newIndex);\n\t\treturn (originalElement === modifiedElement);\n\t}\n\n\tprivate static _getStrictElement(sequence: ISequence, index: number): string | null {\n\t\tif (typeof sequence.getStrictElement === 'function') {\n\t\t\treturn sequence.getStrictElement(index);\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate OriginalElementsAreEqual(index1: number, index2: number): boolean {\n\t\tif (this._originalElementsOrHash[index1] !== this._originalElementsOrHash[index2]) {\n\t\t\treturn false;\n\t\t}\n\t\treturn (this._hasStrings ? this._originalStringElements[index1] === this._originalStringElements[index2] : true);\n\t}\n\n\tprivate ModifiedElementsAreEqual(index1: number, index2: number): boolean {\n\t\tif (this._modifiedElementsOrHash[index1] !== this._modifiedElementsOrHash[index2]) {\n\t\t\treturn false;\n\t\t}\n\t\treturn (this._hasStrings ? this._modifiedStringElements[index1] === this._modifiedStringElements[index2] : true);\n\t}\n\n\tpublic ComputeDiff(pretty: boolean): IDiffResult {\n\t\treturn this._ComputeDiff(0, this._originalElementsOrHash.length - 1, 0, this._modifiedElementsOrHash.length - 1, pretty);\n\t}\n\n\t/**\n\t * Computes the differences between the original and modified input\n\t * sequences on the bounded range.\n\t * @returns An array of the differences between the two input sequences.\n\t */\n\tprivate _ComputeDiff(originalStart: number, originalEnd: number, modifiedStart: number, modifiedEnd: number, pretty: boolean): IDiffResult {\n\t\tconst quitEarlyArr = [false];\n\t\tlet changes = this.ComputeDiffRecursive(originalStart, originalEnd, modifiedStart, modifiedEnd, quitEarlyArr);\n\n\t\tif (pretty) {\n\t\t\t// We have to clean up the computed diff to be more intuitive\n\t\t\t// but it turns out this cannot be done correctly until the entire set\n\t\t\t// of diffs have been computed\n\t\t\tchanges = this.PrettifyChanges(changes);\n\t\t}\n\n\t\treturn {\n\t\t\tquitEarly: quitEarlyArr[0],\n\t\t\tchanges: changes\n\t\t};\n\t}\n\n\t/**\n\t * Private helper method which computes the differences on the bounded range\n\t * recursively.\n\t * @returns An array of the differences between the two input sequences.\n\t */\n\tprivate ComputeDiffRecursive(originalStart: number, originalEnd: number, modifiedStart: number, modifiedEnd: number, quitEarlyArr: boolean[]): DiffChange[] {\n\t\tquitEarlyArr[0] = false;\n\n\t\t// Find the start of the differences\n\t\twhile (originalStart <= originalEnd && modifiedStart <= modifiedEnd && this.ElementsAreEqual(originalStart, modifiedStart)) {\n\t\t\toriginalStart++;\n\t\t\tmodifiedStart++;\n\t\t}\n\n\t\t// Find the end of the differences\n\t\twhile (originalEnd >= originalStart && modifiedEnd >= modifiedStart && this.ElementsAreEqual(originalEnd, modifiedEnd)) {\n\t\t\toriginalEnd--;\n\t\t\tmodifiedEnd--;\n\t\t}\n\n\t\t// In the special case where we either have all insertions or all deletions or the sequences are identical\n\t\tif (originalStart > originalEnd || modifiedStart > modifiedEnd) {\n\t\t\tlet changes: DiffChange[];\n\n\t\t\tif (modifiedStart <= modifiedEnd) {\n\t\t\t\tDebug.Assert(originalStart === originalEnd + 1, 'originalStart should only be one more than originalEnd');\n\n\t\t\t\t// All insertions\n\t\t\t\tchanges = [\n\t\t\t\t\tnew DiffChange(originalStart, 0, modifiedStart, modifiedEnd - modifiedStart + 1)\n\t\t\t\t];\n\t\t\t} else if (originalStart <= originalEnd) {\n\t\t\t\tDebug.Assert(modifiedStart === modifiedEnd + 1, 'modifiedStart should only be one more than modifiedEnd');\n\n\t\t\t\t// All deletions\n\t\t\t\tchanges = [\n\t\t\t\t\tnew DiffChange(originalStart, originalEnd - originalStart + 1, modifiedStart, 0)\n\t\t\t\t];\n\t\t\t} else {\n\t\t\t\tDebug.Assert(originalStart === originalEnd + 1, 'originalStart should only be one more than originalEnd');\n\t\t\t\tDebug.Assert(modifiedStart === modifiedEnd + 1, 'modifiedStart should only be one more than modifiedEnd');\n\n\t\t\t\t// Identical sequences - No differences\n\t\t\t\tchanges = [];\n\t\t\t}\n\n\t\t\treturn changes;\n\t\t}\n\n\t\t// This problem can be solved using the Divide-And-Conquer technique.\n\t\tconst midOriginalArr = [0];\n\t\tconst midModifiedArr = [0];\n\t\tconst result = this.ComputeRecursionPoint(originalStart, originalEnd, modifiedStart, modifiedEnd, midOriginalArr, midModifiedArr, quitEarlyArr);\n\n\t\tconst midOriginal = midOriginalArr[0];\n\t\tconst midModified = midModifiedArr[0];\n\n\t\tif (result !== null) {\n\t\t\t// Result is not-null when there was enough memory to compute the changes while\n\t\t\t// searching for the recursion point\n\t\t\treturn result;\n\t\t} else if (!quitEarlyArr[0]) {\n\t\t\t// We can break the problem down recursively by finding the changes in the\n\t\t\t// First Half: (originalStart, modifiedStart) to (midOriginal, midModified)\n\t\t\t// Second Half: (midOriginal + 1, minModified + 1) to (originalEnd, modifiedEnd)\n\t\t\t// NOTE: ComputeDiff() is inclusive, therefore the second range starts on the next point\n\n\t\t\tconst leftChanges = this.ComputeDiffRecursive(originalStart, midOriginal, modifiedStart, midModified, quitEarlyArr);\n\t\t\tlet rightChanges: DiffChange[] = [];\n\n\t\t\tif (!quitEarlyArr[0]) {\n\t\t\t\trightChanges = this.ComputeDiffRecursive(midOriginal + 1, originalEnd, midModified + 1, modifiedEnd, quitEarlyArr);\n\t\t\t} else {\n\t\t\t\t// We didn't have time to finish the first half, so we don't have time to compute this half.\n\t\t\t\t// Consider the entire rest of the sequence different.\n\t\t\t\trightChanges = [\n\t\t\t\t\tnew DiffChange(midOriginal + 1, originalEnd - (midOriginal + 1) + 1, midModified + 1, modifiedEnd - (midModified + 1) + 1)\n\t\t\t\t];\n\t\t\t}\n\n\t\t\treturn this.ConcatenateChanges(leftChanges, rightChanges);\n\t\t}\n\n\t\t// If we hit here, we quit early, and so can't return anything meaningful\n\t\treturn [\n\t\t\tnew DiffChange(originalStart, originalEnd - originalStart + 1, modifiedStart, modifiedEnd - modifiedStart + 1)\n\t\t];\n\t}\n\n\tprivate WALKTRACE(diagonalForwardBase: number, diagonalForwardStart: number, diagonalForwardEnd: number, diagonalForwardOffset: number,\n\t\tdiagonalReverseBase: number, diagonalReverseStart: number, diagonalReverseEnd: number, diagonalReverseOffset: number,\n\t\tforwardPoints: Int32Array, reversePoints: Int32Array,\n\t\toriginalIndex: number, originalEnd: number, midOriginalArr: number[],\n\t\tmodifiedIndex: number, modifiedEnd: number, midModifiedArr: number[],\n\t\tdeltaIsEven: boolean, quitEarlyArr: boolean[]\n\t): DiffChange[] {\n\t\tlet forwardChanges: DiffChange[] | null = null;\n\t\tlet reverseChanges: DiffChange[] | null = null;\n\n\t\t// First, walk backward through the forward diagonals history\n\t\tlet changeHelper = new DiffChangeHelper();\n\t\tlet diagonalMin = diagonalForwardStart;\n\t\tlet diagonalMax = diagonalForwardEnd;\n\t\tlet diagonalRelative = (midOriginalArr[0] - midModifiedArr[0]) - diagonalForwardOffset;\n\t\tlet lastOriginalIndex = Constants.MIN_SAFE_SMALL_INTEGER;\n\t\tlet historyIndex = this.m_forwardHistory.length - 1;\n\n\t\tdo {\n\t\t\t// Get the diagonal index from the relative diagonal number\n\t\t\tconst diagonal = diagonalRelative + diagonalForwardBase;\n\n\t\t\t// Figure out where we came from\n\t\t\tif (diagonal === diagonalMin || (diagonal < diagonalMax && forwardPoints[diagonal - 1] < forwardPoints[diagonal + 1])) {\n\t\t\t\t// Vertical line (the element is an insert)\n\t\t\t\toriginalIndex = forwardPoints[diagonal + 1];\n\t\t\t\tmodifiedIndex = originalIndex - diagonalRelative - diagonalForwardOffset;\n\t\t\t\tif (originalIndex < lastOriginalIndex) {\n\t\t\t\t\tchangeHelper.MarkNextChange();\n\t\t\t\t}\n\t\t\t\tlastOriginalIndex = originalIndex;\n\t\t\t\tchangeHelper.AddModifiedElement(originalIndex + 1, modifiedIndex);\n\t\t\t\tdiagonalRelative = (diagonal + 1) - diagonalForwardBase; //Setup for the next iteration\n\t\t\t} else {\n\t\t\t\t// Horizontal line (the element is a deletion)\n\t\t\t\toriginalIndex = forwardPoints[diagonal - 1] + 1;\n\t\t\t\tmodifiedIndex = originalIndex - diagonalRelative - diagonalForwardOffset;\n\t\t\t\tif (originalIndex < lastOriginalIndex) {\n\t\t\t\t\tchangeHelper.MarkNextChange();\n\t\t\t\t}\n\t\t\t\tlastOriginalIndex = originalIndex - 1;\n\t\t\t\tchangeHelper.AddOriginalElement(originalIndex, modifiedIndex + 1);\n\t\t\t\tdiagonalRelative = (diagonal - 1) - diagonalForwardBase; //Setup for the next iteration\n\t\t\t}\n\n\t\t\tif (historyIndex >= 0) {\n\t\t\t\tforwardPoints = this.m_forwardHistory[historyIndex];\n\t\t\t\tdiagonalForwardBase = forwardPoints[0]; //We stored this in the first spot\n\t\t\t\tdiagonalMin = 1;\n\t\t\t\tdiagonalMax = forwardPoints.length - 1;\n\t\t\t}\n\t\t} while (--historyIndex >= -1);\n\n\t\t// Ironically, we get the forward changes as the reverse of the\n\t\t// order we added them since we technically added them backwards\n\t\tforwardChanges = changeHelper.getReverseChanges();\n\n\t\tif (quitEarlyArr[0]) {\n\t\t\t// TODO: Calculate a partial from the reverse diagonals.\n\t\t\t// For now, just assume everything after the midOriginal/midModified point is a diff\n\n\t\t\tlet originalStartPoint = midOriginalArr[0] + 1;\n\t\t\tlet modifiedStartPoint = midModifiedArr[0] + 1;\n\n\t\t\tif (forwardChanges !== null && forwardChanges.length > 0) {\n\t\t\t\tconst lastForwardChange = forwardChanges[forwardChanges.length - 1];\n\t\t\t\toriginalStartPoint = Math.max(originalStartPoint, lastForwardChange.getOriginalEnd());\n\t\t\t\tmodifiedStartPoint = Math.max(modifiedStartPoint, lastForwardChange.getModifiedEnd());\n\t\t\t}\n\n\t\t\treverseChanges = [\n\t\t\t\tnew DiffChange(originalStartPoint, originalEnd - originalStartPoint + 1,\n\t\t\t\t\tmodifiedStartPoint, modifiedEnd - modifiedStartPoint + 1)\n\t\t\t];\n\t\t} else {\n\t\t\t// Now walk backward through the reverse diagonals history\n\t\t\tchangeHelper = new DiffChangeHelper();\n\t\t\tdiagonalMin = diagonalReverseStart;\n\t\t\tdiagonalMax = diagonalReverseEnd;\n\t\t\tdiagonalRelative = (midOriginalArr[0] - midModifiedArr[0]) - diagonalReverseOffset;\n\t\t\tlastOriginalIndex = Constants.MAX_SAFE_SMALL_INTEGER;\n\t\t\thistoryIndex = (deltaIsEven) ? this.m_reverseHistory.length - 1 : this.m_reverseHistory.length - 2;\n\n\t\t\tdo {\n\t\t\t\t// Get the diagonal index from the relative diagonal number\n\t\t\t\tconst diagonal = diagonalRelative + diagonalReverseBase;\n\n\t\t\t\t// Figure out where we came from\n\t\t\t\tif (diagonal === diagonalMin || (diagonal < diagonalMax && reversePoints[diagonal - 1] >= reversePoints[diagonal + 1])) {\n\t\t\t\t\t// Horizontal line (the element is a deletion))\n\t\t\t\t\toriginalIndex = reversePoints[diagonal + 1] - 1;\n\t\t\t\t\tmodifiedIndex = originalIndex - diagonalRelative - diagonalReverseOffset;\n\t\t\t\t\tif (originalIndex > lastOriginalIndex) {\n\t\t\t\t\t\tchangeHelper.MarkNextChange();\n\t\t\t\t\t}\n\t\t\t\t\tlastOriginalIndex = originalIndex + 1;\n\t\t\t\t\tchangeHelper.AddOriginalElement(originalIndex + 1, modifiedIndex + 1);\n\t\t\t\t\tdiagonalRelative = (diagonal + 1) - diagonalReverseBase; //Setup for the next iteration\n\t\t\t\t} else {\n\t\t\t\t\t// Vertical line (the element is an insertion)\n\t\t\t\t\toriginalIndex = reversePoints[diagonal - 1];\n\t\t\t\t\tmodifiedIndex = originalIndex - diagonalRelative - diagonalReverseOffset;\n\t\t\t\t\tif (originalIndex > lastOriginalIndex) {\n\t\t\t\t\t\tchangeHelper.MarkNextChange();\n\t\t\t\t\t}\n\t\t\t\t\tlastOriginalIndex = originalIndex;\n\t\t\t\t\tchangeHelper.AddModifiedElement(originalIndex + 1, modifiedIndex + 1);\n\t\t\t\t\tdiagonalRelative = (diagonal - 1) - diagonalReverseBase; //Setup for the next iteration\n\t\t\t\t}\n\n\t\t\t\tif (historyIndex >= 0) {\n\t\t\t\t\treversePoints = this.m_reverseHistory[historyIndex];\n\t\t\t\t\tdiagonalReverseBase = reversePoints[0]; //We stored this in the first spot\n\t\t\t\t\tdiagonalMin = 1;\n\t\t\t\t\tdiagonalMax = reversePoints.length - 1;\n\t\t\t\t}\n\t\t\t} while (--historyIndex >= -1);\n\n\t\t\t// There are cases where the reverse history will find diffs that\n\t\t\t// are correct, but not intuitive, so we need shift them.\n\t\t\treverseChanges = changeHelper.getChanges();\n\t\t}\n\n\t\treturn this.ConcatenateChanges(forwardChanges, reverseChanges);\n\t}\n\n\t/**\n\t * Given the range to compute the diff on, this method finds the point:\n\t * (midOriginal, midModified)\n\t * that exists in the middle of the LCS of the two sequences and\n\t * is the point at which the LCS problem may be broken down recursively.\n\t * This method will try to keep the LCS trace in memory. If the LCS recursion\n\t * point is calculated and the full trace is available in memory, then this method\n\t * will return the change list.\n\t * @param originalStart The start bound of the original sequence range\n\t * @param originalEnd The end bound of the original sequence range\n\t * @param modifiedStart The start bound of the modified sequence range\n\t * @param modifiedEnd The end bound of the modified sequence range\n\t * @param midOriginal The middle point of the original sequence range\n\t * @param midModified The middle point of the modified sequence range\n\t * @returns The diff changes, if available, otherwise null\n\t */\n\tprivate ComputeRecursionPoint(originalStart: number, originalEnd: number, modifiedStart: number, modifiedEnd: number, midOriginalArr: number[], midModifiedArr: number[], quitEarlyArr: boolean[]) {\n\t\tlet originalIndex = 0, modifiedIndex = 0;\n\t\tlet diagonalForwardStart = 0, diagonalForwardEnd = 0;\n\t\tlet diagonalReverseStart = 0, diagonalReverseEnd = 0;\n\n\t\t// To traverse the edit graph and produce the proper LCS, our actual\n\t\t// start position is just outside the given boundary\n\t\toriginalStart--;\n\t\tmodifiedStart--;\n\n\t\t// We set these up to make the compiler happy, but they will\n\t\t// be replaced before we return with the actual recursion point\n\t\tmidOriginalArr[0] = 0;\n\t\tmidModifiedArr[0] = 0;\n\n\t\t// Clear out the history\n\t\tthis.m_forwardHistory = [];\n\t\tthis.m_reverseHistory = [];\n\n\t\t// Each cell in the two arrays corresponds to a diagonal in the edit graph.\n\t\t// The integer value in the cell represents the originalIndex of the furthest\n\t\t// reaching point found so far that ends in that diagonal.\n\t\t// The modifiedIndex can be computed mathematically from the originalIndex and the diagonal number.\n\t\tconst maxDifferences = (originalEnd - originalStart) + (modifiedEnd - modifiedStart);\n\t\tconst numDiagonals = maxDifferences + 1;\n\t\tconst forwardPoints = new Int32Array(numDiagonals);\n\t\tconst reversePoints = new Int32Array(numDiagonals);\n\t\t// diagonalForwardBase: Index into forwardPoints of the diagonal which passes through (originalStart, modifiedStart)\n\t\t// diagonalReverseBase: Index into reversePoints of the diagonal which passes through (originalEnd, modifiedEnd)\n\t\tconst diagonalForwardBase = (modifiedEnd - modifiedStart);\n\t\tconst diagonalReverseBase = (originalEnd - originalStart);\n\t\t// diagonalForwardOffset: Geometric offset which allows modifiedIndex to be computed from originalIndex and the\n\t\t// diagonal number (relative to diagonalForwardBase)\n\t\t// diagonalReverseOffset: Geometric offset which allows modifiedIndex to be computed from originalIndex and the\n\t\t// diagonal number (relative to diagonalReverseBase)\n\t\tconst diagonalForwardOffset = (originalStart - modifiedStart);\n\t\tconst diagonalReverseOffset = (originalEnd - modifiedEnd);\n\n\t\t// delta: The difference between the end diagonal and the start diagonal. This is used to relate diagonal numbers\n\t\t// relative to the start diagonal with diagonal numbers relative to the end diagonal.\n\t\t// The Even/Oddn-ness of this delta is important for determining when we should check for overlap\n\t\tconst delta = diagonalReverseBase - diagonalForwardBase;\n\t\tconst deltaIsEven = (delta % 2 === 0);\n\n\t\t// Here we set up the start and end points as the furthest points found so far\n\t\t// in both the forward and reverse directions, respectively\n\t\tforwardPoints[diagonalForwardBase] = originalStart;\n\t\treversePoints[diagonalReverseBase] = originalEnd;\n\n\t\t// Remember if we quit early, and thus need to do a best-effort result instead of a real result.\n\t\tquitEarlyArr[0] = false;\n\n\n\n\t\t// A couple of points:\n\t\t// --With this method, we iterate on the number of differences between the two sequences.\n\t\t// The more differences there actually are, the longer this will take.\n\t\t// --Also, as the number of differences increases, we have to search on diagonals further\n\t\t// away from the reference diagonal (which is diagonalForwardBase for forward, diagonalReverseBase for reverse).\n\t\t// --We extend on even diagonals (relative to the reference diagonal) only when numDifferences\n\t\t// is even and odd diagonals only when numDifferences is odd.\n\t\tfor (let numDifferences = 1; numDifferences <= (maxDifferences / 2) + 1; numDifferences++) {\n\t\t\tlet furthestOriginalIndex = 0;\n\t\t\tlet furthestModifiedIndex = 0;\n\n\t\t\t// Run the algorithm in the forward direction\n\t\t\tdiagonalForwardStart = this.ClipDiagonalBound(diagonalForwardBase - numDifferences, numDifferences, diagonalForwardBase, numDiagonals);\n\t\t\tdiagonalForwardEnd = this.ClipDiagonalBound(diagonalForwardBase + numDifferences, numDifferences, diagonalForwardBase, numDiagonals);\n\t\t\tfor (let diagonal = diagonalForwardStart; diagonal <= diagonalForwardEnd; diagonal += 2) {\n\t\t\t\t// STEP 1: We extend the furthest reaching point in the present diagonal\n\t\t\t\t// by looking at the diagonals above and below and picking the one whose point\n\t\t\t\t// is further away from the start point (originalStart, modifiedStart)\n\t\t\t\tif (diagonal === diagonalForwardStart || (diagonal < diagonalForwardEnd && forwardPoints[diagonal - 1] < forwardPoints[diagonal + 1])) {\n\t\t\t\t\toriginalIndex = forwardPoints[diagonal + 1];\n\t\t\t\t} else {\n\t\t\t\t\toriginalIndex = forwardPoints[diagonal - 1] + 1;\n\t\t\t\t}\n\t\t\t\tmodifiedIndex = originalIndex - (diagonal - diagonalForwardBase) - diagonalForwardOffset;\n\n\t\t\t\t// Save the current originalIndex so we can test for false overlap in step 3\n\t\t\t\tconst tempOriginalIndex = originalIndex;\n\n\t\t\t\t// STEP 2: We can continue to extend the furthest reaching point in the present diagonal\n\t\t\t\t// so long as the elements are equal.\n\t\t\t\twhile (originalIndex < originalEnd && modifiedIndex < modifiedEnd && this.ElementsAreEqual(originalIndex + 1, modifiedIndex + 1)) {\n\t\t\t\t\toriginalIndex++;\n\t\t\t\t\tmodifiedIndex++;\n\t\t\t\t}\n\t\t\t\tforwardPoints[diagonal] = originalIndex;\n\n\t\t\t\tif (originalIndex + modifiedIndex > furthestOriginalIndex + furthestModifiedIndex) {\n\t\t\t\t\tfurthestOriginalIndex = originalIndex;\n\t\t\t\t\tfurthestModifiedIndex = modifiedIndex;\n\t\t\t\t}\n\n\t\t\t\t// STEP 3: If delta is odd (overlap first happens on forward when delta is odd)\n\t\t\t\t// and diagonal is in the range of reverse diagonals computed for numDifferences-1\n\t\t\t\t// (the previous iteration; we haven't computed reverse diagonals for numDifferences yet)\n\t\t\t\t// then check for overlap.\n\t\t\t\tif (!deltaIsEven && Math.abs(diagonal - diagonalReverseBase) <= (numDifferences - 1)) {\n\t\t\t\t\tif (originalIndex >= reversePoints[diagonal]) {\n\t\t\t\t\t\tmidOriginalArr[0] = originalIndex;\n\t\t\t\t\t\tmidModifiedArr[0] = modifiedIndex;\n\n\t\t\t\t\t\tif (tempOriginalIndex <= reversePoints[diagonal] && LocalConstants.MaxDifferencesHistory > 0 && numDifferences <= (LocalConstants.MaxDifferencesHistory + 1)) {\n\t\t\t\t\t\t\t// BINGO! We overlapped, and we have the full trace in memory!\n\t\t\t\t\t\t\treturn this.WALKTRACE(diagonalForwardBase, diagonalForwardStart, diagonalForwardEnd, diagonalForwardOffset,\n\t\t\t\t\t\t\t\tdiagonalReverseBase, diagonalReverseStart, diagonalReverseEnd, diagonalReverseOffset,\n\t\t\t\t\t\t\t\tforwardPoints, reversePoints,\n\t\t\t\t\t\t\t\toriginalIndex, originalEnd, midOriginalArr,\n\t\t\t\t\t\t\t\tmodifiedIndex, modifiedEnd, midModifiedArr,\n\t\t\t\t\t\t\t\tdeltaIsEven, quitEarlyArr\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Either false overlap, or we didn't have enough memory for the full trace\n\t\t\t\t\t\t\t// Just return the recursion point\n\t\t\t\t\t\t\treturn null;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Check to see if we should be quitting early, before moving on to the next iteration.\n\t\t\tconst matchLengthOfLongest = ((furthestOriginalIndex - originalStart) + (furthestModifiedIndex - modifiedStart) - numDifferences) / 2;\n\n\t\t\tif (this.ContinueProcessingPredicate !== null && !this.ContinueProcessingPredicate(furthestOriginalIndex, matchLengthOfLongest)) {\n\t\t\t\t// We can't finish, so skip ahead to generating a result from what we have.\n\t\t\t\tquitEarlyArr[0] = true;\n\n\t\t\t\t// Use the furthest distance we got in the forward direction.\n\t\t\t\tmidOriginalArr[0] = furthestOriginalIndex;\n\t\t\t\tmidModifiedArr[0] = furthestModifiedIndex;\n\n\t\t\t\tif (matchLengthOfLongest > 0 && LocalConstants.MaxDifferencesHistory > 0 && numDifferences <= (LocalConstants.MaxDifferencesHistory + 1)) {\n\t\t\t\t\t// Enough of the history is in memory to walk it backwards\n\t\t\t\t\treturn this.WALKTRACE(diagonalForwardBase, diagonalForwardStart, diagonalForwardEnd, diagonalForwardOffset,\n\t\t\t\t\t\tdiagonalReverseBase, diagonalReverseStart, diagonalReverseEnd, diagonalReverseOffset,\n\t\t\t\t\t\tforwardPoints, reversePoints,\n\t\t\t\t\t\toriginalIndex, originalEnd, midOriginalArr,\n\t\t\t\t\t\tmodifiedIndex, modifiedEnd, midModifiedArr,\n\t\t\t\t\t\tdeltaIsEven, quitEarlyArr\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\t// We didn't actually remember enough of the history.\n\n\t\t\t\t\t//Since we are quitting the diff early, we need to shift back the originalStart and modified start\n\t\t\t\t\t//back into the boundary limits since we decremented their value above beyond the boundary limit.\n\t\t\t\t\toriginalStart++;\n\t\t\t\t\tmodifiedStart++;\n\n\t\t\t\t\treturn [\n\t\t\t\t\t\tnew DiffChange(originalStart, originalEnd - originalStart + 1,\n\t\t\t\t\t\t\tmodifiedStart, modifiedEnd - modifiedStart + 1)\n\t\t\t\t\t];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Run the algorithm in the reverse direction\n\t\t\tdiagonalReverseStart = this.ClipDiagonalBound(diagonalReverseBase - numDifferences, numDifferences, diagonalReverseBase, numDiagonals);\n\t\t\tdiagonalReverseEnd = this.ClipDiagonalBound(diagonalReverseBase + numDifferences, numDifferences, diagonalReverseBase, numDiagonals);\n\t\t\tfor (let diagonal = diagonalReverseStart; diagonal <= diagonalReverseEnd; diagonal += 2) {\n\t\t\t\t// STEP 1: We extend the furthest reaching point in the present diagonal\n\t\t\t\t// by looking at the diagonals above and below and picking the one whose point\n\t\t\t\t// is further away from the start point (originalEnd, modifiedEnd)\n\t\t\t\tif (diagonal === diagonalReverseStart || (diagonal < diagonalReverseEnd && reversePoints[diagonal - 1] >= reversePoints[diagonal + 1])) {\n\t\t\t\t\toriginalIndex = reversePoints[diagonal + 1] - 1;\n\t\t\t\t} else {\n\t\t\t\t\toriginalIndex = reversePoints[diagonal - 1];\n\t\t\t\t}\n\t\t\t\tmodifiedIndex = originalIndex - (diagonal - diagonalReverseBase) - diagonalReverseOffset;\n\n\t\t\t\t// Save the current originalIndex so we can test for false overlap\n\t\t\t\tconst tempOriginalIndex = originalIndex;\n\n\t\t\t\t// STEP 2: We can continue to extend the furthest reaching point in the present diagonal\n\t\t\t\t// as long as the elements are equal.\n\t\t\t\twhile (originalIndex > originalStart && modifiedIndex > modifiedStart && this.ElementsAreEqual(originalIndex, modifiedIndex)) {\n\t\t\t\t\toriginalIndex--;\n\t\t\t\t\tmodifiedIndex--;\n\t\t\t\t}\n\t\t\t\treversePoints[diagonal] = originalIndex;\n\n\t\t\t\t// STEP 4: If delta is even (overlap first happens on reverse when delta is even)\n\t\t\t\t// and diagonal is in the range of forward diagonals computed for numDifferences\n\t\t\t\t// then check for overlap.\n\t\t\t\tif (deltaIsEven && Math.abs(diagonal - diagonalForwardBase) <= numDifferences) {\n\t\t\t\t\tif (originalIndex <= forwardPoints[diagonal]) {\n\t\t\t\t\t\tmidOriginalArr[0] = originalIndex;\n\t\t\t\t\t\tmidModifiedArr[0] = modifiedIndex;\n\n\t\t\t\t\t\tif (tempOriginalIndex >= forwardPoints[diagonal] && LocalConstants.MaxDifferencesHistory > 0 && numDifferences <= (LocalConstants.MaxDifferencesHistory + 1)) {\n\t\t\t\t\t\t\t// BINGO! We overlapped, and we have the full trace in memory!\n\t\t\t\t\t\t\treturn this.WALKTRACE(diagonalForwardBase, diagonalForwardStart, diagonalForwardEnd, diagonalForwardOffset,\n\t\t\t\t\t\t\t\tdiagonalReverseBase, diagonalReverseStart, diagonalReverseEnd, diagonalReverseOffset,\n\t\t\t\t\t\t\t\tforwardPoints, reversePoints,\n\t\t\t\t\t\t\t\toriginalIndex, originalEnd, midOriginalArr,\n\t\t\t\t\t\t\t\tmodifiedIndex, modifiedEnd, midModifiedArr,\n\t\t\t\t\t\t\t\tdeltaIsEven, quitEarlyArr\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Either false overlap, or we didn't have enough memory for the full trace\n\t\t\t\t\t\t\t// Just return the recursion point\n\t\t\t\t\t\t\treturn null;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Save current vectors to history before the next iteration\n\t\t\tif (numDifferences <= LocalConstants.MaxDifferencesHistory) {\n\t\t\t\t// We are allocating space for one extra int, which we fill with\n\t\t\t\t// the index of the diagonal base index\n\t\t\t\tlet temp = new Int32Array(diagonalForwardEnd - diagonalForwardStart + 2);\n\t\t\t\ttemp[0] = diagonalForwardBase - diagonalForwardStart + 1;\n\t\t\t\tMyArray.Copy2(forwardPoints, diagonalForwardStart, temp, 1, diagonalForwardEnd - diagonalForwardStart + 1);\n\t\t\t\tthis.m_forwardHistory.push(temp);\n\n\t\t\t\ttemp = new Int32Array(diagonalReverseEnd - diagonalReverseStart + 2);\n\t\t\t\ttemp[0] = diagonalReverseBase - diagonalReverseStart + 1;\n\t\t\t\tMyArray.Copy2(reversePoints, diagonalReverseStart, temp, 1, diagonalReverseEnd - diagonalReverseStart + 1);\n\t\t\t\tthis.m_reverseHistory.push(temp);\n\t\t\t}\n\n\t\t}\n\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\n\t\t// NOTE: This part is a bit messy\n\t\treturn this.WALKTRACE(diagonalForwardBase, diagonalForwardStart, diagonalForwardEnd, diagonalForwardOffset,\n\t\t\tdiagonalReverseBase, diagonalReverseStart, diagonalReverseEnd, diagonalReverseOffset,\n\t\t\tforwardPoints, reversePoints,\n\t\t\toriginalIndex, originalEnd, midOriginalArr,\n\t\t\tmodifiedIndex, modifiedEnd, midModifiedArr,\n\t\t\tdeltaIsEven, quitEarlyArr\n\t\t);\n\t}\n\n\t/**\n\t * Shifts the given changes to provide a more intuitive diff.\n\t * While the first element in a diff matches the first element after the diff,\n\t * we shift the diff down.\n\t *\n\t * @param changes The list of changes to shift\n\t * @returns The shifted changes\n\t */\n\tprivate PrettifyChanges(changes: DiffChange[]): DiffChange[] {\n\n\t\t// Shift all the changes down first\n\t\tfor (let i = 0; i < changes.length; i++) {\n\t\t\tconst change = changes[i];\n\t\t\tconst originalStop = (i < changes.length - 1) ? changes[i + 1].originalStart : this._originalElementsOrHash.length;\n\t\t\tconst modifiedStop = (i < changes.length - 1) ? changes[i + 1].modifiedStart : this._modifiedElementsOrHash.length;\n\t\t\tconst checkOriginal = change.originalLength > 0;\n\t\t\tconst checkModified = change.modifiedLength > 0;\n\n\t\t\twhile (\n\t\t\t\tchange.originalStart + change.originalLength < originalStop\n\t\t\t\t&& change.modifiedStart + change.modifiedLength < modifiedStop\n\t\t\t\t&& (!checkOriginal || this.OriginalElementsAreEqual(change.originalStart, change.originalStart + change.originalLength))\n\t\t\t\t&& (!checkModified || this.ModifiedElementsAreEqual(change.modifiedStart, change.modifiedStart + change.modifiedLength))\n\t\t\t) {\n\t\t\t\tconst startStrictEqual = this.ElementsAreStrictEqual(change.originalStart, change.modifiedStart);\n\t\t\t\tconst endStrictEqual = this.ElementsAreStrictEqual(change.originalStart + change.originalLength, change.modifiedStart + change.modifiedLength);\n\t\t\t\tif (endStrictEqual && !startStrictEqual) {\n\t\t\t\t\t// moving the change down would create an equal change, but the elements are not strict equal\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tchange.originalStart++;\n\t\t\t\tchange.modifiedStart++;\n\t\t\t}\n\n\t\t\tconst mergedChangeArr: Array = [null];\n\t\t\tif (i < changes.length - 1 && this.ChangesOverlap(changes[i], changes[i + 1], mergedChangeArr)) {\n\t\t\t\tchanges[i] = mergedChangeArr[0]!;\n\t\t\t\tchanges.splice(i + 1, 1);\n\t\t\t\ti--;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\t// Shift changes back up until we hit empty or whitespace-only lines\n\t\tfor (let i = changes.length - 1; i >= 0; i--) {\n\t\t\tconst change = changes[i];\n\n\t\t\tlet originalStop = 0;\n\t\t\tlet modifiedStop = 0;\n\t\t\tif (i > 0) {\n\t\t\t\tconst prevChange = changes[i - 1];\n\t\t\t\toriginalStop = prevChange.originalStart + prevChange.originalLength;\n\t\t\t\tmodifiedStop = prevChange.modifiedStart + prevChange.modifiedLength;\n\t\t\t}\n\n\t\t\tconst checkOriginal = change.originalLength > 0;\n\t\t\tconst checkModified = change.modifiedLength > 0;\n\n\t\t\tlet bestDelta = 0;\n\t\t\tlet bestScore = this._boundaryScore(change.originalStart, change.originalLength, change.modifiedStart, change.modifiedLength);\n\n\t\t\tfor (let delta = 1; ; delta++) {\n\t\t\t\tconst originalStart = change.originalStart - delta;\n\t\t\t\tconst modifiedStart = change.modifiedStart - delta;\n\n\t\t\t\tif (originalStart < originalStop || modifiedStart < modifiedStop) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tif (checkOriginal && !this.OriginalElementsAreEqual(originalStart, originalStart + change.originalLength)) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tif (checkModified && !this.ModifiedElementsAreEqual(modifiedStart, modifiedStart + change.modifiedLength)) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tconst touchingPreviousChange = (originalStart === originalStop && modifiedStart === modifiedStop);\n\t\t\t\tconst score = (\n\t\t\t\t\t(touchingPreviousChange ? 5 : 0)\n\t\t\t\t\t+ this._boundaryScore(originalStart, change.originalLength, modifiedStart, change.modifiedLength)\n\t\t\t\t);\n\n\t\t\t\tif (score > bestScore) {\n\t\t\t\t\tbestScore = score;\n\t\t\t\t\tbestDelta = delta;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tchange.originalStart -= bestDelta;\n\t\t\tchange.modifiedStart -= bestDelta;\n\n\t\t\tconst mergedChangeArr: Array = [null];\n\t\t\tif (i > 0 && this.ChangesOverlap(changes[i - 1], changes[i], mergedChangeArr)) {\n\t\t\t\tchanges[i - 1] = mergedChangeArr[0]!;\n\t\t\t\tchanges.splice(i, 1);\n\t\t\t\ti++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\t// There could be multiple longest common substrings.\n\t\t// Give preference to the ones containing longer lines\n\t\tif (this._hasStrings) {\n\t\t\tfor (let i = 1, len = changes.length; i < len; i++) {\n\t\t\t\tconst aChange = changes[i - 1];\n\t\t\t\tconst bChange = changes[i];\n\t\t\t\tconst matchedLength = bChange.originalStart - aChange.originalStart - aChange.originalLength;\n\t\t\t\tconst aOriginalStart = aChange.originalStart;\n\t\t\t\tconst bOriginalEnd = bChange.originalStart + bChange.originalLength;\n\t\t\t\tconst abOriginalLength = bOriginalEnd - aOriginalStart;\n\t\t\t\tconst aModifiedStart = aChange.modifiedStart;\n\t\t\t\tconst bModifiedEnd = bChange.modifiedStart + bChange.modifiedLength;\n\t\t\t\tconst abModifiedLength = bModifiedEnd - aModifiedStart;\n\t\t\t\t// Avoid wasting a lot of time with these searches\n\t\t\t\tif (matchedLength < 5 && abOriginalLength < 20 && abModifiedLength < 20) {\n\t\t\t\t\tconst t = this._findBetterContiguousSequence(\n\t\t\t\t\t\taOriginalStart, abOriginalLength,\n\t\t\t\t\t\taModifiedStart, abModifiedLength,\n\t\t\t\t\t\tmatchedLength\n\t\t\t\t\t);\n\t\t\t\t\tif (t) {\n\t\t\t\t\t\tconst [originalMatchStart, modifiedMatchStart] = t;\n\t\t\t\t\t\tif (originalMatchStart !== aChange.originalStart + aChange.originalLength || modifiedMatchStart !== aChange.modifiedStart + aChange.modifiedLength) {\n\t\t\t\t\t\t\t// switch to another sequence that has a better score\n\t\t\t\t\t\t\taChange.originalLength = originalMatchStart - aChange.originalStart;\n\t\t\t\t\t\t\taChange.modifiedLength = modifiedMatchStart - aChange.modifiedStart;\n\t\t\t\t\t\t\tbChange.originalStart = originalMatchStart + matchedLength;\n\t\t\t\t\t\t\tbChange.modifiedStart = modifiedMatchStart + matchedLength;\n\t\t\t\t\t\t\tbChange.originalLength = bOriginalEnd - bChange.originalStart;\n\t\t\t\t\t\t\tbChange.modifiedLength = bModifiedEnd - bChange.modifiedStart;\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}\n\n\t\treturn changes;\n\t}\n\n\tprivate _findBetterContiguousSequence(originalStart: number, originalLength: number, modifiedStart: number, modifiedLength: number, desiredLength: number): [number, number] | null {\n\t\tif (originalLength < desiredLength || modifiedLength < desiredLength) {\n\t\t\treturn null;\n\t\t}\n\t\tconst originalMax = originalStart + originalLength - desiredLength + 1;\n\t\tconst modifiedMax = modifiedStart + modifiedLength - desiredLength + 1;\n\t\tlet bestScore = 0;\n\t\tlet bestOriginalStart = 0;\n\t\tlet bestModifiedStart = 0;\n\t\tfor (let i = originalStart; i < originalMax; i++) {\n\t\t\tfor (let j = modifiedStart; j < modifiedMax; j++) {\n\t\t\t\tconst score = this._contiguousSequenceScore(i, j, desiredLength);\n\t\t\t\tif (score > 0 && score > bestScore) {\n\t\t\t\t\tbestScore = score;\n\t\t\t\t\tbestOriginalStart = i;\n\t\t\t\t\tbestModifiedStart = j;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (bestScore > 0) {\n\t\t\treturn [bestOriginalStart, bestModifiedStart];\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate _contiguousSequenceScore(originalStart: number, modifiedStart: number, length: number): number {\n\t\tlet score = 0;\n\t\tfor (let l = 0; l < length; l++) {\n\t\t\tif (!this.ElementsAreEqual(originalStart + l, modifiedStart + l)) {\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tscore += this._originalStringElements[originalStart + l].length;\n\t\t}\n\t\treturn score;\n\t}\n\n\tprivate _OriginalIsBoundary(index: number): boolean {\n\t\tif (index <= 0 || index >= this._originalElementsOrHash.length - 1) {\n\t\t\treturn true;\n\t\t}\n\t\treturn (this._hasStrings && /^\\s*$/.test(this._originalStringElements[index]));\n\t}\n\n\tprivate _OriginalRegionIsBoundary(originalStart: number, originalLength: number): boolean {\n\t\tif (this._OriginalIsBoundary(originalStart) || this._OriginalIsBoundary(originalStart - 1)) {\n\t\t\treturn true;\n\t\t}\n\t\tif (originalLength > 0) {\n\t\t\tconst originalEnd = originalStart + originalLength;\n\t\t\tif (this._OriginalIsBoundary(originalEnd - 1) || this._OriginalIsBoundary(originalEnd)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate _ModifiedIsBoundary(index: number): boolean {\n\t\tif (index <= 0 || index >= this._modifiedElementsOrHash.length - 1) {\n\t\t\treturn true;\n\t\t}\n\t\treturn (this._hasStrings && /^\\s*$/.test(this._modifiedStringElements[index]));\n\t}\n\n\tprivate _ModifiedRegionIsBoundary(modifiedStart: number, modifiedLength: number): boolean {\n\t\tif (this._ModifiedIsBoundary(modifiedStart) || this._ModifiedIsBoundary(modifiedStart - 1)) {\n\t\t\treturn true;\n\t\t}\n\t\tif (modifiedLength > 0) {\n\t\t\tconst modifiedEnd = modifiedStart + modifiedLength;\n\t\t\tif (this._ModifiedIsBoundary(modifiedEnd - 1) || this._ModifiedIsBoundary(modifiedEnd)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate _boundaryScore(originalStart: number, originalLength: number, modifiedStart: number, modifiedLength: number): number {\n\t\tconst originalScore = (this._OriginalRegionIsBoundary(originalStart, originalLength) ? 1 : 0);\n\t\tconst modifiedScore = (this._ModifiedRegionIsBoundary(modifiedStart, modifiedLength) ? 1 : 0);\n\t\treturn (originalScore + modifiedScore);\n\t}\n\n\t/**\n\t * Concatenates the two input DiffChange lists and returns the resulting\n\t * list.\n\t * @param The left changes\n\t * @param The right changes\n\t * @returns The concatenated list\n\t */\n\tprivate ConcatenateChanges(left: DiffChange[], right: DiffChange[]): DiffChange[] {\n\t\tconst mergedChangeArr: DiffChange[] = [];\n\n\t\tif (left.length === 0 || right.length === 0) {\n\t\t\treturn (right.length > 0) ? right : left;\n\t\t} else if (this.ChangesOverlap(left[left.length - 1], right[0], mergedChangeArr)) {\n\t\t\t// Since we break the problem down recursively, it is possible that we\n\t\t\t// might recurse in the middle of a change thereby splitting it into\n\t\t\t// two changes. Here in the combining stage, we detect and fuse those\n\t\t\t// changes back together\n\t\t\tconst result = new Array(left.length + right.length - 1);\n\t\t\tMyArray.Copy(left, 0, result, 0, left.length - 1);\n\t\t\tresult[left.length - 1] = mergedChangeArr[0];\n\t\t\tMyArray.Copy(right, 1, result, left.length, right.length - 1);\n\n\t\t\treturn result;\n\t\t} else {\n\t\t\tconst result = new Array(left.length + right.length);\n\t\t\tMyArray.Copy(left, 0, result, 0, left.length);\n\t\t\tMyArray.Copy(right, 0, result, left.length, right.length);\n\n\t\t\treturn result;\n\t\t}\n\t}\n\n\t/**\n\t * Returns true if the two changes overlap and can be merged into a single\n\t * change\n\t * @param left The left change\n\t * @param right The right change\n\t * @param mergedChange The merged change if the two overlap, null otherwise\n\t * @returns True if the two changes overlap\n\t */\n\tprivate ChangesOverlap(left: DiffChange, right: DiffChange, mergedChangeArr: Array): boolean {\n\t\tDebug.Assert(left.originalStart <= right.originalStart, 'Left change is not less than or equal to right change');\n\t\tDebug.Assert(left.modifiedStart <= right.modifiedStart, 'Left change is not less than or equal to right change');\n\n\t\tif (left.originalStart + left.originalLength >= right.originalStart || left.modifiedStart + left.modifiedLength >= right.modifiedStart) {\n\t\t\tconst originalStart = left.originalStart;\n\t\t\tlet originalLength = left.originalLength;\n\t\t\tconst modifiedStart = left.modifiedStart;\n\t\t\tlet modifiedLength = left.modifiedLength;\n\n\t\t\tif (left.originalStart + left.originalLength >= right.originalStart) {\n\t\t\t\toriginalLength = right.originalStart + right.originalLength - left.originalStart;\n\t\t\t}\n\t\t\tif (left.modifiedStart + left.modifiedLength >= right.modifiedStart) {\n\t\t\t\tmodifiedLength = right.modifiedStart + right.modifiedLength - left.modifiedStart;\n\t\t\t}\n\n\t\t\tmergedChangeArr[0] = new DiffChange(originalStart, originalLength, modifiedStart, modifiedLength);\n\t\t\treturn true;\n\t\t} else {\n\t\t\tmergedChangeArr[0] = null;\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t/**\n\t * Helper method used to clip a diagonal index to the range of valid\n\t * diagonals. This also decides whether or not the diagonal index,\n\t * if it exceeds the boundary, should be clipped to the boundary or clipped\n\t * one inside the boundary depending on the Even/Odd status of the boundary\n\t * and numDifferences.\n\t * @param diagonal The index of the diagonal to clip.\n\t * @param numDifferences The current number of differences being iterated upon.\n\t * @param diagonalBaseIndex The base reference diagonal.\n\t * @param numDiagonals The total number of diagonals.\n\t * @returns The clipped diagonal index.\n\t */\n\tprivate ClipDiagonalBound(diagonal: number, numDifferences: number, diagonalBaseIndex: number, numDiagonals: number): number {\n\t\tif (diagonal >= 0 && diagonal < numDiagonals) {\n\t\t\t// Nothing to clip, its in range\n\t\t\treturn diagonal;\n\t\t}\n\n\t\t// diagonalsBelow: The number of diagonals below the reference diagonal\n\t\t// diagonalsAbove: The number of diagonals above the reference diagonal\n\t\tconst diagonalsBelow = diagonalBaseIndex;\n\t\tconst diagonalsAbove = numDiagonals - diagonalBaseIndex - 1;\n\t\tconst diffEven = (numDifferences % 2 === 0);\n\n\t\tif (diagonal < 0) {\n\t\t\tconst lowerBoundEven = (diagonalsBelow % 2 === 0);\n\t\t\treturn (diffEven === lowerBoundEven) ? 0 : 1;\n\t\t} else {\n\t\t\tconst upperBoundEven = (diagonalsAbove % 2 === 0);\n\t\t\treturn (diffEven === upperBoundEven) ? numDiagonals - 1 : numDiagonals - 2;\n\t\t}\n\t}\n}\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\nimport * as strings from './strings';\n\nexport function buildReplaceStringWithCasePreserved(matches: string[] | null, pattern: string): string {\n\tif (matches && (matches[0] !== '')) {\n\t\tconst containsHyphens = validateSpecificSpecialCharacter(matches, pattern, '-');\n\t\tconst containsUnderscores = validateSpecificSpecialCharacter(matches, pattern, '_');\n\t\tif (containsHyphens && !containsUnderscores) {\n\t\t\treturn buildReplaceStringForSpecificSpecialCharacter(matches, pattern, '-');\n\t\t} else if (!containsHyphens && containsUnderscores) {\n\t\t\treturn buildReplaceStringForSpecificSpecialCharacter(matches, pattern, '_');\n\t\t}\n\t\tif (matches[0].toUpperCase() === matches[0]) {\n\t\t\treturn pattern.toUpperCase();\n\t\t} else if (matches[0].toLowerCase() === matches[0]) {\n\t\t\treturn pattern.toLowerCase();\n\t\t} else if (strings.containsUppercaseCharacter(matches[0][0]) && pattern.length > 0) {\n\t\t\treturn pattern[0].toUpperCase() + pattern.substr(1);\n\t\t} else if (matches[0][0].toUpperCase() !== matches[0][0] && pattern.length > 0) {\n\t\t\treturn pattern[0].toLowerCase() + pattern.substr(1);\n\t\t} else {\n\t\t\t// we don't understand its pattern yet.\n\t\t\treturn pattern;\n\t\t}\n\t} else {\n\t\treturn pattern;\n\t}\n}\n\nfunction validateSpecificSpecialCharacter(matches: string[], pattern: string, specialCharacter: string): boolean {\n\tconst doesContainSpecialCharacter = matches[0].indexOf(specialCharacter) !== -1 && pattern.indexOf(specialCharacter) !== -1;\n\treturn doesContainSpecialCharacter && matches[0].split(specialCharacter).length === pattern.split(specialCharacter).length;\n}\n\nfunction buildReplaceStringForSpecificSpecialCharacter(matches: string[], pattern: string, specialCharacter: string): string {\n\tconst splitPatternAtSpecialCharacter = pattern.split(specialCharacter);\n\tconst splitMatchAtSpecialCharacter = matches[0].split(specialCharacter);\n\tlet replaceString: string = '';\n\tsplitPatternAtSpecialCharacter.forEach((splitValue, index) => {\n\t\treplaceString += buildReplaceStringWithCasePreserved([splitMatchAtSpecialCharacter[index]], splitValue) + specialCharacter;\n\t});\n\n\treturn replaceString.slice(0, -1);\n}\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\nimport * as strings from 'vs/base/common/strings';\n\nenum Severity {\n\tIgnore = 0,\n\tInfo = 1,\n\tWarning = 2,\n\tError = 3\n}\n\nnamespace Severity {\n\n\tconst _error = 'error';\n\tconst _warning = 'warning';\n\tconst _warn = 'warn';\n\tconst _info = 'info';\n\tconst _ignore = 'ignore';\n\n\t/**\n\t * Parses 'error', 'warning', 'warn', 'info' in call casings\n\t * and falls back to ignore.\n\t */\n\texport function fromValue(value: string): Severity {\n\t\tif (!value) {\n\t\t\treturn Severity.Ignore;\n\t\t}\n\n\t\tif (strings.equalsIgnoreCase(_error, value)) {\n\t\t\treturn Severity.Error;\n\t\t}\n\n\t\tif (strings.equalsIgnoreCase(_warning, value) || strings.equalsIgnoreCase(_warn, value)) {\n\t\t\treturn Severity.Warning;\n\t\t}\n\n\t\tif (strings.equalsIgnoreCase(_info, value)) {\n\t\t\treturn Severity.Info;\n\t\t}\n\t\treturn Severity.Ignore;\n\t}\n\n\texport function toString(severity: Severity): string {\n\t\tswitch (severity) {\n\t\t\tcase Severity.Error: return _error;\n\t\t\tcase Severity.Warning: return _warning;\n\t\t\tcase Severity.Info: return _info;\n\t\t\tdefault: return _ignore;\n\t\t}\n\t}\n}\n\nexport default Severity;\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 * Can be passed into the Delayed to defer using a microtask\n * */\nexport const MicrotaskDelay = Symbol('MicrotaskDelay');\n","\nimport { CharCode } from 'vs/base/common/charCode';\nimport { compare, compareIgnoreCase, compareSubstring, compareSubstringIgnoreCase } from 'vs/base/common/strings';\nimport { URI } from 'vs/base/common/uri';\n\nexport interface IKeyIterator {\n\treset(key: K): this;\n\tnext(): this;\n\n\thasNext(): boolean;\n\tcmp(a: string): number;\n\tvalue(): string;\n}\n\nexport class StringIterator implements IKeyIterator {\n\n\tprivate _value: string = '';\n\tprivate _pos: number = 0;\n\n\treset(key: string): this {\n\t\tthis._value = key;\n\t\tthis._pos = 0;\n\t\treturn this;\n\t}\n\n\tnext(): this {\n\t\tthis._pos += 1;\n\t\treturn this;\n\t}\n\n\thasNext(): boolean {\n\t\treturn this._pos < this._value.length - 1;\n\t}\n\n\tcmp(a: string): number {\n\t\tconst aCode = a.charCodeAt(0);\n\t\tconst thisCode = this._value.charCodeAt(this._pos);\n\t\treturn aCode - thisCode;\n\t}\n\n\tvalue(): string {\n\t\treturn this._value[this._pos];\n\t}\n}\n\nexport class ConfigKeysIterator implements IKeyIterator {\n\n\tprivate _value!: string;\n\tprivate _from!: number;\n\tprivate _to!: number;\n\n\tconstructor(\n\t\tprivate readonly _caseSensitive: boolean = true\n\t) { }\n\n\treset(key: string): this {\n\t\tthis._value = key;\n\t\tthis._from = 0;\n\t\tthis._to = 0;\n\t\treturn this.next();\n\t}\n\n\thasNext(): boolean {\n\t\treturn this._to < this._value.length;\n\t}\n\n\tnext(): this {\n\t\t// this._data = key.split(/[\\\\/]/).filter(s => !!s);\n\t\tthis._from = this._to;\n\t\tlet justSeps = true;\n\t\tfor (; this._to < this._value.length; this._to++) {\n\t\t\tconst ch = this._value.charCodeAt(this._to);\n\t\t\tif (ch === CharCode.Period) {\n\t\t\t\tif (justSeps) {\n\t\t\t\t\tthis._from++;\n\t\t\t\t} else {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tjustSeps = false;\n\t\t\t}\n\t\t}\n\t\treturn this;\n\t}\n\n\tcmp(a: string): number {\n\t\treturn this._caseSensitive\n\t\t\t? compareSubstring(a, this._value, 0, a.length, this._from, this._to)\n\t\t\t: compareSubstringIgnoreCase(a, this._value, 0, a.length, this._from, this._to);\n\t}\n\n\tvalue(): string {\n\t\treturn this._value.substring(this._from, this._to);\n\t}\n}\n\nexport class PathIterator implements IKeyIterator {\n\n\tprivate _value!: string;\n\tprivate _valueLen!: number;\n\tprivate _from!: number;\n\tprivate _to!: number;\n\n\tconstructor(\n\t\tprivate readonly _splitOnBackslash: boolean = true,\n\t\tprivate readonly _caseSensitive: boolean = true\n\t) { }\n\n\treset(key: string): this {\n\t\tthis._from = 0;\n\t\tthis._to = 0;\n\t\tthis._value = key;\n\t\tthis._valueLen = key.length;\n\t\tfor (let pos = key.length - 1; pos >= 0; pos--, this._valueLen--) {\n\t\t\tconst ch = this._value.charCodeAt(pos);\n\t\t\tif (!(ch === CharCode.Slash || this._splitOnBackslash && ch === CharCode.Backslash)) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn this.next();\n\t}\n\n\thasNext(): boolean {\n\t\treturn this._to < this._valueLen;\n\t}\n\n\tnext(): this {\n\t\t// this._data = key.split(/[\\\\/]/).filter(s => !!s);\n\t\tthis._from = this._to;\n\t\tlet justSeps = true;\n\t\tfor (; this._to < this._valueLen; this._to++) {\n\t\t\tconst ch = this._value.charCodeAt(this._to);\n\t\t\tif (ch === CharCode.Slash || this._splitOnBackslash && ch === CharCode.Backslash) {\n\t\t\t\tif (justSeps) {\n\t\t\t\t\tthis._from++;\n\t\t\t\t} else {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tjustSeps = false;\n\t\t\t}\n\t\t}\n\t\treturn this;\n\t}\n\n\tcmp(a: string): number {\n\t\treturn this._caseSensitive\n\t\t\t? compareSubstring(a, this._value, 0, a.length, this._from, this._to)\n\t\t\t: compareSubstringIgnoreCase(a, this._value, 0, a.length, this._from, this._to);\n\t}\n\n\tvalue(): string {\n\t\treturn this._value.substring(this._from, this._to);\n\t}\n}\n\nconst enum UriIteratorState {\n\tScheme = 1, Authority = 2, Path = 3, Query = 4, Fragment = 5\n}\n\nexport class UriIterator implements IKeyIterator {\n\n\tprivate _pathIterator!: PathIterator;\n\tprivate _value!: URI;\n\tprivate _states: UriIteratorState[] = [];\n\tprivate _stateIdx: number = 0;\n\n\tconstructor(\n\t\tprivate readonly _ignorePathCasing: (uri: URI) => boolean,\n\t\tprivate readonly _ignoreQueryAndFragment: (uri: URI) => boolean) { }\n\n\treset(key: URI): this {\n\t\tthis._value = key;\n\t\tthis._states = [];\n\t\tif (this._value.scheme) {\n\t\t\tthis._states.push(UriIteratorState.Scheme);\n\t\t}\n\t\tif (this._value.authority) {\n\t\t\tthis._states.push(UriIteratorState.Authority);\n\t\t}\n\t\tif (this._value.path) {\n\t\t\tthis._pathIterator = new PathIterator(false, !this._ignorePathCasing(key));\n\t\t\tthis._pathIterator.reset(key.path);\n\t\t\tif (this._pathIterator.value()) {\n\t\t\t\tthis._states.push(UriIteratorState.Path);\n\t\t\t}\n\t\t}\n\t\tif (!this._ignoreQueryAndFragment(key)) {\n\t\t\tif (this._value.query) {\n\t\t\t\tthis._states.push(UriIteratorState.Query);\n\t\t\t}\n\t\t\tif (this._value.fragment) {\n\t\t\t\tthis._states.push(UriIteratorState.Fragment);\n\t\t\t}\n\t\t}\n\t\tthis._stateIdx = 0;\n\t\treturn this;\n\t}\n\n\tnext(): this {\n\t\tif (this._states[this._stateIdx] === UriIteratorState.Path && this._pathIterator.hasNext()) {\n\t\t\tthis._pathIterator.next();\n\t\t} else {\n\t\t\tthis._stateIdx += 1;\n\t\t}\n\t\treturn this;\n\t}\n\n\thasNext(): boolean {\n\t\treturn (this._states[this._stateIdx] === UriIteratorState.Path && this._pathIterator.hasNext())\n\t\t\t|| this._stateIdx < this._states.length - 1;\n\t}\n\n\tcmp(a: string): number {\n\t\tif (this._states[this._stateIdx] === UriIteratorState.Scheme) {\n\t\t\treturn compareIgnoreCase(a, this._value.scheme);\n\t\t} else if (this._states[this._stateIdx] === UriIteratorState.Authority) {\n\t\t\treturn compareIgnoreCase(a, this._value.authority);\n\t\t} else if (this._states[this._stateIdx] === UriIteratorState.Path) {\n\t\t\treturn this._pathIterator.cmp(a);\n\t\t} else if (this._states[this._stateIdx] === UriIteratorState.Query) {\n\t\t\treturn compare(a, this._value.query);\n\t\t} else if (this._states[this._stateIdx] === UriIteratorState.Fragment) {\n\t\t\treturn compare(a, this._value.fragment);\n\t\t}\n\t\tthrow new Error();\n\t}\n\n\tvalue(): string {\n\t\tif (this._states[this._stateIdx] === UriIteratorState.Scheme) {\n\t\t\treturn this._value.scheme;\n\t\t} else if (this._states[this._stateIdx] === UriIteratorState.Authority) {\n\t\t\treturn this._value.authority;\n\t\t} else if (this._states[this._stateIdx] === UriIteratorState.Path) {\n\t\t\treturn this._pathIterator.value();\n\t\t} else if (this._states[this._stateIdx] === UriIteratorState.Query) {\n\t\t\treturn this._value.query;\n\t\t} else if (this._states[this._stateIdx] === UriIteratorState.Fragment) {\n\t\t\treturn this._value.fragment;\n\t\t}\n\t\tthrow new Error();\n\t}\n}\nclass TernarySearchTreeNode {\n\theight: number = 1;\n\tsegment!: string;\n\tvalue: V | undefined;\n\tkey: K | undefined;\n\tleft: TernarySearchTreeNode | undefined;\n\tmid: TernarySearchTreeNode | undefined;\n\tright: TernarySearchTreeNode | undefined;\n\n\trotateLeft() {\n\t\tconst tmp = this.right!;\n\t\tthis.right = tmp.left;\n\t\ttmp.left = this;\n\t\tthis.updateHeight();\n\t\ttmp.updateHeight();\n\t\treturn tmp;\n\t}\n\n\trotateRight() {\n\t\tconst tmp = this.left!;\n\t\tthis.left = tmp.right;\n\t\ttmp.right = this;\n\t\tthis.updateHeight();\n\t\ttmp.updateHeight();\n\t\treturn tmp;\n\t}\n\n\tupdateHeight() {\n\t\tthis.height = 1 + Math.max(this.heightLeft, this.heightRight);\n\t}\n\n\tbalanceFactor() {\n\t\treturn this.heightRight - this.heightLeft;\n\t}\n\n\tget heightLeft() {\n\t\treturn this.left?.height ?? 0;\n\t}\n\n\tget heightRight() {\n\t\treturn this.right?.height ?? 0;\n\t}\n}\n\nconst enum Dir {\n\tLeft = -1,\n\tMid = 0,\n\tRight = 1\n}\n\nexport class TernarySearchTree {\n\n\tstatic forUris(ignorePathCasing: (key: URI) => boolean = () => false, ignoreQueryAndFragment: (key: URI) => boolean = () => false): TernarySearchTree {\n\t\treturn new TernarySearchTree(new UriIterator(ignorePathCasing, ignoreQueryAndFragment));\n\t}\n\n\tstatic forStrings(): TernarySearchTree {\n\t\treturn new TernarySearchTree(new StringIterator());\n\t}\n\n\tstatic forConfigKeys(): TernarySearchTree {\n\t\treturn new TernarySearchTree(new ConfigKeysIterator());\n\t}\n\n\tprivate _iter: IKeyIterator;\n\tprivate _root: TernarySearchTreeNode | undefined;\n\n\tconstructor(segments: IKeyIterator) {\n\t\tthis._iter = segments;\n\t}\n\n\tclear(): void {\n\t\tthis._root = undefined;\n\t}\n\n\tset(key: K, element: V): V | undefined {\n\t\tconst iter = this._iter.reset(key);\n\t\tlet node: TernarySearchTreeNode;\n\n\t\tif (!this._root) {\n\t\t\tthis._root = new TernarySearchTreeNode();\n\t\t\tthis._root.segment = iter.value();\n\t\t}\n\t\tconst stack: [Dir, TernarySearchTreeNode][] = [];\n\n\t\t// find insert_node\n\t\tnode = this._root;\n\t\twhile (true) {\n\t\t\tconst val = iter.cmp(node.segment);\n\t\t\tif (val > 0) {\n\t\t\t\t// left\n\t\t\t\tif (!node.left) {\n\t\t\t\t\tnode.left = new TernarySearchTreeNode();\n\t\t\t\t\tnode.left.segment = iter.value();\n\t\t\t\t}\n\t\t\t\tstack.push([Dir.Left, node]);\n\t\t\t\tnode = node.left;\n\n\t\t\t} else if (val < 0) {\n\t\t\t\t// right\n\t\t\t\tif (!node.right) {\n\t\t\t\t\tnode.right = new TernarySearchTreeNode();\n\t\t\t\t\tnode.right.segment = iter.value();\n\t\t\t\t}\n\t\t\t\tstack.push([Dir.Right, node]);\n\t\t\t\tnode = node.right;\n\n\t\t\t} else if (iter.hasNext()) {\n\t\t\t\t// mid\n\t\t\t\titer.next();\n\t\t\t\tif (!node.mid) {\n\t\t\t\t\tnode.mid = new TernarySearchTreeNode();\n\t\t\t\t\tnode.mid.segment = iter.value();\n\t\t\t\t}\n\t\t\t\tstack.push([Dir.Mid, node]);\n\t\t\t\tnode = node.mid;\n\t\t\t} else {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// set value\n\t\tconst oldElement = node.value;\n\t\tnode.value = element;\n\t\tnode.key = key;\n\n\t\t// balance\n\t\tfor (let i = stack.length - 1; i >= 0; i--) {\n\t\t\tconst node = stack[i][1];\n\n\t\t\tnode.updateHeight();\n\t\t\tconst bf = node.balanceFactor();\n\n\t\t\tif (bf < -1 || bf > 1) {\n\t\t\t\t// needs rotate\n\t\t\t\tconst d1 = stack[i][0];\n\t\t\t\tconst d2 = stack[i + 1][0];\n\n\t\t\t\tif (d1 === Dir.Right && d2 === Dir.Right) {\n\t\t\t\t\t//right, right -> rotate left\n\t\t\t\t\tstack[i][1] = node.rotateLeft();\n\n\t\t\t\t} else if (d1 === Dir.Left && d2 === Dir.Left) {\n\t\t\t\t\t// left, left -> rotate right\n\t\t\t\t\tstack[i][1] = node.rotateRight();\n\n\t\t\t\t} else if (d1 === Dir.Right && d2 === Dir.Left) {\n\t\t\t\t\t// right, left -> double rotate right, left\n\t\t\t\t\tnode.right = stack[i + 1][1] = stack[i + 1][1].rotateRight();\n\t\t\t\t\tstack[i][1] = node.rotateLeft();\n\n\t\t\t\t} else if (d1 === Dir.Left && d2 === Dir.Right) {\n\t\t\t\t\t// left, right -> double rotate left, right\n\t\t\t\t\tnode.left = stack[i + 1][1] = stack[i + 1][1].rotateLeft();\n\t\t\t\t\tstack[i][1] = node.rotateRight();\n\n\t\t\t\t} else {\n\t\t\t\t\tthrow new Error();\n\t\t\t\t}\n\n\t\t\t\t// patch path to parent\n\t\t\t\tif (i > 0) {\n\t\t\t\t\tswitch (stack[i - 1][0]) {\n\t\t\t\t\t\tcase Dir.Left:\n\t\t\t\t\t\t\tstack[i - 1][1].left = stack[i][1];\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase Dir.Right:\n\t\t\t\t\t\t\tstack[i - 1][1].right = stack[i][1];\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase Dir.Mid:\n\t\t\t\t\t\t\tstack[i - 1][1].mid = stack[i][1];\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tthis._root = stack[0][1];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn oldElement;\n\t}\n\n\tget(key: K): V | undefined {\n\t\treturn this._getNode(key)?.value;\n\t}\n\n\tprivate _getNode(key: K) {\n\t\tconst iter = this._iter.reset(key);\n\t\tlet node = this._root;\n\t\twhile (node) {\n\t\t\tconst val = iter.cmp(node.segment);\n\t\t\tif (val > 0) {\n\t\t\t\t// left\n\t\t\t\tnode = node.left;\n\t\t\t} else if (val < 0) {\n\t\t\t\t// right\n\t\t\t\tnode = node.right;\n\t\t\t} else if (iter.hasNext()) {\n\t\t\t\t// mid\n\t\t\t\titer.next();\n\t\t\t\tnode = node.mid;\n\t\t\t} else {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\treturn node;\n\t}\n\n\thas(key: K): boolean {\n\t\tconst node = this._getNode(key);\n\t\treturn !(node?.value === undefined && node?.mid === undefined);\n\t}\n\n\tdelete(key: K): void {\n\t\treturn this._delete(key, false);\n\t}\n\n\tdeleteSuperstr(key: K): void {\n\t\treturn this._delete(key, true);\n\t}\n\n\tprivate _delete(key: K, superStr: boolean): void {\n\t\tconst iter = this._iter.reset(key);\n\t\tconst stack: [Dir, TernarySearchTreeNode][] = [];\n\t\tlet node = this._root;\n\n\t\t// find node\n\t\twhile (node) {\n\t\t\tconst val = iter.cmp(node.segment);\n\t\t\tif (val > 0) {\n\t\t\t\t// left\n\t\t\t\tstack.push([Dir.Left, node]);\n\t\t\t\tnode = node.left;\n\t\t\t} else if (val < 0) {\n\t\t\t\t// right\n\t\t\t\tstack.push([Dir.Right, node]);\n\t\t\t\tnode = node.right;\n\t\t\t} else if (iter.hasNext()) {\n\t\t\t\t// mid\n\t\t\t\titer.next();\n\t\t\t\tstack.push([Dir.Mid, node]);\n\t\t\t\tnode = node.mid;\n\t\t\t} else {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (!node) {\n\t\t\t// node not found\n\t\t\treturn;\n\t\t}\n\n\t\tif (superStr) {\n\t\t\t// removing children, reset height\n\t\t\tnode.left = undefined;\n\t\t\tnode.mid = undefined;\n\t\t\tnode.right = undefined;\n\t\t\tnode.height = 1;\n\t\t} else {\n\t\t\t// removing element\n\t\t\tnode.key = undefined;\n\t\t\tnode.value = undefined;\n\t\t}\n\n\t\t// BST node removal\n\t\tif (!node.mid && !node.value) {\n\t\t\tif (node.left && node.right) {\n\t\t\t\t// full node\n\t\t\t\t// replace deleted-node with the min-node of the right branch.\n\t\t\t\t// If there is no true min-node leave things as they are\n\t\t\t\tconst min = this._min(node.right);\n\t\t\t\tif (min.key) {\n\t\t\t\t\tconst { key, value, segment } = min;\n\t\t\t\t\tthis._delete(min.key, false);\n\t\t\t\t\tnode.key = key;\n\t\t\t\t\tnode.value = value;\n\t\t\t\t\tnode.segment = segment;\n\t\t\t\t}\n\n\t\t\t} else {\n\t\t\t\t// empty or half empty\n\t\t\t\tconst newChild = node.left ?? node.right;\n\t\t\t\tif (stack.length > 0) {\n\t\t\t\t\tconst [dir, parent] = stack[stack.length - 1];\n\t\t\t\t\tswitch (dir) {\n\t\t\t\t\t\tcase Dir.Left: parent.left = newChild; break;\n\t\t\t\t\t\tcase Dir.Mid: parent.mid = newChild; break;\n\t\t\t\t\t\tcase Dir.Right: parent.right = newChild; break;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tthis._root = newChild;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// AVL balance\n\t\tfor (let i = stack.length - 1; i >= 0; i--) {\n\t\t\tconst node = stack[i][1];\n\n\t\t\tnode.updateHeight();\n\t\t\tconst bf = node.balanceFactor();\n\t\t\tif (bf > 1) {\n\t\t\t\t// right heavy\n\t\t\t\tif (node.right!.balanceFactor() >= 0) {\n\t\t\t\t\t// right, right -> rotate left\n\t\t\t\t\tstack[i][1] = node.rotateLeft();\n\t\t\t\t} else {\n\t\t\t\t\t// right, left -> double rotate\n\t\t\t\t\tnode.right = node.right!.rotateRight();\n\t\t\t\t\tstack[i][1] = node.rotateLeft();\n\t\t\t\t}\n\n\t\t\t} else if (bf < -1) {\n\t\t\t\t// left heavy\n\t\t\t\tif (node.left!.balanceFactor() <= 0) {\n\t\t\t\t\t// left, left -> rotate right\n\t\t\t\t\tstack[i][1] = node.rotateRight();\n\t\t\t\t} else {\n\t\t\t\t\t// left, right -> double rotate\n\t\t\t\t\tnode.left = node.left!.rotateLeft();\n\t\t\t\t\tstack[i][1] = node.rotateRight();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// patch path to parent\n\t\t\tif (i > 0) {\n\t\t\t\tswitch (stack[i - 1][0]) {\n\t\t\t\t\tcase Dir.Left:\n\t\t\t\t\t\tstack[i - 1][1].left = stack[i][1];\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase Dir.Right:\n\t\t\t\t\t\tstack[i - 1][1].right = stack[i][1];\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase Dir.Mid:\n\t\t\t\t\t\tstack[i - 1][1].mid = stack[i][1];\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis._root = stack[0][1];\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate _min(node: TernarySearchTreeNode): TernarySearchTreeNode {\n\t\twhile (node.left) {\n\t\t\tnode = node.left;\n\t\t}\n\t\treturn node;\n\t}\n\n\tfindSubstr(key: K): V | undefined {\n\t\tconst iter = this._iter.reset(key);\n\t\tlet node = this._root;\n\t\tlet candidate: V | undefined = undefined;\n\t\twhile (node) {\n\t\t\tconst val = iter.cmp(node.segment);\n\t\t\tif (val > 0) {\n\t\t\t\t// left\n\t\t\t\tnode = node.left;\n\t\t\t} else if (val < 0) {\n\t\t\t\t// right\n\t\t\t\tnode = node.right;\n\t\t\t} else if (iter.hasNext()) {\n\t\t\t\t// mid\n\t\t\t\titer.next();\n\t\t\t\tcandidate = node.value || candidate;\n\t\t\t\tnode = node.mid;\n\t\t\t} else {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\treturn node && node.value || candidate;\n\t}\n\n\tfindSuperstr(key: K): IterableIterator<[K, V]> | undefined {\n\t\treturn this._findSuperstrOrElement(key, false);\n\t}\n\n\tprivate _findSuperstrOrElement(key: K, allowValue: true): IterableIterator<[K, V]> | V | undefined;\n\tprivate _findSuperstrOrElement(key: K, allowValue: false): IterableIterator<[K, V]> | undefined;\n\tprivate _findSuperstrOrElement(key: K, allowValue: boolean): IterableIterator<[K, V]> | V | undefined {\n\t\tconst iter = this._iter.reset(key);\n\t\tlet node = this._root;\n\t\twhile (node) {\n\t\t\tconst val = iter.cmp(node.segment);\n\t\t\tif (val > 0) {\n\t\t\t\t// left\n\t\t\t\tnode = node.left;\n\t\t\t} else if (val < 0) {\n\t\t\t\t// right\n\t\t\t\tnode = node.right;\n\t\t\t} else if (iter.hasNext()) {\n\t\t\t\t// mid\n\t\t\t\titer.next();\n\t\t\t\tnode = node.mid;\n\t\t\t} else {\n\t\t\t\t// collect\n\t\t\t\tif (!node.mid) {\n\t\t\t\t\tif (allowValue) {\n\t\t\t\t\t\treturn node.value;\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\treturn this._entries(node.mid);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tforEach(callback: (value: V, index: K) => any): void {\n\t\tfor (const [key, value] of this) {\n\t\t\tcallback(value, key);\n\t\t}\n\t}\n\n\t*[Symbol.iterator](): IterableIterator<[K, V]> {\n\t\tyield* this._entries(this._root);\n\t}\n\n\tprivate _entries(node: TernarySearchTreeNode | undefined): IterableIterator<[K, V]> {\n\t\tconst result: [K, V][] = [];\n\t\tthis._dfsEntries(node, result);\n\t\treturn result[Symbol.iterator]();\n\t}\n\n\tprivate _dfsEntries(node: TernarySearchTreeNode | undefined, bucket: [K, V][]) {\n\t\t// DFS\n\t\tif (!node) {\n\t\t\treturn;\n\t\t}\n\t\tif (node.left) {\n\t\t\tthis._dfsEntries(node.left, bucket);\n\t\t}\n\t\tif (node.value) {\n\t\t\tbucket.push([node.key!, node.value]);\n\t\t}\n\t\tif (node.mid) {\n\t\t\tthis._dfsEntries(node.mid, bucket);\n\t\t}\n\t\tif (node.right) {\n\t\t\tthis._dfsEntries(node.right, bucket);\n\t\t}\n\t}\n}\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\nimport { CancellationToken } from 'vs/base/common/cancellation';\n\ntype SparseEmbedding = Record;\ntype TermFrequencies = Map;\ntype DocumentOccurrences = Map;\n\nfunction countMapFrom(values: Iterable): Map {\n\tconst map = new Map();\n\tfor (const value of values) {\n\t\tmap.set(value, (map.get(value) ?? 0) + 1);\n\t}\n\treturn map;\n}\n\ninterface DocumentChunkEntry {\n\treadonly tf: TermFrequencies;\n}\n\nexport interface TfIdfDocument {\n\treadonly key: string;\n\treadonly textChunks: readonly string[];\n}\n\nexport interface TfIdfScore {\n\treadonly key: string;\n\t/**\n\t * An unbounded number.\n\t */\n\treadonly score: number;\n}\n\nexport interface NormalizedTfIdfScore {\n\treadonly key: string;\n\t/**\n\t * A number between 0 and 1.\n\t */\n\treadonly score: number;\n}\n\n/**\n * Implementation of tf-idf (term frequency-inverse document frequency) for a set of\n * documents where each document contains one or more chunks of text.\n * Each document is identified by a key, and the score for each document is computed\n * by taking the max score over all the chunks in the document.\n */\nexport class TfIdfCalculator {\n\tcalculateScores(query: string, token: CancellationToken): TfIdfScore[] {\n\t\tconst embedding = this.computeEmbedding(query);\n\t\tconst idfCache = new Map();\n\t\tconst scores: TfIdfScore[] = [];\n\t\t// For each document, generate one score\n\t\tfor (const [key, doc] of this.documents) {\n\t\t\tif (token.isCancellationRequested) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tfor (const chunk of doc.chunks) {\n\t\t\t\tconst score = this.computeSimilarityScore(chunk, embedding, idfCache);\n\t\t\t\tif (score > 0) {\n\t\t\t\t\tscores.push({ key, score });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn scores;\n\t}\n\n\t/**\n\t * Count how many times each term (word) appears in a string.\n\t */\n\tprivate static termFrequencies(input: string): TermFrequencies {\n\t\treturn countMapFrom(TfIdfCalculator.splitTerms(input));\n\t}\n\n\t/**\n\t * Break a string into terms (words).\n\t */\n\tprivate static *splitTerms(input: string): Iterable {\n\t\tconst normalize = (word: string) => word.toLowerCase();\n\n\t\t// Only match on words that are at least 3 characters long and start with a letter\n\t\tfor (const [word] of input.matchAll(/\\b\\p{Letter}[\\p{Letter}\\d]{2,}\\b/gu)) {\n\t\t\tyield normalize(word);\n\n\t\t\tconst camelParts = word.replace(/([a-z])([A-Z])/g, '$1 $2').split(/\\s+/g);\n\t\t\tif (camelParts.length > 1) {\n\t\t\t\tfor (const part of camelParts) {\n\t\t\t\t\t// Require at least 3 letters in the parts of a camel case word\n\t\t\t\t\tif (part.length > 2 && /\\p{Letter}{3,}/gu.test(part)) {\n\t\t\t\t\t\tyield normalize(part);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Total number of chunks\n\t */\n\tprivate chunkCount = 0;\n\n\tprivate readonly chunkOccurrences: DocumentOccurrences = new Map();\n\n\tprivate readonly documents = new Map;\n\t}>();\n\n\tupdateDocuments(documents: ReadonlyArray): this {\n\t\tfor (const { key } of documents) {\n\t\t\tthis.deleteDocument(key);\n\t\t}\n\n\t\tfor (const doc of documents) {\n\t\t\tconst chunks: Array<{ text: string; tf: TermFrequencies }> = [];\n\t\t\tfor (const text of doc.textChunks) {\n\t\t\t\t// TODO: See if we can compute the tf lazily\n\t\t\t\t// The challenge is that we need to also update the `chunkOccurrences`\n\t\t\t\t// and all of those updates need to get flushed before the real TF-IDF of\n\t\t\t\t// anything is computed.\n\t\t\t\tconst tf = TfIdfCalculator.termFrequencies(text);\n\n\t\t\t\t// Update occurrences list\n\t\t\t\tfor (const term of tf.keys()) {\n\t\t\t\t\tthis.chunkOccurrences.set(term, (this.chunkOccurrences.get(term) ?? 0) + 1);\n\t\t\t\t}\n\n\t\t\t\tchunks.push({ text, tf });\n\t\t\t}\n\n\t\t\tthis.chunkCount += chunks.length;\n\t\t\tthis.documents.set(doc.key, { chunks });\n\t\t}\n\t\treturn this;\n\t}\n\n\tdeleteDocument(key: string) {\n\t\tconst doc = this.documents.get(key);\n\t\tif (!doc) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.documents.delete(key);\n\t\tthis.chunkCount -= doc.chunks.length;\n\n\t\t// Update term occurrences for the document\n\t\tfor (const chunk of doc.chunks) {\n\t\t\tfor (const term of chunk.tf.keys()) {\n\t\t\t\tconst currentOccurrences = this.chunkOccurrences.get(term);\n\t\t\t\tif (typeof currentOccurrences === 'number') {\n\t\t\t\t\tconst newOccurrences = currentOccurrences - 1;\n\t\t\t\t\tif (newOccurrences <= 0) {\n\t\t\t\t\t\tthis.chunkOccurrences.delete(term);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.chunkOccurrences.set(term, newOccurrences);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate computeSimilarityScore(chunk: DocumentChunkEntry, queryEmbedding: SparseEmbedding, idfCache: Map): number {\n\t\t// Compute the dot product between the chunk's embedding and the query embedding\n\n\t\t// Note that the chunk embedding is computed lazily on a per-term basis.\n\t\t// This lets us skip a large number of calculations because the majority\n\t\t// of chunks do not share any terms with the query.\n\n\t\tlet sum = 0;\n\t\tfor (const [term, termTfidf] of Object.entries(queryEmbedding)) {\n\t\t\tconst chunkTf = chunk.tf.get(term);\n\t\t\tif (!chunkTf) {\n\t\t\t\t// Term does not appear in chunk so it has no contribution\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tlet chunkIdf = idfCache.get(term);\n\t\t\tif (typeof chunkIdf !== 'number') {\n\t\t\t\tchunkIdf = this.computeIdf(term);\n\t\t\t\tidfCache.set(term, chunkIdf);\n\t\t\t}\n\n\t\t\tconst chunkTfidf = chunkTf * chunkIdf;\n\t\t\tsum += chunkTfidf * termTfidf;\n\t\t}\n\t\treturn sum;\n\t}\n\n\tprivate computeEmbedding(input: string): SparseEmbedding {\n\t\tconst tf = TfIdfCalculator.termFrequencies(input);\n\t\treturn this.computeTfidf(tf);\n\t}\n\n\tprivate computeIdf(term: string): number {\n\t\tconst chunkOccurrences = this.chunkOccurrences.get(term) ?? 0;\n\t\treturn chunkOccurrences > 0\n\t\t\t? Math.log((this.chunkCount + 1) / chunkOccurrences)\n\t\t\t: 0;\n\t}\n\n\tprivate computeTfidf(termFrequencies: TermFrequencies): SparseEmbedding {\n\t\tconst embedding = Object.create(null);\n\t\tfor (const [word, occurrences] of termFrequencies) {\n\t\t\tconst idf = this.computeIdf(word);\n\t\t\tif (idf > 0) {\n\t\t\t\tembedding[word] = occurrences * idf;\n\t\t\t}\n\t\t}\n\t\treturn embedding;\n\t}\n}\n\n/**\n * Normalize the scores to be between 0 and 1 and sort them decending.\n * @param scores array of scores from {@link TfIdfCalculator.calculateScores}\n * @returns normalized scores\n */\nexport function normalizeTfIdfScores(scores: TfIdfScore[]): NormalizedTfIdfScore[] {\n\n\t// copy of scores\n\tconst result = scores.slice(0) as { score: number }[];\n\n\t// sort descending\n\tresult.sort((a, b) => b.score - a.score);\n\n\t// normalize\n\tconst max = result[0]?.score ?? 0;\n\tif (max > 0) {\n\t\tfor (const score of result) {\n\t\t\tscore.score /= max;\n\t\t}\n\t}\n\n\treturn result as TfIdfScore[];\n}\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 * @returns whether the provided parameter is a JavaScript String or not.\n */\nexport function isString(str: unknown): str is string {\n\treturn (typeof str === 'string');\n}\n\n/**\n * @returns whether the provided parameter is of type `object` but **not**\n *\t`null`, an `array`, a `regexp`, nor a `date`.\n */\nexport function isObject(obj: unknown): obj is Object {\n\t// The method can't do a type cast since there are type (like strings) which\n\t// are subclasses of any put not positvely matched by the function. Hence type\n\t// narrowing results in wrong results.\n\treturn typeof obj === 'object'\n\t\t&& obj !== null\n\t\t&& !Array.isArray(obj)\n\t\t&& !(obj instanceof RegExp)\n\t\t&& !(obj instanceof Date);\n}\n\n/**\n * @returns whether the provided parameter is of type `Buffer` or Uint8Array dervived type\n */\nexport function isTypedArray(obj: unknown): obj is Object {\n\tconst TypedArray = Object.getPrototypeOf(Uint8Array);\n\treturn typeof obj === 'object'\n\t\t&& obj instanceof TypedArray;\n}\n\n/**\n * In **contrast** to just checking `typeof` this will return `false` for `NaN`.\n * @returns whether the provided parameter is a JavaScript Number or not.\n */\nexport function isNumber(obj: unknown): obj is number {\n\treturn (typeof obj === 'number' && !isNaN(obj));\n}\n\n/**\n * @returns whether the provided parameter is an Iterable, casting to the given generic\n */\nexport function isIterable(obj: unknown): obj is Iterable {\n\treturn !!obj && typeof (obj as any)[Symbol.iterator] === 'function';\n}\n\n/**\n * @returns whether the provided parameter is a JavaScript Boolean or not.\n */\nexport function isBoolean(obj: unknown): obj is boolean {\n\treturn (obj === true || obj === false);\n}\n\n/**\n * @returns whether the provided parameter is undefined.\n */\nexport function isUndefined(obj: unknown): obj is undefined {\n\treturn (typeof obj === 'undefined');\n}\n\n/**\n * @returns whether the provided parameter is defined.\n */\nexport function isDefined(arg: T | null | undefined): arg is T {\n\treturn !isUndefinedOrNull(arg);\n}\n\n/**\n * @returns whether the provided parameter is undefined or null.\n */\nexport function isUndefinedOrNull(obj: unknown): obj is undefined | null {\n\treturn (isUndefined(obj) || obj === null);\n}\n\n\nexport function assertType(condition: unknown, type?: string): asserts condition {\n\tif (!condition) {\n\t\tthrow new Error(type ? `Unexpected type, expected '${type}'` : 'Unexpected type');\n\t}\n}\n\n/**\n * Asserts that the argument passed in is neither undefined nor null.\n */\nexport function assertIsDefined(arg: T | null | undefined): T {\n\tif (isUndefinedOrNull(arg)) {\n\t\tthrow new Error('Assertion Failed: argument is undefined or null');\n\t}\n\n\treturn arg;\n}\n\n/**\n * @returns whether the provided parameter is a JavaScript Function or not.\n */\nexport function isFunction(obj: unknown): obj is Function {\n\treturn (typeof obj === 'function');\n}\n\nexport type TypeConstraint = string | Function;\n\nexport function validateConstraints(args: unknown[], constraints: Array): void {\n\tconst len = Math.min(args.length, constraints.length);\n\tfor (let i = 0; i < len; i++) {\n\t\tvalidateConstraint(args[i], constraints[i]);\n\t}\n}\n\nexport function validateConstraint(arg: unknown, constraint: TypeConstraint | undefined): void {\n\n\tif (isString(constraint)) {\n\t\tif (typeof arg !== constraint) {\n\t\t\tthrow new Error(`argument does not match constraint: typeof ${constraint}`);\n\t\t}\n\t} else if (isFunction(constraint)) {\n\t\ttry {\n\t\t\tif (arg instanceof constraint) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t} catch {\n\t\t\t// ignore\n\t\t}\n\t\tif (!isUndefinedOrNull(arg) && (arg as any).constructor === constraint) {\n\t\t\treturn;\n\t\t}\n\t\tif (constraint.length === 1 && constraint.call(undefined, arg) === true) {\n\t\t\treturn;\n\t\t}\n\t\tthrow new Error(`argument does not match one of these constraints: arg instanceof constraint, arg.constructor === constraint, nor constraint(arg) === true`);\n\t}\n}\n\n/**\n * Only picks the non-optional properties of a type.\n */\nexport type OmitOptional = { [K in keyof T as T[K] extends Required[K] ? K : never]: T[K] };\n\n/**\n * A type that removed readonly-less from all properties of `T`\n */\nexport type Mutable = {\n\t-readonly [P in keyof T]: T[P]\n};\n\n/**\n * Represents a type that is a partial version of a given type `T`, except a subset.\n */\nexport type PartialExcept = Partial> & Pick;\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 *--------------------------------------------------------------------------------------------*/\nimport { ThemeIcon } from 'vs/base/common/themables';\nimport { isString } from 'vs/base/common/types';\n\n\nconst _codiconFontCharacters: { [id: string]: number } = Object.create(null);\n\nexport function register(id: string, fontCharacter: number | string): ThemeIcon {\n\tif (isString(fontCharacter)) {\n\t\tconst val = _codiconFontCharacters[fontCharacter];\n\t\tif (val === undefined) {\n\t\t\tthrow new Error(`${id} references an unknown codicon: ${fontCharacter}`);\n\t\t}\n\t\tfontCharacter = val;\n\t}\n\t_codiconFontCharacters[id] = fontCharacter;\n\treturn { id };\n}\n\n/**\n * Only to be used by the iconRegistry.\n */\nexport function getCodiconFontCharacters(): { [id: string]: number } {\n\treturn _codiconFontCharacters;\n}\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 *--------------------------------------------------------------------------------------------*/\nimport { register } from 'vs/base/common/codiconsUtil';\n\n\n// This file is automatically generated by (microsoft/vscode-codicons)/scripts/export-to-ts.js\n// Please don't edit it, as your changes will be overwritten.\n// Instead, add mappings to codiconsDerived in codicons.ts.\nexport const codiconsLibrary = {\n\tadd: register('add', 0xea60),\n\tplus: register('plus', 0xea60),\n\tgistNew: register('gist-new', 0xea60),\n\trepoCreate: register('repo-create', 0xea60),\n\tlightbulb: register('lightbulb', 0xea61),\n\tlightBulb: register('light-bulb', 0xea61),\n\trepo: register('repo', 0xea62),\n\trepoDelete: register('repo-delete', 0xea62),\n\tgistFork: register('gist-fork', 0xea63),\n\trepoForked: register('repo-forked', 0xea63),\n\tgitPullRequest: register('git-pull-request', 0xea64),\n\tgitPullRequestAbandoned: register('git-pull-request-abandoned', 0xea64),\n\trecordKeys: register('record-keys', 0xea65),\n\tkeyboard: register('keyboard', 0xea65),\n\ttag: register('tag', 0xea66),\n\tgitPullRequestLabel: register('git-pull-request-label', 0xea66),\n\ttagAdd: register('tag-add', 0xea66),\n\ttagRemove: register('tag-remove', 0xea66),\n\tperson: register('person', 0xea67),\n\tpersonFollow: register('person-follow', 0xea67),\n\tpersonOutline: register('person-outline', 0xea67),\n\tpersonFilled: register('person-filled', 0xea67),\n\tgitBranch: register('git-branch', 0xea68),\n\tgitBranchCreate: register('git-branch-create', 0xea68),\n\tgitBranchDelete: register('git-branch-delete', 0xea68),\n\tsourceControl: register('source-control', 0xea68),\n\tmirror: register('mirror', 0xea69),\n\tmirrorPublic: register('mirror-public', 0xea69),\n\tstar: register('star', 0xea6a),\n\tstarAdd: register('star-add', 0xea6a),\n\tstarDelete: register('star-delete', 0xea6a),\n\tstarEmpty: register('star-empty', 0xea6a),\n\tcomment: register('comment', 0xea6b),\n\tcommentAdd: register('comment-add', 0xea6b),\n\talert: register('alert', 0xea6c),\n\twarning: register('warning', 0xea6c),\n\tsearch: register('search', 0xea6d),\n\tsearchSave: register('search-save', 0xea6d),\n\tlogOut: register('log-out', 0xea6e),\n\tsignOut: register('sign-out', 0xea6e),\n\tlogIn: register('log-in', 0xea6f),\n\tsignIn: register('sign-in', 0xea6f),\n\teye: register('eye', 0xea70),\n\teyeUnwatch: register('eye-unwatch', 0xea70),\n\teyeWatch: register('eye-watch', 0xea70),\n\tcircleFilled: register('circle-filled', 0xea71),\n\tprimitiveDot: register('primitive-dot', 0xea71),\n\tcloseDirty: register('close-dirty', 0xea71),\n\tdebugBreakpoint: register('debug-breakpoint', 0xea71),\n\tdebugBreakpointDisabled: register('debug-breakpoint-disabled', 0xea71),\n\tdebugHint: register('debug-hint', 0xea71),\n\tterminalDecorationSuccess: register('terminal-decoration-success', 0xea71),\n\tprimitiveSquare: register('primitive-square', 0xea72),\n\tedit: register('edit', 0xea73),\n\tpencil: register('pencil', 0xea73),\n\tinfo: register('info', 0xea74),\n\tissueOpened: register('issue-opened', 0xea74),\n\tgistPrivate: register('gist-private', 0xea75),\n\tgitForkPrivate: register('git-fork-private', 0xea75),\n\tlock: register('lock', 0xea75),\n\tmirrorPrivate: register('mirror-private', 0xea75),\n\tclose: register('close', 0xea76),\n\tremoveClose: register('remove-close', 0xea76),\n\tx: register('x', 0xea76),\n\trepoSync: register('repo-sync', 0xea77),\n\tsync: register('sync', 0xea77),\n\tclone: register('clone', 0xea78),\n\tdesktopDownload: register('desktop-download', 0xea78),\n\tbeaker: register('beaker', 0xea79),\n\tmicroscope: register('microscope', 0xea79),\n\tvm: register('vm', 0xea7a),\n\tdeviceDesktop: register('device-desktop', 0xea7a),\n\tfile: register('file', 0xea7b),\n\tfileText: register('file-text', 0xea7b),\n\tmore: register('more', 0xea7c),\n\tellipsis: register('ellipsis', 0xea7c),\n\tkebabHorizontal: register('kebab-horizontal', 0xea7c),\n\tmailReply: register('mail-reply', 0xea7d),\n\treply: register('reply', 0xea7d),\n\torganization: register('organization', 0xea7e),\n\torganizationFilled: register('organization-filled', 0xea7e),\n\torganizationOutline: register('organization-outline', 0xea7e),\n\tnewFile: register('new-file', 0xea7f),\n\tfileAdd: register('file-add', 0xea7f),\n\tnewFolder: register('new-folder', 0xea80),\n\tfileDirectoryCreate: register('file-directory-create', 0xea80),\n\ttrash: register('trash', 0xea81),\n\ttrashcan: register('trashcan', 0xea81),\n\thistory: register('history', 0xea82),\n\tclock: register('clock', 0xea82),\n\tfolder: register('folder', 0xea83),\n\tfileDirectory: register('file-directory', 0xea83),\n\tsymbolFolder: register('symbol-folder', 0xea83),\n\tlogoGithub: register('logo-github', 0xea84),\n\tmarkGithub: register('mark-github', 0xea84),\n\tgithub: register('github', 0xea84),\n\tterminal: register('terminal', 0xea85),\n\tconsole: register('console', 0xea85),\n\trepl: register('repl', 0xea85),\n\tzap: register('zap', 0xea86),\n\tsymbolEvent: register('symbol-event', 0xea86),\n\terror: register('error', 0xea87),\n\tstop: register('stop', 0xea87),\n\tvariable: register('variable', 0xea88),\n\tsymbolVariable: register('symbol-variable', 0xea88),\n\tarray: register('array', 0xea8a),\n\tsymbolArray: register('symbol-array', 0xea8a),\n\tsymbolModule: register('symbol-module', 0xea8b),\n\tsymbolPackage: register('symbol-package', 0xea8b),\n\tsymbolNamespace: register('symbol-namespace', 0xea8b),\n\tsymbolObject: register('symbol-object', 0xea8b),\n\tsymbolMethod: register('symbol-method', 0xea8c),\n\tsymbolFunction: register('symbol-function', 0xea8c),\n\tsymbolConstructor: register('symbol-constructor', 0xea8c),\n\tsymbolBoolean: register('symbol-boolean', 0xea8f),\n\tsymbolNull: register('symbol-null', 0xea8f),\n\tsymbolNumeric: register('symbol-numeric', 0xea90),\n\tsymbolNumber: register('symbol-number', 0xea90),\n\tsymbolStructure: register('symbol-structure', 0xea91),\n\tsymbolStruct: register('symbol-struct', 0xea91),\n\tsymbolParameter: register('symbol-parameter', 0xea92),\n\tsymbolTypeParameter: register('symbol-type-parameter', 0xea92),\n\tsymbolKey: register('symbol-key', 0xea93),\n\tsymbolText: register('symbol-text', 0xea93),\n\tsymbolReference: register('symbol-reference', 0xea94),\n\tgoToFile: register('go-to-file', 0xea94),\n\tsymbolEnum: register('symbol-enum', 0xea95),\n\tsymbolValue: register('symbol-value', 0xea95),\n\tsymbolRuler: register('symbol-ruler', 0xea96),\n\tsymbolUnit: register('symbol-unit', 0xea96),\n\tactivateBreakpoints: register('activate-breakpoints', 0xea97),\n\tarchive: register('archive', 0xea98),\n\tarrowBoth: register('arrow-both', 0xea99),\n\tarrowDown: register('arrow-down', 0xea9a),\n\tarrowLeft: register('arrow-left', 0xea9b),\n\tarrowRight: register('arrow-right', 0xea9c),\n\tarrowSmallDown: register('arrow-small-down', 0xea9d),\n\tarrowSmallLeft: register('arrow-small-left', 0xea9e),\n\tarrowSmallRight: register('arrow-small-right', 0xea9f),\n\tarrowSmallUp: register('arrow-small-up', 0xeaa0),\n\tarrowUp: register('arrow-up', 0xeaa1),\n\tbell: register('bell', 0xeaa2),\n\tbold: register('bold', 0xeaa3),\n\tbook: register('book', 0xeaa4),\n\tbookmark: register('bookmark', 0xeaa5),\n\tdebugBreakpointConditionalUnverified: register('debug-breakpoint-conditional-unverified', 0xeaa6),\n\tdebugBreakpointConditional: register('debug-breakpoint-conditional', 0xeaa7),\n\tdebugBreakpointConditionalDisabled: register('debug-breakpoint-conditional-disabled', 0xeaa7),\n\tdebugBreakpointDataUnverified: register('debug-breakpoint-data-unverified', 0xeaa8),\n\tdebugBreakpointData: register('debug-breakpoint-data', 0xeaa9),\n\tdebugBreakpointDataDisabled: register('debug-breakpoint-data-disabled', 0xeaa9),\n\tdebugBreakpointLogUnverified: register('debug-breakpoint-log-unverified', 0xeaaa),\n\tdebugBreakpointLog: register('debug-breakpoint-log', 0xeaab),\n\tdebugBreakpointLogDisabled: register('debug-breakpoint-log-disabled', 0xeaab),\n\tbriefcase: register('briefcase', 0xeaac),\n\tbroadcast: register('broadcast', 0xeaad),\n\tbrowser: register('browser', 0xeaae),\n\tbug: register('bug', 0xeaaf),\n\tcalendar: register('calendar', 0xeab0),\n\tcaseSensitive: register('case-sensitive', 0xeab1),\n\tcheck: register('check', 0xeab2),\n\tchecklist: register('checklist', 0xeab3),\n\tchevronDown: register('chevron-down', 0xeab4),\n\tchevronLeft: register('chevron-left', 0xeab5),\n\tchevronRight: register('chevron-right', 0xeab6),\n\tchevronUp: register('chevron-up', 0xeab7),\n\tchromeClose: register('chrome-close', 0xeab8),\n\tchromeMaximize: register('chrome-maximize', 0xeab9),\n\tchromeMinimize: register('chrome-minimize', 0xeaba),\n\tchromeRestore: register('chrome-restore', 0xeabb),\n\tcircleOutline: register('circle-outline', 0xeabc),\n\tcircle: register('circle', 0xeabc),\n\tdebugBreakpointUnverified: register('debug-breakpoint-unverified', 0xeabc),\n\tterminalDecorationIncomplete: register('terminal-decoration-incomplete', 0xeabc),\n\tcircleSlash: register('circle-slash', 0xeabd),\n\tcircuitBoard: register('circuit-board', 0xeabe),\n\tclearAll: register('clear-all', 0xeabf),\n\tclippy: register('clippy', 0xeac0),\n\tcloseAll: register('close-all', 0xeac1),\n\tcloudDownload: register('cloud-download', 0xeac2),\n\tcloudUpload: register('cloud-upload', 0xeac3),\n\tcode: register('code', 0xeac4),\n\tcollapseAll: register('collapse-all', 0xeac5),\n\tcolorMode: register('color-mode', 0xeac6),\n\tcommentDiscussion: register('comment-discussion', 0xeac7),\n\tcreditCard: register('credit-card', 0xeac9),\n\tdash: register('dash', 0xeacc),\n\tdashboard: register('dashboard', 0xeacd),\n\tdatabase: register('database', 0xeace),\n\tdebugContinue: register('debug-continue', 0xeacf),\n\tdebugDisconnect: register('debug-disconnect', 0xead0),\n\tdebugPause: register('debug-pause', 0xead1),\n\tdebugRestart: register('debug-restart', 0xead2),\n\tdebugStart: register('debug-start', 0xead3),\n\tdebugStepInto: register('debug-step-into', 0xead4),\n\tdebugStepOut: register('debug-step-out', 0xead5),\n\tdebugStepOver: register('debug-step-over', 0xead6),\n\tdebugStop: register('debug-stop', 0xead7),\n\tdebug: register('debug', 0xead8),\n\tdeviceCameraVideo: register('device-camera-video', 0xead9),\n\tdeviceCamera: register('device-camera', 0xeada),\n\tdeviceMobile: register('device-mobile', 0xeadb),\n\tdiffAdded: register('diff-added', 0xeadc),\n\tdiffIgnored: register('diff-ignored', 0xeadd),\n\tdiffModified: register('diff-modified', 0xeade),\n\tdiffRemoved: register('diff-removed', 0xeadf),\n\tdiffRenamed: register('diff-renamed', 0xeae0),\n\tdiff: register('diff', 0xeae1),\n\tdiffSidebyside: register('diff-sidebyside', 0xeae1),\n\tdiscard: register('discard', 0xeae2),\n\teditorLayout: register('editor-layout', 0xeae3),\n\temptyWindow: register('empty-window', 0xeae4),\n\texclude: register('exclude', 0xeae5),\n\textensions: register('extensions', 0xeae6),\n\teyeClosed: register('eye-closed', 0xeae7),\n\tfileBinary: register('file-binary', 0xeae8),\n\tfileCode: register('file-code', 0xeae9),\n\tfileMedia: register('file-media', 0xeaea),\n\tfilePdf: register('file-pdf', 0xeaeb),\n\tfileSubmodule: register('file-submodule', 0xeaec),\n\tfileSymlinkDirectory: register('file-symlink-directory', 0xeaed),\n\tfileSymlinkFile: register('file-symlink-file', 0xeaee),\n\tfileZip: register('file-zip', 0xeaef),\n\tfiles: register('files', 0xeaf0),\n\tfilter: register('filter', 0xeaf1),\n\tflame: register('flame', 0xeaf2),\n\tfoldDown: register('fold-down', 0xeaf3),\n\tfoldUp: register('fold-up', 0xeaf4),\n\tfold: register('fold', 0xeaf5),\n\tfolderActive: register('folder-active', 0xeaf6),\n\tfolderOpened: register('folder-opened', 0xeaf7),\n\tgear: register('gear', 0xeaf8),\n\tgift: register('gift', 0xeaf9),\n\tgistSecret: register('gist-secret', 0xeafa),\n\tgist: register('gist', 0xeafb),\n\tgitCommit: register('git-commit', 0xeafc),\n\tgitCompare: register('git-compare', 0xeafd),\n\tcompareChanges: register('compare-changes', 0xeafd),\n\tgitMerge: register('git-merge', 0xeafe),\n\tgithubAction: register('github-action', 0xeaff),\n\tgithubAlt: register('github-alt', 0xeb00),\n\tglobe: register('globe', 0xeb01),\n\tgrabber: register('grabber', 0xeb02),\n\tgraph: register('graph', 0xeb03),\n\tgripper: register('gripper', 0xeb04),\n\theart: register('heart', 0xeb05),\n\thome: register('home', 0xeb06),\n\thorizontalRule: register('horizontal-rule', 0xeb07),\n\thubot: register('hubot', 0xeb08),\n\tinbox: register('inbox', 0xeb09),\n\tissueReopened: register('issue-reopened', 0xeb0b),\n\tissues: register('issues', 0xeb0c),\n\titalic: register('italic', 0xeb0d),\n\tjersey: register('jersey', 0xeb0e),\n\tjson: register('json', 0xeb0f),\n\tkebabVertical: register('kebab-vertical', 0xeb10),\n\tkey: register('key', 0xeb11),\n\tlaw: register('law', 0xeb12),\n\tlightbulbAutofix: register('lightbulb-autofix', 0xeb13),\n\tlinkExternal: register('link-external', 0xeb14),\n\tlink: register('link', 0xeb15),\n\tlistOrdered: register('list-ordered', 0xeb16),\n\tlistUnordered: register('list-unordered', 0xeb17),\n\tliveShare: register('live-share', 0xeb18),\n\tloading: register('loading', 0xeb19),\n\tlocation: register('location', 0xeb1a),\n\tmailRead: register('mail-read', 0xeb1b),\n\tmail: register('mail', 0xeb1c),\n\tmarkdown: register('markdown', 0xeb1d),\n\tmegaphone: register('megaphone', 0xeb1e),\n\tmention: register('mention', 0xeb1f),\n\tmilestone: register('milestone', 0xeb20),\n\tgitPullRequestMilestone: register('git-pull-request-milestone', 0xeb20),\n\tmortarBoard: register('mortar-board', 0xeb21),\n\tmove: register('move', 0xeb22),\n\tmultipleWindows: register('multiple-windows', 0xeb23),\n\tmute: register('mute', 0xeb24),\n\tnoNewline: register('no-newline', 0xeb25),\n\tnote: register('note', 0xeb26),\n\toctoface: register('octoface', 0xeb27),\n\topenPreview: register('open-preview', 0xeb28),\n\tpackage: register('package', 0xeb29),\n\tpaintcan: register('paintcan', 0xeb2a),\n\tpin: register('pin', 0xeb2b),\n\tplay: register('play', 0xeb2c),\n\trun: register('run', 0xeb2c),\n\tplug: register('plug', 0xeb2d),\n\tpreserveCase: register('preserve-case', 0xeb2e),\n\tpreview: register('preview', 0xeb2f),\n\tproject: register('project', 0xeb30),\n\tpulse: register('pulse', 0xeb31),\n\tquestion: register('question', 0xeb32),\n\tquote: register('quote', 0xeb33),\n\tradioTower: register('radio-tower', 0xeb34),\n\treactions: register('reactions', 0xeb35),\n\treferences: register('references', 0xeb36),\n\trefresh: register('refresh', 0xeb37),\n\tregex: register('regex', 0xeb38),\n\tremoteExplorer: register('remote-explorer', 0xeb39),\n\tremote: register('remote', 0xeb3a),\n\tremove: register('remove', 0xeb3b),\n\treplaceAll: register('replace-all', 0xeb3c),\n\treplace: register('replace', 0xeb3d),\n\trepoClone: register('repo-clone', 0xeb3e),\n\trepoForcePush: register('repo-force-push', 0xeb3f),\n\trepoPull: register('repo-pull', 0xeb40),\n\trepoPush: register('repo-push', 0xeb41),\n\treport: register('report', 0xeb42),\n\trequestChanges: register('request-changes', 0xeb43),\n\trocket: register('rocket', 0xeb44),\n\trootFolderOpened: register('root-folder-opened', 0xeb45),\n\trootFolder: register('root-folder', 0xeb46),\n\trss: register('rss', 0xeb47),\n\truby: register('ruby', 0xeb48),\n\tsaveAll: register('save-all', 0xeb49),\n\tsaveAs: register('save-as', 0xeb4a),\n\tsave: register('save', 0xeb4b),\n\tscreenFull: register('screen-full', 0xeb4c),\n\tscreenNormal: register('screen-normal', 0xeb4d),\n\tsearchStop: register('search-stop', 0xeb4e),\n\tserver: register('server', 0xeb50),\n\tsettingsGear: register('settings-gear', 0xeb51),\n\tsettings: register('settings', 0xeb52),\n\tshield: register('shield', 0xeb53),\n\tsmiley: register('smiley', 0xeb54),\n\tsortPrecedence: register('sort-precedence', 0xeb55),\n\tsplitHorizontal: register('split-horizontal', 0xeb56),\n\tsplitVertical: register('split-vertical', 0xeb57),\n\tsquirrel: register('squirrel', 0xeb58),\n\tstarFull: register('star-full', 0xeb59),\n\tstarHalf: register('star-half', 0xeb5a),\n\tsymbolClass: register('symbol-class', 0xeb5b),\n\tsymbolColor: register('symbol-color', 0xeb5c),\n\tsymbolConstant: register('symbol-constant', 0xeb5d),\n\tsymbolEnumMember: register('symbol-enum-member', 0xeb5e),\n\tsymbolField: register('symbol-field', 0xeb5f),\n\tsymbolFile: register('symbol-file', 0xeb60),\n\tsymbolInterface: register('symbol-interface', 0xeb61),\n\tsymbolKeyword: register('symbol-keyword', 0xeb62),\n\tsymbolMisc: register('symbol-misc', 0xeb63),\n\tsymbolOperator: register('symbol-operator', 0xeb64),\n\tsymbolProperty: register('symbol-property', 0xeb65),\n\twrench: register('wrench', 0xeb65),\n\twrenchSubaction: register('wrench-subaction', 0xeb65),\n\tsymbolSnippet: register('symbol-snippet', 0xeb66),\n\ttasklist: register('tasklist', 0xeb67),\n\ttelescope: register('telescope', 0xeb68),\n\ttextSize: register('text-size', 0xeb69),\n\tthreeBars: register('three-bars', 0xeb6a),\n\tthumbsdown: register('thumbsdown', 0xeb6b),\n\tthumbsup: register('thumbsup', 0xeb6c),\n\ttools: register('tools', 0xeb6d),\n\ttriangleDown: register('triangle-down', 0xeb6e),\n\ttriangleLeft: register('triangle-left', 0xeb6f),\n\ttriangleRight: register('triangle-right', 0xeb70),\n\ttriangleUp: register('triangle-up', 0xeb71),\n\ttwitter: register('twitter', 0xeb72),\n\tunfold: register('unfold', 0xeb73),\n\tunlock: register('unlock', 0xeb74),\n\tunmute: register('unmute', 0xeb75),\n\tunverified: register('unverified', 0xeb76),\n\tverified: register('verified', 0xeb77),\n\tversions: register('versions', 0xeb78),\n\tvmActive: register('vm-active', 0xeb79),\n\tvmOutline: register('vm-outline', 0xeb7a),\n\tvmRunning: register('vm-running', 0xeb7b),\n\twatch: register('watch', 0xeb7c),\n\twhitespace: register('whitespace', 0xeb7d),\n\twholeWord: register('whole-word', 0xeb7e),\n\twindow: register('window', 0xeb7f),\n\twordWrap: register('word-wrap', 0xeb80),\n\tzoomIn: register('zoom-in', 0xeb81),\n\tzoomOut: register('zoom-out', 0xeb82),\n\tlistFilter: register('list-filter', 0xeb83),\n\tlistFlat: register('list-flat', 0xeb84),\n\tlistSelection: register('list-selection', 0xeb85),\n\tselection: register('selection', 0xeb85),\n\tlistTree: register('list-tree', 0xeb86),\n\tdebugBreakpointFunctionUnverified: register('debug-breakpoint-function-unverified', 0xeb87),\n\tdebugBreakpointFunction: register('debug-breakpoint-function', 0xeb88),\n\tdebugBreakpointFunctionDisabled: register('debug-breakpoint-function-disabled', 0xeb88),\n\tdebugStackframeActive: register('debug-stackframe-active', 0xeb89),\n\tcircleSmallFilled: register('circle-small-filled', 0xeb8a),\n\tdebugStackframeDot: register('debug-stackframe-dot', 0xeb8a),\n\tterminalDecorationMark: register('terminal-decoration-mark', 0xeb8a),\n\tdebugStackframe: register('debug-stackframe', 0xeb8b),\n\tdebugStackframeFocused: register('debug-stackframe-focused', 0xeb8b),\n\tdebugBreakpointUnsupported: register('debug-breakpoint-unsupported', 0xeb8c),\n\tsymbolString: register('symbol-string', 0xeb8d),\n\tdebugReverseContinue: register('debug-reverse-continue', 0xeb8e),\n\tdebugStepBack: register('debug-step-back', 0xeb8f),\n\tdebugRestartFrame: register('debug-restart-frame', 0xeb90),\n\tdebugAlt: register('debug-alt', 0xeb91),\n\tcallIncoming: register('call-incoming', 0xeb92),\n\tcallOutgoing: register('call-outgoing', 0xeb93),\n\tmenu: register('menu', 0xeb94),\n\texpandAll: register('expand-all', 0xeb95),\n\tfeedback: register('feedback', 0xeb96),\n\tgitPullRequestReviewer: register('git-pull-request-reviewer', 0xeb96),\n\tgroupByRefType: register('group-by-ref-type', 0xeb97),\n\tungroupByRefType: register('ungroup-by-ref-type', 0xeb98),\n\taccount: register('account', 0xeb99),\n\tgitPullRequestAssignee: register('git-pull-request-assignee', 0xeb99),\n\tbellDot: register('bell-dot', 0xeb9a),\n\tdebugConsole: register('debug-console', 0xeb9b),\n\tlibrary: register('library', 0xeb9c),\n\toutput: register('output', 0xeb9d),\n\trunAll: register('run-all', 0xeb9e),\n\tsyncIgnored: register('sync-ignored', 0xeb9f),\n\tpinned: register('pinned', 0xeba0),\n\tgithubInverted: register('github-inverted', 0xeba1),\n\tserverProcess: register('server-process', 0xeba2),\n\tserverEnvironment: register('server-environment', 0xeba3),\n\tpass: register('pass', 0xeba4),\n\tissueClosed: register('issue-closed', 0xeba4),\n\tstopCircle: register('stop-circle', 0xeba5),\n\tplayCircle: register('play-circle', 0xeba6),\n\trecord: register('record', 0xeba7),\n\tdebugAltSmall: register('debug-alt-small', 0xeba8),\n\tvmConnect: register('vm-connect', 0xeba9),\n\tcloud: register('cloud', 0xebaa),\n\tmerge: register('merge', 0xebab),\n\texport: register('export', 0xebac),\n\tgraphLeft: register('graph-left', 0xebad),\n\tmagnet: register('magnet', 0xebae),\n\tnotebook: register('notebook', 0xebaf),\n\tredo: register('redo', 0xebb0),\n\tcheckAll: register('check-all', 0xebb1),\n\tpinnedDirty: register('pinned-dirty', 0xebb2),\n\tpassFilled: register('pass-filled', 0xebb3),\n\tcircleLargeFilled: register('circle-large-filled', 0xebb4),\n\tcircleLarge: register('circle-large', 0xebb5),\n\tcircleLargeOutline: register('circle-large-outline', 0xebb5),\n\tcombine: register('combine', 0xebb6),\n\tgather: register('gather', 0xebb6),\n\ttable: register('table', 0xebb7),\n\tvariableGroup: register('variable-group', 0xebb8),\n\ttypeHierarchy: register('type-hierarchy', 0xebb9),\n\ttypeHierarchySub: register('type-hierarchy-sub', 0xebba),\n\ttypeHierarchySuper: register('type-hierarchy-super', 0xebbb),\n\tgitPullRequestCreate: register('git-pull-request-create', 0xebbc),\n\trunAbove: register('run-above', 0xebbd),\n\trunBelow: register('run-below', 0xebbe),\n\tnotebookTemplate: register('notebook-template', 0xebbf),\n\tdebugRerun: register('debug-rerun', 0xebc0),\n\tworkspaceTrusted: register('workspace-trusted', 0xebc1),\n\tworkspaceUntrusted: register('workspace-untrusted', 0xebc2),\n\tworkspaceUnknown: register('workspace-unknown', 0xebc3),\n\tterminalCmd: register('terminal-cmd', 0xebc4),\n\tterminalDebian: register('terminal-debian', 0xebc5),\n\tterminalLinux: register('terminal-linux', 0xebc6),\n\tterminalPowershell: register('terminal-powershell', 0xebc7),\n\tterminalTmux: register('terminal-tmux', 0xebc8),\n\tterminalUbuntu: register('terminal-ubuntu', 0xebc9),\n\tterminalBash: register('terminal-bash', 0xebca),\n\tarrowSwap: register('arrow-swap', 0xebcb),\n\tcopy: register('copy', 0xebcc),\n\tpersonAdd: register('person-add', 0xebcd),\n\tfilterFilled: register('filter-filled', 0xebce),\n\twand: register('wand', 0xebcf),\n\tdebugLineByLine: register('debug-line-by-line', 0xebd0),\n\tinspect: register('inspect', 0xebd1),\n\tlayers: register('layers', 0xebd2),\n\tlayersDot: register('layers-dot', 0xebd3),\n\tlayersActive: register('layers-active', 0xebd4),\n\tcompass: register('compass', 0xebd5),\n\tcompassDot: register('compass-dot', 0xebd6),\n\tcompassActive: register('compass-active', 0xebd7),\n\tazure: register('azure', 0xebd8),\n\tissueDraft: register('issue-draft', 0xebd9),\n\tgitPullRequestClosed: register('git-pull-request-closed', 0xebda),\n\tgitPullRequestDraft: register('git-pull-request-draft', 0xebdb),\n\tdebugAll: register('debug-all', 0xebdc),\n\tdebugCoverage: register('debug-coverage', 0xebdd),\n\trunErrors: register('run-errors', 0xebde),\n\tfolderLibrary: register('folder-library', 0xebdf),\n\tdebugContinueSmall: register('debug-continue-small', 0xebe0),\n\tbeakerStop: register('beaker-stop', 0xebe1),\n\tgraphLine: register('graph-line', 0xebe2),\n\tgraphScatter: register('graph-scatter', 0xebe3),\n\tpieChart: register('pie-chart', 0xebe4),\n\tbracket: register('bracket', 0xeb0f),\n\tbracketDot: register('bracket-dot', 0xebe5),\n\tbracketError: register('bracket-error', 0xebe6),\n\tlockSmall: register('lock-small', 0xebe7),\n\tazureDevops: register('azure-devops', 0xebe8),\n\tverifiedFilled: register('verified-filled', 0xebe9),\n\tnewline: register('newline', 0xebea),\n\tlayout: register('layout', 0xebeb),\n\tlayoutActivitybarLeft: register('layout-activitybar-left', 0xebec),\n\tlayoutActivitybarRight: register('layout-activitybar-right', 0xebed),\n\tlayoutPanelLeft: register('layout-panel-left', 0xebee),\n\tlayoutPanelCenter: register('layout-panel-center', 0xebef),\n\tlayoutPanelJustify: register('layout-panel-justify', 0xebf0),\n\tlayoutPanelRight: register('layout-panel-right', 0xebf1),\n\tlayoutPanel: register('layout-panel', 0xebf2),\n\tlayoutSidebarLeft: register('layout-sidebar-left', 0xebf3),\n\tlayoutSidebarRight: register('layout-sidebar-right', 0xebf4),\n\tlayoutStatusbar: register('layout-statusbar', 0xebf5),\n\tlayoutMenubar: register('layout-menubar', 0xebf6),\n\tlayoutCentered: register('layout-centered', 0xebf7),\n\ttarget: register('target', 0xebf8),\n\tindent: register('indent', 0xebf9),\n\trecordSmall: register('record-small', 0xebfa),\n\terrorSmall: register('error-small', 0xebfb),\n\tterminalDecorationError: register('terminal-decoration-error', 0xebfb),\n\tarrowCircleDown: register('arrow-circle-down', 0xebfc),\n\tarrowCircleLeft: register('arrow-circle-left', 0xebfd),\n\tarrowCircleRight: register('arrow-circle-right', 0xebfe),\n\tarrowCircleUp: register('arrow-circle-up', 0xebff),\n\tlayoutSidebarRightOff: register('layout-sidebar-right-off', 0xec00),\n\tlayoutPanelOff: register('layout-panel-off', 0xec01),\n\tlayoutSidebarLeftOff: register('layout-sidebar-left-off', 0xec02),\n\tblank: register('blank', 0xec03),\n\theartFilled: register('heart-filled', 0xec04),\n\tmap: register('map', 0xec05),\n\tmapHorizontal: register('map-horizontal', 0xec05),\n\tfoldHorizontal: register('fold-horizontal', 0xec05),\n\tmapFilled: register('map-filled', 0xec06),\n\tmapHorizontalFilled: register('map-horizontal-filled', 0xec06),\n\tfoldHorizontalFilled: register('fold-horizontal-filled', 0xec06),\n\tcircleSmall: register('circle-small', 0xec07),\n\tbellSlash: register('bell-slash', 0xec08),\n\tbellSlashDot: register('bell-slash-dot', 0xec09),\n\tcommentUnresolved: register('comment-unresolved', 0xec0a),\n\tgitPullRequestGoToChanges: register('git-pull-request-go-to-changes', 0xec0b),\n\tgitPullRequestNewChanges: register('git-pull-request-new-changes', 0xec0c),\n\tsearchFuzzy: register('search-fuzzy', 0xec0d),\n\tcommentDraft: register('comment-draft', 0xec0e),\n\tsend: register('send', 0xec0f),\n\tsparkle: register('sparkle', 0xec10),\n\tinsert: register('insert', 0xec11),\n\tmic: register('mic', 0xec12),\n\tthumbsdownFilled: register('thumbsdown-filled', 0xec13),\n\tthumbsupFilled: register('thumbsup-filled', 0xec14),\n\tcoffee: register('coffee', 0xec15),\n\tsnake: register('snake', 0xec16),\n\tgame: register('game', 0xec17),\n\tvr: register('vr', 0xec18),\n\tchip: register('chip', 0xec19),\n\tpiano: register('piano', 0xec1a),\n\tmusic: register('music', 0xec1b),\n\tmicFilled: register('mic-filled', 0xec1c),\n\trepoFetch: register('repo-fetch', 0xec1d),\n\tcopilot: register('copilot', 0xec1e),\n\tlightbulbSparkle: register('lightbulb-sparkle', 0xec1f),\n\trobot: register('robot', 0xec20),\n\tsparkleFilled: register('sparkle-filled', 0xec21),\n\tdiffSingle: register('diff-single', 0xec22),\n\tdiffMultiple: register('diff-multiple', 0xec23),\n\tsurroundWith: register('surround-with', 0xec24),\n\tshare: register('share', 0xec25),\n\tgitStash: register('git-stash', 0xec26),\n\tgitStashApply: register('git-stash-apply', 0xec27),\n\tgitStashPop: register('git-stash-pop', 0xec28),\n\tvscode: register('vscode', 0xec29),\n\tvscodeInsiders: register('vscode-insiders', 0xec2a),\n\tcodeOss: register('code-oss', 0xec2b),\n\trunCoverage: register('run-coverage', 0xec2c),\n\trunAllCoverage: register('run-all-coverage', 0xec2d),\n\tcoverage: register('coverage', 0xec2e),\n\tgithubProject: register('github-project', 0xec2f),\n\tmapVertical: register('map-vertical', 0xec30),\n\tfoldVertical: register('fold-vertical', 0xec30),\n\tmapVerticalFilled: register('map-vertical-filled', 0xec31),\n\tfoldVerticalFilled: register('fold-vertical-filled', 0xec31),\n\tgoToSearch: register('go-to-search', 0xec32),\n\tpercentage: register('percentage', 0xec33),\n\tsortPercentage: register('sort-percentage', 0xec33),\n\tattach: register('attach', 0xec34),\n} as const;\n","\nimport { register } from 'vs/base/common/codiconsUtil';\nimport { codiconsLibrary } from 'vs/base/common/codiconsLibrary';\n\n/**\n * Derived icons, that could become separate icons.\n * These mappings should be moved into the mapping file in the vscode-codicons repo at some point.\n */\nexport const codiconsDerived = {\n\tdialogError: register('dialog-error', 'error'),\n\tdialogWarning: register('dialog-warning', 'warning'),\n\tdialogInfo: register('dialog-info', 'info'),\n\tdialogClose: register('dialog-close', 'close'),\n\ttreeItemExpanded: register('tree-item-expanded', 'chevron-down'), // collapsed is done with rotation\n\ttreeFilterOnTypeOn: register('tree-filter-on-type-on', 'list-filter'),\n\ttreeFilterOnTypeOff: register('tree-filter-on-type-off', 'list-selection'),\n\ttreeFilterClear: register('tree-filter-clear', 'close'),\n\ttreeItemLoading: register('tree-item-loading', 'loading'),\n\tmenuSelection: register('menu-selection', 'check'),\n\tmenuSubmenu: register('menu-submenu', 'chevron-right'),\n\tmenuBarMore: register('menubar-more', 'more'),\n\tscrollbarButtonLeft: register('scrollbar-button-left', 'triangle-left'),\n\tscrollbarButtonRight: register('scrollbar-button-right', 'triangle-right'),\n\tscrollbarButtonUp: register('scrollbar-button-up', 'triangle-up'),\n\tscrollbarButtonDown: register('scrollbar-button-down', 'triangle-down'),\n\ttoolBarMore: register('toolbar-more', 'more'),\n\tquickInputBack: register('quick-input-back', 'arrow-left'),\n\tdropDownButton: register('drop-down-button', 0xeab4),\n\tsymbolCustomColor: register('symbol-customcolor', 0xeb5c),\n\texportIcon: register('export', 0xebac),\n\tworkspaceUnspecified: register('workspace-unspecified', 0xebc3),\n\tnewLine: register('newline', 0xebea),\n\tthumbsDownFilled: register('thumbsdown-filled', 0xec13),\n\tthumbsUpFilled: register('thumbsup-filled', 0xec14),\n\tgitFetch: register('git-fetch', 0xec1d),\n\tlightbulbSparkleAutofix: register('lightbulb-sparkle-autofix', 0xec1f),\n\tdebugBreakpointPending: register('debug-breakpoint-pending', 0xebd9),\n\n} as const;\n\n/**\n * The Codicon library is a set of default icons that are built-in in VS Code.\n *\n * In the product (outside of base) Codicons should only be used as defaults. In order to have all icons in VS Code\n * themeable, component should define new, UI component specific icons using `iconRegistry.registerIcon`.\n * In that call a Codicon can be named as default.\n */\nexport const Codicon = {\n\t...codiconsLibrary,\n\t...codiconsDerived\n\n} as const;\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\nimport { isTypedArray, isObject, isUndefinedOrNull } from 'vs/base/common/types';\n\nexport function deepClone(obj: T): T {\n\tif (!obj || typeof obj !== 'object') {\n\t\treturn obj;\n\t}\n\tif (obj instanceof RegExp) {\n\t\treturn obj;\n\t}\n\tconst result: any = Array.isArray(obj) ? [] : {};\n\tObject.entries(obj).forEach(([key, value]) => {\n\t\tresult[key] = value && typeof value === 'object' ? deepClone(value) : value;\n\t});\n\treturn result;\n}\n\nexport function deepFreeze(obj: T): T {\n\tif (!obj || typeof obj !== 'object') {\n\t\treturn obj;\n\t}\n\tconst stack: any[] = [obj];\n\twhile (stack.length > 0) {\n\t\tconst obj = stack.shift();\n\t\tObject.freeze(obj);\n\t\tfor (const key in obj) {\n\t\t\tif (_hasOwnProperty.call(obj, key)) {\n\t\t\t\tconst prop = obj[key];\n\t\t\t\tif (typeof prop === 'object' && !Object.isFrozen(prop) && !isTypedArray(prop)) {\n\t\t\t\t\tstack.push(prop);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn obj;\n}\n\nconst _hasOwnProperty = Object.prototype.hasOwnProperty;\n\n\nexport function cloneAndChange(obj: any, changer: (orig: any) => any): any {\n\treturn _cloneAndChange(obj, changer, new Set());\n}\n\nfunction _cloneAndChange(obj: any, changer: (orig: any) => any, seen: Set): any {\n\tif (isUndefinedOrNull(obj)) {\n\t\treturn obj;\n\t}\n\n\tconst changed = changer(obj);\n\tif (typeof changed !== 'undefined') {\n\t\treturn changed;\n\t}\n\n\tif (Array.isArray(obj)) {\n\t\tconst r1: any[] = [];\n\t\tfor (const e of obj) {\n\t\t\tr1.push(_cloneAndChange(e, changer, seen));\n\t\t}\n\t\treturn r1;\n\t}\n\n\tif (isObject(obj)) {\n\t\tif (seen.has(obj)) {\n\t\t\tthrow new Error('Cannot clone recursive data-structure');\n\t\t}\n\t\tseen.add(obj);\n\t\tconst r2 = {};\n\t\tfor (const i2 in obj) {\n\t\t\tif (_hasOwnProperty.call(obj, i2)) {\n\t\t\t\t(r2 as any)[i2] = _cloneAndChange(obj[i2], changer, seen);\n\t\t\t}\n\t\t}\n\t\tseen.delete(obj);\n\t\treturn r2;\n\t}\n\n\treturn obj;\n}\n\n/**\n * Copies all properties of source into destination. The optional parameter \"overwrite\" allows to control\n * if existing properties on the destination should be overwritten or not. Defaults to true (overwrite).\n */\nexport function mixin(destination: any, source: any, overwrite: boolean = true): any {\n\tif (!isObject(destination)) {\n\t\treturn source;\n\t}\n\n\tif (isObject(source)) {\n\t\tObject.keys(source).forEach(key => {\n\t\t\tif (key in destination) {\n\t\t\t\tif (overwrite) {\n\t\t\t\t\tif (isObject(destination[key]) && isObject(source[key])) {\n\t\t\t\t\t\tmixin(destination[key], source[key], overwrite);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tdestination[key] = source[key];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tdestination[key] = source[key];\n\t\t\t}\n\t\t});\n\t}\n\treturn destination;\n}\n\nexport function equals(one: any, other: any): boolean {\n\tif (one === other) {\n\t\treturn true;\n\t}\n\tif (one === null || one === undefined || other === null || other === undefined) {\n\t\treturn false;\n\t}\n\tif (typeof one !== typeof other) {\n\t\treturn false;\n\t}\n\tif (typeof one !== 'object') {\n\t\treturn false;\n\t}\n\tif ((Array.isArray(one)) !== (Array.isArray(other))) {\n\t\treturn false;\n\t}\n\n\tlet i: number;\n\tlet key: string;\n\n\tif (Array.isArray(one)) {\n\t\tif (one.length !== other.length) {\n\t\t\treturn false;\n\t\t}\n\t\tfor (i = 0; i < one.length; i++) {\n\t\t\tif (!equals(one[i], other[i])) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t} else {\n\t\tconst oneKeys: string[] = [];\n\n\t\tfor (key in one) {\n\t\t\toneKeys.push(key);\n\t\t}\n\t\toneKeys.sort();\n\t\tconst otherKeys: string[] = [];\n\t\tfor (key in other) {\n\t\t\totherKeys.push(key);\n\t\t}\n\t\totherKeys.sort();\n\t\tif (!equals(oneKeys, otherKeys)) {\n\t\t\treturn false;\n\t\t}\n\t\tfor (i = 0; i < oneKeys.length; i++) {\n\t\t\tif (!equals(one[oneKeys[i]], other[oneKeys[i]])) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t}\n\treturn true;\n}\n\nexport function getAllPropertyNames(obj: object): string[] {\n\tlet res: string[] = [];\n\twhile (Object.prototype !== obj) {\n\t\tres = res.concat(Object.getOwnPropertyNames(obj));\n\t\tobj = Object.getPrototypeOf(obj);\n\t}\n\treturn res;\n}\n\nexport function getAllMethodNames(obj: object): string[] {\n\tconst methods: string[] = [];\n\tfor (const prop of getAllPropertyNames(obj)) {\n\t\tif (typeof (obj as any)[prop] === 'function') {\n\t\t\tmethods.push(prop);\n\t\t}\n\t}\n\treturn methods;\n}\n\nexport function createProxyObject(methodNames: string[], invoke: (method: string, args: unknown[]) => unknown): T {\n\tconst createProxyMethod = (method: string): () => unknown => {\n\t\treturn function () {\n\t\t\tconst args = Array.prototype.slice.call(arguments, 0);\n\t\t\treturn invoke(method, args);\n\t\t};\n\t};\n\n\tconst result = {} as T;\n\tfor (const methodName of methodNames) {\n\t\t(result)[methodName] = createProxyMethod(methodName);\n\t}\n\treturn result;\n}\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\nimport { Codicon } from 'vs/base/common/codicons';\n\nexport type IconIdentifier = string;\n\nexport interface ThemeColor {\n\tid: string;\n}\n\nexport namespace ThemeColor {\n\texport function isThemeColor(obj: any): obj is ThemeColor {\n\t\treturn obj && typeof obj === 'object' && typeof (obj).id === 'string';\n\t}\n}\n\n\nexport interface ThemeIcon {\n\treadonly id: string;\n\treadonly color?: ThemeColor;\n}\n\nexport namespace ThemeIcon {\n\texport const iconNameSegment = '[A-Za-z0-9]+';\n\texport const iconNameExpression = '[A-Za-z0-9-]+';\n\texport const iconModifierExpression = '~[A-Za-z]+';\n\texport const iconNameCharacter = '[A-Za-z0-9~-]';\n\n\tconst ThemeIconIdRegex = new RegExp(`^(${iconNameExpression})(${iconModifierExpression})?$`);\n\n\texport function asClassNameArray(icon: ThemeIcon): string[] {\n\t\tconst match = ThemeIconIdRegex.exec(icon.id);\n\t\tif (!match) {\n\t\t\treturn asClassNameArray(Codicon.error);\n\t\t}\n\t\tconst [, id, modifier] = match;\n\t\tconst classNames = ['codicon', 'codicon-' + id];\n\t\tif (modifier) {\n\t\t\tclassNames.push('codicon-modifier-' + modifier.substring(1));\n\t\t}\n\t\treturn classNames;\n\t}\n\n\texport function asClassName(icon: ThemeIcon): string {\n\t\treturn asClassNameArray(icon).join(' ');\n\t}\n\n\texport function asCSSSelector(icon: ThemeIcon): string {\n\t\treturn '.' + asClassNameArray(icon).join('.');\n\t}\n\n\texport function isThemeIcon(obj: any): obj is ThemeIcon {\n\t\treturn obj && typeof obj === 'object' && typeof (obj).id === 'string' && (typeof (obj).color === 'undefined' || ThemeColor.isThemeColor((obj).color));\n\t}\n\n\tconst _regexFromString = new RegExp(`^\\\\$\\\\((${ThemeIcon.iconNameExpression}(?:${ThemeIcon.iconModifierExpression})?)\\\\)$`);\n\n\texport function fromString(str: string): ThemeIcon | undefined {\n\t\tconst match = _regexFromString.exec(str);\n\t\tif (!match) {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst [, name] = match;\n\t\treturn { id: name };\n\t}\n\n\texport function fromId(id: string): ThemeIcon {\n\t\treturn { id };\n\t}\n\n\texport function modify(icon: ThemeIcon, modifier: 'disabled' | 'spin' | undefined): ThemeIcon {\n\t\tlet id = icon.id;\n\t\tconst tildeIndex = id.lastIndexOf('~');\n\t\tif (tildeIndex !== -1) {\n\t\t\tid = id.substring(0, tildeIndex);\n\t\t}\n\t\tif (modifier) {\n\t\t\tid = `${id}~${modifier}`;\n\t\t}\n\t\treturn { id };\n\t}\n\n\texport function getModifier(icon: ThemeIcon): string | undefined {\n\t\tconst tildeIndex = icon.id.lastIndexOf('~');\n\t\tif (tildeIndex !== -1) {\n\t\t\treturn icon.id.substring(tildeIndex + 1);\n\t\t}\n\t\treturn undefined;\n\t}\n\n\texport function isEqual(ti1: ThemeIcon, ti2: ThemeIcon): boolean {\n\t\treturn ti1.id === ti2.id && ti1.color?.id === ti2.color?.id;\n\t}\n\n}\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\nimport { IMatch, matchesFuzzy } from 'vs/base/common/filters';\nimport { ltrim } from 'vs/base/common/strings';\nimport { ThemeIcon } from 'vs/base/common/themables';\n\nconst iconStartMarker = '$(';\n\nconst iconsRegex = new RegExp(`\\\\$\\\\(${ThemeIcon.iconNameExpression}(?:${ThemeIcon.iconModifierExpression})?\\\\)`, 'g'); // no capturing groups\n\nconst escapeIconsRegex = new RegExp(`(\\\\\\\\)?${iconsRegex.source}`, 'g');\nexport function escapeIcons(text: string): string {\n\treturn text.replace(escapeIconsRegex, (match, escaped) => escaped ? match : `\\\\${match}`);\n}\n\nconst markdownEscapedIconsRegex = new RegExp(`\\\\\\\\${iconsRegex.source}`, 'g');\nexport function markdownEscapeEscapedIcons(text: string): string {\n\t// Need to add an extra \\ for escaping in markdown\n\treturn text.replace(markdownEscapedIconsRegex, match => `\\\\${match}`);\n}\n\nconst stripIconsRegex = new RegExp(`(\\\\s)?(\\\\\\\\)?${iconsRegex.source}(\\\\s)?`, 'g');\n\n/**\n * Takes a label with icons (`$(iconId)xyz`) and strips the icons out (`xyz`)\n */\nexport function stripIcons(text: string): string {\n\tif (text.indexOf(iconStartMarker) === -1) {\n\t\treturn text;\n\t}\n\n\treturn text.replace(stripIconsRegex, (match, preWhitespace, escaped, postWhitespace) => escaped ? match : preWhitespace || postWhitespace || '');\n}\n\n\n/**\n * Takes a label with icons (`$(iconId)xyz`), removes the icon syntax adds whitespace so that screen readers can read the text better.\n */\nexport function getCodiconAriaLabel(text: string | undefined) {\n\tif (!text) {\n\t\treturn '';\n\t}\n\n\treturn text.replace(/\\$\\((.*?)\\)/g, (_match, codiconName) => ` ${codiconName} `).trim();\n}\n\n\nexport interface IParsedLabelWithIcons {\n\treadonly text: string;\n\treadonly iconOffsets?: readonly number[];\n}\n\nconst _parseIconsRegex = new RegExp(`\\\\$\\\\(${ThemeIcon.iconNameCharacter}+\\\\)`, 'g');\n\n/**\n * Takes a label with icons (`abc $(iconId)xyz`) and returns the text (`abc xyz`) and the offsets of the icons (`[3]`)\n */\nexport function parseLabelWithIcons(input: string): IParsedLabelWithIcons {\n\n\t_parseIconsRegex.lastIndex = 0;\n\n\tlet text = '';\n\tconst iconOffsets: number[] = [];\n\tlet iconsOffset = 0;\n\n\twhile (true) {\n\t\tconst pos = _parseIconsRegex.lastIndex;\n\t\tconst match = _parseIconsRegex.exec(input);\n\n\t\tconst chars = input.substring(pos, match?.index);\n\t\tif (chars.length > 0) {\n\t\t\ttext += chars;\n\t\t\tfor (let i = 0; i < chars.length; i++) {\n\t\t\t\ticonOffsets.push(iconsOffset);\n\t\t\t}\n\t\t}\n\t\tif (!match) {\n\t\t\tbreak;\n\t\t}\n\t\ticonsOffset += match[0].length;\n\t}\n\n\treturn { text, iconOffsets };\n}\n\n\nexport function matchesFuzzyIconAware(query: string, target: IParsedLabelWithIcons, enableSeparateSubstringMatching = false): IMatch[] | null {\n\tconst { text, iconOffsets } = target;\n\n\t// Return early if there are no icon markers in the word to match against\n\tif (!iconOffsets || iconOffsets.length === 0) {\n\t\treturn matchesFuzzy(query, text, enableSeparateSubstringMatching);\n\t}\n\n\t// Trim the word to match against because it could have leading\n\t// whitespace now if the word started with an icon\n\tconst wordToMatchAgainstWithoutIconsTrimmed = ltrim(text, ' ');\n\tconst leadingWhitespaceOffset = text.length - wordToMatchAgainstWithoutIconsTrimmed.length;\n\n\t// match on value without icon\n\tconst matches = matchesFuzzy(query, wordToMatchAgainstWithoutIconsTrimmed, enableSeparateSubstringMatching);\n\n\t// Map matches back to offsets with icon and trimming\n\tif (matches) {\n\t\tfor (const match of matches) {\n\t\t\tconst iconOffset = iconOffsets[match.start + leadingWhitespaceOffset] /* icon offsets at index */ + leadingWhitespaceOffset /* overall leading whitespace offset */;\n\t\t\tmatch.start += iconOffset;\n\t\t\tmatch.end += iconOffset;\n\t\t}\n\t}\n\n\treturn matches;\n}\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\nexport const enum Constants {\n\t/**\n\t * MAX SMI (SMall Integer) as defined in v8.\n\t * one bit is lost for boxing/unboxing flag.\n\t * one bit is lost for sign flag.\n\t * See https://thibaultlaurens.github.io/javascript/2013/04/29/how-the-v8-engine-works/#tagged-values\n\t */\n\tMAX_SAFE_SMALL_INTEGER = 1 << 30,\n\n\t/**\n\t * MIN SMI (SMall Integer) as defined in v8.\n\t * one bit is lost for boxing/unboxing flag.\n\t * one bit is lost for sign flag.\n\t * See https://thibaultlaurens.github.io/javascript/2013/04/29/how-the-v8-engine-works/#tagged-values\n\t */\n\tMIN_SAFE_SMALL_INTEGER = -(1 << 30),\n\n\t/**\n\t * Max unsigned integer that fits on 8 bits.\n\t */\n\tMAX_UINT_8 = 255, // 2^8 - 1\n\n\t/**\n\t * Max unsigned integer that fits on 16 bits.\n\t */\n\tMAX_UINT_16 = 65535, // 2^16 - 1\n\n\t/**\n\t * Max unsigned integer that fits on 32 bits.\n\t */\n\tMAX_UINT_32 = 4294967295, // 2^32 - 1\n\n\tUNICODE_SUPPLEMENTARY_PLANE_BEGIN = 0x010000\n}\n\nexport function toUint8(v: number): number {\n\tif (v < 0) {\n\t\treturn 0;\n\t}\n\tif (v > Constants.MAX_UINT_8) {\n\t\treturn Constants.MAX_UINT_8;\n\t}\n\treturn v | 0;\n}\n\nexport function toUint32(v: number): number {\n\tif (v < 0) {\n\t\treturn 0;\n\t}\n\tif (v > Constants.MAX_UINT_32) {\n\t\treturn Constants.MAX_UINT_32;\n\t}\n\treturn v | 0;\n}\n","\n\ndeclare const crypto: undefined | {\n\t//https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues#browser_compatibility\n\tgetRandomValues?(data: Uint8Array): Uint8Array;\n\t//https://developer.mozilla.org/en-US/docs/Web/API/Crypto/randomUUID#browser_compatibility\n\trandomUUID?(): string;\n};\n\nexport const generateUuid = (function (): () => string {\n\n\t// use `randomUUID` if possible\n\tif (typeof crypto === 'object' && typeof crypto.randomUUID === 'function') {\n\t\treturn crypto.randomUUID.bind(crypto);\n\t}\n\n\t// use `randomValues` if possible\n\tlet getRandomValues: (bucket: Uint8Array) => Uint8Array;\n\tif (typeof crypto === 'object' && typeof crypto.getRandomValues === 'function') {\n\t\tgetRandomValues = crypto.getRandomValues.bind(crypto);\n\n\t} else {\n\t\tgetRandomValues = function (bucket: Uint8Array): Uint8Array {\n\t\t\tfor (let i = 0; i < bucket.length; i++) {\n\t\t\t\tbucket[i] = Math.floor(Math.random() * 256);\n\t\t\t}\n\t\t\treturn bucket;\n\t\t};\n\t}\n\n\t// prep-work\n\tconst _data = new Uint8Array(16);\n\tconst _hex: string[] = [];\n\tfor (let i = 0; i < 256; i++) {\n\t\t_hex.push(i.toString(16).padStart(2, '0'));\n\t}\n\n\treturn function generateUuid(): string {\n\t\t// get data\n\t\tgetRandomValues(_data);\n\n\t\t// set version bits\n\t\t_data[6] = (_data[6] & 0x0f) | 0x40;\n\t\t_data[8] = (_data[8] & 0x3f) | 0x80;\n\n\t\t// print as string\n\t\tlet i = 0;\n\t\tlet result = '';\n\t\tresult += _hex[_data[i++]];\n\t\tresult += _hex[_data[i++]];\n\t\tresult += _hex[_data[i++]];\n\t\tresult += _hex[_data[i++]];\n\t\tresult += '-';\n\t\tresult += _hex[_data[i++]];\n\t\tresult += _hex[_data[i++]];\n\t\tresult += '-';\n\t\tresult += _hex[_data[i++]];\n\t\tresult += _hex[_data[i++]];\n\t\tresult += '-';\n\t\tresult += _hex[_data[i++]];\n\t\tresult += _hex[_data[i++]];\n\t\tresult += '-';\n\t\tresult += _hex[_data[i++]];\n\t\tresult += _hex[_data[i++]];\n\t\tresult += _hex[_data[i++]];\n\t\tresult += _hex[_data[i++]];\n\t\tresult += _hex[_data[i++]];\n\t\tresult += _hex[_data[i++]];\n\t\treturn result;\n\t};\n})();\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\nimport { distinct } from 'vs/base/common/arrays';\nimport { Iterable } from 'vs/base/common/iterator';\nimport { URI } from 'vs/base/common/uri';\nimport { generateUuid } from 'vs/base/common/uuid';\n\nexport interface IDataTransferFile {\n}\n\nexport interface IDataTransferItem {\n\tasString(): Thenable;\n\tasFile(): IDataTransferFile | undefined;\n\tvalue: any;\n}\n\nexport function createStringDataTransferItem(stringOrPromise: string | Promise): IDataTransferItem {\n\treturn {\n\t\tasString: async () => stringOrPromise,\n\t\tasFile: () => undefined,\n\t\tvalue: typeof stringOrPromise === 'string' ? stringOrPromise : undefined,\n\t};\n}\n\nexport function createFileDataTransferItem(fileName: string, uri: URI | undefined, data: () => Promise): IDataTransferItem {\n\tconst file = { id: generateUuid(), name: fileName, uri, data };\n\treturn {\n\t\tasString: async () => '',\n\t\tasFile: () => file,\n\t\tvalue: undefined,\n\t};\n}\n\nexport interface IReadonlyVSDataTransfer extends Iterable {\n\t/**\n\t * Get the total number of entries in this data transfer.\n\t */\n\tget size(): number;\n\n\t/**\n\t * Check if this data transfer contains data for `mimeType`.\n\t *\n\t * This uses exact matching and does not support wildcards.\n\t */\n\thas(mimeType: string): boolean;\n\n\t/**\n\t * Retrieve the first entry for `mimeType`.\n\t *\n\t * Note that if you want to find all entries for a given mime type, use {@link IReadonlyVSDataTransfer.entries} instead.\n\t */\n\tget(mimeType: string): IDataTransferItem | undefined;\n}\n\nexport class VSDataTransfer implements IReadonlyVSDataTransfer {\n\n\tprivate readonly _entries = new Map();\n\n\tpublic get size(): number {\n\t\tlet size = 0;\n\t\tfor (const _ of this._entries) {\n\t\t\tsize++;\n\t\t}\n\t\treturn size;\n\t}\n\n\tpublic has(mimeType: string): boolean {\n\t\treturn this._entries.has(this.toKey(mimeType));\n\t}\n\n\tpublic matches(pattern: string): boolean {\n\t\tconst mimes = [...this._entries.keys()];\n\t\tif (Iterable.some(this, ([_, item]) => item.asFile())) {\n\t\t\tmimes.push('files');\n\t\t}\n\n\t\treturn matchesMimeType_normalized(normalizeMimeType(pattern), mimes);\n\t}\n\n\tpublic get(mimeType: string): IDataTransferItem | undefined {\n\t\treturn this._entries.get(this.toKey(mimeType))?.[0];\n\t}\n\n\t/**\n\t * Add a new entry to this data transfer.\n\t *\n\t * This does not replace existing entries for `mimeType`.\n\t */\n\tpublic append(mimeType: string, value: IDataTransferItem): void {\n\t\tconst existing = this._entries.get(mimeType);\n\t\tif (existing) {\n\t\t\texisting.push(value);\n\t\t} else {\n\t\t\tthis._entries.set(this.toKey(mimeType), [value]);\n\t\t}\n\t}\n\n\t/**\n\t * Set the entry for a given mime type.\n\t *\n\t * This replaces all existing entries for `mimeType`.\n\t */\n\tpublic replace(mimeType: string, value: IDataTransferItem): void {\n\t\tthis._entries.set(this.toKey(mimeType), [value]);\n\t}\n\n\t/**\n\t * Remove all entries for `mimeType`.\n\t */\n\tpublic delete(mimeType: string) {\n\t\tthis._entries.delete(this.toKey(mimeType));\n\t}\n\n\t/**\n\t * Iterate over all `[mime, item]` pairs in this data transfer.\n\t *\n\t * There may be multiple entries for each mime type.\n\t */\n\tpublic *[Symbol.iterator](): IterableIterator {\n\t\tfor (const [mine, items] of this._entries) {\n\t\t\tfor (const item of items) {\n\t\t\t\tyield [mine, item];\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate toKey(mimeType: string): string {\n\t\treturn normalizeMimeType(mimeType);\n\t}\n}\n\nfunction normalizeMimeType(mimeType: string): string {\n\treturn mimeType.toLowerCase();\n}\n\nexport function matchesMimeType(pattern: string, mimeTypes: readonly string[]): boolean {\n\treturn matchesMimeType_normalized(\n\t\tnormalizeMimeType(pattern),\n\t\tmimeTypes.map(normalizeMimeType));\n}\n\nfunction matchesMimeType_normalized(normalizedPattern: string, normalizedMimeTypes: readonly string[]): boolean {\n\t// Anything wildcard\n\tif (normalizedPattern === '*/*') {\n\t\treturn normalizedMimeTypes.length > 0;\n\t}\n\n\t// Exact match\n\tif (normalizedMimeTypes.includes(normalizedPattern)) {\n\t\treturn true;\n\t}\n\n\t// Wildcard, such as `image/*`\n\tconst wildcard = normalizedPattern.match(/^([a-z]+)\\/([a-z]+|\\*)$/i);\n\tif (!wildcard) {\n\t\treturn false;\n\t}\n\n\tconst [_, type, subtype] = wildcard;\n\tif (subtype === '*') {\n\t\treturn normalizedMimeTypes.some(mime => mime.startsWith(type + '/'));\n\t}\n\n\treturn false;\n}\n\n\nexport const UriList = Object.freeze({\n\t// http://amundsen.com/hypermedia/urilist/\n\tcreate: (entries: ReadonlyArray): string => {\n\t\treturn distinct(entries.map(x => x.toString())).join('\\r\\n');\n\t},\n\tsplit: (str: string): string[] => {\n\t\treturn str.split('\\r\\n');\n\t},\n\tparse: (str: string): string[] => {\n\t\treturn UriList.split(str).filter(value => !value.startsWith('#'));\n\t}\n});\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\nimport 'vs/css!./codicon/codicon';\nimport 'vs/css!./codicon/codicon-modifiers';\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\nimport 'vs/css!./mouseCursor';\n\nexport const MOUSE_CURSOR_TEXT_CSS_CLASS_NAME = `monaco-mouse-cursor-text`;\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\nimport { FastDomNode } from 'vs/base/browser/fastDomNode';\nimport { BareFontInfo } from 'vs/editor/common/config/fontInfo';\n\nexport function applyFontInfo(domNode: FastDomNode | HTMLElement, fontInfo: BareFontInfo): void {\n\tif (domNode instanceof FastDomNode) {\n\t\tdomNode.setFontFamily(fontInfo.getMassagedFontFamily());\n\t\tdomNode.setFontWeight(fontInfo.fontWeight);\n\t\tdomNode.setFontSize(fontInfo.fontSize);\n\t\tdomNode.setFontFeatureSettings(fontInfo.fontFeatureSettings);\n\t\tdomNode.setFontVariationSettings(fontInfo.fontVariationSettings);\n\t\tdomNode.setLineHeight(fontInfo.lineHeight);\n\t\tdomNode.setLetterSpacing(fontInfo.letterSpacing);\n\t} else {\n\t\tdomNode.style.fontFamily = fontInfo.getMassagedFontFamily();\n\t\tdomNode.style.fontWeight = fontInfo.fontWeight;\n\t\tdomNode.style.fontSize = fontInfo.fontSize + 'px';\n\t\tdomNode.style.fontFeatureSettings = fontInfo.fontFeatureSettings;\n\t\tdomNode.style.fontVariationSettings = fontInfo.fontVariationSettings;\n\t\tdomNode.style.lineHeight = fontInfo.lineHeight + 'px';\n\t\tdomNode.style.letterSpacing = fontInfo.letterSpacing + 'px';\n\t}\n}\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\nimport { applyFontInfo } from 'vs/editor/browser/config/domFontInfo';\nimport { BareFontInfo } from 'vs/editor/common/config/fontInfo';\n\nexport const enum CharWidthRequestType {\n\tRegular = 0,\n\tItalic = 1,\n\tBold = 2\n}\n\nexport class CharWidthRequest {\n\n\tpublic readonly chr: string;\n\tpublic readonly type: CharWidthRequestType;\n\tpublic width: number;\n\n\tconstructor(chr: string, type: CharWidthRequestType) {\n\t\tthis.chr = chr;\n\t\tthis.type = type;\n\t\tthis.width = 0;\n\t}\n\n\tpublic fulfill(width: number) {\n\t\tthis.width = width;\n\t}\n}\n\nclass DomCharWidthReader {\n\n\tprivate readonly _bareFontInfo: BareFontInfo;\n\tprivate readonly _requests: CharWidthRequest[];\n\n\tprivate _container: HTMLElement | null;\n\tprivate _testElements: HTMLSpanElement[] | null;\n\n\tconstructor(bareFontInfo: BareFontInfo, requests: CharWidthRequest[]) {\n\t\tthis._bareFontInfo = bareFontInfo;\n\t\tthis._requests = requests;\n\n\t\tthis._container = null;\n\t\tthis._testElements = null;\n\t}\n\n\tpublic read(targetWindow: Window): void {\n\t\t// Create a test container with all these test elements\n\t\tthis._createDomElements();\n\n\t\t// Add the container to the DOM\n\t\ttargetWindow.document.body.appendChild(this._container!);\n\n\t\t// Read character widths\n\t\tthis._readFromDomElements();\n\n\t\t// Remove the container from the DOM\n\t\ttargetWindow.document.body.removeChild(this._container!);\n\n\t\tthis._container = null;\n\t\tthis._testElements = null;\n\t}\n\n\tprivate _createDomElements(): void {\n\t\tconst container = document.createElement('div');\n\t\tcontainer.style.position = 'absolute';\n\t\tcontainer.style.top = '-50000px';\n\t\tcontainer.style.width = '50000px';\n\n\t\tconst regularDomNode = document.createElement('div');\n\t\tapplyFontInfo(regularDomNode, this._bareFontInfo);\n\t\tcontainer.appendChild(regularDomNode);\n\n\t\tconst boldDomNode = document.createElement('div');\n\t\tapplyFontInfo(boldDomNode, this._bareFontInfo);\n\t\tboldDomNode.style.fontWeight = 'bold';\n\t\tcontainer.appendChild(boldDomNode);\n\n\t\tconst italicDomNode = document.createElement('div');\n\t\tapplyFontInfo(italicDomNode, this._bareFontInfo);\n\t\titalicDomNode.style.fontStyle = 'italic';\n\t\tcontainer.appendChild(italicDomNode);\n\n\t\tconst testElements: HTMLSpanElement[] = [];\n\t\tfor (const request of this._requests) {\n\n\t\t\tlet parent: HTMLElement;\n\t\t\tif (request.type === CharWidthRequestType.Regular) {\n\t\t\t\tparent = regularDomNode;\n\t\t\t}\n\t\t\tif (request.type === CharWidthRequestType.Bold) {\n\t\t\t\tparent = boldDomNode;\n\t\t\t}\n\t\t\tif (request.type === CharWidthRequestType.Italic) {\n\t\t\t\tparent = italicDomNode;\n\t\t\t}\n\n\t\t\tparent!.appendChild(document.createElement('br'));\n\n\t\t\tconst testElement = document.createElement('span');\n\t\t\tDomCharWidthReader._render(testElement, request);\n\t\t\tparent!.appendChild(testElement);\n\n\t\t\ttestElements.push(testElement);\n\t\t}\n\n\t\tthis._container = container;\n\t\tthis._testElements = testElements;\n\t}\n\n\tprivate static _render(testElement: HTMLElement, request: CharWidthRequest): void {\n\t\tif (request.chr === ' ') {\n\t\t\tlet htmlString = '\\u00a0';\n\t\t\t// Repeat character 256 (2^8) times\n\t\t\tfor (let i = 0; i < 8; i++) {\n\t\t\t\thtmlString += htmlString;\n\t\t\t}\n\t\t\ttestElement.innerText = htmlString;\n\t\t} else {\n\t\t\tlet testString = request.chr;\n\t\t\t// Repeat character 256 (2^8) times\n\t\t\tfor (let i = 0; i < 8; i++) {\n\t\t\t\ttestString += testString;\n\t\t\t}\n\t\t\ttestElement.textContent = testString;\n\t\t}\n\t}\n\n\tprivate _readFromDomElements(): void {\n\t\tfor (let i = 0, len = this._requests.length; i < len; i++) {\n\t\t\tconst request = this._requests[i];\n\t\t\tconst testElement = this._testElements![i];\n\n\t\t\trequest.fulfill(testElement.offsetWidth / 256);\n\t\t}\n\t}\n}\n\nexport function readCharWidths(targetWindow: Window, bareFontInfo: BareFontInfo, requests: CharWidthRequest[]): void {\n\tconst reader = new DomCharWidthReader(bareFontInfo, requests);\n\treader.read(targetWindow);\n}\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\nimport { IEditorOptions } from 'vs/editor/common/config/editorOptions';\n\nexport interface ISettingsReader {\n\t(key: string): any;\n}\n\nexport interface ISettingsWriter {\n\t(key: string, value: any): void;\n}\n\nexport class EditorSettingMigration {\n\n\tpublic static items: EditorSettingMigration[] = [];\n\n\tconstructor(\n\t\tpublic readonly key: string,\n\t\tpublic readonly migrate: (value: any, read: ISettingsReader, write: ISettingsWriter) => void\n\t) { }\n\n\tapply(options: any): void {\n\t\tconst value = EditorSettingMigration._read(options, this.key);\n\t\tconst read = (key: string) => EditorSettingMigration._read(options, key);\n\t\tconst write = (key: string, value: any) => EditorSettingMigration._write(options, key, value);\n\t\tthis.migrate(value, read, write);\n\t}\n\n\tprivate static _read(source: any, key: string): any {\n\t\tif (typeof source === 'undefined') {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst firstDotIndex = key.indexOf('.');\n\t\tif (firstDotIndex >= 0) {\n\t\t\tconst firstSegment = key.substring(0, firstDotIndex);\n\t\t\treturn this._read(source[firstSegment], key.substring(firstDotIndex + 1));\n\t\t}\n\t\treturn source[key];\n\t}\n\n\tprivate static _write(target: any, key: string, value: any): void {\n\t\tconst firstDotIndex = key.indexOf('.');\n\t\tif (firstDotIndex >= 0) {\n\t\t\tconst firstSegment = key.substring(0, firstDotIndex);\n\t\t\ttarget[firstSegment] = target[firstSegment] || {};\n\t\t\tthis._write(target[firstSegment], key.substring(firstDotIndex + 1), value);\n\t\t\treturn;\n\t\t}\n\t\ttarget[key] = value;\n\t}\n}\n\nfunction registerEditorSettingMigration(key: string, migrate: (value: any, read: ISettingsReader, write: ISettingsWriter) => void): void {\n\tEditorSettingMigration.items.push(new EditorSettingMigration(key, migrate));\n}\n\nfunction registerSimpleEditorSettingMigration(key: string, values: [any, any][]): void {\n\tregisterEditorSettingMigration(key, (value, read, write) => {\n\t\tif (typeof value !== 'undefined') {\n\t\t\tfor (const [oldValue, newValue] of values) {\n\t\t\t\tif (value === oldValue) {\n\t\t\t\t\twrite(key, newValue);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t});\n}\n\n/**\n * Compatibility with old options\n */\nexport function migrateOptions(options: IEditorOptions): void {\n\tEditorSettingMigration.items.forEach(migration => migration.apply(options));\n}\n\nregisterSimpleEditorSettingMigration('wordWrap', [[true, 'on'], [false, 'off']]);\nregisterSimpleEditorSettingMigration('lineNumbers', [[true, 'on'], [false, 'off']]);\nregisterSimpleEditorSettingMigration('cursorBlinking', [['visible', 'solid']]);\nregisterSimpleEditorSettingMigration('renderWhitespace', [[true, 'boundary'], [false, 'none']]);\nregisterSimpleEditorSettingMigration('renderLineHighlight', [[true, 'line'], [false, 'none']]);\nregisterSimpleEditorSettingMigration('acceptSuggestionOnEnter', [[true, 'on'], [false, 'off']]);\nregisterSimpleEditorSettingMigration('tabCompletion', [[false, 'off'], [true, 'onlySnippets']]);\nregisterSimpleEditorSettingMigration('hover', [[true, { enabled: true }], [false, { enabled: false }]]);\nregisterSimpleEditorSettingMigration('parameterHints', [[true, { enabled: true }], [false, { enabled: false }]]);\nregisterSimpleEditorSettingMigration('autoIndent', [[false, 'advanced'], [true, 'full']]);\nregisterSimpleEditorSettingMigration('matchBrackets', [[true, 'always'], [false, 'never']]);\nregisterSimpleEditorSettingMigration('renderFinalNewline', [[true, 'on'], [false, 'off']]);\nregisterSimpleEditorSettingMigration('cursorSmoothCaretAnimation', [[true, 'on'], [false, 'off']]);\nregisterSimpleEditorSettingMigration('occurrencesHighlight', [[true, 'singleFile'], [false, 'off']]);\nregisterSimpleEditorSettingMigration('wordBasedSuggestions', [[true, 'matchingDocuments'], [false, 'off']]);\n\nregisterEditorSettingMigration('autoClosingBrackets', (value, read, write) => {\n\tif (value === false) {\n\t\twrite('autoClosingBrackets', 'never');\n\t\tif (typeof read('autoClosingQuotes') === 'undefined') {\n\t\t\twrite('autoClosingQuotes', 'never');\n\t\t}\n\t\tif (typeof read('autoSurround') === 'undefined') {\n\t\t\twrite('autoSurround', 'never');\n\t\t}\n\t}\n});\n\nregisterEditorSettingMigration('renderIndentGuides', (value, read, write) => {\n\tif (typeof value !== 'undefined') {\n\t\twrite('renderIndentGuides', undefined);\n\t\tif (typeof read('guides.indentation') === 'undefined') {\n\t\t\twrite('guides.indentation', !!value);\n\t\t}\n\t}\n});\n\nregisterEditorSettingMigration('highlightActiveIndentGuide', (value, read, write) => {\n\tif (typeof value !== 'undefined') {\n\t\twrite('highlightActiveIndentGuide', undefined);\n\t\tif (typeof read('guides.highlightActiveIndentation') === 'undefined') {\n\t\t\twrite('guides.highlightActiveIndentation', !!value);\n\t\t}\n\t}\n});\n\nconst suggestFilteredTypesMapping: Record = {\n\tmethod: 'showMethods',\n\tfunction: 'showFunctions',\n\tconstructor: 'showConstructors',\n\tdeprecated: 'showDeprecated',\n\tfield: 'showFields',\n\tvariable: 'showVariables',\n\tclass: 'showClasses',\n\tstruct: 'showStructs',\n\tinterface: 'showInterfaces',\n\tmodule: 'showModules',\n\tproperty: 'showProperties',\n\tevent: 'showEvents',\n\toperator: 'showOperators',\n\tunit: 'showUnits',\n\tvalue: 'showValues',\n\tconstant: 'showConstants',\n\tenum: 'showEnums',\n\tenumMember: 'showEnumMembers',\n\tkeyword: 'showKeywords',\n\ttext: 'showWords',\n\tcolor: 'showColors',\n\tfile: 'showFiles',\n\treference: 'showReferences',\n\tfolder: 'showFolders',\n\ttypeParameter: 'showTypeParameters',\n\tsnippet: 'showSnippets',\n};\n\nregisterEditorSettingMigration('suggest.filteredTypes', (value, read, write) => {\n\tif (value && typeof value === 'object') {\n\t\tfor (const entry of Object.entries(suggestFilteredTypesMapping)) {\n\t\t\tconst v = value[entry[0]];\n\t\t\tif (v === false) {\n\t\t\t\tif (typeof read(`suggest.${entry[1]}`) === 'undefined') {\n\t\t\t\t\twrite(`suggest.${entry[1]}`, false);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\twrite('suggest.filteredTypes', undefined);\n\t}\n});\n\nregisterEditorSettingMigration('quickSuggestions', (input, read, write) => {\n\tif (typeof input === 'boolean') {\n\t\tconst value = input ? 'on' : 'off';\n\t\tconst newValue = { comments: value, strings: value, other: value };\n\t\twrite('quickSuggestions', newValue);\n\t}\n});\n\n// Sticky Scroll\n\nregisterEditorSettingMigration('experimental.stickyScroll.enabled', (value, read, write) => {\n\tif (typeof value === 'boolean') {\n\t\twrite('experimental.stickyScroll.enabled', undefined);\n\t\tif (typeof read('stickyScroll.enabled') === 'undefined') {\n\t\t\twrite('stickyScroll.enabled', value);\n\t\t}\n\t}\n});\n\nregisterEditorSettingMigration('experimental.stickyScroll.maxLineCount', (value, read, write) => {\n\tif (typeof value === 'number') {\n\t\twrite('experimental.stickyScroll.maxLineCount', undefined);\n\t\tif (typeof read('stickyScroll.maxLineCount') === 'undefined') {\n\t\t\twrite('stickyScroll.maxLineCount', value);\n\t\t}\n\t}\n});\n\n// Code Actions on Save\nregisterEditorSettingMigration('codeActionsOnSave', (value, read, write) => {\n\tif (value && typeof value === 'object') {\n\t\tlet toBeModified = false;\n\t\tconst newValue = {} as any;\n\t\tfor (const entry of Object.entries(value)) {\n\t\t\tif (typeof entry[1] === 'boolean') {\n\t\t\t\ttoBeModified = true;\n\t\t\t\tnewValue[entry[0]] = entry[1] ? 'explicit' : 'never';\n\t\t\t} else {\n\t\t\t\tnewValue[entry[0]] = entry[1];\n\t\t\t}\n\t\t}\n\t\tif (toBeModified) {\n\t\t\twrite(`codeActionsOnSave`, newValue);\n\t\t}\n\t}\n});\n\n// Migrate Quick Fix Settings\nregisterEditorSettingMigration('codeActionWidget.includeNearbyQuickfixes', (value, read, write) => {\n\tif (typeof value === 'boolean') {\n\t\twrite('codeActionWidget.includeNearbyQuickfixes', undefined);\n\t\tif (typeof read('codeActionWidget.includeNearbyQuickFixes') === 'undefined') {\n\t\t\twrite('codeActionWidget.includeNearbyQuickFixes', value);\n\t\t}\n\t}\n});\n\n// Migrate the lightbulb settings\nregisterEditorSettingMigration('lightbulb.enabled', (value, read, write) => {\n\tif (typeof value === 'boolean') {\n\t\twrite('lightbulb.enabled', value ? undefined : 'off');\n\t}\n});\n\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\nimport { Emitter, Event } from 'vs/base/common/event';\n\nclass TabFocusImpl {\n\tprivate _tabFocus: boolean = false;\n\tprivate readonly _onDidChangeTabFocus = new Emitter();\n\tpublic readonly onDidChangeTabFocus: Event = this._onDidChangeTabFocus.event;\n\n\tpublic getTabFocusMode(): boolean {\n\t\treturn this._tabFocus;\n\t}\n\n\tpublic setTabFocusMode(tabFocusMode: boolean): void {\n\t\tthis._tabFocus = tabFocusMode;\n\t\tthis._onDidChangeTabFocus.fire(this._tabFocus);\n\t}\n}\n\n/**\n * Control what pressing Tab does.\n * If it is false, pressing Tab or Shift-Tab will be handled by the editor.\n * If it is true, pressing Tab or Shift-Tab will move the browser focus.\n * Defaults to false.\n */\nexport const TabFocus = new TabFocusImpl();\n","\nimport { observableFromEvent } from 'vs/base/common/observable';\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\n\n/**\n * Returns a facade for the code editor that provides observables for various states/events.\n*/\nexport function obsCodeEditor(editor: ICodeEditor): ObservableCodeEditor {\n\treturn ObservableCodeEditor.get(editor);\n}\n\nclass ObservableCodeEditor {\n\tprivate static _map = new Map();\n\n\t/**\n\t * Make sure that editor is not disposed yet!\n\t*/\n\tpublic static get(editor: ICodeEditor): ObservableCodeEditor {\n\t\tlet result = ObservableCodeEditor._map.get(editor);\n\t\tif (!result) {\n\t\t\tresult = new ObservableCodeEditor(editor);\n\t\t\tObservableCodeEditor._map.set(editor, result);\n\t\t\tconst d = editor.onDidDispose(() => {\n\t\t\t\tObservableCodeEditor._map.delete(editor);\n\t\t\t\td.dispose();\n\t\t\t});\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate constructor(public readonly editor: ICodeEditor) {\n\t}\n\n\tpublic readonly model = observableFromEvent(this.editor.onDidChangeModel, () => this.editor.getModel());\n}\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\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\nimport { Position } from 'vs/editor/common/core/position';\nimport { ScrollType } from 'vs/editor/common/editorCommon';\n\nexport class StableEditorScrollState {\n\n\tpublic static capture(editor: ICodeEditor): StableEditorScrollState {\n\t\tif (editor.getScrollTop() === 0 || editor.hasPendingScrollAnimation()) {\n\t\t\t// Never mess with the scroll top if the editor is at the top of the file or if there is a pending scroll animation\n\t\t\treturn new StableEditorScrollState(editor.getScrollTop(), editor.getContentHeight(), null, 0, null);\n\t\t}\n\n\t\tlet visiblePosition: Position | null = null;\n\t\tlet visiblePositionScrollDelta = 0;\n\t\tconst visibleRanges = editor.getVisibleRanges();\n\t\tif (visibleRanges.length > 0) {\n\t\t\tvisiblePosition = visibleRanges[0].getStartPosition();\n\t\t\tconst visiblePositionScrollTop = editor.getTopForPosition(visiblePosition.lineNumber, visiblePosition.column);\n\t\t\tvisiblePositionScrollDelta = editor.getScrollTop() - visiblePositionScrollTop;\n\t\t}\n\t\treturn new StableEditorScrollState(editor.getScrollTop(), editor.getContentHeight(), visiblePosition, visiblePositionScrollDelta, editor.getPosition());\n\t}\n\n\tconstructor(\n\t\tprivate readonly _initialScrollTop: number,\n\t\tprivate readonly _initialContentHeight: number,\n\t\tprivate readonly _visiblePosition: Position | null,\n\t\tprivate readonly _visiblePositionScrollDelta: number,\n\t\tprivate readonly _cursorPosition: Position | null,\n\t) {\n\t}\n\n\tpublic restore(editor: ICodeEditor): void {\n\t\tif (this._initialContentHeight === editor.getContentHeight() && this._initialScrollTop === editor.getScrollTop()) {\n\t\t\t// The editor's content height and scroll top haven't changed, so we don't need to do anything\n\t\t\treturn;\n\t\t}\n\n\t\tif (this._visiblePosition) {\n\t\t\tconst visiblePositionScrollTop = editor.getTopForPosition(this._visiblePosition.lineNumber, this._visiblePosition.column);\n\t\t\teditor.setScrollTop(visiblePositionScrollTop + this._visiblePositionScrollDelta);\n\t\t}\n\t}\n\n\tpublic restoreRelativeVerticalPositionOfCursor(editor: ICodeEditor): void {\n\t\tif (this._initialContentHeight === editor.getContentHeight() && this._initialScrollTop === editor.getScrollTop()) {\n\t\t\t// The editor's content height and scroll top haven't changed, so we don't need to do anything\n\t\t\treturn;\n\t\t}\n\n\t\tconst currentCursorPosition = editor.getPosition();\n\n\t\tif (!this._cursorPosition || !currentCursorPosition) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst offset = editor.getTopForLineNumber(currentCursorPosition.lineNumber) - editor.getTopForLineNumber(this._cursorPosition.lineNumber);\n\t\teditor.setScrollTop(editor.getScrollTop() + offset, ScrollType.Immediate);\n\t}\n}\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\nimport { Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\nimport { ViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData';\nimport { IViewLayout, ViewModelDecoration } from 'vs/editor/common/viewModel';\n\nexport interface IViewLines {\n\tlinesVisibleRangesForRange(range: Range, includeNewLines: boolean): LineVisibleRanges[] | null;\n\tvisibleRangeForPosition(position: Position): HorizontalPosition | null;\n}\n\nexport abstract class RestrictedRenderingContext {\n\t_restrictedRenderingContextBrand: void = undefined;\n\n\tpublic readonly viewportData: ViewportData;\n\n\tpublic readonly scrollWidth: number;\n\tpublic readonly scrollHeight: number;\n\n\tpublic readonly visibleRange: Range;\n\tpublic readonly bigNumbersDelta: number;\n\n\tpublic readonly scrollTop: number;\n\tpublic readonly scrollLeft: number;\n\n\tpublic readonly viewportWidth: number;\n\tpublic readonly viewportHeight: number;\n\n\tprivate readonly _viewLayout: IViewLayout;\n\n\tconstructor(viewLayout: IViewLayout, viewportData: ViewportData) {\n\t\tthis._viewLayout = viewLayout;\n\t\tthis.viewportData = viewportData;\n\n\t\tthis.scrollWidth = this._viewLayout.getScrollWidth();\n\t\tthis.scrollHeight = this._viewLayout.getScrollHeight();\n\n\t\tthis.visibleRange = this.viewportData.visibleRange;\n\t\tthis.bigNumbersDelta = this.viewportData.bigNumbersDelta;\n\n\t\tconst vInfo = this._viewLayout.getCurrentViewport();\n\t\tthis.scrollTop = vInfo.top;\n\t\tthis.scrollLeft = vInfo.left;\n\t\tthis.viewportWidth = vInfo.width;\n\t\tthis.viewportHeight = vInfo.height;\n\t}\n\n\tpublic getScrolledTopFromAbsoluteTop(absoluteTop: number): number {\n\t\treturn absoluteTop - this.scrollTop;\n\t}\n\n\tpublic getVerticalOffsetForLineNumber(lineNumber: number, includeViewZones?: boolean): number {\n\t\treturn this._viewLayout.getVerticalOffsetForLineNumber(lineNumber, includeViewZones);\n\t}\n\n\tpublic getVerticalOffsetAfterLineNumber(lineNumber: number, includeViewZones?: boolean): number {\n\t\treturn this._viewLayout.getVerticalOffsetAfterLineNumber(lineNumber, includeViewZones);\n\t}\n\n\tpublic getDecorationsInViewport(): ViewModelDecoration[] {\n\t\treturn this.viewportData.getDecorationsInViewport();\n\t}\n\n}\n\nexport class RenderingContext extends RestrictedRenderingContext {\n\t_renderingContextBrand: void = undefined;\n\n\tprivate readonly _viewLines: IViewLines;\n\n\tconstructor(viewLayout: IViewLayout, viewportData: ViewportData, viewLines: IViewLines) {\n\t\tsuper(viewLayout, viewportData);\n\t\tthis._viewLines = viewLines;\n\t}\n\n\tpublic linesVisibleRangesForRange(range: Range, includeNewLines: boolean): LineVisibleRanges[] | null {\n\t\treturn this._viewLines.linesVisibleRangesForRange(range, includeNewLines);\n\t}\n\n\tpublic visibleRangeForPosition(position: Position): HorizontalPosition | null {\n\t\treturn this._viewLines.visibleRangeForPosition(position);\n\t}\n}\n\nexport class LineVisibleRanges {\n\n\tconstructor(\n\t\tpublic readonly outsideRenderedLine: boolean,\n\t\tpublic readonly lineNumber: number,\n\t\tpublic readonly ranges: HorizontalRange[],\n\t\t/**\n\t\t * Indicates if the requested range does not end in this line, but continues on the next line.\n\t\t */\n\t\tpublic readonly continuesOnNextLine: boolean,\n\t) { }\n}\n\nexport class HorizontalRange {\n\t_horizontalRangeBrand: void = undefined;\n\n\tpublic left: number;\n\tpublic width: number;\n\n\tpublic static from(ranges: FloatHorizontalRange[]): HorizontalRange[] {\n\t\tconst result = new Array(ranges.length);\n\t\tfor (let i = 0, len = ranges.length; i < len; i++) {\n\t\t\tconst range = ranges[i];\n\t\t\tresult[i] = new HorizontalRange(range.left, range.width);\n\t\t}\n\t\treturn result;\n\t}\n\n\tconstructor(left: number, width: number) {\n\t\tthis.left = Math.round(left);\n\t\tthis.width = Math.round(width);\n\t}\n\n\tpublic toString(): string {\n\t\treturn `[${this.left},${this.width}]`;\n\t}\n}\n\nexport class FloatHorizontalRange {\n\t_floatHorizontalRangeBrand: void = undefined;\n\n\tpublic left: number;\n\tpublic width: number;\n\n\tconstructor(left: number, width: number) {\n\t\tthis.left = left;\n\t\tthis.width = width;\n\t}\n\n\tpublic toString(): string {\n\t\treturn `[${this.left},${this.width}]`;\n\t}\n\n\tpublic static compare(a: FloatHorizontalRange, b: FloatHorizontalRange): number {\n\t\treturn a.left - b.left;\n\t}\n}\n\nexport class HorizontalPosition {\n\tpublic outsideRenderedLine: boolean;\n\t/**\n\t * Math.round(this.originalLeft)\n\t */\n\tpublic left: number;\n\tpublic originalLeft: number;\n\n\tconstructor(outsideRenderedLine: boolean, left: number) {\n\t\tthis.outsideRenderedLine = outsideRenderedLine;\n\t\tthis.originalLeft = left;\n\t\tthis.left = Math.round(this.originalLeft);\n\t}\n}\n\nexport class VisibleRanges {\n\tconstructor(\n\t\tpublic readonly outsideRenderedLine: boolean,\n\t\tpublic readonly ranges: FloatHorizontalRange[]\n\t) {\n\t}\n}\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\nexport class DomReadingContext {\n\n\tprivate _didDomLayout: boolean = false;\n\tprivate _clientRectDeltaLeft: number = 0;\n\tprivate _clientRectScale: number = 1;\n\tprivate _clientRectRead: boolean = false;\n\n\tpublic get didDomLayout(): boolean {\n\t\treturn this._didDomLayout;\n\t}\n\n\tprivate readClientRect(): void {\n\t\tif (!this._clientRectRead) {\n\t\t\tthis._clientRectRead = true;\n\t\t\tconst rect = this._domNode.getBoundingClientRect();\n\t\t\tthis.markDidDomLayout();\n\t\t\tthis._clientRectDeltaLeft = rect.left;\n\t\t\tthis._clientRectScale = rect.width / this._domNode.offsetWidth;\n\t\t}\n\t}\n\n\tpublic get clientRectDeltaLeft(): number {\n\t\tif (!this._clientRectRead) {\n\t\t\tthis.readClientRect();\n\t\t}\n\t\treturn this._clientRectDeltaLeft;\n\t}\n\n\tpublic get clientRectScale(): number {\n\t\tif (!this._clientRectRead) {\n\t\t\tthis.readClientRect();\n\t\t}\n\t\treturn this._clientRectScale;\n\t}\n\n\tconstructor(\n\t\tprivate readonly _domNode: HTMLElement,\n\t\tpublic readonly endNode: HTMLElement\n\t) {\n\t}\n\n\tpublic markDidDomLayout(): void {\n\t\tthis._didDomLayout = true;\n\t}\n}\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\nimport { Constants } from 'vs/base/common/uint';\nimport { FloatHorizontalRange } from 'vs/editor/browser/view/renderingContext';\nimport { DomReadingContext } from 'vs/editor/browser/viewParts/lines/domReadingContext';\n\nexport class RangeUtil {\n\n\t/**\n\t * Reusing the same range here\n\t * because IE is buggy and constantly freezes when using a large number\n\t * of ranges and calling .detach on them\n\t */\n\tprivate static _handyReadyRange: Range;\n\n\tprivate static _createRange(): Range {\n\t\tif (!this._handyReadyRange) {\n\t\t\tthis._handyReadyRange = document.createRange();\n\t\t}\n\t\treturn this._handyReadyRange;\n\t}\n\n\tprivate static _detachRange(range: Range, endNode: HTMLElement): void {\n\t\t// Move range out of the span node, IE doesn't like having many ranges in\n\t\t// the same spot and will act badly for lines containing dashes ('-')\n\t\trange.selectNodeContents(endNode);\n\t}\n\n\tprivate static _readClientRects(startElement: Node, startOffset: number, endElement: Node, endOffset: number, endNode: HTMLElement): DOMRectList | null {\n\t\tconst range = this._createRange();\n\t\ttry {\n\t\t\trange.setStart(startElement, startOffset);\n\t\t\trange.setEnd(endElement, endOffset);\n\n\t\t\treturn range.getClientRects();\n\t\t} catch (e) {\n\t\t\t// This is life ...\n\t\t\treturn null;\n\t\t} finally {\n\t\t\tthis._detachRange(range, endNode);\n\t\t}\n\t}\n\n\tprivate static _mergeAdjacentRanges(ranges: FloatHorizontalRange[]): FloatHorizontalRange[] {\n\t\tif (ranges.length === 1) {\n\t\t\t// There is nothing to merge\n\t\t\treturn ranges;\n\t\t}\n\n\t\tranges.sort(FloatHorizontalRange.compare);\n\n\t\tconst result: FloatHorizontalRange[] = [];\n\t\tlet resultLen = 0;\n\t\tlet prev = ranges[0];\n\n\t\tfor (let i = 1, len = ranges.length; i < len; i++) {\n\t\t\tconst range = ranges[i];\n\t\t\tif (prev.left + prev.width + 0.9 /* account for browser's rounding errors*/ >= range.left) {\n\t\t\t\tprev.width = Math.max(prev.width, range.left + range.width - prev.left);\n\t\t\t} else {\n\t\t\t\tresult[resultLen++] = prev;\n\t\t\t\tprev = range;\n\t\t\t}\n\t\t}\n\n\t\tresult[resultLen++] = prev;\n\n\t\treturn result;\n\t}\n\n\tprivate static _createHorizontalRangesFromClientRects(clientRects: DOMRectList | null, clientRectDeltaLeft: number, clientRectScale: number): FloatHorizontalRange[] | null {\n\t\tif (!clientRects || clientRects.length === 0) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// We go through FloatHorizontalRange because it has been observed in bi-di text\n\t\t// that the clientRects are not coming in sorted from the browser\n\n\t\tconst result: FloatHorizontalRange[] = [];\n\t\tfor (let i = 0, len = clientRects.length; i < len; i++) {\n\t\t\tconst clientRect = clientRects[i];\n\t\t\tresult[i] = new FloatHorizontalRange(Math.max(0, (clientRect.left - clientRectDeltaLeft) / clientRectScale), clientRect.width / clientRectScale);\n\t\t}\n\n\t\treturn this._mergeAdjacentRanges(result);\n\t}\n\n\tpublic static readHorizontalRanges(domNode: HTMLElement, startChildIndex: number, startOffset: number, endChildIndex: number, endOffset: number, context: DomReadingContext): FloatHorizontalRange[] | null {\n\t\t// Panic check\n\t\tconst min = 0;\n\t\tconst max = domNode.children.length - 1;\n\t\tif (min > max) {\n\t\t\treturn null;\n\t\t}\n\t\tstartChildIndex = Math.min(max, Math.max(min, startChildIndex));\n\t\tendChildIndex = Math.min(max, Math.max(min, endChildIndex));\n\n\t\tif (startChildIndex === endChildIndex && startOffset === endOffset && startOffset === 0 && !domNode.children[startChildIndex].firstChild) {\n\t\t\t// We must find the position at the beginning of a \n\t\t\t// To cover cases of empty s, avoid using a range and use the 's bounding box\n\t\t\tconst clientRects = domNode.children[startChildIndex].getClientRects();\n\t\t\tcontext.markDidDomLayout();\n\t\t\treturn this._createHorizontalRangesFromClientRects(clientRects, context.clientRectDeltaLeft, context.clientRectScale);\n\t\t}\n\n\t\t// If crossing over to a span only to select offset 0, then use the previous span's maximum offset\n\t\t// Chrome is buggy and doesn't handle 0 offsets well sometimes.\n\t\tif (startChildIndex !== endChildIndex) {\n\t\t\tif (endChildIndex > 0 && endOffset === 0) {\n\t\t\t\tendChildIndex--;\n\t\t\t\tendOffset = Constants.MAX_SAFE_SMALL_INTEGER;\n\t\t\t}\n\t\t}\n\n\t\tlet startElement = domNode.children[startChildIndex].firstChild;\n\t\tlet endElement = domNode.children[endChildIndex].firstChild;\n\n\t\tif (!startElement || !endElement) {\n\t\t\t// When having an empty (without any text content), try to move to the previous \n\t\t\tif (!startElement && startOffset === 0 && startChildIndex > 0) {\n\t\t\t\tstartElement = domNode.children[startChildIndex - 1].firstChild;\n\t\t\t\tstartOffset = Constants.MAX_SAFE_SMALL_INTEGER;\n\t\t\t}\n\t\t\tif (!endElement && endOffset === 0 && endChildIndex > 0) {\n\t\t\t\tendElement = domNode.children[endChildIndex - 1].firstChild;\n\t\t\t\tendOffset = Constants.MAX_SAFE_SMALL_INTEGER;\n\t\t\t}\n\t\t}\n\n\t\tif (!startElement || !endElement) {\n\t\t\treturn null;\n\t\t}\n\n\t\tstartOffset = Math.min(startElement.textContent!.length, Math.max(0, startOffset));\n\t\tendOffset = Math.min(endElement.textContent!.length, Math.max(0, endOffset));\n\n\t\tconst clientRects = this._readClientRects(startElement, startOffset, endElement, endOffset, context.endNode);\n\t\tcontext.markDidDomLayout();\n\t\treturn this._createHorizontalRangesFromClientRects(clientRects, context.clientRectDeltaLeft, context.clientRectScale);\n\t}\n}\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\nexport const enum Constants {\n\tSTART_CH_CODE = 32, // Space\n\tEND_CH_CODE = 126, // Tilde (~)\n\tUNKNOWN_CODE = 65533, // UTF placeholder code\n\tCHAR_COUNT = END_CH_CODE - START_CH_CODE + 2,\n\n\tSAMPLED_CHAR_HEIGHT = 16,\n\tSAMPLED_CHAR_WIDTH = 10,\n\n\tBASE_CHAR_HEIGHT = 2,\n\tBASE_CHAR_WIDTH = 1,\n\n\tRGBA_CHANNELS_CNT = 4,\n\tRGBA_SAMPLED_ROW_WIDTH = RGBA_CHANNELS_CNT * CHAR_COUNT * SAMPLED_CHAR_WIDTH\n}\n\nexport const allCharCodes: ReadonlyArray = (() => {\n\tconst v: number[] = [];\n\tfor (let i = Constants.START_CH_CODE; i <= Constants.END_CH_CODE; i++) {\n\t\tv.push(i);\n\t}\n\n\tv.push(Constants.UNKNOWN_CODE);\n\treturn v;\n})();\n\nexport const getCharIndex = (chCode: number, fontScale: number) => {\n\tchCode -= Constants.START_CH_CODE;\n\tif (chCode < 0 || chCode > Constants.CHAR_COUNT) {\n\t\tif (fontScale <= 2) {\n\t\t\t// for smaller scales, we can get away with using any ASCII character...\n\t\t\treturn (chCode + Constants.CHAR_COUNT) % Constants.CHAR_COUNT;\n\t\t}\n\t\treturn Constants.CHAR_COUNT - 1; // unknown symbol\n\t}\n\n\treturn chCode;\n};\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\nimport { RGBA8 } from 'vs/editor/common/core/rgba';\nimport { Constants, getCharIndex } from './minimapCharSheet';\nimport { toUint8 } from 'vs/base/common/uint';\n\nexport class MinimapCharRenderer {\n\t_minimapCharRendererBrand: void = undefined;\n\n\tprivate readonly charDataNormal: Uint8ClampedArray;\n\tprivate readonly charDataLight: Uint8ClampedArray;\n\n\tconstructor(charData: Uint8ClampedArray, public readonly scale: number) {\n\t\tthis.charDataNormal = MinimapCharRenderer.soften(charData, 12 / 15);\n\t\tthis.charDataLight = MinimapCharRenderer.soften(charData, 50 / 60);\n\t}\n\n\tprivate static soften(input: Uint8ClampedArray, ratio: number): Uint8ClampedArray {\n\t\tconst result = new Uint8ClampedArray(input.length);\n\t\tfor (let i = 0, len = input.length; i < len; i++) {\n\t\t\tresult[i] = toUint8(input[i] * ratio);\n\t\t}\n\t\treturn result;\n\t}\n\n\tpublic renderChar(\n\t\ttarget: ImageData,\n\t\tdx: number,\n\t\tdy: number,\n\t\tchCode: number,\n\t\tcolor: RGBA8,\n\t\tforegroundAlpha: number,\n\t\tbackgroundColor: RGBA8,\n\t\tbackgroundAlpha: number,\n\t\tfontScale: number,\n\t\tuseLighterFont: boolean,\n\t\tforce1pxHeight: boolean\n\t): void {\n\t\tconst charWidth = Constants.BASE_CHAR_WIDTH * this.scale;\n\t\tconst charHeight = Constants.BASE_CHAR_HEIGHT * this.scale;\n\t\tconst renderHeight = (force1pxHeight ? 1 : charHeight);\n\t\tif (dx + charWidth > target.width || dy + renderHeight > target.height) {\n\t\t\tconsole.warn('bad render request outside image data');\n\t\t\treturn;\n\t\t}\n\n\t\tconst charData = useLighterFont ? this.charDataLight : this.charDataNormal;\n\t\tconst charIndex = getCharIndex(chCode, fontScale);\n\n\t\tconst destWidth = target.width * Constants.RGBA_CHANNELS_CNT;\n\n\t\tconst backgroundR = backgroundColor.r;\n\t\tconst backgroundG = backgroundColor.g;\n\t\tconst backgroundB = backgroundColor.b;\n\n\t\tconst deltaR = color.r - backgroundR;\n\t\tconst deltaG = color.g - backgroundG;\n\t\tconst deltaB = color.b - backgroundB;\n\n\t\tconst destAlpha = Math.max(foregroundAlpha, backgroundAlpha);\n\n\t\tconst dest = target.data;\n\t\tlet sourceOffset = charIndex * charWidth * charHeight;\n\n\t\tlet row = dy * destWidth + dx * Constants.RGBA_CHANNELS_CNT;\n\t\tfor (let y = 0; y < renderHeight; y++) {\n\t\t\tlet column = row;\n\t\t\tfor (let x = 0; x < charWidth; x++) {\n\t\t\t\tconst c = (charData[sourceOffset++] / 255) * (foregroundAlpha / 255);\n\t\t\t\tdest[column++] = backgroundR + deltaR * c;\n\t\t\t\tdest[column++] = backgroundG + deltaG * c;\n\t\t\t\tdest[column++] = backgroundB + deltaB * c;\n\t\t\t\tdest[column++] = destAlpha;\n\t\t\t}\n\n\t\t\trow += destWidth;\n\t\t}\n\t}\n\n\tpublic blockRenderChar(\n\t\ttarget: ImageData,\n\t\tdx: number,\n\t\tdy: number,\n\t\tcolor: RGBA8,\n\t\tforegroundAlpha: number,\n\t\tbackgroundColor: RGBA8,\n\t\tbackgroundAlpha: number,\n\t\tforce1pxHeight: boolean\n\t): void {\n\t\tconst charWidth = Constants.BASE_CHAR_WIDTH * this.scale;\n\t\tconst charHeight = Constants.BASE_CHAR_HEIGHT * this.scale;\n\t\tconst renderHeight = (force1pxHeight ? 1 : charHeight);\n\t\tif (dx + charWidth > target.width || dy + renderHeight > target.height) {\n\t\t\tconsole.warn('bad render request outside image data');\n\t\t\treturn;\n\t\t}\n\n\t\tconst destWidth = target.width * Constants.RGBA_CHANNELS_CNT;\n\n\t\tconst c = 0.5 * (foregroundAlpha / 255);\n\n\t\tconst backgroundR = backgroundColor.r;\n\t\tconst backgroundG = backgroundColor.g;\n\t\tconst backgroundB = backgroundColor.b;\n\n\t\tconst deltaR = color.r - backgroundR;\n\t\tconst deltaG = color.g - backgroundG;\n\t\tconst deltaB = color.b - backgroundB;\n\n\t\tconst colorR = backgroundR + deltaR * c;\n\t\tconst colorG = backgroundG + deltaG * c;\n\t\tconst colorB = backgroundB + deltaB * c;\n\n\t\tconst destAlpha = Math.max(foregroundAlpha, backgroundAlpha);\n\n\t\tconst dest = target.data;\n\n\t\tlet row = dy * destWidth + dx * Constants.RGBA_CHANNELS_CNT;\n\t\tfor (let y = 0; y < renderHeight; y++) {\n\t\t\tlet column = row;\n\t\t\tfor (let x = 0; x < charWidth; x++) {\n\t\t\t\tdest[column++] = colorR;\n\t\t\t\tdest[column++] = colorG;\n\t\t\t\tdest[column++] = colorB;\n\t\t\t\tdest[column++] = destAlpha;\n\t\t\t}\n\n\t\t\trow += destWidth;\n\t\t}\n\t}\n}\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\nimport { createSingleCallFunction } from 'vs/base/common/functional';\n\nconst charTable: { [hex: string]: number } = {\n\t'0': 0,\n\t'1': 1,\n\t'2': 2,\n\t'3': 3,\n\t'4': 4,\n\t'5': 5,\n\t'6': 6,\n\t'7': 7,\n\t'8': 8,\n\t'9': 9,\n\tA: 10,\n\tB: 11,\n\tC: 12,\n\tD: 13,\n\tE: 14,\n\tF: 15\n};\n\nconst decodeData = (str: string) => {\n\tconst output = new Uint8ClampedArray(str.length / 2);\n\tfor (let i = 0; i < str.length; i += 2) {\n\t\toutput[i >> 1] = (charTable[str[i]] << 4) | (charTable[str[i + 1]] & 0xF);\n\t}\n\n\treturn output;\n};\n\n/*\nconst encodeData = (data: Uint8ClampedArray, length: string) => {\n\tconst chars = '0123456789ABCDEF';\n\tlet output = '';\n\tfor (let i = 0; i < data.length; i++) {\n\t\toutput += chars[data[i] >> 4] + chars[data[i] & 0xf];\n\t}\n\treturn output;\n};\n*/\n\n/**\n * Map of minimap scales to prebaked sample data at those scales. We don't\n * sample much larger data, because then font family becomes visible, which\n * is use-configurable.\n */\nexport const prebakedMiniMaps: { [scale: number]: () => Uint8ClampedArray } = {\n\t1: createSingleCallFunction(() =>\n\t\tdecodeData(\n\t\t\t'0000511D6300CF609C709645A78432005642574171487021003C451900274D35D762755E8B629C5BA856AF57BA649530C167D1512A272A3F6038604460398526BCA2A968DB6F8957C768BE5FBE2FB467CF5D8D5B795DC7625B5DFF50DE64C466DB2FC47CD860A65E9A2EB96CB54CE06DA763AB2EA26860524D3763536601005116008177A8705E53AB738E6A982F88BAA35B5F5B626D9C636B449B737E5B7B678598869A662F6B5B8542706C704C80736A607578685B70594A49715A4522E792'\n\t\t)\n\t),\n\t2: createSingleCallFunction(() =>\n\t\tdecodeData(\n\t\t\t'000000000000000055394F383D2800008B8B1F210002000081B1CBCBCC820000847AAF6B9AAF2119BE08B8881AD60000A44FD07DCCF107015338130C00000000385972265F390B406E2437634B4B48031B12B8A0847000001E15B29A402F0000000000004B33460B00007A752C2A0000000000004D3900000084394B82013400ABA5CFC7AD9C0302A45A3E5A98AB000089A43382D97900008BA54AA087A70A0248A6A7AE6DBE0000BF6F94987EA40A01A06DCFA7A7A9030496C32F77891D0000A99FB1A0AFA80603B29AB9CA75930D010C0948354D3900000C0948354F37460D0028BE673D8400000000AF9D7B6E00002B007AA8933400007AA642675C2700007984CFB9C3985B768772A8A6B7B20000CAAECAAFC4B700009F94A6009F840009D09F9BA4CA9C0000CC8FC76DC87F0000C991C472A2000000A894A48CA7B501079BA2C9C69BA20000B19A5D3FA89000005CA6009DA2960901B0A7F0669FB200009D009E00B7890000DAD0F5D092820000D294D4C48BD10000B5A7A4A3B1A50402CAB6CBA6A2000000B5A7A4A3B1A8044FCDADD19D9CB00000B7778F7B8AAE0803C9AB5D3F5D3F00009EA09EA0BAB006039EA0989A8C7900009B9EF4D6B7C00000A9A7816CACA80000ABAC84705D3F000096DA635CDC8C00006F486F266F263D4784006124097B00374F6D2D6D2D6D4A3A95872322000000030000000000008D8939130000000000002E22A5C9CBC70600AB25C0B5C9B400061A2DB04CA67001082AA6BEBEBFC606002321DACBC19E03087AA08B6768380000282FBAC0B8CA7A88AD25BBA5A29900004C396C5894A6000040485A6E356E9442A32CD17EADA70000B4237923628600003E2DE9C1D7B500002F25BBA5A2990000231DB6AFB4A804023025C0B5CAB588062B2CBDBEC0C706882435A75CA20000002326BD6A82A908048B4B9A5A668000002423A09CB4BB060025259C9D8A7900001C1FCAB2C7C700002A2A9387ABA200002626A4A47D6E9D14333163A0C87500004B6F9C2D643A257049364936493647358A34438355497F1A0000A24C1D590000D38DFFBDD4CD3126'\n\t\t)\n\t)\n};\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\nimport { MinimapCharRenderer } from 'vs/editor/browser/viewParts/minimap/minimapCharRenderer';\nimport { allCharCodes, Constants } from 'vs/editor/browser/viewParts/minimap/minimapCharSheet';\nimport { prebakedMiniMaps } from 'vs/editor/browser/viewParts/minimap/minimapPreBaked';\nimport { toUint8 } from 'vs/base/common/uint';\n\n/**\n * Creates character renderers. It takes a 'scale' that determines how large\n * characters should be drawn. Using this, it draws data into a canvas and\n * then downsamples the characters as necessary for the current display.\n * This makes rendering more efficient, rather than drawing a full (tiny)\n * font, or downsampling in real-time.\n */\nexport class MinimapCharRendererFactory {\n\tprivate static lastCreated?: MinimapCharRenderer;\n\tprivate static lastFontFamily?: string;\n\n\t/**\n\t * Creates a new character renderer factory with the given scale.\n\t */\n\tpublic static create(scale: number, fontFamily: string) {\n\t\t// renderers are immutable. By default we'll 'create' a new minimap\n\t\t// character renderer whenever we switch editors, no need to do extra work.\n\t\tif (this.lastCreated && scale === this.lastCreated.scale && fontFamily === this.lastFontFamily) {\n\t\t\treturn this.lastCreated;\n\t\t}\n\n\t\tlet factory: MinimapCharRenderer;\n\t\tif (prebakedMiniMaps[scale]) {\n\t\t\tfactory = new MinimapCharRenderer(prebakedMiniMaps[scale](), scale);\n\t\t} else {\n\t\t\tfactory = MinimapCharRendererFactory.createFromSampleData(\n\t\t\t\tMinimapCharRendererFactory.createSampleData(fontFamily).data,\n\t\t\t\tscale\n\t\t\t);\n\t\t}\n\n\t\tthis.lastFontFamily = fontFamily;\n\t\tthis.lastCreated = factory;\n\t\treturn factory;\n\t}\n\n\t/**\n\t * Creates the font sample data, writing to a canvas.\n\t */\n\tpublic static createSampleData(fontFamily: string): ImageData {\n\t\tconst canvas = document.createElement('canvas');\n\t\tconst ctx = canvas.getContext('2d')!;\n\n\t\tcanvas.style.height = `${Constants.SAMPLED_CHAR_HEIGHT}px`;\n\t\tcanvas.height = Constants.SAMPLED_CHAR_HEIGHT;\n\t\tcanvas.width = Constants.CHAR_COUNT * Constants.SAMPLED_CHAR_WIDTH;\n\t\tcanvas.style.width = Constants.CHAR_COUNT * Constants.SAMPLED_CHAR_WIDTH + 'px';\n\n\t\tctx.fillStyle = '#ffffff';\n\t\tctx.font = `bold ${Constants.SAMPLED_CHAR_HEIGHT}px ${fontFamily}`;\n\t\tctx.textBaseline = 'middle';\n\n\t\tlet x = 0;\n\t\tfor (const code of allCharCodes) {\n\t\t\tctx.fillText(String.fromCharCode(code), x, Constants.SAMPLED_CHAR_HEIGHT / 2);\n\t\t\tx += Constants.SAMPLED_CHAR_WIDTH;\n\t\t}\n\n\t\treturn ctx.getImageData(0, 0, Constants.CHAR_COUNT * Constants.SAMPLED_CHAR_WIDTH, Constants.SAMPLED_CHAR_HEIGHT);\n\t}\n\n\t/**\n\t * Creates a character renderer from the canvas sample data.\n\t */\n\tpublic static createFromSampleData(source: Uint8ClampedArray, scale: number): MinimapCharRenderer {\n\t\tconst expectedLength =\n\t\t\tConstants.SAMPLED_CHAR_HEIGHT * Constants.SAMPLED_CHAR_WIDTH * Constants.RGBA_CHANNELS_CNT * Constants.CHAR_COUNT;\n\t\tif (source.length !== expectedLength) {\n\t\t\tthrow new Error('Unexpected source in MinimapCharRenderer');\n\t\t}\n\n\t\tconst charData = MinimapCharRendererFactory._downsample(source, scale);\n\t\treturn new MinimapCharRenderer(charData, scale);\n\t}\n\n\tprivate static _downsampleChar(\n\t\tsource: Uint8ClampedArray,\n\t\tsourceOffset: number,\n\t\tdest: Uint8ClampedArray,\n\t\tdestOffset: number,\n\t\tscale: number\n\t): number {\n\t\tconst width = Constants.BASE_CHAR_WIDTH * scale;\n\t\tconst height = Constants.BASE_CHAR_HEIGHT * scale;\n\n\t\tlet targetIndex = destOffset;\n\t\tlet brightest = 0;\n\n\t\t// This is essentially an ad-hoc rescaling algorithm. Standard approaches\n\t\t// like bicubic interpolation are awesome for scaling between image sizes,\n\t\t// but don't work so well when scaling to very small pixel values, we end\n\t\t// up with blurry, indistinct forms.\n\t\t//\n\t\t// The approach taken here is simply mapping each source pixel to the target\n\t\t// pixels, and taking the weighted values for all pixels in each, and then\n\t\t// averaging them out. Finally we apply an intensity boost in _downsample,\n\t\t// since when scaling to the smallest pixel sizes there's more black space\n\t\t// which causes characters to be much less distinct.\n\t\tfor (let y = 0; y < height; y++) {\n\t\t\t// 1. For this destination pixel, get the source pixels we're sampling\n\t\t\t// from (x1, y1) to the next pixel (x2, y2)\n\t\t\tconst sourceY1 = (y / height) * Constants.SAMPLED_CHAR_HEIGHT;\n\t\t\tconst sourceY2 = ((y + 1) / height) * Constants.SAMPLED_CHAR_HEIGHT;\n\n\t\t\tfor (let x = 0; x < width; x++) {\n\t\t\t\tconst sourceX1 = (x / width) * Constants.SAMPLED_CHAR_WIDTH;\n\t\t\t\tconst sourceX2 = ((x + 1) / width) * Constants.SAMPLED_CHAR_WIDTH;\n\n\t\t\t\t// 2. Sample all of them, summing them up and weighting them. Similar\n\t\t\t\t// to bilinear interpolation.\n\t\t\t\tlet value = 0;\n\t\t\t\tlet samples = 0;\n\t\t\t\tfor (let sy = sourceY1; sy < sourceY2; sy++) {\n\t\t\t\t\tconst sourceRow = sourceOffset + Math.floor(sy) * Constants.RGBA_SAMPLED_ROW_WIDTH;\n\t\t\t\t\tconst yBalance = 1 - (sy - Math.floor(sy));\n\t\t\t\t\tfor (let sx = sourceX1; sx < sourceX2; sx++) {\n\t\t\t\t\t\tconst xBalance = 1 - (sx - Math.floor(sx));\n\t\t\t\t\t\tconst sourceIndex = sourceRow + Math.floor(sx) * Constants.RGBA_CHANNELS_CNT;\n\n\t\t\t\t\t\tconst weight = xBalance * yBalance;\n\t\t\t\t\t\tsamples += weight;\n\t\t\t\t\t\tvalue += ((source[sourceIndex] * source[sourceIndex + 3]) / 255) * weight;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst final = value / samples;\n\t\t\t\tbrightest = Math.max(brightest, final);\n\t\t\t\tdest[targetIndex++] = toUint8(final);\n\t\t\t}\n\t\t}\n\n\t\treturn brightest;\n\t}\n\n\tprivate static _downsample(data: Uint8ClampedArray, scale: number): Uint8ClampedArray {\n\t\tconst pixelsPerCharacter = Constants.BASE_CHAR_HEIGHT * scale * Constants.BASE_CHAR_WIDTH * scale;\n\t\tconst resultLen = pixelsPerCharacter * Constants.CHAR_COUNT;\n\t\tconst result = new Uint8ClampedArray(resultLen);\n\n\t\tlet resultOffset = 0;\n\t\tlet sourceOffset = 0;\n\t\tlet brightest = 0;\n\t\tfor (let charIndex = 0; charIndex < Constants.CHAR_COUNT; charIndex++) {\n\t\t\tbrightest = Math.max(brightest, this._downsampleChar(data, sourceOffset, result, resultOffset, scale));\n\t\t\tresultOffset += pixelsPerCharacter;\n\t\t\tsourceOffset += Constants.SAMPLED_CHAR_WIDTH * Constants.RGBA_CHANNELS_CNT;\n\t\t}\n\n\t\tif (brightest > 0) {\n\t\t\tconst adjust = 255 / brightest;\n\t\t\tfor (let i = 0; i < resultLen; i++) {\n\t\t\t\tresult[i] *= adjust;\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n}\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\nimport { Emitter } from 'vs/base/common/event';\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditor/codeEditorWidget';\nimport { IEditorOptions } from 'vs/editor/common/config/editorOptions';\nimport { IDimension } from 'vs/editor/common/core/dimension';\nimport { IPosition, Position } from 'vs/editor/common/core/position';\nimport { IRange, Range } from 'vs/editor/common/core/range';\nimport { ISelection, Selection } from 'vs/editor/common/core/selection';\nimport { IDiffEditorViewModel, IEditor, IEditorAction, IEditorDecorationsCollection, IEditorModel, IEditorViewState, ScrollType } from 'vs/editor/common/editorCommon';\nimport { IModelDecorationsChangeAccessor, IModelDeltaDecoration } from 'vs/editor/common/model';\n\nexport abstract class DelegatingEditor extends Disposable implements IEditor {\n\tprivate static idCounter = 0;\n\tprivate readonly _id = ++DelegatingEditor.idCounter;\n\n\tprivate readonly _onDidDispose = this._register(new Emitter());\n\tpublic readonly onDidDispose = this._onDidDispose.event;\n\n\tprotected abstract get _targetEditor(): CodeEditorWidget;\n\n\tgetId(): string { return this.getEditorType() + ':v2:' + this._id; }\n\n\tabstract getEditorType(): string;\n\tabstract updateOptions(newOptions: IEditorOptions): void;\n\tabstract layout(dimension?: IDimension | undefined): void;\n\tabstract hasTextFocus(): boolean;\n\tabstract saveViewState(): IEditorViewState | null;\n\tabstract restoreViewState(state: IEditorViewState | null): void;\n\tabstract getModel(): IEditorModel | null;\n\tabstract setModel(model: IEditorModel | null | IDiffEditorViewModel): void;\n\n\t// #region editorBrowser.IDiffEditor: Delegating to modified Editor\n\n\tpublic getVisibleColumnFromPosition(position: IPosition): number {\n\t\treturn this._targetEditor.getVisibleColumnFromPosition(position);\n\t}\n\n\tpublic getPosition(): Position | null {\n\t\treturn this._targetEditor.getPosition();\n\t}\n\n\tpublic setPosition(position: IPosition, source: string = 'api'): void {\n\t\tthis._targetEditor.setPosition(position, source);\n\t}\n\n\tpublic revealLine(lineNumber: number, scrollType: ScrollType = ScrollType.Smooth): void {\n\t\tthis._targetEditor.revealLine(lineNumber, scrollType);\n\t}\n\n\tpublic revealLineInCenter(lineNumber: number, scrollType: ScrollType = ScrollType.Smooth): void {\n\t\tthis._targetEditor.revealLineInCenter(lineNumber, scrollType);\n\t}\n\n\tpublic revealLineInCenterIfOutsideViewport(lineNumber: number, scrollType: ScrollType = ScrollType.Smooth): void {\n\t\tthis._targetEditor.revealLineInCenterIfOutsideViewport(lineNumber, scrollType);\n\t}\n\n\tpublic revealLineNearTop(lineNumber: number, scrollType: ScrollType = ScrollType.Smooth): void {\n\t\tthis._targetEditor.revealLineNearTop(lineNumber, scrollType);\n\t}\n\n\tpublic revealPosition(position: IPosition, scrollType: ScrollType = ScrollType.Smooth): void {\n\t\tthis._targetEditor.revealPosition(position, scrollType);\n\t}\n\n\tpublic revealPositionInCenter(position: IPosition, scrollType: ScrollType = ScrollType.Smooth): void {\n\t\tthis._targetEditor.revealPositionInCenter(position, scrollType);\n\t}\n\n\tpublic revealPositionInCenterIfOutsideViewport(position: IPosition, scrollType: ScrollType = ScrollType.Smooth): void {\n\t\tthis._targetEditor.revealPositionInCenterIfOutsideViewport(position, scrollType);\n\t}\n\n\tpublic revealPositionNearTop(position: IPosition, scrollType: ScrollType = ScrollType.Smooth): void {\n\t\tthis._targetEditor.revealPositionNearTop(position, scrollType);\n\t}\n\n\tpublic getSelection(): Selection | null {\n\t\treturn this._targetEditor.getSelection();\n\t}\n\n\tpublic getSelections(): Selection[] | null {\n\t\treturn this._targetEditor.getSelections();\n\t}\n\n\tpublic setSelection(range: IRange, source?: string): void;\n\tpublic setSelection(editorRange: Range, source?: string): void;\n\tpublic setSelection(selection: ISelection, source?: string): void;\n\tpublic setSelection(editorSelection: Selection, source?: string): void;\n\tpublic setSelection(something: any, source: string = 'api'): void {\n\t\tthis._targetEditor.setSelection(something, source);\n\t}\n\n\tpublic setSelections(ranges: readonly ISelection[], source: string = 'api'): void {\n\t\tthis._targetEditor.setSelections(ranges, source);\n\t}\n\n\tpublic revealLines(startLineNumber: number, endLineNumber: number, scrollType: ScrollType = ScrollType.Smooth): void {\n\t\tthis._targetEditor.revealLines(startLineNumber, endLineNumber, scrollType);\n\t}\n\n\tpublic revealLinesInCenter(startLineNumber: number, endLineNumber: number, scrollType: ScrollType = ScrollType.Smooth): void {\n\t\tthis._targetEditor.revealLinesInCenter(startLineNumber, endLineNumber, scrollType);\n\t}\n\n\tpublic revealLinesInCenterIfOutsideViewport(startLineNumber: number, endLineNumber: number, scrollType: ScrollType = ScrollType.Smooth): void {\n\t\tthis._targetEditor.revealLinesInCenterIfOutsideViewport(startLineNumber, endLineNumber, scrollType);\n\t}\n\n\tpublic revealLinesNearTop(startLineNumber: number, endLineNumber: number, scrollType: ScrollType = ScrollType.Smooth): void {\n\t\tthis._targetEditor.revealLinesNearTop(startLineNumber, endLineNumber, scrollType);\n\t}\n\n\tpublic revealRange(range: IRange, scrollType: ScrollType = ScrollType.Smooth, revealVerticalInCenter: boolean = false, revealHorizontal: boolean = true): void {\n\t\tthis._targetEditor.revealRange(range, scrollType, revealVerticalInCenter, revealHorizontal);\n\t}\n\n\tpublic revealRangeInCenter(range: IRange, scrollType: ScrollType = ScrollType.Smooth): void {\n\t\tthis._targetEditor.revealRangeInCenter(range, scrollType);\n\t}\n\n\tpublic revealRangeInCenterIfOutsideViewport(range: IRange, scrollType: ScrollType = ScrollType.Smooth): void {\n\t\tthis._targetEditor.revealRangeInCenterIfOutsideViewport(range, scrollType);\n\t}\n\n\tpublic revealRangeNearTop(range: IRange, scrollType: ScrollType = ScrollType.Smooth): void {\n\t\tthis._targetEditor.revealRangeNearTop(range, scrollType);\n\t}\n\n\tpublic revealRangeNearTopIfOutsideViewport(range: IRange, scrollType: ScrollType = ScrollType.Smooth): void {\n\t\tthis._targetEditor.revealRangeNearTopIfOutsideViewport(range, scrollType);\n\t}\n\n\tpublic revealRangeAtTop(range: IRange, scrollType: ScrollType = ScrollType.Smooth): void {\n\t\tthis._targetEditor.revealRangeAtTop(range, scrollType);\n\t}\n\n\tpublic getSupportedActions(): IEditorAction[] {\n\t\treturn this._targetEditor.getSupportedActions();\n\t}\n\n\tpublic focus(): void {\n\t\tthis._targetEditor.focus();\n\t}\n\n\tpublic trigger(source: string | null | undefined, handlerId: string, payload: any): void {\n\t\tthis._targetEditor.trigger(source, handlerId, payload);\n\t}\n\n\tpublic createDecorationsCollection(decorations?: IModelDeltaDecoration[]): IEditorDecorationsCollection {\n\t\treturn this._targetEditor.createDecorationsCollection(decorations);\n\t}\n\n\tpublic changeDecorations(callback: (changeAccessor: IModelDecorationsChangeAccessor) => any): any {\n\t\treturn this._targetEditor.changeDecorations(callback);\n\t}\n\n\t// #endregion\n}\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 *--------------------------------------------------------------------------------------------*/\nimport { IDisposable, IReference } from 'vs/base/common/lifecycle';\n\nexport class ObjectPool> implements IDisposable {\n\tprivate readonly _unused = new Set();\n\tprivate readonly _used = new Set();\n\tprivate readonly _itemData = new Map();\n\n\tconstructor(\n\t\tprivate readonly _create: (data: TData) => T,\n\t) { }\n\n\tpublic getUnusedObj(data: TData): IReference {\n\t\tlet obj: T;\n\n\t\tif (this._unused.size === 0) {\n\t\t\tobj = this._create(data);\n\t\t\tthis._itemData.set(obj, data);\n\t\t} else {\n\t\t\tconst values = [...this._unused.values()];\n\t\t\tobj = values.find(obj => this._itemData.get(obj)!.getId() === data.getId()) ?? values[0];\n\t\t\tthis._unused.delete(obj);\n\t\t\tthis._itemData.set(obj, data);\n\t\t\tobj.setData(data);\n\t\t}\n\t\tthis._used.add(obj);\n\t\treturn {\n\t\t\tobject: obj,\n\t\t\tdispose: () => {\n\t\t\t\tthis._used.delete(obj);\n\t\t\t\tif (this._unused.size > 5) {\n\t\t\t\t\tobj.dispose();\n\t\t\t\t} else {\n\t\t\t\t\tthis._unused.add(obj);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n\n\tdispose(): void {\n\t\tfor (const obj of this._used) {\n\t\t\tobj.dispose();\n\t\t}\n\t\tfor (const obj of this._unused) {\n\t\t\tobj.dispose();\n\t\t}\n\t\tthis._used.clear();\n\t\tthis._unused.clear();\n\t}\n}\n\nexport interface IObjectData {\n\tgetId(): unknown;\n}\n\nexport interface IPooledObject extends IDisposable {\n\tsetData(data: TData): void;\n}\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\nimport { ValidDiffEditorBaseOptions } from 'vs/editor/common/config/editorOptions';\n\nexport const diffEditorDefaultOptions = {\n\tenableSplitViewResizing: true,\n\tsplitViewDefaultRatio: 0.5,\n\trenderSideBySide: true,\n\trenderMarginRevertIcon: true,\n\trenderGutterMenu: true,\n\tmaxComputationTime: 5000,\n\tmaxFileSize: 50,\n\tignoreTrimWhitespace: true,\n\trenderIndicators: true,\n\toriginalEditable: false,\n\tdiffCodeLens: false,\n\trenderOverviewRuler: true,\n\tdiffWordWrap: 'inherit',\n\tdiffAlgorithm: 'advanced',\n\taccessibilityVerbose: false,\n\texperimental: {\n\t\tshowMoves: false,\n\t\tshowEmptyDecorations: true,\n\t},\n\thideUnchangedRegions: {\n\t\tenabled: false,\n\t\tcontextLineCount: 3,\n\t\tminimumLineCount: 3,\n\t\trevealLineCount: 20,\n\t},\n\tisInEmbeddedEditor: false,\n\tonlyShowAccessibleDiffViewer: false,\n\trenderSideBySideInlineBreakpoint: 900,\n\tuseInlineViewWhenSpaceIsLimited: true,\n} satisfies ValidDiffEditorBaseOptions;\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\nimport { Emitter, Event } from 'vs/base/common/event';\n\nexport interface IEditorZoom {\n\tonDidChangeZoomLevel: Event;\n\tgetZoomLevel(): number;\n\tsetZoomLevel(zoomLevel: number): void;\n}\n\nexport const EditorZoom: IEditorZoom = new class implements IEditorZoom {\n\n\tprivate _zoomLevel: number = 0;\n\n\tprivate readonly _onDidChangeZoomLevel = new Emitter();\n\tpublic readonly onDidChangeZoomLevel: Event = this._onDidChangeZoomLevel.event;\n\n\tpublic getZoomLevel(): number {\n\t\treturn this._zoomLevel;\n\t}\n\n\tpublic setZoomLevel(zoomLevel: number): void {\n\t\tzoomLevel = Math.min(Math.max(-5, zoomLevel), 20);\n\t\tif (this._zoomLevel === zoomLevel) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._zoomLevel = zoomLevel;\n\t\tthis._onDidChangeZoomLevel.fire(this._zoomLevel);\n\t}\n};\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\nimport { toUint8 } from 'vs/base/common/uint';\n\n/**\n * A fast character classifier that uses a compact array for ASCII values.\n */\nexport class CharacterClassifier {\n\t/**\n\t * Maintain a compact (fully initialized ASCII map for quickly classifying ASCII characters - used more often in code).\n\t */\n\tprotected readonly _asciiMap: Uint8Array;\n\n\t/**\n\t * The entire map (sparse array).\n\t */\n\tprotected readonly _map: Map;\n\n\tprotected readonly _defaultValue: number;\n\n\tconstructor(_defaultValue: T) {\n\t\tconst defaultValue = toUint8(_defaultValue);\n\n\t\tthis._defaultValue = defaultValue;\n\t\tthis._asciiMap = CharacterClassifier._createAsciiMap(defaultValue);\n\t\tthis._map = new Map();\n\t}\n\n\tprivate static _createAsciiMap(defaultValue: number): Uint8Array {\n\t\tconst asciiMap = new Uint8Array(256);\n\t\tasciiMap.fill(defaultValue);\n\t\treturn asciiMap;\n\t}\n\n\tpublic set(charCode: number, _value: T): void {\n\t\tconst value = toUint8(_value);\n\n\t\tif (charCode >= 0 && charCode < 256) {\n\t\t\tthis._asciiMap[charCode] = value;\n\t\t} else {\n\t\t\tthis._map.set(charCode, value);\n\t\t}\n\t}\n\n\tpublic get(charCode: number): T {\n\t\tif (charCode >= 0 && charCode < 256) {\n\t\t\treturn this._asciiMap[charCode];\n\t\t} else {\n\t\t\treturn (this._map.get(charCode) || this._defaultValue);\n\t\t}\n\t}\n\n\tpublic clear() {\n\t\tthis._asciiMap.fill(this._defaultValue);\n\t\tthis._map.clear();\n\t}\n}\n\nconst enum Boolean {\n\tFalse = 0,\n\tTrue = 1\n}\n\nexport class CharacterSet {\n\n\tprivate readonly _actual: CharacterClassifier;\n\n\tconstructor() {\n\t\tthis._actual = new CharacterClassifier(Boolean.False);\n\t}\n\n\tpublic add(charCode: number): void {\n\t\tthis._actual.set(charCode, Boolean.True);\n\t}\n\n\tpublic has(charCode: number): boolean {\n\t\treturn (this._actual.get(charCode) === Boolean.True);\n\t}\n\n\tpublic clear(): void {\n\t\treturn this._actual.clear();\n\t}\n}\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\nimport { CharCode } from 'vs/base/common/charCode';\nimport * as strings from 'vs/base/common/strings';\n\n/**\n * A column in a position is the gap between two adjacent characters. The methods here\n * work with a concept called \"visible column\". A visible column is a very rough approximation\n * of the horizontal screen position of a column. For example, using a tab size of 4:\n * ```txt\n * |||T|ext\n * | | | \\---- column = 4, visible column = 9\n * | | \\------ column = 3, visible column = 8\n * | \\------------ column = 2, visible column = 4\n * \\------------------ column = 1, visible column = 0\n * ```\n *\n * **NOTE**: Visual columns do not work well for RTL text or variable-width fonts or characters.\n *\n * **NOTE**: These methods work and make sense both on the model and on the view model.\n */\nexport class CursorColumns {\n\n\tprivate static _nextVisibleColumn(codePoint: number, visibleColumn: number, tabSize: number): number {\n\t\tif (codePoint === CharCode.Tab) {\n\t\t\treturn CursorColumns.nextRenderTabStop(visibleColumn, tabSize);\n\t\t}\n\t\tif (strings.isFullWidthCharacter(codePoint) || strings.isEmojiImprecise(codePoint)) {\n\t\t\treturn visibleColumn + 2;\n\t\t}\n\t\treturn visibleColumn + 1;\n\t}\n\n\t/**\n\t * Returns a visible column from a column.\n\t * @see {@link CursorColumns}\n\t */\n\tpublic static visibleColumnFromColumn(lineContent: string, column: number, tabSize: number): number {\n\t\tconst textLen = Math.min(column - 1, lineContent.length);\n\t\tconst text = lineContent.substring(0, textLen);\n\t\tconst iterator = new strings.GraphemeIterator(text);\n\n\t\tlet result = 0;\n\t\twhile (!iterator.eol()) {\n\t\t\tconst codePoint = strings.getNextCodePoint(text, textLen, iterator.offset);\n\t\t\titerator.nextGraphemeLength();\n\n\t\t\tresult = this._nextVisibleColumn(codePoint, result, tabSize);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Returns a column from a visible column.\n\t * @see {@link CursorColumns}\n\t */\n\tpublic static columnFromVisibleColumn(lineContent: string, visibleColumn: number, tabSize: number): number {\n\t\tif (visibleColumn <= 0) {\n\t\t\treturn 1;\n\t\t}\n\n\t\tconst lineContentLength = lineContent.length;\n\t\tconst iterator = new strings.GraphemeIterator(lineContent);\n\n\t\tlet beforeVisibleColumn = 0;\n\t\tlet beforeColumn = 1;\n\t\twhile (!iterator.eol()) {\n\t\t\tconst codePoint = strings.getNextCodePoint(lineContent, lineContentLength, iterator.offset);\n\t\t\titerator.nextGraphemeLength();\n\n\t\t\tconst afterVisibleColumn = this._nextVisibleColumn(codePoint, beforeVisibleColumn, tabSize);\n\t\t\tconst afterColumn = iterator.offset + 1;\n\n\t\t\tif (afterVisibleColumn >= visibleColumn) {\n\t\t\t\tconst beforeDelta = visibleColumn - beforeVisibleColumn;\n\t\t\t\tconst afterDelta = afterVisibleColumn - visibleColumn;\n\t\t\t\tif (afterDelta < beforeDelta) {\n\t\t\t\t\treturn afterColumn;\n\t\t\t\t} else {\n\t\t\t\t\treturn beforeColumn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tbeforeVisibleColumn = afterVisibleColumn;\n\t\t\tbeforeColumn = afterColumn;\n\t\t}\n\n\t\t// walked the entire string\n\t\treturn lineContentLength + 1;\n\t}\n\n\t/**\n\t * ATTENTION: This works with 0-based columns (as opposed to the regular 1-based columns)\n\t * @see {@link CursorColumns}\n\t */\n\tpublic static nextRenderTabStop(visibleColumn: number, tabSize: number): number {\n\t\treturn visibleColumn + tabSize - visibleColumn % tabSize;\n\t}\n\n\t/**\n\t * ATTENTION: This works with 0-based columns (as opposed to the regular 1-based columns)\n\t * @see {@link CursorColumns}\n\t */\n\tpublic static nextIndentTabStop(visibleColumn: number, indentSize: number): number {\n\t\treturn visibleColumn + indentSize - visibleColumn % indentSize;\n\t}\n\n\t/**\n\t * ATTENTION: This works with 0-based columns (as opposed to the regular 1-based columns)\n\t * @see {@link CursorColumns}\n\t */\n\tpublic static prevRenderTabStop(column: number, tabSize: number): number {\n\t\treturn Math.max(0, column - 1 - (column - 1) % tabSize);\n\t}\n\n\t/**\n\t * ATTENTION: This works with 0-based columns (as opposed to the regular 1-based columns)\n\t * @see {@link CursorColumns}\n\t */\n\tpublic static prevIndentTabStop(column: number, indentSize: number): number {\n\t\treturn Math.max(0, column - 1 - (column - 1) % indentSize);\n\t}\n}\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\nimport { CharCode } from 'vs/base/common/charCode';\n\nexport const enum StringEOL {\n\tUnknown = 0,\n\tInvalid = 3,\n\tLF = 1,\n\tCRLF = 2\n}\n\nexport function countEOL(text: string): [number, number, number, StringEOL] {\n\tlet eolCount = 0;\n\tlet firstLineLength = 0;\n\tlet lastLineStart = 0;\n\tlet eol: StringEOL = StringEOL.Unknown;\n\tfor (let i = 0, len = text.length; i < len; i++) {\n\t\tconst chr = text.charCodeAt(i);\n\n\t\tif (chr === CharCode.CarriageReturn) {\n\t\t\tif (eolCount === 0) {\n\t\t\t\tfirstLineLength = i;\n\t\t\t}\n\t\t\teolCount++;\n\t\t\tif (i + 1 < len && text.charCodeAt(i + 1) === CharCode.LineFeed) {\n\t\t\t\t// \\r\\n... case\n\t\t\t\teol |= StringEOL.CRLF;\n\t\t\t\ti++; // skip \\n\n\t\t\t} else {\n\t\t\t\t// \\r... case\n\t\t\t\teol |= StringEOL.Invalid;\n\t\t\t}\n\t\t\tlastLineStart = i + 1;\n\t\t} else if (chr === CharCode.LineFeed) {\n\t\t\t// \\n... case\n\t\t\teol |= StringEOL.LF;\n\t\t\tif (eolCount === 0) {\n\t\t\t\tfirstLineLength = i;\n\t\t\t}\n\t\t\teolCount++;\n\t\t\tlastLineStart = i + 1;\n\t\t}\n\t}\n\tif (eolCount === 0) {\n\t\tfirstLineLength = text.length;\n\t}\n\treturn [eolCount, firstLineLength, text.length - lastLineStart, eol];\n}\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\nimport * as strings from 'vs/base/common/strings';\nimport { CursorColumns } from 'vs/editor/common/core/cursorColumns';\n\nfunction _normalizeIndentationFromWhitespace(str: string, indentSize: number, insertSpaces: boolean): string {\n\tlet spacesCnt = 0;\n\tfor (let i = 0; i < str.length; i++) {\n\t\tif (str.charAt(i) === '\\t') {\n\t\t\tspacesCnt = CursorColumns.nextIndentTabStop(spacesCnt, indentSize);\n\t\t} else {\n\t\t\tspacesCnt++;\n\t\t}\n\t}\n\n\tlet result = '';\n\tif (!insertSpaces) {\n\t\tconst tabsCnt = Math.floor(spacesCnt / indentSize);\n\t\tspacesCnt = spacesCnt % indentSize;\n\t\tfor (let i = 0; i < tabsCnt; i++) {\n\t\t\tresult += '\\t';\n\t\t}\n\t}\n\n\tfor (let i = 0; i < spacesCnt; i++) {\n\t\tresult += ' ';\n\t}\n\n\treturn result;\n}\n\nexport function normalizeIndentation(str: string, indentSize: number, insertSpaces: boolean): string {\n\tlet firstNonWhitespaceIndex = strings.firstNonWhitespaceIndex(str);\n\tif (firstNonWhitespaceIndex === -1) {\n\t\tfirstNonWhitespaceIndex = str.length;\n\t}\n\treturn _normalizeIndentationFromWhitespace(str.substring(0, firstNonWhitespaceIndex), indentSize, insertSpaces) + str.substring(firstNonWhitespaceIndex);\n}\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\nimport { BugIndicatingError } from 'vs/base/common/errors';\n\nexport interface IOffsetRange {\n}\n\n/**\n * A range of offsets (0-based).\n*/\nexport class OffsetRange implements IOffsetRange {\n\tpublic static addRange(range: OffsetRange, sortedRanges: OffsetRange[]): void {\n\t\tlet i = 0;\n\t\twhile (i < sortedRanges.length && sortedRanges[i].endExclusive < range.start) {\n\t\t\ti++;\n\t\t}\n\t\tlet j = i;\n\t\twhile (j < sortedRanges.length && sortedRanges[j].start <= range.endExclusive) {\n\t\t\tj++;\n\t\t}\n\t\tif (i === j) {\n\t\t\tsortedRanges.splice(i, 0, range);\n\t\t} else {\n\t\t\tconst start = Math.min(range.start, sortedRanges[i].start);\n\t\t\tconst end = Math.max(range.endExclusive, sortedRanges[j - 1].endExclusive);\n\t\t\tsortedRanges.splice(i, j - i, new OffsetRange(start, end));\n\t\t}\n\t}\n\n\tpublic static tryCreate(start: number, endExclusive: number): OffsetRange | undefined {\n\t\tif (start > endExclusive) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn new OffsetRange(start, endExclusive);\n\t}\n\n\tpublic static ofLength(length: number): OffsetRange {\n\t\treturn new OffsetRange(0, length);\n\t}\n\n\tpublic static ofStartAndLength(start: number, length: number): OffsetRange {\n\t\treturn new OffsetRange(start, start + length);\n\t}\n\n\tconstructor(public readonly start: number, public readonly endExclusive: number) {\n\t\tif (start > endExclusive) {\n\t\t\tthrow new BugIndicatingError(`Invalid range: ${this.toString()}`);\n\t\t}\n\t}\n\n\tget isEmpty(): boolean {\n\t\treturn this.start === this.endExclusive;\n\t}\n\n\tpublic delta(offset: number): OffsetRange {\n\t\treturn new OffsetRange(this.start + offset, this.endExclusive + offset);\n\t}\n\n\tpublic deltaStart(offset: number): OffsetRange {\n\t\treturn new OffsetRange(this.start + offset, this.endExclusive);\n\t}\n\n\tpublic deltaEnd(offset: number): OffsetRange {\n\t\treturn new OffsetRange(this.start, this.endExclusive + offset);\n\t}\n\n\tpublic get length(): number {\n\t\treturn this.endExclusive - this.start;\n\t}\n\n\tpublic toString() {\n\t\treturn `[${this.start}, ${this.endExclusive})`;\n\t}\n\n\tpublic contains(offset: number): boolean {\n\t\treturn this.start <= offset && offset < this.endExclusive;\n\t}\n\n\t/**\n\t * for all numbers n: range1.contains(n) or range2.contains(n) => range1.join(range2).contains(n)\n\t * The joined range is the smallest range that contains both ranges.\n\t */\n\tpublic join(other: OffsetRange): OffsetRange {\n\t\treturn new OffsetRange(Math.min(this.start, other.start), Math.max(this.endExclusive, other.endExclusive));\n\t}\n\n\t/**\n\t * for all numbers n: range1.contains(n) and range2.contains(n) <=> range1.intersect(range2).contains(n)\n\t *\n\t * The resulting range is empty if the ranges do not intersect, but touch.\n\t * If the ranges don't even touch, the result is undefined.\n\t */\n\tpublic intersect(other: OffsetRange): OffsetRange | undefined {\n\t\tconst start = Math.max(this.start, other.start);\n\t\tconst end = Math.min(this.endExclusive, other.endExclusive);\n\t\tif (start <= end) {\n\t\t\treturn new OffsetRange(start, end);\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tpublic intersects(other: OffsetRange): boolean {\n\t\tconst start = Math.max(this.start, other.start);\n\t\tconst end = Math.min(this.endExclusive, other.endExclusive);\n\t\treturn start < end;\n\t}\n\n\tpublic isBefore(other: OffsetRange): boolean {\n\t\treturn this.endExclusive <= other.start;\n\t}\n\n\tpublic isAfter(other: OffsetRange): boolean {\n\t\treturn this.start >= other.endExclusive;\n\t}\n\n\tpublic slice(arr: T[]): T[] {\n\t\treturn arr.slice(this.start, this.endExclusive);\n\t}\n\n\tpublic substring(str: string): string {\n\t\treturn str.substring(this.start, this.endExclusive);\n\t}\n\n\t/**\n\t * Returns the given value if it is contained in this instance, otherwise the closest value that is contained.\n\t * The range must not be empty.\n\t */\n\tpublic clip(value: number): number {\n\t\tif (this.isEmpty) {\n\t\t\tthrow new BugIndicatingError(`Invalid clipping range: ${this.toString()}`);\n\t\t}\n\t\treturn Math.max(this.start, Math.min(this.endExclusive - 1, value));\n\t}\n\n\t/**\n\t * Returns `r := value + k * length` such that `r` is contained in this range.\n\t * The range must not be empty.\n\t *\n\t * E.g. `[5, 10).clipCyclic(10) === 5`, `[5, 10).clipCyclic(11) === 6` and `[5, 10).clipCyclic(4) === 9`.\n\t */\n\tpublic clipCyclic(value: number): number {\n\t\tif (this.isEmpty) {\n\t\t\tthrow new BugIndicatingError(`Invalid clipping range: ${this.toString()}`);\n\t\t}\n\t\tif (value < this.start) {\n\t\t\treturn this.endExclusive - ((this.start - value) % this.length);\n\t\t}\n\t\tif (value >= this.endExclusive) {\n\t\t\treturn this.start + ((value - this.start) % this.length);\n\t\t}\n\t\treturn value;\n\t}\n\n\tpublic forEach(f: (offset: number) => void): void {\n\t\tfor (let i = this.start; i < this.endExclusive; i++) {\n\t\t\tf(i);\n\t\t}\n\t}\n}\n\nexport class OffsetRangeSet {\n\tprivate readonly _sortedRanges: OffsetRange[] = [];\n\n\tpublic addRange(range: OffsetRange): void {\n\t\tlet i = 0;\n\t\twhile (i < this._sortedRanges.length && this._sortedRanges[i].endExclusive < range.start) {\n\t\t\ti++;\n\t\t}\n\t\tlet j = i;\n\t\twhile (j < this._sortedRanges.length && this._sortedRanges[j].start <= range.endExclusive) {\n\t\t\tj++;\n\t\t}\n\t\tif (i === j) {\n\t\t\tthis._sortedRanges.splice(i, 0, range);\n\t\t} else {\n\t\t\tconst start = Math.min(range.start, this._sortedRanges[i].start);\n\t\t\tconst end = Math.max(range.endExclusive, this._sortedRanges[j - 1].endExclusive);\n\t\t\tthis._sortedRanges.splice(i, j - i, new OffsetRange(start, end));\n\t\t}\n\t}\n\n\tpublic toString(): string {\n\t\treturn this._sortedRanges.map(r => r.toString()).join(', ');\n\t}\n\n\t/**\n\t * Returns of there is a value that is contained in this instance and the given range.\n\t */\n\tpublic intersectsStrict(other: OffsetRange): boolean {\n\t\t// TODO use binary search\n\t\tlet i = 0;\n\t\twhile (i < this._sortedRanges.length && this._sortedRanges[i].endExclusive <= other.start) {\n\t\t\ti++;\n\t\t}\n\t\treturn i < this._sortedRanges.length && this._sortedRanges[i].start < other.endExclusive;\n\t}\n\n\tpublic intersectWithRange(other: OffsetRange): OffsetRangeSet {\n\t\t// TODO use binary search + slice\n\t\tconst result = new OffsetRangeSet();\n\t\tfor (const range of this._sortedRanges) {\n\t\t\tconst intersection = range.intersect(other);\n\t\t\tif (intersection) {\n\t\t\t\tresult.addRange(intersection);\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tpublic intersectWithRangeLength(other: OffsetRange): number {\n\t\treturn this.intersectWithRange(other).length;\n\t}\n\n\tpublic get length(): number {\n\t\treturn this._sortedRanges.reduce((prev, cur) => prev + cur.length, 0);\n\t}\n}\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 * A position in the editor. This interface is suitable for serialization.\n */\nexport interface IPosition {\n\t/**\n\t * line number (starts at 1)\n\t */\n\treadonly lineNumber: number;\n\t/**\n\t * column (the first character in a line is between column 1 and column 2)\n\t */\n\treadonly column: number;\n}\n\n/**\n * A position in the editor.\n */\nexport class Position {\n\t/**\n\t * line number (starts at 1)\n\t */\n\tpublic readonly lineNumber: number;\n\t/**\n\t * column (the first character in a line is between column 1 and column 2)\n\t */\n\tpublic readonly column: number;\n\n\tconstructor(lineNumber: number, column: number) {\n\t\tthis.lineNumber = lineNumber;\n\t\tthis.column = column;\n\t}\n\n\t/**\n\t * Create a new position from this position.\n\t *\n\t * @param newLineNumber new line number\n\t * @param newColumn new column\n\t */\n\twith(newLineNumber: number = this.lineNumber, newColumn: number = this.column): Position {\n\t\tif (newLineNumber === this.lineNumber && newColumn === this.column) {\n\t\t\treturn this;\n\t\t} else {\n\t\t\treturn new Position(newLineNumber, newColumn);\n\t\t}\n\t}\n\n\t/**\n\t * Derive a new position from this position.\n\t *\n\t * @param deltaLineNumber line number delta\n\t * @param deltaColumn column delta\n\t */\n\tdelta(deltaLineNumber: number = 0, deltaColumn: number = 0): Position {\n\t\treturn this.with(this.lineNumber + deltaLineNumber, this.column + deltaColumn);\n\t}\n\n\t/**\n\t * Test if this position equals other position\n\t */\n\tpublic equals(other: IPosition): boolean {\n\t\treturn Position.equals(this, other);\n\t}\n\n\t/**\n\t * Test if position `a` equals position `b`\n\t */\n\tpublic static equals(a: IPosition | null, b: IPosition | null): boolean {\n\t\tif (!a && !b) {\n\t\t\treturn true;\n\t\t}\n\t\treturn (\n\t\t\t!!a &&\n\t\t\t!!b &&\n\t\t\ta.lineNumber === b.lineNumber &&\n\t\t\ta.column === b.column\n\t\t);\n\t}\n\n\t/**\n\t * Test if this position is before other position.\n\t * If the two positions are equal, the result will be false.\n\t */\n\tpublic isBefore(other: IPosition): boolean {\n\t\treturn Position.isBefore(this, other);\n\t}\n\n\t/**\n\t * Test if position `a` is before position `b`.\n\t * If the two positions are equal, the result will be false.\n\t */\n\tpublic static isBefore(a: IPosition, b: IPosition): boolean {\n\t\tif (a.lineNumber < b.lineNumber) {\n\t\t\treturn true;\n\t\t}\n\t\tif (b.lineNumber < a.lineNumber) {\n\t\t\treturn false;\n\t\t}\n\t\treturn a.column < b.column;\n\t}\n\n\t/**\n\t * Test if this position is before other position.\n\t * If the two positions are equal, the result will be true.\n\t */\n\tpublic isBeforeOrEqual(other: IPosition): boolean {\n\t\treturn Position.isBeforeOrEqual(this, other);\n\t}\n\n\t/**\n\t * Test if position `a` is before position `b`.\n\t * If the two positions are equal, the result will be true.\n\t */\n\tpublic static isBeforeOrEqual(a: IPosition, b: IPosition): boolean {\n\t\tif (a.lineNumber < b.lineNumber) {\n\t\t\treturn true;\n\t\t}\n\t\tif (b.lineNumber < a.lineNumber) {\n\t\t\treturn false;\n\t\t}\n\t\treturn a.column <= b.column;\n\t}\n\n\t/**\n\t * A function that compares positions, useful for sorting\n\t */\n\tpublic static compare(a: IPosition, b: IPosition): number {\n\t\tconst aLineNumber = a.lineNumber | 0;\n\t\tconst bLineNumber = b.lineNumber | 0;\n\n\t\tif (aLineNumber === bLineNumber) {\n\t\t\tconst aColumn = a.column | 0;\n\t\t\tconst bColumn = b.column | 0;\n\t\t\treturn aColumn - bColumn;\n\t\t}\n\n\t\treturn aLineNumber - bLineNumber;\n\t}\n\n\t/**\n\t * Clone this position.\n\t */\n\tpublic clone(): Position {\n\t\treturn new Position(this.lineNumber, this.column);\n\t}\n\n\t/**\n\t * Convert to a human-readable representation.\n\t */\n\tpublic toString(): string {\n\t\treturn '(' + this.lineNumber + ',' + this.column + ')';\n\t}\n\n\t// ---\n\n\t/**\n\t * Create a `Position` from an `IPosition`.\n\t */\n\tpublic static lift(pos: IPosition): Position {\n\t\treturn new Position(pos.lineNumber, pos.column);\n\t}\n\n\t/**\n\t * Test if `obj` is an `IPosition`.\n\t */\n\tpublic static isIPosition(obj: any): obj is IPosition {\n\t\treturn (\n\t\t\tobj\n\t\t\t&& (typeof obj.lineNumber === 'number')\n\t\t\t&& (typeof obj.column === 'number')\n\t\t);\n\t}\n\n\tpublic toJSON(): IPosition {\n\t\treturn {\n\t\t\tlineNumber: this.lineNumber,\n\t\t\tcolumn: this.column\n\t\t};\n\t}\n}\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\nimport { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';\nimport { IEditorMouseEvent, IMouseTarget, IMouseTargetViewZoneData, IPartialEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser';\nimport { ICoordinatesConverter } from 'vs/editor/common/viewModel';\nimport { IMouseWheelEvent } from 'vs/base/browser/mouseEvent';\nimport { Position } from 'vs/editor/common/core/position';\n\nexport interface EventCallback {\n\t(event: T): void;\n}\n\nexport class ViewUserInputEvents {\n\n\tpublic onKeyDown: EventCallback | null = null;\n\tpublic onKeyUp: EventCallback | null = null;\n\tpublic onContextMenu: EventCallback | null = null;\n\tpublic onMouseMove: EventCallback | null = null;\n\tpublic onMouseLeave: EventCallback | null = null;\n\tpublic onMouseDown: EventCallback | null = null;\n\tpublic onMouseUp: EventCallback | null = null;\n\tpublic onMouseDrag: EventCallback | null = null;\n\tpublic onMouseDrop: EventCallback | null = null;\n\tpublic onMouseDropCanceled: EventCallback | null = null;\n\tpublic onMouseWheel: EventCallback | null = null;\n\n\tprivate readonly _coordinatesConverter: ICoordinatesConverter;\n\n\tconstructor(coordinatesConverter: ICoordinatesConverter) {\n\t\tthis._coordinatesConverter = coordinatesConverter;\n\t}\n\n\tpublic emitKeyDown(e: IKeyboardEvent): void {\n\t\tthis.onKeyDown?.(e);\n\t}\n\n\tpublic emitKeyUp(e: IKeyboardEvent): void {\n\t\tthis.onKeyUp?.(e);\n\t}\n\n\tpublic emitContextMenu(e: IEditorMouseEvent): void {\n\t\tthis.onContextMenu?.(this._convertViewToModelMouseEvent(e));\n\t}\n\n\tpublic emitMouseMove(e: IEditorMouseEvent): void {\n\t\tthis.onMouseMove?.(this._convertViewToModelMouseEvent(e));\n\t}\n\n\tpublic emitMouseLeave(e: IPartialEditorMouseEvent): void {\n\t\tthis.onMouseLeave?.(this._convertViewToModelMouseEvent(e));\n\t}\n\n\tpublic emitMouseDown(e: IEditorMouseEvent): void {\n\t\tthis.onMouseDown?.(this._convertViewToModelMouseEvent(e));\n\t}\n\n\tpublic emitMouseUp(e: IEditorMouseEvent): void {\n\t\tthis.onMouseUp?.(this._convertViewToModelMouseEvent(e));\n\t}\n\n\tpublic emitMouseDrag(e: IEditorMouseEvent): void {\n\t\tthis.onMouseDrag?.(this._convertViewToModelMouseEvent(e));\n\t}\n\n\tpublic emitMouseDrop(e: IPartialEditorMouseEvent): void {\n\t\tthis.onMouseDrop?.(this._convertViewToModelMouseEvent(e));\n\t}\n\n\tpublic emitMouseDropCanceled(): void {\n\t\tthis.onMouseDropCanceled?.();\n\t}\n\n\tpublic emitMouseWheel(e: IMouseWheelEvent): void {\n\t\tthis.onMouseWheel?.(e);\n\t}\n\n\tprivate _convertViewToModelMouseEvent(e: IEditorMouseEvent): IEditorMouseEvent;\n\tprivate _convertViewToModelMouseEvent(e: IPartialEditorMouseEvent): IPartialEditorMouseEvent;\n\tprivate _convertViewToModelMouseEvent(e: IEditorMouseEvent | IPartialEditorMouseEvent): IEditorMouseEvent | IPartialEditorMouseEvent {\n\t\tif (e.target) {\n\t\t\treturn {\n\t\t\t\tevent: e.event,\n\t\t\t\ttarget: this._convertViewToModelMouseTarget(e.target)\n\t\t\t};\n\t\t}\n\t\treturn e;\n\t}\n\n\tprivate _convertViewToModelMouseTarget(target: IMouseTarget): IMouseTarget {\n\t\treturn ViewUserInputEvents.convertViewToModelMouseTarget(target, this._coordinatesConverter);\n\t}\n\n\tpublic static convertViewToModelMouseTarget(target: IMouseTarget, coordinatesConverter: ICoordinatesConverter): IMouseTarget {\n\t\tconst result = { ...target };\n\t\tif (result.position) {\n\t\t\tresult.position = coordinatesConverter.convertViewPositionToModelPosition(result.position);\n\t\t}\n\t\tif (result.range) {\n\t\t\tresult.range = coordinatesConverter.convertViewRangeToModelRange(result.range);\n\t\t}\n\t\tif (result.type === MouseTargetType.GUTTER_VIEW_ZONE || result.type === MouseTargetType.CONTENT_VIEW_ZONE) {\n\t\t\tresult.detail = this.convertViewToModelViewZoneData(result.detail, coordinatesConverter);\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate static convertViewToModelViewZoneData(data: IMouseTargetViewZoneData, coordinatesConverter: ICoordinatesConverter): IMouseTargetViewZoneData {\n\t\treturn {\n\t\t\tviewZoneId: data.viewZoneId,\n\t\t\tpositionBefore: data.positionBefore ? coordinatesConverter.convertViewPositionToModelPosition(data.positionBefore) : data.positionBefore,\n\t\t\tpositionAfter: data.positionAfter ? coordinatesConverter.convertViewPositionToModelPosition(data.positionAfter) : data.positionAfter,\n\t\t\tposition: coordinatesConverter.convertViewPositionToModelPosition(data.position),\n\t\t\tafterLineNumber: coordinatesConverter.convertViewPositionToModelPosition(new Position(data.afterLineNumber, 1)).lineNumber,\n\t\t};\n\t}\n}\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\nimport { IPosition, Position } from 'vs/editor/common/core/position';\n\n/**\n * A range in the editor. This interface is suitable for serialization.\n */\nexport interface IRange {\n\t/**\n\t * Line number on which the range starts (starts at 1).\n\t */\n\treadonly startLineNumber: number;\n\t/**\n\t * Column on which the range starts in line `startLineNumber` (starts at 1).\n\t */\n\treadonly startColumn: number;\n\t/**\n\t * Line number on which the range ends.\n\t */\n\treadonly endLineNumber: number;\n\t/**\n\t * Column on which the range ends in line `endLineNumber`.\n\t */\n\treadonly endColumn: number;\n}\n\n/**\n * A range in the editor. (startLineNumber,startColumn) is <= (endLineNumber,endColumn)\n */\nexport class Range {\n\n\t/**\n\t * Line number on which the range starts (starts at 1).\n\t */\n\tpublic readonly startLineNumber: number;\n\t/**\n\t * Column on which the range starts in line `startLineNumber` (starts at 1).\n\t */\n\tpublic readonly startColumn: number;\n\t/**\n\t * Line number on which the range ends.\n\t */\n\tpublic readonly endLineNumber: number;\n\t/**\n\t * Column on which the range ends in line `endLineNumber`.\n\t */\n\tpublic readonly endColumn: number;\n\n\tconstructor(startLineNumber: number, startColumn: number, endLineNumber: number, endColumn: number) {\n\t\tif ((startLineNumber > endLineNumber) || (startLineNumber === endLineNumber && startColumn > endColumn)) {\n\t\t\tthis.startLineNumber = endLineNumber;\n\t\t\tthis.startColumn = endColumn;\n\t\t\tthis.endLineNumber = startLineNumber;\n\t\t\tthis.endColumn = startColumn;\n\t\t} else {\n\t\t\tthis.startLineNumber = startLineNumber;\n\t\t\tthis.startColumn = startColumn;\n\t\t\tthis.endLineNumber = endLineNumber;\n\t\t\tthis.endColumn = endColumn;\n\t\t}\n\t}\n\n\t/**\n\t * Test if this range is empty.\n\t */\n\tpublic isEmpty(): boolean {\n\t\treturn Range.isEmpty(this);\n\t}\n\n\t/**\n\t * Test if `range` is empty.\n\t */\n\tpublic static isEmpty(range: IRange): boolean {\n\t\treturn (range.startLineNumber === range.endLineNumber && range.startColumn === range.endColumn);\n\t}\n\n\t/**\n\t * Test if position is in this range. If the position is at the edges, will return true.\n\t */\n\tpublic containsPosition(position: IPosition): boolean {\n\t\treturn Range.containsPosition(this, position);\n\t}\n\n\t/**\n\t * Test if `position` is in `range`. If the position is at the edges, will return true.\n\t */\n\tpublic static containsPosition(range: IRange, position: IPosition): boolean {\n\t\tif (position.lineNumber < range.startLineNumber || position.lineNumber > range.endLineNumber) {\n\t\t\treturn false;\n\t\t}\n\t\tif (position.lineNumber === range.startLineNumber && position.column < range.startColumn) {\n\t\t\treturn false;\n\t\t}\n\t\tif (position.lineNumber === range.endLineNumber && position.column > range.endColumn) {\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Test if `position` is in `range`. If the position is at the edges, will return false.\n\t * @internal\n\t */\n\tpublic static strictContainsPosition(range: IRange, position: IPosition): boolean {\n\t\tif (position.lineNumber < range.startLineNumber || position.lineNumber > range.endLineNumber) {\n\t\t\treturn false;\n\t\t}\n\t\tif (position.lineNumber === range.startLineNumber && position.column <= range.startColumn) {\n\t\t\treturn false;\n\t\t}\n\t\tif (position.lineNumber === range.endLineNumber && position.column >= range.endColumn) {\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Test if range is in this range. If the range is equal to this range, will return true.\n\t */\n\tpublic containsRange(range: IRange): boolean {\n\t\treturn Range.containsRange(this, range);\n\t}\n\n\t/**\n\t * Test if `otherRange` is in `range`. If the ranges are equal, will return true.\n\t */\n\tpublic static containsRange(range: IRange, otherRange: IRange): boolean {\n\t\tif (otherRange.startLineNumber < range.startLineNumber || otherRange.endLineNumber < range.startLineNumber) {\n\t\t\treturn false;\n\t\t}\n\t\tif (otherRange.startLineNumber > range.endLineNumber || otherRange.endLineNumber > range.endLineNumber) {\n\t\t\treturn false;\n\t\t}\n\t\tif (otherRange.startLineNumber === range.startLineNumber && otherRange.startColumn < range.startColumn) {\n\t\t\treturn false;\n\t\t}\n\t\tif (otherRange.endLineNumber === range.endLineNumber && otherRange.endColumn > range.endColumn) {\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\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.\n\t */\n\tpublic strictContainsRange(range: IRange): boolean {\n\t\treturn Range.strictContainsRange(this, range);\n\t}\n\n\t/**\n\t * Test if `otherRange` is strictly in `range` (must start after, and end before). If the ranges are equal, will return false.\n\t */\n\tpublic static strictContainsRange(range: IRange, otherRange: IRange): boolean {\n\t\tif (otherRange.startLineNumber < range.startLineNumber || otherRange.endLineNumber < range.startLineNumber) {\n\t\t\treturn false;\n\t\t}\n\t\tif (otherRange.startLineNumber > range.endLineNumber || otherRange.endLineNumber > range.endLineNumber) {\n\t\t\treturn false;\n\t\t}\n\t\tif (otherRange.startLineNumber === range.startLineNumber && otherRange.startColumn <= range.startColumn) {\n\t\t\treturn false;\n\t\t}\n\t\tif (otherRange.endLineNumber === range.endLineNumber && otherRange.endColumn >= range.endColumn) {\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * A reunion of the two ranges.\n\t * The smallest position will be used as the start point, and the largest one as the end point.\n\t */\n\tpublic plusRange(range: IRange): Range {\n\t\treturn Range.plusRange(this, range);\n\t}\n\n\t/**\n\t * A reunion of the two ranges.\n\t * The smallest position will be used as the start point, and the largest one as the end point.\n\t */\n\tpublic static plusRange(a: IRange, b: IRange): Range {\n\t\tlet startLineNumber: number;\n\t\tlet startColumn: number;\n\t\tlet endLineNumber: number;\n\t\tlet endColumn: number;\n\n\t\tif (b.startLineNumber < a.startLineNumber) {\n\t\t\tstartLineNumber = b.startLineNumber;\n\t\t\tstartColumn = b.startColumn;\n\t\t} else if (b.startLineNumber === a.startLineNumber) {\n\t\t\tstartLineNumber = b.startLineNumber;\n\t\t\tstartColumn = Math.min(b.startColumn, a.startColumn);\n\t\t} else {\n\t\t\tstartLineNumber = a.startLineNumber;\n\t\t\tstartColumn = a.startColumn;\n\t\t}\n\n\t\tif (b.endLineNumber > a.endLineNumber) {\n\t\t\tendLineNumber = b.endLineNumber;\n\t\t\tendColumn = b.endColumn;\n\t\t} else if (b.endLineNumber === a.endLineNumber) {\n\t\t\tendLineNumber = b.endLineNumber;\n\t\t\tendColumn = Math.max(b.endColumn, a.endColumn);\n\t\t} else {\n\t\t\tendLineNumber = a.endLineNumber;\n\t\t\tendColumn = a.endColumn;\n\t\t}\n\n\t\treturn new Range(startLineNumber, startColumn, endLineNumber, endColumn);\n\t}\n\n\t/**\n\t * A intersection of the two ranges.\n\t */\n\tpublic intersectRanges(range: IRange): Range | null {\n\t\treturn Range.intersectRanges(this, range);\n\t}\n\n\t/**\n\t * A intersection of the two ranges.\n\t */\n\tpublic static intersectRanges(a: IRange, b: IRange): Range | null {\n\t\tlet resultStartLineNumber = a.startLineNumber;\n\t\tlet resultStartColumn = a.startColumn;\n\t\tlet resultEndLineNumber = a.endLineNumber;\n\t\tlet resultEndColumn = a.endColumn;\n\t\tconst otherStartLineNumber = b.startLineNumber;\n\t\tconst otherStartColumn = b.startColumn;\n\t\tconst otherEndLineNumber = b.endLineNumber;\n\t\tconst otherEndColumn = b.endColumn;\n\n\t\tif (resultStartLineNumber < otherStartLineNumber) {\n\t\t\tresultStartLineNumber = otherStartLineNumber;\n\t\t\tresultStartColumn = otherStartColumn;\n\t\t} else if (resultStartLineNumber === otherStartLineNumber) {\n\t\t\tresultStartColumn = Math.max(resultStartColumn, otherStartColumn);\n\t\t}\n\n\t\tif (resultEndLineNumber > otherEndLineNumber) {\n\t\t\tresultEndLineNumber = otherEndLineNumber;\n\t\t\tresultEndColumn = otherEndColumn;\n\t\t} else if (resultEndLineNumber === otherEndLineNumber) {\n\t\t\tresultEndColumn = Math.min(resultEndColumn, otherEndColumn);\n\t\t}\n\n\t\t// Check if selection is now empty\n\t\tif (resultStartLineNumber > resultEndLineNumber) {\n\t\t\treturn null;\n\t\t}\n\t\tif (resultStartLineNumber === resultEndLineNumber && resultStartColumn > resultEndColumn) {\n\t\t\treturn null;\n\t\t}\n\t\treturn new Range(resultStartLineNumber, resultStartColumn, resultEndLineNumber, resultEndColumn);\n\t}\n\n\t/**\n\t * Test if this range equals other.\n\t */\n\tpublic equalsRange(other: IRange | null | undefined): boolean {\n\t\treturn Range.equalsRange(this, other);\n\t}\n\n\t/**\n\t * Test if range `a` equals `b`.\n\t */\n\tpublic static equalsRange(a: IRange | null | undefined, b: IRange | null | undefined): boolean {\n\t\tif (!a && !b) {\n\t\t\treturn true;\n\t\t}\n\t\treturn (\n\t\t\t!!a &&\n\t\t\t!!b &&\n\t\t\ta.startLineNumber === b.startLineNumber &&\n\t\t\ta.startColumn === b.startColumn &&\n\t\t\ta.endLineNumber === b.endLineNumber &&\n\t\t\ta.endColumn === b.endColumn\n\t\t);\n\t}\n\n\t/**\n\t * Return the end position (which will be after or equal to the start position)\n\t */\n\tpublic getEndPosition(): Position {\n\t\treturn Range.getEndPosition(this);\n\t}\n\n\t/**\n\t * Return the end position (which will be after or equal to the start position)\n\t */\n\tpublic static getEndPosition(range: IRange): Position {\n\t\treturn new Position(range.endLineNumber, range.endColumn);\n\t}\n\n\t/**\n\t * Return the start position (which will be before or equal to the end position)\n\t */\n\tpublic getStartPosition(): Position {\n\t\treturn Range.getStartPosition(this);\n\t}\n\n\t/**\n\t * Return the start position (which will be before or equal to the end position)\n\t */\n\tpublic static getStartPosition(range: IRange): Position {\n\t\treturn new Position(range.startLineNumber, range.startColumn);\n\t}\n\n\t/**\n\t * Transform to a user presentable string representation.\n\t */\n\tpublic toString(): string {\n\t\treturn '[' + this.startLineNumber + ',' + this.startColumn + ' -> ' + this.endLineNumber + ',' + this.endColumn + ']';\n\t}\n\n\t/**\n\t * Create a new range using this range's start position, and using endLineNumber and endColumn as the end position.\n\t */\n\tpublic setEndPosition(endLineNumber: number, endColumn: number): Range {\n\t\treturn new Range(this.startLineNumber, this.startColumn, endLineNumber, endColumn);\n\t}\n\n\t/**\n\t * Create a new range using this range's end position, and using startLineNumber and startColumn as the start position.\n\t */\n\tpublic setStartPosition(startLineNumber: number, startColumn: number): Range {\n\t\treturn new Range(startLineNumber, startColumn, this.endLineNumber, this.endColumn);\n\t}\n\n\t/**\n\t * Create a new empty range using this range's start position.\n\t */\n\tpublic collapseToStart(): Range {\n\t\treturn Range.collapseToStart(this);\n\t}\n\n\t/**\n\t * Create a new empty range using this range's start position.\n\t */\n\tpublic static collapseToStart(range: IRange): Range {\n\t\treturn new Range(range.startLineNumber, range.startColumn, range.startLineNumber, range.startColumn);\n\t}\n\n\t/**\n\t * Create a new empty range using this range's end position.\n\t */\n\tpublic collapseToEnd(): Range {\n\t\treturn Range.collapseToEnd(this);\n\t}\n\n\t/**\n\t * Create a new empty range using this range's end position.\n\t */\n\tpublic static collapseToEnd(range: IRange): Range {\n\t\treturn new Range(range.endLineNumber, range.endColumn, range.endLineNumber, range.endColumn);\n\t}\n\n\t/**\n\t * Moves the range by the given amount of lines.\n\t */\n\tpublic delta(lineCount: number): Range {\n\t\treturn new Range(this.startLineNumber + lineCount, this.startColumn, this.endLineNumber + lineCount, this.endColumn);\n\t}\n\n\t// ---\n\n\tpublic static fromPositions(start: IPosition, end: IPosition = start): Range {\n\t\treturn new Range(start.lineNumber, start.column, end.lineNumber, end.column);\n\t}\n\n\t/**\n\t * Create a `Range` from an `IRange`.\n\t */\n\tpublic static lift(range: undefined | null): null;\n\tpublic static lift(range: IRange): Range;\n\tpublic static lift(range: IRange | undefined | null): Range | null;\n\tpublic static lift(range: IRange | undefined | null): Range | null {\n\t\tif (!range) {\n\t\t\treturn null;\n\t\t}\n\t\treturn new Range(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn);\n\t}\n\n\t/**\n\t * Test if `obj` is an `IRange`.\n\t */\n\tpublic static isIRange(obj: any): obj is IRange {\n\t\treturn (\n\t\t\tobj\n\t\t\t&& (typeof obj.startLineNumber === 'number')\n\t\t\t&& (typeof obj.startColumn === 'number')\n\t\t\t&& (typeof obj.endLineNumber === 'number')\n\t\t\t&& (typeof obj.endColumn === 'number')\n\t\t);\n\t}\n\n\t/**\n\t * Test if the two ranges are touching in any way.\n\t */\n\tpublic static areIntersectingOrTouching(a: IRange, b: IRange): boolean {\n\t\t// Check if `a` is before `b`\n\t\tif (a.endLineNumber < b.startLineNumber || (a.endLineNumber === b.startLineNumber && a.endColumn < b.startColumn)) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Check if `b` is before `a`\n\t\tif (b.endLineNumber < a.startLineNumber || (b.endLineNumber === a.startLineNumber && b.endColumn < a.startColumn)) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// These ranges must intersect\n\t\treturn true;\n\t}\n\n\t/**\n\t * Test if the two ranges are intersecting. If the ranges are touching it returns true.\n\t */\n\tpublic static areIntersecting(a: IRange, b: IRange): boolean {\n\t\t// Check if `a` is before `b`\n\t\tif (a.endLineNumber < b.startLineNumber || (a.endLineNumber === b.startLineNumber && a.endColumn <= b.startColumn)) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Check if `b` is before `a`\n\t\tif (b.endLineNumber < a.startLineNumber || (b.endLineNumber === a.startLineNumber && b.endColumn <= a.startColumn)) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// These ranges must intersect\n\t\treturn true;\n\t}\n\n\t/**\n\t * A function that compares ranges, useful for sorting ranges\n\t * It will first compare ranges on the startPosition and then on the endPosition\n\t */\n\tpublic static compareRangesUsingStarts(a: IRange | null | undefined, b: IRange | null | undefined): number {\n\t\tif (a && b) {\n\t\t\tconst aStartLineNumber = a.startLineNumber | 0;\n\t\t\tconst bStartLineNumber = b.startLineNumber | 0;\n\n\t\t\tif (aStartLineNumber === bStartLineNumber) {\n\t\t\t\tconst aStartColumn = a.startColumn | 0;\n\t\t\t\tconst bStartColumn = b.startColumn | 0;\n\n\t\t\t\tif (aStartColumn === bStartColumn) {\n\t\t\t\t\tconst aEndLineNumber = a.endLineNumber | 0;\n\t\t\t\t\tconst bEndLineNumber = b.endLineNumber | 0;\n\n\t\t\t\t\tif (aEndLineNumber === bEndLineNumber) {\n\t\t\t\t\t\tconst aEndColumn = a.endColumn | 0;\n\t\t\t\t\t\tconst bEndColumn = b.endColumn | 0;\n\t\t\t\t\t\treturn aEndColumn - bEndColumn;\n\t\t\t\t\t}\n\t\t\t\t\treturn aEndLineNumber - bEndLineNumber;\n\t\t\t\t}\n\t\t\t\treturn aStartColumn - bStartColumn;\n\t\t\t}\n\t\t\treturn aStartLineNumber - bStartLineNumber;\n\t\t}\n\t\tconst aExists = (a ? 1 : 0);\n\t\tconst bExists = (b ? 1 : 0);\n\t\treturn aExists - bExists;\n\t}\n\n\t/**\n\t * A function that compares ranges, useful for sorting ranges\n\t * It will first compare ranges on the endPosition and then on the startPosition\n\t */\n\tpublic static compareRangesUsingEnds(a: IRange, b: IRange): number {\n\t\tif (a.endLineNumber === b.endLineNumber) {\n\t\t\tif (a.endColumn === b.endColumn) {\n\t\t\t\tif (a.startLineNumber === b.startLineNumber) {\n\t\t\t\t\treturn a.startColumn - b.startColumn;\n\t\t\t\t}\n\t\t\t\treturn a.startLineNumber - b.startLineNumber;\n\t\t\t}\n\t\t\treturn a.endColumn - b.endColumn;\n\t\t}\n\t\treturn a.endLineNumber - b.endLineNumber;\n\t}\n\n\t/**\n\t * Test if the range spans multiple lines.\n\t */\n\tpublic static spansMultipleLines(range: IRange): boolean {\n\t\treturn range.endLineNumber > range.startLineNumber;\n\t}\n\n\tpublic toJSON(): IRange {\n\t\treturn this;\n\t}\n}\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\nimport * as strings from 'vs/base/common/strings';\nimport { Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\nimport { EndOfLinePreference } from 'vs/editor/common/model';\n\nexport const _debugComposition = false;\n\nexport interface ITextAreaWrapper {\n\tgetValue(): string;\n\tsetValue(reason: string, value: string): void;\n\n\tgetSelectionStart(): number;\n\tgetSelectionEnd(): number;\n\tsetSelectionRange(reason: string, selectionStart: number, selectionEnd: number): void;\n}\n\nexport interface ISimpleModel {\n\tgetLineCount(): number;\n\tgetLineMaxColumn(lineNumber: number): number;\n\tgetValueInRange(range: Range, eol: EndOfLinePreference): string;\n\tgetValueLengthInRange(range: Range, eol: EndOfLinePreference): number;\n\tmodifyPosition(position: Position, offset: number): Position;\n}\n\nexport interface ITypeData {\n\ttext: string;\n\treplacePrevCharCnt: number;\n\treplaceNextCharCnt: number;\n\tpositionDelta: number;\n}\n\nexport class TextAreaState {\n\n\tpublic static readonly EMPTY = new TextAreaState('', 0, 0, null, undefined);\n\n\tconstructor(\n\t\tpublic readonly value: string,\n\t\t/** the offset where selection starts inside `value` */\n\t\tpublic readonly selectionStart: number,\n\t\t/** the offset where selection ends inside `value` */\n\t\tpublic readonly selectionEnd: number,\n\t\t/** the editor range in the view coordinate system that matches the selection inside `value` */\n\t\tpublic readonly selection: Range | null,\n\t\t/** the visible line count (wrapped, not necessarily matching \\n characters) for the text in `value` before `selectionStart` */\n\t\tpublic readonly newlineCountBeforeSelection: number | undefined,\n\t) { }\n\n\tpublic toString(): string {\n\t\treturn `[ <${this.value}>, selectionStart: ${this.selectionStart}, selectionEnd: ${this.selectionEnd}]`;\n\t}\n\n\tpublic static readFromTextArea(textArea: ITextAreaWrapper, previousState: TextAreaState | null): TextAreaState {\n\t\tconst value = textArea.getValue();\n\t\tconst selectionStart = textArea.getSelectionStart();\n\t\tconst selectionEnd = textArea.getSelectionEnd();\n\t\tlet newlineCountBeforeSelection: number | undefined = undefined;\n\t\tif (previousState) {\n\t\t\tconst valueBeforeSelectionStart = value.substring(0, selectionStart);\n\t\t\tconst previousValueBeforeSelectionStart = previousState.value.substring(0, previousState.selectionStart);\n\t\t\tif (valueBeforeSelectionStart === previousValueBeforeSelectionStart) {\n\t\t\t\tnewlineCountBeforeSelection = previousState.newlineCountBeforeSelection;\n\t\t\t}\n\t\t}\n\t\treturn new TextAreaState(value, selectionStart, selectionEnd, null, newlineCountBeforeSelection);\n\t}\n\n\tpublic collapseSelection(): TextAreaState {\n\t\tif (this.selectionStart === this.value.length) {\n\t\t\treturn this;\n\t\t}\n\t\treturn new TextAreaState(this.value, this.value.length, this.value.length, null, undefined);\n\t}\n\n\tpublic writeToTextArea(reason: string, textArea: ITextAreaWrapper, select: boolean): void {\n\t\tif (_debugComposition) {\n\t\t\tconsole.log(`writeToTextArea ${reason}: ${this.toString()}`);\n\t\t}\n\t\ttextArea.setValue(reason, this.value);\n\t\tif (select) {\n\t\t\ttextArea.setSelectionRange(reason, this.selectionStart, this.selectionEnd);\n\t\t}\n\t}\n\n\tpublic deduceEditorPosition(offset: number): [Position | null, number, number] {\n\t\tif (offset <= this.selectionStart) {\n\t\t\tconst str = this.value.substring(offset, this.selectionStart);\n\t\t\treturn this._finishDeduceEditorPosition(this.selection?.getStartPosition() ?? null, str, -1);\n\t\t}\n\t\tif (offset >= this.selectionEnd) {\n\t\t\tconst str = this.value.substring(this.selectionEnd, offset);\n\t\t\treturn this._finishDeduceEditorPosition(this.selection?.getEndPosition() ?? null, str, 1);\n\t\t}\n\t\tconst str1 = this.value.substring(this.selectionStart, offset);\n\t\tif (str1.indexOf(String.fromCharCode(8230)) === -1) {\n\t\t\treturn this._finishDeduceEditorPosition(this.selection?.getStartPosition() ?? null, str1, 1);\n\t\t}\n\t\tconst str2 = this.value.substring(offset, this.selectionEnd);\n\t\treturn this._finishDeduceEditorPosition(this.selection?.getEndPosition() ?? null, str2, -1);\n\t}\n\n\tprivate _finishDeduceEditorPosition(anchor: Position | null, deltaText: string, signum: number): [Position | null, number, number] {\n\t\tlet lineFeedCnt = 0;\n\t\tlet lastLineFeedIndex = -1;\n\t\twhile ((lastLineFeedIndex = deltaText.indexOf('\\n', lastLineFeedIndex + 1)) !== -1) {\n\t\t\tlineFeedCnt++;\n\t\t}\n\t\treturn [anchor, signum * deltaText.length, lineFeedCnt];\n\t}\n\n\tpublic static deduceInput(previousState: TextAreaState, currentState: TextAreaState, couldBeEmojiInput: boolean): ITypeData {\n\t\tif (!previousState) {\n\t\t\t// This is the EMPTY state\n\t\t\treturn {\n\t\t\t\ttext: '',\n\t\t\t\treplacePrevCharCnt: 0,\n\t\t\t\treplaceNextCharCnt: 0,\n\t\t\t\tpositionDelta: 0\n\t\t\t};\n\t\t}\n\n\t\tif (_debugComposition) {\n\t\t\tconsole.log('------------------------deduceInput');\n\t\t\tconsole.log(`PREVIOUS STATE: ${previousState.toString()}`);\n\t\t\tconsole.log(`CURRENT STATE: ${currentState.toString()}`);\n\t\t}\n\n\t\tconst prefixLength = Math.min(\n\t\t\tstrings.commonPrefixLength(previousState.value, currentState.value),\n\t\t\tpreviousState.selectionStart,\n\t\t\tcurrentState.selectionStart\n\t\t);\n\t\tconst suffixLength = Math.min(\n\t\t\tstrings.commonSuffixLength(previousState.value, currentState.value),\n\t\t\tpreviousState.value.length - previousState.selectionEnd,\n\t\t\tcurrentState.value.length - currentState.selectionEnd\n\t\t);\n\t\tconst previousValue = previousState.value.substring(prefixLength, previousState.value.length - suffixLength);\n\t\tconst currentValue = currentState.value.substring(prefixLength, currentState.value.length - suffixLength);\n\t\tconst previousSelectionStart = previousState.selectionStart - prefixLength;\n\t\tconst previousSelectionEnd = previousState.selectionEnd - prefixLength;\n\t\tconst currentSelectionStart = currentState.selectionStart - prefixLength;\n\t\tconst currentSelectionEnd = currentState.selectionEnd - prefixLength;\n\n\t\tif (_debugComposition) {\n\t\t\tconsole.log(`AFTER DIFFING PREVIOUS STATE: <${previousValue}>, selectionStart: ${previousSelectionStart}, selectionEnd: ${previousSelectionEnd}`);\n\t\t\tconsole.log(`AFTER DIFFING CURRENT STATE: <${currentValue}>, selectionStart: ${currentSelectionStart}, selectionEnd: ${currentSelectionEnd}`);\n\t\t}\n\n\t\tif (currentSelectionStart === currentSelectionEnd) {\n\t\t\t// no current selection\n\t\t\tconst replacePreviousCharacters = (previousState.selectionStart - prefixLength);\n\t\t\tif (_debugComposition) {\n\t\t\t\tconsole.log(`REMOVE PREVIOUS: ${replacePreviousCharacters} chars`);\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\ttext: currentValue,\n\t\t\t\treplacePrevCharCnt: replacePreviousCharacters,\n\t\t\t\treplaceNextCharCnt: 0,\n\t\t\t\tpositionDelta: 0\n\t\t\t};\n\t\t}\n\n\t\t// there is a current selection => composition case\n\t\tconst replacePreviousCharacters = previousSelectionEnd - previousSelectionStart;\n\t\treturn {\n\t\t\ttext: currentValue,\n\t\t\treplacePrevCharCnt: replacePreviousCharacters,\n\t\t\treplaceNextCharCnt: 0,\n\t\t\tpositionDelta: 0\n\t\t};\n\t}\n\n\tpublic static deduceAndroidCompositionInput(previousState: TextAreaState, currentState: TextAreaState): ITypeData {\n\t\tif (!previousState) {\n\t\t\t// This is the EMPTY state\n\t\t\treturn {\n\t\t\t\ttext: '',\n\t\t\t\treplacePrevCharCnt: 0,\n\t\t\t\treplaceNextCharCnt: 0,\n\t\t\t\tpositionDelta: 0\n\t\t\t};\n\t\t}\n\n\t\tif (_debugComposition) {\n\t\t\tconsole.log('------------------------deduceAndroidCompositionInput');\n\t\t\tconsole.log(`PREVIOUS STATE: ${previousState.toString()}`);\n\t\t\tconsole.log(`CURRENT STATE: ${currentState.toString()}`);\n\t\t}\n\n\t\tif (previousState.value === currentState.value) {\n\t\t\treturn {\n\t\t\t\ttext: '',\n\t\t\t\treplacePrevCharCnt: 0,\n\t\t\t\treplaceNextCharCnt: 0,\n\t\t\t\tpositionDelta: currentState.selectionEnd - previousState.selectionEnd\n\t\t\t};\n\t\t}\n\n\t\tconst prefixLength = Math.min(strings.commonPrefixLength(previousState.value, currentState.value), previousState.selectionEnd);\n\t\tconst suffixLength = Math.min(strings.commonSuffixLength(previousState.value, currentState.value), previousState.value.length - previousState.selectionEnd);\n\t\tconst previousValue = previousState.value.substring(prefixLength, previousState.value.length - suffixLength);\n\t\tconst currentValue = currentState.value.substring(prefixLength, currentState.value.length - suffixLength);\n\t\tconst previousSelectionStart = previousState.selectionStart - prefixLength;\n\t\tconst previousSelectionEnd = previousState.selectionEnd - prefixLength;\n\t\tconst currentSelectionStart = currentState.selectionStart - prefixLength;\n\t\tconst currentSelectionEnd = currentState.selectionEnd - prefixLength;\n\n\t\tif (_debugComposition) {\n\t\t\tconsole.log(`AFTER DIFFING PREVIOUS STATE: <${previousValue}>, selectionStart: ${previousSelectionStart}, selectionEnd: ${previousSelectionEnd}`);\n\t\t\tconsole.log(`AFTER DIFFING CURRENT STATE: <${currentValue}>, selectionStart: ${currentSelectionStart}, selectionEnd: ${currentSelectionEnd}`);\n\t\t}\n\n\t\treturn {\n\t\t\ttext: currentValue,\n\t\t\treplacePrevCharCnt: previousSelectionEnd,\n\t\t\treplaceNextCharCnt: previousValue.length - previousSelectionEnd,\n\t\t\tpositionDelta: currentSelectionEnd - currentValue.length\n\t\t};\n\t}\n}\n\nexport class PagedScreenReaderStrategy {\n\tprivate static _getPageOfLine(lineNumber: number, linesPerPage: number): number {\n\t\treturn Math.floor((lineNumber - 1) / linesPerPage);\n\t}\n\n\tprivate static _getRangeForPage(page: number, linesPerPage: number): Range {\n\t\tconst offset = page * linesPerPage;\n\t\tconst startLineNumber = offset + 1;\n\t\tconst endLineNumber = offset + linesPerPage;\n\t\treturn new Range(startLineNumber, 1, endLineNumber + 1, 1);\n\t}\n\n\tpublic static fromEditorSelection(model: ISimpleModel, selection: Range, linesPerPage: number, trimLongText: boolean): TextAreaState {\n\t\t// Chromium handles very poorly text even of a few thousand chars\n\t\t// Cut text to avoid stalling the entire UI\n\t\tconst LIMIT_CHARS = 500;\n\n\t\tconst selectionStartPage = PagedScreenReaderStrategy._getPageOfLine(selection.startLineNumber, linesPerPage);\n\t\tconst selectionStartPageRange = PagedScreenReaderStrategy._getRangeForPage(selectionStartPage, linesPerPage);\n\n\t\tconst selectionEndPage = PagedScreenReaderStrategy._getPageOfLine(selection.endLineNumber, linesPerPage);\n\t\tconst selectionEndPageRange = PagedScreenReaderStrategy._getRangeForPage(selectionEndPage, linesPerPage);\n\n\t\tlet pretextRange = selectionStartPageRange.intersectRanges(new Range(1, 1, selection.startLineNumber, selection.startColumn))!;\n\t\tif (trimLongText && model.getValueLengthInRange(pretextRange, EndOfLinePreference.LF) > LIMIT_CHARS) {\n\t\t\tconst pretextStart = model.modifyPosition(pretextRange.getEndPosition(), -LIMIT_CHARS);\n\t\t\tpretextRange = Range.fromPositions(pretextStart, pretextRange.getEndPosition());\n\t\t}\n\t\tconst pretext = model.getValueInRange(pretextRange, EndOfLinePreference.LF);\n\n\t\tconst lastLine = model.getLineCount();\n\t\tconst lastLineMaxColumn = model.getLineMaxColumn(lastLine);\n\t\tlet posttextRange = selectionEndPageRange.intersectRanges(new Range(selection.endLineNumber, selection.endColumn, lastLine, lastLineMaxColumn))!;\n\t\tif (trimLongText && model.getValueLengthInRange(posttextRange, EndOfLinePreference.LF) > LIMIT_CHARS) {\n\t\t\tconst posttextEnd = model.modifyPosition(posttextRange.getStartPosition(), LIMIT_CHARS);\n\t\t\tposttextRange = Range.fromPositions(posttextRange.getStartPosition(), posttextEnd);\n\t\t}\n\t\tconst posttext = model.getValueInRange(posttextRange, EndOfLinePreference.LF);\n\n\n\t\tlet text: string;\n\t\tif (selectionStartPage === selectionEndPage || selectionStartPage + 1 === selectionEndPage) {\n\t\t\t// take full selection\n\t\t\ttext = model.getValueInRange(selection, EndOfLinePreference.LF);\n\t\t} else {\n\t\t\tconst selectionRange1 = selectionStartPageRange.intersectRanges(selection)!;\n\t\t\tconst selectionRange2 = selectionEndPageRange.intersectRanges(selection)!;\n\t\t\ttext = (\n\t\t\t\tmodel.getValueInRange(selectionRange1, EndOfLinePreference.LF)\n\t\t\t\t+ String.fromCharCode(8230)\n\t\t\t\t+ model.getValueInRange(selectionRange2, EndOfLinePreference.LF)\n\t\t\t);\n\t\t}\n\t\tif (trimLongText && text.length > 2 * LIMIT_CHARS) {\n\t\t\ttext = text.substring(0, LIMIT_CHARS) + String.fromCharCode(8230) + text.substring(text.length - LIMIT_CHARS, text.length);\n\t\t}\n\n\t\treturn new TextAreaState(pretext + text + posttext, pretext.length, pretext.length + text.length, selection, pretextRange.endLineNumber - pretextRange.startLineNumber);\n\t}\n}\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\nimport { Position } from 'vs/editor/common/core/position';\nimport { IRange, Range } from 'vs/editor/common/core/range';\n\n/**\n * A single edit operation, that acts as a simple replace.\n * i.e. Replace text at `range` with `text` in model.\n */\nexport interface ISingleEditOperation {\n\t/**\n\t * The range to replace. This can be empty to emulate a simple insert.\n\t */\n\trange: IRange;\n\t/**\n\t * The text to replace with. This can be null to emulate a simple delete.\n\t */\n\ttext: string | null;\n\t/**\n\t * This indicates that this operation has \"insert\" semantics.\n\t * i.e. forceMoveMarkers = true => if `range` is collapsed, all markers at the position will be moved.\n\t */\n\tforceMoveMarkers?: boolean;\n}\n\nexport class EditOperation {\n\n\tpublic static insert(position: Position, text: string): ISingleEditOperation {\n\t\treturn {\n\t\t\trange: new Range(position.lineNumber, position.column, position.lineNumber, position.column),\n\t\t\ttext: text,\n\t\t\tforceMoveMarkers: true\n\t\t};\n\t}\n\n\tpublic static delete(range: Range): ISingleEditOperation {\n\t\treturn {\n\t\t\trange: range,\n\t\t\ttext: null\n\t\t};\n\t}\n\n\tpublic static replace(range: Range, text: string | null): ISingleEditOperation {\n\t\treturn {\n\t\t\trange: range,\n\t\t\ttext: text\n\t\t};\n\t}\n\n\tpublic static replaceMove(range: Range, text: string | null): ISingleEditOperation {\n\t\treturn {\n\t\t\trange: range,\n\t\t\ttext: text,\n\t\t\tforceMoveMarkers: true\n\t\t};\n\t}\n}\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\nimport * as strings from 'vs/base/common/strings';\nimport { EditOperation, ISingleEditOperation } from 'vs/editor/common/core/editOperation';\nimport { Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\nimport { Selection } from 'vs/editor/common/core/selection';\nimport { ICommand, ICursorStateComputerData, IEditOperationBuilder } from 'vs/editor/common/editorCommon';\nimport { StandardTokenType } from 'vs/editor/common/encodedTokenAttributes';\nimport { ITextModel } from 'vs/editor/common/model';\n\nexport class TrimTrailingWhitespaceCommand implements ICommand {\n\n\tprivate readonly _selection: Selection;\n\tprivate _selectionId: string | null;\n\tprivate readonly _cursors: Position[];\n\tprivate readonly _trimInRegexesAndStrings: boolean;\n\n\tconstructor(selection: Selection, cursors: Position[], trimInRegexesAndStrings: boolean) {\n\t\tthis._selection = selection;\n\t\tthis._cursors = cursors;\n\t\tthis._selectionId = null;\n\t\tthis._trimInRegexesAndStrings = trimInRegexesAndStrings;\n\t}\n\n\tpublic getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {\n\t\tconst ops = trimTrailingWhitespace(model, this._cursors, this._trimInRegexesAndStrings);\n\t\tfor (let i = 0, len = ops.length; i < len; i++) {\n\t\t\tconst op = ops[i];\n\n\t\t\tbuilder.addEditOperation(op.range, op.text);\n\t\t}\n\n\t\tthis._selectionId = builder.trackSelection(this._selection);\n\t}\n\n\tpublic computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {\n\t\treturn helper.getTrackedSelection(this._selectionId!);\n\t}\n}\n\n/**\n * Generate commands for trimming trailing whitespace on a model and ignore lines on which cursors are sitting.\n */\nexport function trimTrailingWhitespace(model: ITextModel, cursors: Position[], trimInRegexesAndStrings: boolean): ISingleEditOperation[] {\n\t// Sort cursors ascending\n\tcursors.sort((a, b) => {\n\t\tif (a.lineNumber === b.lineNumber) {\n\t\t\treturn a.column - b.column;\n\t\t}\n\t\treturn a.lineNumber - b.lineNumber;\n\t});\n\n\t// Reduce multiple cursors on the same line and only keep the last one on the line\n\tfor (let i = cursors.length - 2; i >= 0; i--) {\n\t\tif (cursors[i].lineNumber === cursors[i + 1].lineNumber) {\n\t\t\t// Remove cursor at `i`\n\t\t\tcursors.splice(i, 1);\n\t\t}\n\t}\n\n\tconst r: ISingleEditOperation[] = [];\n\tlet rLen = 0;\n\tlet cursorIndex = 0;\n\tconst cursorLen = cursors.length;\n\n\tfor (let lineNumber = 1, lineCount = model.getLineCount(); lineNumber <= lineCount; lineNumber++) {\n\t\tconst lineContent = model.getLineContent(lineNumber);\n\t\tconst maxLineColumn = lineContent.length + 1;\n\t\tlet minEditColumn = 0;\n\n\t\tif (cursorIndex < cursorLen && cursors[cursorIndex].lineNumber === lineNumber) {\n\t\t\tminEditColumn = cursors[cursorIndex].column;\n\t\t\tcursorIndex++;\n\t\t\tif (minEditColumn === maxLineColumn) {\n\t\t\t\t// The cursor is at the end of the line => no edits for sure on this line\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\tif (lineContent.length === 0) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst lastNonWhitespaceIndex = strings.lastNonWhitespaceIndex(lineContent);\n\n\t\tlet fromColumn = 0;\n\t\tif (lastNonWhitespaceIndex === -1) {\n\t\t\t// Entire line is whitespace\n\t\t\tfromColumn = 1;\n\t\t} else if (lastNonWhitespaceIndex !== lineContent.length - 1) {\n\t\t\t// There is trailing whitespace\n\t\t\tfromColumn = lastNonWhitespaceIndex + 2;\n\t\t} else {\n\t\t\t// There is no trailing whitespace\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (!trimInRegexesAndStrings) {\n\t\t\tif (!model.tokenization.hasAccurateTokensForLine(lineNumber)) {\n\t\t\t\t// We don't want to force line tokenization, as that can be expensive, but we also don't want to trim\n\t\t\t\t// trailing whitespace in lines that are not tokenized yet, as that can be wrong and trim whitespace from\n\t\t\t\t// lines that the user requested we don't. So we bail out if the tokens are not accurate for this line.\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst lineTokens = model.tokenization.getLineTokens(lineNumber);\n\t\t\tconst fromColumnType = lineTokens.getStandardTokenType(lineTokens.findTokenIndexAtOffset(fromColumn));\n\n\t\t\tif (fromColumnType === StandardTokenType.String || fromColumnType === StandardTokenType.RegEx) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\tfromColumn = Math.max(minEditColumn, fromColumn);\n\t\tr[rLen++] = EditOperation.delete(new Range(\n\t\t\tlineNumber, fromColumn,\n\t\t\tlineNumber, maxLineColumn\n\t\t));\n\t}\n\n\treturn r;\n}\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\nimport { BugIndicatingError } from 'vs/base/common/errors';\nimport { OffsetRange } from 'vs/editor/common/core/offsetRange';\nimport { Range } from 'vs/editor/common/core/range';\nimport { findFirstIdxMonotonousOrArrLen, findLastIdxMonotonous, findLastMonotonous } from 'vs/base/common/arraysFind';\n\n/**\n * A range of lines (1-based).\n */\nexport class LineRange {\n\n\tpublic static fromRangeInclusive(range: Range): LineRange {\n\t\treturn new LineRange(range.startLineNumber, range.endLineNumber + 1);\n\t}\n\n\t/**\n\t * @param lineRanges An array of sorted line ranges.\n\t */\n\tpublic static joinMany(lineRanges: readonly (readonly LineRange[])[]): readonly LineRange[] {\n\t\tif (lineRanges.length === 0) {\n\t\t\treturn [];\n\t\t}\n\t\tlet result = new LineRangeSet(lineRanges[0].slice());\n\t\tfor (let i = 1; i < lineRanges.length; i++) {\n\t\t\tresult = result.getUnion(new LineRangeSet(lineRanges[i].slice()));\n\t\t}\n\t\treturn result.ranges;\n\t}\n\n\tpublic static join(lineRanges: LineRange[]): LineRange {\n\t\tif (lineRanges.length === 0) {\n\t\t\tthrow new BugIndicatingError('lineRanges cannot be empty');\n\t\t}\n\t\tlet startLineNumber = lineRanges[0].startLineNumber;\n\t\tlet endLineNumberExclusive = lineRanges[0].endLineNumberExclusive;\n\t\tfor (let i = 1; i < lineRanges.length; i++) {\n\t\t\tstartLineNumber = Math.min(startLineNumber, lineRanges[i].startLineNumber);\n\t\t\tendLineNumberExclusive = Math.max(endLineNumberExclusive, lineRanges[i].endLineNumberExclusive);\n\t\t}\n\t\treturn new LineRange(startLineNumber, endLineNumberExclusive);\n\t}\n\n\tpublic static ofLength(startLineNumber: number, length: number): LineRange {\n\t\treturn new LineRange(startLineNumber, startLineNumber + length);\n\t}\n\n\t/**\n\t * @internal\n\t */\n\tpublic static deserialize(lineRange: ISerializedLineRange): LineRange {\n\t\treturn new LineRange(lineRange[0], lineRange[1]);\n\t}\n\n\t/**\n\t * The start line number.\n\t */\n\tpublic readonly startLineNumber: number;\n\n\t/**\n\t * The end line number (exclusive).\n\t */\n\tpublic readonly endLineNumberExclusive: number;\n\n\tconstructor(\n\t\tstartLineNumber: number,\n\t\tendLineNumberExclusive: number,\n\t) {\n\t\tif (startLineNumber > endLineNumberExclusive) {\n\t\t\tthrow new BugIndicatingError(`startLineNumber ${startLineNumber} cannot be after endLineNumberExclusive ${endLineNumberExclusive}`);\n\t\t}\n\t\tthis.startLineNumber = startLineNumber;\n\t\tthis.endLineNumberExclusive = endLineNumberExclusive;\n\t}\n\n\t/**\n\t * Indicates if this line range contains the given line number.\n\t */\n\tpublic contains(lineNumber: number): boolean {\n\t\treturn this.startLineNumber <= lineNumber && lineNumber < this.endLineNumberExclusive;\n\t}\n\n\t/**\n\t * Indicates if this line range is empty.\n\t */\n\tget isEmpty(): boolean {\n\t\treturn this.startLineNumber === this.endLineNumberExclusive;\n\t}\n\n\t/**\n\t * Moves this line range by the given offset of line numbers.\n\t */\n\tpublic delta(offset: number): LineRange {\n\t\treturn new LineRange(this.startLineNumber + offset, this.endLineNumberExclusive + offset);\n\t}\n\n\tpublic deltaLength(offset: number): LineRange {\n\t\treturn new LineRange(this.startLineNumber, this.endLineNumberExclusive + offset);\n\t}\n\n\t/**\n\t * The number of lines this line range spans.\n\t */\n\tpublic get length(): number {\n\t\treturn this.endLineNumberExclusive - this.startLineNumber;\n\t}\n\n\t/**\n\t * Creates a line range that combines this and the given line range.\n\t */\n\tpublic join(other: LineRange): LineRange {\n\t\treturn new LineRange(\n\t\t\tMath.min(this.startLineNumber, other.startLineNumber),\n\t\t\tMath.max(this.endLineNumberExclusive, other.endLineNumberExclusive)\n\t\t);\n\t}\n\n\tpublic toString(): string {\n\t\treturn `[${this.startLineNumber},${this.endLineNumberExclusive})`;\n\t}\n\n\t/**\n\t * The resulting range is empty if the ranges do not intersect, but touch.\n\t * If the ranges don't even touch, the result is undefined.\n\t */\n\tpublic intersect(other: LineRange): LineRange | undefined {\n\t\tconst startLineNumber = Math.max(this.startLineNumber, other.startLineNumber);\n\t\tconst endLineNumberExclusive = Math.min(this.endLineNumberExclusive, other.endLineNumberExclusive);\n\t\tif (startLineNumber <= endLineNumberExclusive) {\n\t\t\treturn new LineRange(startLineNumber, endLineNumberExclusive);\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tpublic intersectsStrict(other: LineRange): boolean {\n\t\treturn this.startLineNumber < other.endLineNumberExclusive && other.startLineNumber < this.endLineNumberExclusive;\n\t}\n\n\tpublic overlapOrTouch(other: LineRange): boolean {\n\t\treturn this.startLineNumber <= other.endLineNumberExclusive && other.startLineNumber <= this.endLineNumberExclusive;\n\t}\n\n\tpublic equals(b: LineRange): boolean {\n\t\treturn this.startLineNumber === b.startLineNumber && this.endLineNumberExclusive === b.endLineNumberExclusive;\n\t}\n\n\tpublic toInclusiveRange(): Range | null {\n\t\tif (this.isEmpty) {\n\t\t\treturn null;\n\t\t}\n\t\treturn new Range(this.startLineNumber, 1, this.endLineNumberExclusive - 1, Number.MAX_SAFE_INTEGER);\n\t}\n\n\t/**\n\t * @deprecated Using this function is discouraged because it might lead to bugs: The end position is not guaranteed to be a valid position!\n\t*/\n\tpublic toExclusiveRange(): Range {\n\t\treturn new Range(this.startLineNumber, 1, this.endLineNumberExclusive, 1);\n\t}\n\n\tpublic mapToLineArray(f: (lineNumber: number) => T): T[] {\n\t\tconst result: T[] = [];\n\t\tfor (let lineNumber = this.startLineNumber; lineNumber < this.endLineNumberExclusive; lineNumber++) {\n\t\t\tresult.push(f(lineNumber));\n\t\t}\n\t\treturn result;\n\t}\n\n\tpublic forEach(f: (lineNumber: number) => void): void {\n\t\tfor (let lineNumber = this.startLineNumber; lineNumber < this.endLineNumberExclusive; lineNumber++) {\n\t\t\tf(lineNumber);\n\t\t}\n\t}\n\n\t/**\n\t * @internal\n\t */\n\tpublic serialize(): ISerializedLineRange {\n\t\treturn [this.startLineNumber, this.endLineNumberExclusive];\n\t}\n\n\tpublic includes(lineNumber: number): boolean {\n\t\treturn this.startLineNumber <= lineNumber && lineNumber < this.endLineNumberExclusive;\n\t}\n\n\t/**\n\t * Converts this 1-based line range to a 0-based offset range (subtracts 1!).\n\t * @internal\n\t */\n\tpublic toOffsetRange(): OffsetRange {\n\t\treturn new OffsetRange(this.startLineNumber - 1, this.endLineNumberExclusive - 1);\n\t}\n}\n\nexport type ISerializedLineRange = [startLineNumber: number, endLineNumberExclusive: number];\n\n\nexport class LineRangeSet {\n\tconstructor(\n\t\t/**\n\t\t * Sorted by start line number.\n\t\t * No two line ranges are touching or intersecting.\n\t\t */\n\t\tprivate readonly _normalizedRanges: LineRange[] = []\n\t) {\n\t}\n\n\tget ranges(): readonly LineRange[] {\n\t\treturn this._normalizedRanges;\n\t}\n\n\taddRange(range: LineRange): void {\n\t\tif (range.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Idea: Find joinRange such that:\n\t\t// replaceRange = _normalizedRanges.replaceRange(joinRange, range.joinAll(joinRange.map(idx => this._normalizedRanges[idx])))\n\n\t\t// idx of first element that touches range or that is after range\n\t\tconst joinRangeStartIdx = findFirstIdxMonotonousOrArrLen(this._normalizedRanges, r => r.endLineNumberExclusive >= range.startLineNumber);\n\t\t// idx of element after { last element that touches range or that is before range }\n\t\tconst joinRangeEndIdxExclusive = findLastIdxMonotonous(this._normalizedRanges, r => r.startLineNumber <= range.endLineNumberExclusive) + 1;\n\n\t\tif (joinRangeStartIdx === joinRangeEndIdxExclusive) {\n\t\t\t// If there is no element that touches range, then joinRangeStartIdx === joinRangeEndIdxExclusive and that value is the index of the element after range\n\t\t\tthis._normalizedRanges.splice(joinRangeStartIdx, 0, range);\n\t\t} else if (joinRangeStartIdx === joinRangeEndIdxExclusive - 1) {\n\t\t\t// Else, there is an element that touches range and in this case it is both the first and last element. Thus we can replace it\n\t\t\tconst joinRange = this._normalizedRanges[joinRangeStartIdx];\n\t\t\tthis._normalizedRanges[joinRangeStartIdx] = joinRange.join(range);\n\t\t} else {\n\t\t\t// First and last element are different - we need to replace the entire range\n\t\t\tconst joinRange = this._normalizedRanges[joinRangeStartIdx].join(this._normalizedRanges[joinRangeEndIdxExclusive - 1]).join(range);\n\t\t\tthis._normalizedRanges.splice(joinRangeStartIdx, joinRangeEndIdxExclusive - joinRangeStartIdx, joinRange);\n\t\t}\n\t}\n\n\tcontains(lineNumber: number): boolean {\n\t\tconst rangeThatStartsBeforeEnd = findLastMonotonous(this._normalizedRanges, r => r.startLineNumber <= lineNumber);\n\t\treturn !!rangeThatStartsBeforeEnd && rangeThatStartsBeforeEnd.endLineNumberExclusive > lineNumber;\n\t}\n\n\tintersects(range: LineRange): boolean {\n\t\tconst rangeThatStartsBeforeEnd = findLastMonotonous(this._normalizedRanges, r => r.startLineNumber < range.endLineNumberExclusive);\n\t\treturn !!rangeThatStartsBeforeEnd && rangeThatStartsBeforeEnd.endLineNumberExclusive > range.startLineNumber;\n\t}\n\n\tgetUnion(other: LineRangeSet): LineRangeSet {\n\t\tif (this._normalizedRanges.length === 0) {\n\t\t\treturn other;\n\t\t}\n\t\tif (other._normalizedRanges.length === 0) {\n\t\t\treturn this;\n\t\t}\n\n\t\tconst result: LineRange[] = [];\n\t\tlet i1 = 0;\n\t\tlet i2 = 0;\n\t\tlet current: LineRange | null = null;\n\t\twhile (i1 < this._normalizedRanges.length || i2 < other._normalizedRanges.length) {\n\t\t\tlet next: LineRange | null = null;\n\t\t\tif (i1 < this._normalizedRanges.length && i2 < other._normalizedRanges.length) {\n\t\t\t\tconst lineRange1 = this._normalizedRanges[i1];\n\t\t\t\tconst lineRange2 = other._normalizedRanges[i2];\n\t\t\t\tif (lineRange1.startLineNumber < lineRange2.startLineNumber) {\n\t\t\t\t\tnext = lineRange1;\n\t\t\t\t\ti1++;\n\t\t\t\t} else {\n\t\t\t\t\tnext = lineRange2;\n\t\t\t\t\ti2++;\n\t\t\t\t}\n\t\t\t} else if (i1 < this._normalizedRanges.length) {\n\t\t\t\tnext = this._normalizedRanges[i1];\n\t\t\t\ti1++;\n\t\t\t} else {\n\t\t\t\tnext = other._normalizedRanges[i2];\n\t\t\t\ti2++;\n\t\t\t}\n\n\t\t\tif (current === null) {\n\t\t\t\tcurrent = next;\n\t\t\t} else {\n\t\t\t\tif (current.endLineNumberExclusive >= next.startLineNumber) {\n\t\t\t\t\t// merge\n\t\t\t\t\tcurrent = new LineRange(current.startLineNumber, Math.max(current.endLineNumberExclusive, next.endLineNumberExclusive));\n\t\t\t\t} else {\n\t\t\t\t\t// push\n\t\t\t\t\tresult.push(current);\n\t\t\t\t\tcurrent = next;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (current !== null) {\n\t\t\tresult.push(current);\n\t\t}\n\t\treturn new LineRangeSet(result);\n\t}\n\n\t/**\n\t * Subtracts all ranges in this set from `range` and returns the result.\n\t */\n\tsubtractFrom(range: LineRange): LineRangeSet {\n\t\t// idx of first element that touches range or that is after range\n\t\tconst joinRangeStartIdx = findFirstIdxMonotonousOrArrLen(this._normalizedRanges, r => r.endLineNumberExclusive >= range.startLineNumber);\n\t\t// idx of element after { last element that touches range or that is before range }\n\t\tconst joinRangeEndIdxExclusive = findLastIdxMonotonous(this._normalizedRanges, r => r.startLineNumber <= range.endLineNumberExclusive) + 1;\n\n\t\tif (joinRangeStartIdx === joinRangeEndIdxExclusive) {\n\t\t\treturn new LineRangeSet([range]);\n\t\t}\n\n\t\tconst result: LineRange[] = [];\n\t\tlet startLineNumber = range.startLineNumber;\n\t\tfor (let i = joinRangeStartIdx; i < joinRangeEndIdxExclusive; i++) {\n\t\t\tconst r = this._normalizedRanges[i];\n\t\t\tif (r.startLineNumber > startLineNumber) {\n\t\t\t\tresult.push(new LineRange(startLineNumber, r.startLineNumber));\n\t\t\t}\n\t\t\tstartLineNumber = r.endLineNumberExclusive;\n\t\t}\n\t\tif (startLineNumber < range.endLineNumberExclusive) {\n\t\t\tresult.push(new LineRange(startLineNumber, range.endLineNumberExclusive));\n\t\t}\n\n\t\treturn new LineRangeSet(result);\n\t}\n\n\ttoString() {\n\t\treturn this._normalizedRanges.map(r => r.toString()).join(', ');\n\t}\n\n\tgetIntersection(other: LineRangeSet): LineRangeSet {\n\t\tconst result: LineRange[] = [];\n\n\t\tlet i1 = 0;\n\t\tlet i2 = 0;\n\t\twhile (i1 < this._normalizedRanges.length && i2 < other._normalizedRanges.length) {\n\t\t\tconst r1 = this._normalizedRanges[i1];\n\t\t\tconst r2 = other._normalizedRanges[i2];\n\n\t\t\tconst i = r1.intersect(r2);\n\t\t\tif (i && !i.isEmpty) {\n\t\t\t\tresult.push(i);\n\t\t\t}\n\n\t\t\tif (r1.endLineNumberExclusive < r2.endLineNumberExclusive) {\n\t\t\t\ti1++;\n\t\t\t} else {\n\t\t\t\ti2++;\n\t\t\t}\n\t\t}\n\n\t\treturn new LineRangeSet(result);\n\t}\n\n\tgetWithDelta(value: number): LineRangeSet {\n\t\treturn new LineRangeSet(this._normalizedRanges.map(r => r.delta(value)));\n\t}\n}\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 * A very VM friendly rgba datastructure.\n * Please don't touch unless you take a look at the IR.\n */\nexport class RGBA8 {\n\t_rgba8Brand: void = undefined;\n\n\tstatic readonly Empty = new RGBA8(0, 0, 0, 0);\n\n\t/**\n\t * Red: integer in [0-255]\n\t */\n\tpublic readonly r: number;\n\t/**\n\t * Green: integer in [0-255]\n\t */\n\tpublic readonly g: number;\n\t/**\n\t * Blue: integer in [0-255]\n\t */\n\tpublic readonly b: number;\n\t/**\n\t * Alpha: integer in [0-255]\n\t */\n\tpublic readonly a: number;\n\n\tconstructor(r: number, g: number, b: number, a: number) {\n\t\tthis.r = RGBA8._clamp(r);\n\t\tthis.g = RGBA8._clamp(g);\n\t\tthis.b = RGBA8._clamp(b);\n\t\tthis.a = RGBA8._clamp(a);\n\t}\n\n\tpublic equals(other: RGBA8): boolean {\n\t\treturn (\n\t\t\tthis.r === other.r\n\t\t\t&& this.g === other.g\n\t\t\t&& this.b === other.b\n\t\t\t&& this.a === other.a\n\t\t);\n\t}\n\n\tpublic static _clamp(c: number): number {\n\t\tif (c < 0) {\n\t\t\treturn 0;\n\t\t}\n\t\tif (c > 255) {\n\t\t\treturn 255;\n\t\t}\n\t\treturn c | 0;\n\t}\n}\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\nimport { IPosition, Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\n\n/**\n * A selection in the editor.\n * The selection is a range that has an orientation.\n */\nexport interface ISelection {\n\t/**\n\t * The line number on which the selection has started.\n\t */\n\treadonly selectionStartLineNumber: number;\n\t/**\n\t * The column on `selectionStartLineNumber` where the selection has started.\n\t */\n\treadonly selectionStartColumn: number;\n\t/**\n\t * The line number on which the selection has ended.\n\t */\n\treadonly positionLineNumber: number;\n\t/**\n\t * The column on `positionLineNumber` where the selection has ended.\n\t */\n\treadonly positionColumn: number;\n}\n\n/**\n * The direction of a selection.\n */\nexport const enum SelectionDirection {\n\t/**\n\t * The selection starts above where it ends.\n\t */\n\tLTR,\n\t/**\n\t * The selection starts below where it ends.\n\t */\n\tRTL\n}\n\n/**\n * A selection in the editor.\n * The selection is a range that has an orientation.\n */\nexport class Selection extends Range {\n\t/**\n\t * The line number on which the selection has started.\n\t */\n\tpublic readonly selectionStartLineNumber: number;\n\t/**\n\t * The column on `selectionStartLineNumber` where the selection has started.\n\t */\n\tpublic readonly selectionStartColumn: number;\n\t/**\n\t * The line number on which the selection has ended.\n\t */\n\tpublic readonly positionLineNumber: number;\n\t/**\n\t * The column on `positionLineNumber` where the selection has ended.\n\t */\n\tpublic readonly positionColumn: number;\n\n\tconstructor(selectionStartLineNumber: number, selectionStartColumn: number, positionLineNumber: number, positionColumn: number) {\n\t\tsuper(selectionStartLineNumber, selectionStartColumn, positionLineNumber, positionColumn);\n\t\tthis.selectionStartLineNumber = selectionStartLineNumber;\n\t\tthis.selectionStartColumn = selectionStartColumn;\n\t\tthis.positionLineNumber = positionLineNumber;\n\t\tthis.positionColumn = positionColumn;\n\t}\n\n\t/**\n\t * Transform to a human-readable representation.\n\t */\n\tpublic override toString(): string {\n\t\treturn '[' + this.selectionStartLineNumber + ',' + this.selectionStartColumn + ' -> ' + this.positionLineNumber + ',' + this.positionColumn + ']';\n\t}\n\n\t/**\n\t * Test if equals other selection.\n\t */\n\tpublic equalsSelection(other: ISelection): boolean {\n\t\treturn (\n\t\t\tSelection.selectionsEqual(this, other)\n\t\t);\n\t}\n\n\t/**\n\t * Test if the two selections are equal.\n\t */\n\tpublic static selectionsEqual(a: ISelection, b: ISelection): boolean {\n\t\treturn (\n\t\t\ta.selectionStartLineNumber === b.selectionStartLineNumber &&\n\t\t\ta.selectionStartColumn === b.selectionStartColumn &&\n\t\t\ta.positionLineNumber === b.positionLineNumber &&\n\t\t\ta.positionColumn === b.positionColumn\n\t\t);\n\t}\n\n\t/**\n\t * Get directions (LTR or RTL).\n\t */\n\tpublic getDirection(): SelectionDirection {\n\t\tif (this.selectionStartLineNumber === this.startLineNumber && this.selectionStartColumn === this.startColumn) {\n\t\t\treturn SelectionDirection.LTR;\n\t\t}\n\t\treturn SelectionDirection.RTL;\n\t}\n\n\t/**\n\t * Create a new selection with a different `positionLineNumber` and `positionColumn`.\n\t */\n\tpublic override setEndPosition(endLineNumber: number, endColumn: number): Selection {\n\t\tif (this.getDirection() === SelectionDirection.LTR) {\n\t\t\treturn new Selection(this.startLineNumber, this.startColumn, endLineNumber, endColumn);\n\t\t}\n\t\treturn new Selection(endLineNumber, endColumn, this.startLineNumber, this.startColumn);\n\t}\n\n\t/**\n\t * Get the position at `positionLineNumber` and `positionColumn`.\n\t */\n\tpublic getPosition(): Position {\n\t\treturn new Position(this.positionLineNumber, this.positionColumn);\n\t}\n\n\t/**\n\t * Get the position at the start of the selection.\n\t*/\n\tpublic getSelectionStart(): Position {\n\t\treturn new Position(this.selectionStartLineNumber, this.selectionStartColumn);\n\t}\n\n\t/**\n\t * Create a new selection with a different `selectionStartLineNumber` and `selectionStartColumn`.\n\t */\n\tpublic override setStartPosition(startLineNumber: number, startColumn: number): Selection {\n\t\tif (this.getDirection() === SelectionDirection.LTR) {\n\t\t\treturn new Selection(startLineNumber, startColumn, this.endLineNumber, this.endColumn);\n\t\t}\n\t\treturn new Selection(this.endLineNumber, this.endColumn, startLineNumber, startColumn);\n\t}\n\n\t// ----\n\n\t/**\n\t * Create a `Selection` from one or two positions\n\t */\n\tpublic static override fromPositions(start: IPosition, end: IPosition = start): Selection {\n\t\treturn new Selection(start.lineNumber, start.column, end.lineNumber, end.column);\n\t}\n\n\t/**\n\t * Creates a `Selection` from a range, given a direction.\n\t */\n\tpublic static fromRange(range: Range, direction: SelectionDirection): Selection {\n\t\tif (direction === SelectionDirection.LTR) {\n\t\t\treturn new Selection(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn);\n\t\t} else {\n\t\t\treturn new Selection(range.endLineNumber, range.endColumn, range.startLineNumber, range.startColumn);\n\t\t}\n\t}\n\n\t/**\n\t * Create a `Selection` from an `ISelection`.\n\t */\n\tpublic static liftSelection(sel: ISelection): Selection {\n\t\treturn new Selection(sel.selectionStartLineNumber, sel.selectionStartColumn, sel.positionLineNumber, sel.positionColumn);\n\t}\n\n\t/**\n\t * `a` equals `b`.\n\t */\n\tpublic static selectionsArrEqual(a: ISelection[], b: ISelection[]): boolean {\n\t\tif (a && !b || !a && b) {\n\t\t\treturn false;\n\t\t}\n\t\tif (!a && !b) {\n\t\t\treturn true;\n\t\t}\n\t\tif (a.length !== b.length) {\n\t\t\treturn false;\n\t\t}\n\t\tfor (let i = 0, len = a.length; i < len; i++) {\n\t\t\tif (!this.selectionsEqual(a[i], b[i])) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Test if `obj` is an `ISelection`.\n\t */\n\tpublic static isISelection(obj: any): obj is ISelection {\n\t\treturn (\n\t\t\tobj\n\t\t\t&& (typeof obj.selectionStartLineNumber === 'number')\n\t\t\t&& (typeof obj.selectionStartColumn === 'number')\n\t\t\t&& (typeof obj.positionLineNumber === 'number')\n\t\t\t&& (typeof obj.positionColumn === 'number')\n\t\t);\n\t}\n\n\t/**\n\t * Create with a direction.\n\t */\n\tpublic static createWithDirection(startLineNumber: number, startColumn: number, endLineNumber: number, endColumn: number, direction: SelectionDirection): Selection {\n\n\t\tif (direction === SelectionDirection.LTR) {\n\t\t\treturn new Selection(startLineNumber, startColumn, endLineNumber, endColumn);\n\t\t}\n\n\t\treturn new Selection(endLineNumber, endColumn, startLineNumber, startColumn);\n\t}\n}\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\nimport { Range } from 'vs/editor/common/core/range';\nimport { Selection, SelectionDirection } from 'vs/editor/common/core/selection';\nimport { ICommand, ICursorStateComputerData, IEditOperationBuilder } from 'vs/editor/common/editorCommon';\nimport { ITextModel } from 'vs/editor/common/model';\n\nexport class ReplaceCommand implements ICommand {\n\n\tprivate readonly _range: Range;\n\tprivate readonly _text: string;\n\tpublic readonly insertsAutoWhitespace: boolean;\n\n\tconstructor(range: Range, text: string, insertsAutoWhitespace: boolean = false) {\n\t\tthis._range = range;\n\t\tthis._text = text;\n\t\tthis.insertsAutoWhitespace = insertsAutoWhitespace;\n\t}\n\n\tpublic getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {\n\t\tbuilder.addTrackedEditOperation(this._range, this._text);\n\t}\n\n\tpublic computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {\n\t\tconst inverseEditOperations = helper.getInverseEditOperations();\n\t\tconst srcRange = inverseEditOperations[0].range;\n\t\treturn Selection.fromPositions(srcRange.getEndPosition());\n\t}\n}\n\nexport class ReplaceCommandThatSelectsText implements ICommand {\n\n\tprivate readonly _range: Range;\n\tprivate readonly _text: string;\n\n\tconstructor(range: Range, text: string) {\n\t\tthis._range = range;\n\t\tthis._text = text;\n\t}\n\n\tpublic getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {\n\t\tbuilder.addTrackedEditOperation(this._range, this._text);\n\t}\n\n\tpublic computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {\n\t\tconst inverseEditOperations = helper.getInverseEditOperations();\n\t\tconst srcRange = inverseEditOperations[0].range;\n\t\treturn Selection.fromRange(srcRange, SelectionDirection.LTR);\n\t}\n}\n\nexport class ReplaceCommandWithoutChangingPosition implements ICommand {\n\n\tprivate readonly _range: Range;\n\tprivate readonly _text: string;\n\tpublic readonly insertsAutoWhitespace: boolean;\n\n\tconstructor(range: Range, text: string, insertsAutoWhitespace: boolean = false) {\n\t\tthis._range = range;\n\t\tthis._text = text;\n\t\tthis.insertsAutoWhitespace = insertsAutoWhitespace;\n\t}\n\n\tpublic getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {\n\t\tbuilder.addTrackedEditOperation(this._range, this._text);\n\t}\n\n\tpublic computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {\n\t\tconst inverseEditOperations = helper.getInverseEditOperations();\n\t\tconst srcRange = inverseEditOperations[0].range;\n\t\treturn Selection.fromPositions(srcRange.getStartPosition());\n\t}\n}\n\nexport class ReplaceCommandWithOffsetCursorState implements ICommand {\n\n\tprivate readonly _range: Range;\n\tprivate readonly _text: string;\n\tprivate readonly _columnDeltaOffset: number;\n\tprivate readonly _lineNumberDeltaOffset: number;\n\tpublic readonly insertsAutoWhitespace: boolean;\n\n\tconstructor(range: Range, text: string, lineNumberDeltaOffset: number, columnDeltaOffset: number, insertsAutoWhitespace: boolean = false) {\n\t\tthis._range = range;\n\t\tthis._text = text;\n\t\tthis._columnDeltaOffset = columnDeltaOffset;\n\t\tthis._lineNumberDeltaOffset = lineNumberDeltaOffset;\n\t\tthis.insertsAutoWhitespace = insertsAutoWhitespace;\n\t}\n\n\tpublic getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {\n\t\tbuilder.addTrackedEditOperation(this._range, this._text);\n\t}\n\n\tpublic computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {\n\t\tconst inverseEditOperations = helper.getInverseEditOperations();\n\t\tconst srcRange = inverseEditOperations[0].range;\n\t\treturn Selection.fromPositions(srcRange.getEndPosition().delta(this._lineNumberDeltaOffset, this._columnDeltaOffset));\n\t}\n}\n\nexport class ReplaceCommandThatPreservesSelection implements ICommand {\n\n\tprivate readonly _range: Range;\n\tprivate readonly _text: string;\n\tprivate readonly _initialSelection: Selection;\n\tprivate readonly _forceMoveMarkers: boolean;\n\tprivate _selectionId: string | null;\n\n\tconstructor(editRange: Range, text: string, initialSelection: Selection, forceMoveMarkers: boolean = false) {\n\t\tthis._range = editRange;\n\t\tthis._text = text;\n\t\tthis._initialSelection = initialSelection;\n\t\tthis._forceMoveMarkers = forceMoveMarkers;\n\t\tthis._selectionId = null;\n\t}\n\n\tpublic getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {\n\t\tbuilder.addTrackedEditOperation(this._range, this._text, this._forceMoveMarkers);\n\t\tthis._selectionId = builder.trackSelection(this._initialSelection);\n\t}\n\n\tpublic computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {\n\t\treturn helper.getTrackedSelection(this._selectionId!);\n\t}\n}\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\nimport { Range } from 'vs/editor/common/core/range';\nimport { Position } from 'vs/editor/common/core/position';\nimport { Selection } from 'vs/editor/common/core/selection';\nimport { ICommand, ICursorStateComputerData, IEditOperationBuilder } from 'vs/editor/common/editorCommon';\nimport { ITextModel } from 'vs/editor/common/model';\n\nexport class SurroundSelectionCommand implements ICommand {\n\tprivate readonly _range: Selection;\n\tprivate readonly _charBeforeSelection: string;\n\tprivate readonly _charAfterSelection: string;\n\n\tconstructor(range: Selection, charBeforeSelection: string, charAfterSelection: string) {\n\t\tthis._range = range;\n\t\tthis._charBeforeSelection = charBeforeSelection;\n\t\tthis._charAfterSelection = charAfterSelection;\n\t}\n\n\tpublic getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {\n\t\tbuilder.addTrackedEditOperation(new Range(\n\t\t\tthis._range.startLineNumber,\n\t\t\tthis._range.startColumn,\n\t\t\tthis._range.startLineNumber,\n\t\t\tthis._range.startColumn\n\t\t), this._charBeforeSelection);\n\n\t\tbuilder.addTrackedEditOperation(new Range(\n\t\t\tthis._range.endLineNumber,\n\t\t\tthis._range.endColumn,\n\t\t\tthis._range.endLineNumber,\n\t\t\tthis._range.endColumn\n\t\t), this._charAfterSelection);\n\t}\n\n\tpublic computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {\n\t\tconst inverseEditOperations = helper.getInverseEditOperations();\n\t\tconst firstOperationRange = inverseEditOperations[0].range;\n\t\tconst secondOperationRange = inverseEditOperations[1].range;\n\n\t\treturn new Selection(\n\t\t\tfirstOperationRange.endLineNumber,\n\t\t\tfirstOperationRange.endColumn,\n\t\t\tsecondOperationRange.endLineNumber,\n\t\t\tsecondOperationRange.endColumn - this._charAfterSelection.length\n\t\t);\n\t}\n}\n\n/**\n * A surround selection command that runs after composition finished.\n */\nexport class CompositionSurroundSelectionCommand implements ICommand {\n\n\tconstructor(\n\t\tprivate readonly _position: Position,\n\t\tprivate readonly _text: string,\n\t\tprivate readonly _charAfter: string\n\t) { }\n\n\tpublic getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {\n\t\tbuilder.addTrackedEditOperation(new Range(\n\t\t\tthis._position.lineNumber,\n\t\t\tthis._position.column,\n\t\t\tthis._position.lineNumber,\n\t\t\tthis._position.column\n\t\t), this._text + this._charAfter);\n\t}\n\n\tpublic computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {\n\t\tconst inverseEditOperations = helper.getInverseEditOperations();\n\t\tconst opRange = inverseEditOperations[0].range;\n\n\t\treturn new Selection(\n\t\t\topRange.endLineNumber,\n\t\t\topRange.startColumn,\n\t\t\topRange.endLineNumber,\n\t\t\topRange.endColumn - this._charAfter.length\n\t\t);\n\t}\n}\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 *--------------------------------------------------------------------------------------------*/\nimport { Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\n\n/**\n * Represents a non-negative length of text in terms of line and column count.\n*/\nexport class TextLength {\n\tpublic static zero = new TextLength(0, 0);\n\n\tpublic static betweenPositions(position1: Position, position2: Position): TextLength {\n\t\tif (position1.lineNumber === position2.lineNumber) {\n\t\t\treturn new TextLength(0, position2.column - position1.column);\n\t\t} else {\n\t\t\treturn new TextLength(position2.lineNumber - position1.lineNumber, position2.column - 1);\n\t\t}\n\t}\n\n\tpublic static ofRange(range: Range) {\n\t\treturn TextLength.betweenPositions(range.getStartPosition(), range.getEndPosition());\n\t}\n\n\tpublic static ofText(text: string): TextLength {\n\t\tlet line = 0;\n\t\tlet column = 0;\n\t\tfor (const c of text) {\n\t\t\tif (c === '\\n') {\n\t\t\t\tline++;\n\t\t\t\tcolumn = 0;\n\t\t\t} else {\n\t\t\t\tcolumn++;\n\t\t\t}\n\t\t}\n\t\treturn new TextLength(line, column);\n\t}\n\n\tconstructor(\n\t\tpublic readonly lineCount: number,\n\t\tpublic readonly columnCount: number\n\t) { }\n\n\tpublic isGreaterThanOrEqualTo(other: TextLength): boolean {\n\t\tif (this.lineCount !== other.lineCount) {\n\t\t\treturn this.lineCount > other.lineCount;\n\t\t}\n\t\treturn this.columnCount >= other.columnCount;\n\t}\n\n\tpublic createRange(startPosition: Position): Range {\n\t\tif (this.lineCount === 0) {\n\t\t\treturn new Range(startPosition.lineNumber, startPosition.column, startPosition.lineNumber, startPosition.column + this.columnCount);\n\t\t} else {\n\t\t\treturn new Range(startPosition.lineNumber, startPosition.column, startPosition.lineNumber + this.lineCount, this.columnCount + 1);\n\t\t}\n\t}\n\n\tpublic addToPosition(position: Position): Position {\n\t\tif (this.lineCount === 0) {\n\t\t\treturn new Position(position.lineNumber, position.column + this.columnCount);\n\t\t} else {\n\t\t\treturn new Position(position.lineNumber + this.lineCount, this.columnCount + 1);\n\t\t}\n\t}\n\n\ttoString() {\n\t\treturn `${this.lineCount},${this.columnCount}`;\n\t}\n}\n","\nimport { OffsetRange } from 'vs/editor/common/core/offsetRange';\nimport { Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\nimport { TextLength } from 'vs/editor/common/core/textLength';\n\nexport class PositionOffsetTransformer {\n\tprivate readonly lineStartOffsetByLineIdx: number[];\n\n\tconstructor(public readonly text: string) {\n\t\tthis.lineStartOffsetByLineIdx = [];\n\t\tthis.lineStartOffsetByLineIdx.push(0);\n\t\tfor (let i = 0; i < text.length; i++) {\n\t\t\tif (text.charAt(i) === '\\n') {\n\t\t\t\tthis.lineStartOffsetByLineIdx.push(i + 1);\n\t\t\t}\n\t\t}\n\t}\n\n\tgetOffset(position: Position): number {\n\t\treturn this.lineStartOffsetByLineIdx[position.lineNumber - 1] + position.column - 1;\n\t}\n\n\tgetOffsetRange(range: Range): OffsetRange {\n\t\treturn new OffsetRange(\n\t\t\tthis.getOffset(range.getStartPosition()),\n\t\t\tthis.getOffset(range.getEndPosition())\n\t\t);\n\t}\n\n\tget textLength(): TextLength {\n\t\tconst lineIdx = this.lineStartOffsetByLineIdx.length - 1;\n\t\treturn new TextLength(lineIdx, this.text.length - this.lineStartOffsetByLineIdx[lineIdx]);\n\t}\n}\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\nimport { assertFn, checkAdjacentItems } from 'vs/base/common/assert';\nimport { BugIndicatingError } from 'vs/base/common/errors';\nimport { Position } from 'vs/editor/common/core/position';\nimport { PositionOffsetTransformer } from 'vs/editor/common/core/positionToOffset';\nimport { Range } from 'vs/editor/common/core/range';\nimport { TextLength } from 'vs/editor/common/core/textLength';\n\nexport class TextEdit {\n\n\tconstructor(public readonly edits: readonly SingleTextEdit[]) {\n\t\tassertFn(() => checkAdjacentItems(edits, (a, b) => a.range.getEndPosition().isBeforeOrEqual(b.range.getStartPosition())));\n\t}\n\n\tapply(text: AbstractText): string {\n\t\tlet result = '';\n\t\tlet lastEditEnd = new Position(1, 1);\n\t\tfor (const edit of this.edits) {\n\t\t\tconst editRange = edit.range;\n\t\t\tconst editStart = editRange.getStartPosition();\n\t\t\tconst editEnd = editRange.getEndPosition();\n\n\t\t\tconst r = rangeFromPositions(lastEditEnd, editStart);\n\t\t\tif (!r.isEmpty()) {\n\t\t\t\tresult += text.getValueOfRange(r);\n\t\t\t}\n\t\t\tresult += edit.text;\n\t\t\tlastEditEnd = editEnd;\n\t\t}\n\t\tconst r = rangeFromPositions(lastEditEnd, text.endPositionExclusive);\n\t\tif (!r.isEmpty()) {\n\t\t\tresult += text.getValueOfRange(r);\n\t\t}\n\t\treturn result;\n\t}\n\n\tapplyToString(str: string): string {\n\t\tconst strText = new StringText(str);\n\t\treturn this.apply(strText);\n\t}\n\n\tgetNewRanges(): Range[] {\n\t\tconst newRanges: Range[] = [];\n\t\tlet previousEditEndLineNumber = 0;\n\t\tlet lineOffset = 0;\n\t\tlet columnOffset = 0;\n\t\tfor (const edit of this.edits) {\n\t\t\tconst textLength = TextLength.ofText(edit.text);\n\t\t\tconst newRangeStart = Position.lift({\n\t\t\t\tlineNumber: edit.range.startLineNumber + lineOffset,\n\t\t\t\tcolumn: edit.range.startColumn + (edit.range.startLineNumber === previousEditEndLineNumber ? columnOffset : 0)\n\t\t\t});\n\t\t\tconst newRange = textLength.createRange(newRangeStart);\n\t\t\tnewRanges.push(newRange);\n\t\t\tlineOffset = newRange.endLineNumber - edit.range.endLineNumber;\n\t\t\tcolumnOffset = newRange.endColumn - edit.range.endColumn;\n\t\t\tpreviousEditEndLineNumber = edit.range.endLineNumber;\n\t\t}\n\t\treturn newRanges;\n\t}\n}\n\nexport class SingleTextEdit {\n\tconstructor(\n\t\tpublic readonly range: Range,\n\t\tpublic readonly text: string,\n\t) {\n\t}\n}\n\nfunction rangeFromPositions(start: Position, end: Position): Range {\n\tif (start.lineNumber === end.lineNumber && start.column === Number.MAX_SAFE_INTEGER) {\n\t\treturn Range.fromPositions(end, end);\n\t} else if (!start.isBeforeOrEqual(end)) {\n\t\tthrow new BugIndicatingError('start must be before end');\n\t}\n\treturn new Range(start.lineNumber, start.column, end.lineNumber, end.column);\n}\n\nexport abstract class AbstractText {\n\tabstract getValueOfRange(range: Range): string;\n\tabstract readonly length: TextLength;\n\n\tget endPositionExclusive(): Position {\n\t\treturn this.length.addToPosition(new Position(1, 1));\n\t}\n}\n\nexport class StringText extends AbstractText {\n\tprivate readonly _t = new PositionOffsetTransformer(this.value);\n\n\tconstructor(public readonly value: string) {\n\t\tsuper();\n\t}\n\n\tgetValueOfRange(range: Range): string {\n\t\treturn this._t.getOffsetRange(range).substring(this.value);\n\t}\n\n\tget length(): TextLength {\n\t\treturn this._t.textLength;\n\t}\n}\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\nexport const EDITOR_MODEL_DEFAULTS = {\n\ttabSize: 4,\n\tindentSize: 4,\n\tinsertSpaces: true,\n\tdetectIndentation: true,\n\ttrimAutoWhitespace: true,\n\tlargeFileOptimizations: true,\n\tbracketPairColorizationOptions: {\n\t\tenabled: true,\n\t\tindependentColorPoolPerBracketType: false,\n\t},\n};\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\nimport { CharCode } from 'vs/base/common/charCode';\nimport { LRUCache } from 'vs/base/common/map';\nimport { CharacterClassifier } from 'vs/editor/common/core/characterClassifier';\n\nexport const enum WordCharacterClass {\n\tRegular = 0,\n\tWhitespace = 1,\n\tWordSeparator = 2\n}\n\nexport class WordCharacterClassifier extends CharacterClassifier {\n\n\tpublic readonly intlSegmenterLocales: Intl.UnicodeBCP47LocaleIdentifier[];\n\tprivate readonly _segmenter: Intl.Segmenter | null = null;\n\tprivate _cachedLine: string | null = null;\n\tprivate _cachedSegments: IntlWordSegmentData[] = [];\n\n\tconstructor(wordSeparators: string, intlSegmenterLocales: Intl.UnicodeBCP47LocaleIdentifier[]) {\n\t\tsuper(WordCharacterClass.Regular);\n\t\tthis.intlSegmenterLocales = intlSegmenterLocales;\n\t\tif (this.intlSegmenterLocales.length > 0) {\n\t\t\tthis._segmenter = new Intl.Segmenter(this.intlSegmenterLocales, { granularity: 'word' });\n\t\t} else {\n\t\t\tthis._segmenter = null;\n\t\t}\n\n\t\tfor (let i = 0, len = wordSeparators.length; i < len; i++) {\n\t\t\tthis.set(wordSeparators.charCodeAt(i), WordCharacterClass.WordSeparator);\n\t\t}\n\n\t\tthis.set(CharCode.Space, WordCharacterClass.Whitespace);\n\t\tthis.set(CharCode.Tab, WordCharacterClass.Whitespace);\n\t}\n\n\tpublic findPrevIntlWordBeforeOrAtOffset(line: string, offset: number): IntlWordSegmentData | null {\n\t\tlet candidate: IntlWordSegmentData | null = null;\n\t\tfor (const segment of this._getIntlSegmenterWordsOnLine(line)) {\n\t\t\tif (segment.index > offset) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcandidate = segment;\n\t\t}\n\t\treturn candidate;\n\t}\n\n\tpublic findNextIntlWordAtOrAfterOffset(lineContent: string, offset: number): IntlWordSegmentData | null {\n\t\tfor (const segment of this._getIntlSegmenterWordsOnLine(lineContent)) {\n\t\t\tif (segment.index < offset) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\treturn segment;\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate _getIntlSegmenterWordsOnLine(line: string): IntlWordSegmentData[] {\n\t\tif (!this._segmenter) {\n\t\t\treturn [];\n\t\t}\n\n\t\t// Check if the line has changed from the previous call\n\t\tif (this._cachedLine === line) {\n\t\t\treturn this._cachedSegments;\n\t\t}\n\n\t\t// Update the cache with the new line\n\t\tthis._cachedLine = line;\n\t\tthis._cachedSegments = this._filterWordSegments(this._segmenter.segment(line));\n\n\t\treturn this._cachedSegments;\n\t}\n\n\tprivate _filterWordSegments(segments: Intl.Segments): IntlWordSegmentData[] {\n\t\tconst result: IntlWordSegmentData[] = [];\n\t\tfor (const segment of segments) {\n\t\t\tif (this._isWordLike(segment)) {\n\t\t\t\tresult.push(segment);\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate _isWordLike(segment: Intl.SegmentData): segment is IntlWordSegmentData {\n\t\tif (segment.isWordLike) {\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n}\n\nexport interface IntlWordSegmentData extends Intl.SegmentData {\n\tisWordLike: true;\n}\n\nconst wordClassifierCache = new LRUCache(10);\n\nexport function getMapForWordSeparators(wordSeparators: string, intlSegmenterLocales: Intl.UnicodeBCP47LocaleIdentifier[]): WordCharacterClassifier {\n\tconst key = `${wordSeparators}/${intlSegmenterLocales.join(',')}`;\n\tlet result = wordClassifierCache.get(key)!;\n\tif (!result) {\n\t\tresult = new WordCharacterClassifier(wordSeparators, intlSegmenterLocales);\n\t\twordClassifierCache.set(key, result);\n\t}\n\treturn result;\n}\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\nimport { Iterable } from 'vs/base/common/iterator';\nimport { LinkedList } from 'vs/base/common/linkedList';\n\nexport const USUAL_WORD_SEPARATORS = '`~!@#$%^&*()-=+[{]}\\\\|;:\\'\",.<>/?';\n\n/**\n * Word inside a model.\n */\nexport interface IWordAtPosition {\n\t/**\n\t * The word.\n\t */\n\treadonly word: string;\n\t/**\n\t * The column where the word starts.\n\t */\n\treadonly startColumn: number;\n\t/**\n\t * The column where the word ends.\n\t */\n\treadonly endColumn: number;\n}\n\n/**\n * Create a word definition regular expression based on default word separators.\n * Optionally provide allowed separators that should be included in words.\n *\n * The default would look like this:\n * /(-?\\d*\\.\\d\\w*)|([^\\`\\~\\!\\@\\#\\$\\%\\^\\&\\*\\(\\)\\-\\=\\+\\[\\{\\]\\}\\\\\\|\\;\\:\\'\\\"\\,\\.\\<\\>\\/\\?\\s]+)/g\n */\nfunction createWordRegExp(allowInWords: string = ''): RegExp {\n\tlet source = '(-?\\\\d*\\\\.\\\\d\\\\w*)|([^';\n\tfor (const sep of USUAL_WORD_SEPARATORS) {\n\t\tif (allowInWords.indexOf(sep) >= 0) {\n\t\t\tcontinue;\n\t\t}\n\t\tsource += '\\\\' + sep;\n\t}\n\tsource += '\\\\s]+)';\n\treturn new RegExp(source, 'g');\n}\n\n// catches numbers (including floating numbers) in the first group, and alphanum in the second\nexport const DEFAULT_WORD_REGEXP = createWordRegExp();\n\nexport function ensureValidWordDefinition(wordDefinition?: RegExp | null): RegExp {\n\tlet result: RegExp = DEFAULT_WORD_REGEXP;\n\n\tif (wordDefinition && (wordDefinition instanceof RegExp)) {\n\t\tif (!wordDefinition.global) {\n\t\t\tlet flags = 'g';\n\t\t\tif (wordDefinition.ignoreCase) {\n\t\t\t\tflags += 'i';\n\t\t\t}\n\t\t\tif (wordDefinition.multiline) {\n\t\t\t\tflags += 'm';\n\t\t\t}\n\t\t\tif (wordDefinition.unicode) {\n\t\t\t\tflags += 'u';\n\t\t\t}\n\t\t\tresult = new RegExp(wordDefinition.source, flags);\n\t\t} else {\n\t\t\tresult = wordDefinition;\n\t\t}\n\t}\n\n\tresult.lastIndex = 0;\n\n\treturn result;\n}\n\n\nexport interface IGetWordAtTextConfig {\n\tmaxLen: number;\n\twindowSize: number;\n\ttimeBudget: number;\n}\n\n\nconst _defaultConfig = new LinkedList();\n_defaultConfig.unshift({\n\tmaxLen: 1000,\n\twindowSize: 15,\n\ttimeBudget: 150\n});\n\nexport function getWordAtText(column: number, wordDefinition: RegExp, text: string, textOffset: number, config?: IGetWordAtTextConfig): IWordAtPosition | null {\n\t// Ensure the regex has the 'g' flag, otherwise this will loop forever\n\twordDefinition = ensureValidWordDefinition(wordDefinition);\n\n\tif (!config) {\n\t\tconfig = Iterable.first(_defaultConfig)!;\n\t}\n\n\tif (text.length > config.maxLen) {\n\t\t// don't throw strings that long at the regexp\n\t\t// but use a sub-string in which a word must occur\n\t\tlet start = column - config.maxLen / 2;\n\t\tif (start < 0) {\n\t\t\tstart = 0;\n\t\t} else {\n\t\t\ttextOffset += start;\n\t\t}\n\t\ttext = text.substring(start, column + config.maxLen / 2);\n\t\treturn getWordAtText(column, wordDefinition, text, textOffset, config);\n\t}\n\n\tconst t1 = Date.now();\n\tconst pos = column - 1 - textOffset;\n\n\tlet prevRegexIndex = -1;\n\tlet match: RegExpExecArray | null = null;\n\n\tfor (let i = 1; ; i++) {\n\t\t// check time budget\n\t\tif (Date.now() - t1 >= config.timeBudget) {\n\t\t\tbreak;\n\t\t}\n\n\t\t// reset the index at which the regexp should start matching, also know where it\n\t\t// should stop so that subsequent search don't repeat previous searches\n\t\tconst regexIndex = pos - config.windowSize * i;\n\t\twordDefinition.lastIndex = Math.max(0, regexIndex);\n\t\tconst thisMatch = _findRegexMatchEnclosingPosition(wordDefinition, text, pos, prevRegexIndex);\n\n\t\tif (!thisMatch && match) {\n\t\t\t// stop: we have something\n\t\t\tbreak;\n\t\t}\n\n\t\tmatch = thisMatch;\n\n\t\t// stop: searched at start\n\t\tif (regexIndex <= 0) {\n\t\t\tbreak;\n\t\t}\n\t\tprevRegexIndex = regexIndex;\n\t}\n\n\tif (match) {\n\t\tconst result = {\n\t\t\tword: match[0],\n\t\t\tstartColumn: textOffset + 1 + match.index,\n\t\t\tendColumn: textOffset + 1 + match.index + match[0].length\n\t\t};\n\t\twordDefinition.lastIndex = 0;\n\t\treturn result;\n\t}\n\n\treturn null;\n}\n\nfunction _findRegexMatchEnclosingPosition(wordDefinition: RegExp, text: string, pos: number, stopPos: number): RegExpExecArray | null {\n\tlet match: RegExpExecArray | null;\n\twhile (match = wordDefinition.exec(text)) {\n\t\tconst matchIndex = match.index || 0;\n\t\tif (matchIndex <= pos && wordDefinition.lastIndex >= pos) {\n\t\t\treturn match;\n\t\t} else if (stopPos > 0 && matchIndex > stopPos) {\n\t\t\treturn null;\n\t\t}\n\t}\n\treturn null;\n}\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\nimport { CharCode } from 'vs/base/common/charCode';\nimport { CursorColumns } from 'vs/editor/common/core/cursorColumns';\n\nexport const enum Direction {\n\tLeft,\n\tRight,\n\tNearest,\n}\n\nexport class AtomicTabMoveOperations {\n\t/**\n\t * Get the visible column at the position. If we get to a non-whitespace character first\n\t * or past the end of string then return -1.\n\t *\n\t * **Note** `position` and the return value are 0-based.\n\t */\n\tpublic static whitespaceVisibleColumn(lineContent: string, position: number, tabSize: number): [number, number, number] {\n\t\tconst lineLength = lineContent.length;\n\t\tlet visibleColumn = 0;\n\t\tlet prevTabStopPosition = -1;\n\t\tlet prevTabStopVisibleColumn = -1;\n\t\tfor (let i = 0; i < lineLength; i++) {\n\t\t\tif (i === position) {\n\t\t\t\treturn [prevTabStopPosition, prevTabStopVisibleColumn, visibleColumn];\n\t\t\t}\n\t\t\tif (visibleColumn % tabSize === 0) {\n\t\t\t\tprevTabStopPosition = i;\n\t\t\t\tprevTabStopVisibleColumn = visibleColumn;\n\t\t\t}\n\t\t\tconst chCode = lineContent.charCodeAt(i);\n\t\t\tswitch (chCode) {\n\t\t\t\tcase CharCode.Space:\n\t\t\t\t\tvisibleColumn += 1;\n\t\t\t\t\tbreak;\n\t\t\t\tcase CharCode.Tab:\n\t\t\t\t\t// Skip to the next multiple of tabSize.\n\t\t\t\t\tvisibleColumn = CursorColumns.nextRenderTabStop(visibleColumn, tabSize);\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\treturn [-1, -1, -1];\n\t\t\t}\n\t\t}\n\t\tif (position === lineLength) {\n\t\t\treturn [prevTabStopPosition, prevTabStopVisibleColumn, visibleColumn];\n\t\t}\n\t\treturn [-1, -1, -1];\n\t}\n\n\t/**\n\t * Return the position that should result from a move left, right or to the\n\t * nearest tab, if atomic tabs are enabled. Left and right are used for the\n\t * arrow key movements, nearest is used for mouse selection. It returns\n\t * -1 if atomic tabs are not relevant and you should fall back to normal\n\t * behaviour.\n\t *\n\t * **Note**: `position` and the return value are 0-based.\n\t */\n\tpublic static atomicPosition(lineContent: string, position: number, tabSize: number, direction: Direction): number {\n\t\tconst lineLength = lineContent.length;\n\n\t\t// Get the 0-based visible column corresponding to the position, or return\n\t\t// -1 if it is not in the initial whitespace.\n\t\tconst [prevTabStopPosition, prevTabStopVisibleColumn, visibleColumn] = AtomicTabMoveOperations.whitespaceVisibleColumn(lineContent, position, tabSize);\n\n\t\tif (visibleColumn === -1) {\n\t\t\treturn -1;\n\t\t}\n\n\t\t// Is the output left or right of the current position. The case for nearest\n\t\t// where it is the same as the current position is handled in the switch.\n\t\tlet left: boolean;\n\t\tswitch (direction) {\n\t\t\tcase Direction.Left:\n\t\t\t\tleft = true;\n\t\t\t\tbreak;\n\t\t\tcase Direction.Right:\n\t\t\t\tleft = false;\n\t\t\t\tbreak;\n\t\t\tcase Direction.Nearest:\n\t\t\t\t// The code below assumes the output position is either left or right\n\t\t\t\t// of the input position. If it is the same, return immediately.\n\t\t\t\tif (visibleColumn % tabSize === 0) {\n\t\t\t\t\treturn position;\n\t\t\t\t}\n\t\t\t\t// Go to the nearest indentation.\n\t\t\t\tleft = visibleColumn % tabSize <= (tabSize / 2);\n\t\t\t\tbreak;\n\t\t}\n\n\t\t// If going left, we can just use the info about the last tab stop position and\n\t\t// last tab stop visible column that we computed in the first walk over the whitespace.\n\t\tif (left) {\n\t\t\tif (prevTabStopPosition === -1) {\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t\t// If the direction is left, we need to keep scanning right to ensure\n\t\t\t// that targetVisibleColumn + tabSize is before non-whitespace.\n\t\t\t// This is so that when we press left at the end of a partial\n\t\t\t// indentation it only goes one character. For example ' foo' with\n\t\t\t// tabSize 4, should jump from position 6 to position 5, not 4.\n\t\t\tlet currentVisibleColumn = prevTabStopVisibleColumn;\n\t\t\tfor (let i = prevTabStopPosition; i < lineLength; ++i) {\n\t\t\t\tif (currentVisibleColumn === prevTabStopVisibleColumn + tabSize) {\n\t\t\t\t\t// It is a full indentation.\n\t\t\t\t\treturn prevTabStopPosition;\n\t\t\t\t}\n\n\t\t\t\tconst chCode = lineContent.charCodeAt(i);\n\t\t\t\tswitch (chCode) {\n\t\t\t\t\tcase CharCode.Space:\n\t\t\t\t\t\tcurrentVisibleColumn += 1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase CharCode.Tab:\n\t\t\t\t\t\tcurrentVisibleColumn = CursorColumns.nextRenderTabStop(currentVisibleColumn, tabSize);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn -1;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (currentVisibleColumn === prevTabStopVisibleColumn + tabSize) {\n\t\t\t\treturn prevTabStopPosition;\n\t\t\t}\n\t\t\t// It must have been a partial indentation.\n\t\t\treturn -1;\n\t\t}\n\n\t\t// We are going right.\n\t\tconst targetVisibleColumn = CursorColumns.nextRenderTabStop(visibleColumn, tabSize);\n\n\t\t// We can just continue from where whitespaceVisibleColumn got to.\n\t\tlet currentVisibleColumn = visibleColumn;\n\t\tfor (let i = position; i < lineLength; i++) {\n\t\t\tif (currentVisibleColumn === targetVisibleColumn) {\n\t\t\t\treturn i;\n\t\t\t}\n\n\t\t\tconst chCode = lineContent.charCodeAt(i);\n\t\t\tswitch (chCode) {\n\t\t\t\tcase CharCode.Space:\n\t\t\t\t\tcurrentVisibleColumn += 1;\n\t\t\t\t\tbreak;\n\t\t\t\tcase CharCode.Tab:\n\t\t\t\t\tcurrentVisibleColumn = CursorColumns.nextRenderTabStop(currentVisibleColumn, tabSize);\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\treturn -1;\n\t\t\t}\n\t\t}\n\t\t// This condition handles when the target column is at the end of the line.\n\t\tif (currentVisibleColumn === targetVisibleColumn) {\n\t\t\treturn lineLength;\n\t\t}\n\t\treturn -1;\n\t}\n}\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\nimport { ITextModel } from 'vs/editor/common/model';\nimport { ICoordinatesConverter } from 'vs/editor/common/viewModel';\nimport { CursorConfiguration, ICursorSimpleModel } from 'vs/editor/common/cursorCommon';\n\nexport class CursorContext {\n\t_cursorContextBrand: void = undefined;\n\n\tpublic readonly model: ITextModel;\n\tpublic readonly viewModel: ICursorSimpleModel;\n\tpublic readonly coordinatesConverter: ICoordinatesConverter;\n\tpublic readonly cursorConfig: CursorConfiguration;\n\n\tconstructor(model: ITextModel, viewModel: ICursorSimpleModel, coordinatesConverter: ICoordinatesConverter, cursorConfig: CursorConfiguration) {\n\t\tthis.model = model;\n\t\tthis.viewModel = viewModel;\n\t\tthis.coordinatesConverter = coordinatesConverter;\n\t\tthis.cursorConfig = cursorConfig;\n\t}\n}\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\nimport { forEachAdjacent } from 'vs/base/common/arrays';\nimport { BugIndicatingError } from 'vs/base/common/errors';\nimport { OffsetRange } from 'vs/editor/common/core/offsetRange';\n\n/**\n * Represents a synchronous diff algorithm. Should be executed in a worker.\n*/\nexport interface IDiffAlgorithm {\n}\n\nexport class DiffAlgorithmResult {\n\tstatic trivial(seq1: ISequence, seq2: ISequence): DiffAlgorithmResult {\n\t\treturn new DiffAlgorithmResult([new SequenceDiff(OffsetRange.ofLength(seq1.length), OffsetRange.ofLength(seq2.length))], false);\n\t}\n\n\tstatic trivialTimedOut(seq1: ISequence, seq2: ISequence): DiffAlgorithmResult {\n\t\treturn new DiffAlgorithmResult([new SequenceDiff(OffsetRange.ofLength(seq1.length), OffsetRange.ofLength(seq2.length))], true);\n\t}\n\n\tconstructor(\n\t\tpublic readonly diffs: SequenceDiff[],\n\t\t/**\n\t\t * Indicates if the time out was reached.\n\t\t * In that case, the diffs might be an approximation and the user should be asked to rerun the diff with more time.\n\t\t */\n\t\tpublic readonly hitTimeout: boolean,\n\t) { }\n}\n\nexport class SequenceDiff {\n\tpublic static invert(sequenceDiffs: SequenceDiff[], doc1Length: number): SequenceDiff[] {\n\t\tconst result: SequenceDiff[] = [];\n\t\tforEachAdjacent(sequenceDiffs, (a, b) => {\n\t\t\tresult.push(SequenceDiff.fromOffsetPairs(\n\t\t\t\ta ? a.getEndExclusives() : OffsetPair.zero,\n\t\t\t\tb ? b.getStarts() : new OffsetPair(doc1Length, (a ? a.seq2Range.endExclusive - a.seq1Range.endExclusive : 0) + doc1Length)\n\t\t\t));\n\t\t});\n\t\treturn result;\n\t}\n\n\tpublic static fromOffsetPairs(start: OffsetPair, endExclusive: OffsetPair): SequenceDiff {\n\t\treturn new SequenceDiff(\n\t\t\tnew OffsetRange(start.offset1, endExclusive.offset1),\n\t\t\tnew OffsetRange(start.offset2, endExclusive.offset2),\n\t\t);\n\t}\n\n\tconstructor(\n\t\tpublic readonly seq1Range: OffsetRange,\n\t\tpublic readonly seq2Range: OffsetRange,\n\t) { }\n\n\tpublic swap(): SequenceDiff {\n\t\treturn new SequenceDiff(this.seq2Range, this.seq1Range);\n\t}\n\n\tpublic toString(): string {\n\t\treturn `${this.seq1Range} <-> ${this.seq2Range}`;\n\t}\n\n\tpublic join(other: SequenceDiff): SequenceDiff {\n\t\treturn new SequenceDiff(this.seq1Range.join(other.seq1Range), this.seq2Range.join(other.seq2Range));\n\t}\n\n\tpublic delta(offset: number): SequenceDiff {\n\t\tif (offset === 0) {\n\t\t\treturn this;\n\t\t}\n\t\treturn new SequenceDiff(this.seq1Range.delta(offset), this.seq2Range.delta(offset));\n\t}\n\n\tpublic deltaStart(offset: number): SequenceDiff {\n\t\tif (offset === 0) {\n\t\t\treturn this;\n\t\t}\n\t\treturn new SequenceDiff(this.seq1Range.deltaStart(offset), this.seq2Range.deltaStart(offset));\n\t}\n\n\tpublic deltaEnd(offset: number): SequenceDiff {\n\t\tif (offset === 0) {\n\t\t\treturn this;\n\t\t}\n\t\treturn new SequenceDiff(this.seq1Range.deltaEnd(offset), this.seq2Range.deltaEnd(offset));\n\t}\n\n\tpublic intersect(other: SequenceDiff): SequenceDiff | undefined {\n\t\tconst i1 = this.seq1Range.intersect(other.seq1Range);\n\t\tconst i2 = this.seq2Range.intersect(other.seq2Range);\n\t\tif (!i1 || !i2) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn new SequenceDiff(i1, i2);\n\t}\n\n\tpublic getStarts(): OffsetPair {\n\t\treturn new OffsetPair(this.seq1Range.start, this.seq2Range.start);\n\t}\n\n\tpublic getEndExclusives(): OffsetPair {\n\t\treturn new OffsetPair(this.seq1Range.endExclusive, this.seq2Range.endExclusive);\n\t}\n}\n\nexport class OffsetPair {\n\tpublic static readonly zero = new OffsetPair(0, 0);\n\tpublic static readonly max = new OffsetPair(Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER);\n\n\tconstructor(\n\t\tpublic readonly offset1: number,\n\t\tpublic readonly offset2: number,\n\t) {\n\t}\n\n\tpublic toString(): string {\n\t\treturn `${this.offset1} <-> ${this.offset2}`;\n\t}\n\n\tpublic delta(offset: number): OffsetPair {\n\t\tif (offset === 0) {\n\t\t\treturn this;\n\t\t}\n\t\treturn new OffsetPair(this.offset1 + offset, this.offset2 + offset);\n\t}\n\n\tpublic equals(other: OffsetPair): boolean {\n\t\treturn this.offset1 === other.offset1 && this.offset2 === other.offset2;\n\t}\n}\n\nexport interface ISequence {\n\tgetElement(offset: number): number;\n\tget length(): number;\n\n\t/**\n\t * The higher the score, the better that offset can be used to split the sequence.\n\t * Is used to optimize insertions.\n\t * Must not be negative.\n\t*/\n\tgetBoundaryScore?(length: number): number;\n\n\t/**\n\t * For line sequences, getElement returns a number representing trimmed lines.\n\t * This however checks equality for the original lines.\n\t * It prevents shifting to less matching lines.\n\t */\n\tisStronglyEqual(offset1: number, offset2: number): boolean;\n}\n\nexport interface ITimeout {\n\tisValid(): boolean;\n}\n\nexport class InfiniteTimeout implements ITimeout {\n\tpublic static instance = new InfiniteTimeout();\n\n\tisValid(): boolean {\n\t\treturn true;\n\t}\n}\n\nexport class DateTimeout implements ITimeout {\n\tprivate readonly startTime = Date.now();\n\tprivate valid = true;\n\n\tconstructor(private timeout: number) {\n\t\tif (timeout <= 0) {\n\t\t\tthrow new BugIndicatingError('timeout must be positive');\n\t\t}\n\t}\n\n\t// Recommendation: Set a log-point `{this.disable()}` in the body\n\tpublic isValid(): boolean {\n\t\tconst valid = Date.now() - this.startTime < this.timeout;\n\t\tif (!valid && this.valid) {\n\t\t\tthis.valid = false; // timeout reached\n\t\t\t// eslint-disable-next-line no-debugger\n\t\t\tdebugger; // WARNING: Most likely debugging caused the timeout. Call `this.disable()` to continue without timing out.\n\t\t}\n\t\treturn this.valid;\n\t}\n}\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\nimport { OffsetRange } from 'vs/editor/common/core/offsetRange';\nimport { DiffAlgorithmResult, IDiffAlgorithm, ISequence, ITimeout, InfiniteTimeout, SequenceDiff } from 'vs/editor/common/diff/defaultLinesDiffComputer/algorithms/diffAlgorithm';\n\n/**\n * An O(ND) diff algorithm that has a quadratic space worst-case complexity.\n*/\nexport class MyersDiffAlgorithm implements IDiffAlgorithm {\n\tcompute(seq1: ISequence, seq2: ISequence, timeout: ITimeout = InfiniteTimeout.instance): DiffAlgorithmResult {\n\t\t// These are common special cases.\n\t\t// The early return improves performance dramatically.\n\t\tif (seq1.length === 0 || seq2.length === 0) {\n\t\t\treturn DiffAlgorithmResult.trivial(seq1, seq2);\n\t\t}\n\n\t\tconst seqX = seq1; // Text on the x axis\n\t\tconst seqY = seq2; // Text on the y axis\n\n\t\tfunction getXAfterSnake(x: number, y: number): number {\n\t\t\twhile (x < seqX.length && y < seqY.length && seqX.getElement(x) === seqY.getElement(y)) {\n\t\t\t\tx++;\n\t\t\t\ty++;\n\t\t\t}\n\t\t\treturn x;\n\t\t}\n\n\t\tlet d = 0;\n\t\t// V[k]: X value of longest d-line that ends in diagonal k.\n\t\t// d-line: path from (0,0) to (x,y) that uses exactly d non-diagonals.\n\t\t// diagonal k: Set of points (x,y) with x-y = k.\n\t\t// k=1 -> (1,0),(2,1)\n\t\tconst V = new FastInt32Array();\n\t\tV.set(0, getXAfterSnake(0, 0));\n\n\t\tconst paths = new FastArrayNegativeIndices();\n\t\tpaths.set(0, V.get(0) === 0 ? null : new SnakePath(null, 0, 0, V.get(0)));\n\n\t\tlet k = 0;\n\n\t\tloop: while (true) {\n\t\t\td++;\n\t\t\tif (!timeout.isValid()) {\n\t\t\t\treturn DiffAlgorithmResult.trivialTimedOut(seqX, seqY);\n\t\t\t}\n\t\t\t// The paper has `for (k = -d; k <= d; k += 2)`, but we can ignore diagonals that cannot influence the result.\n\t\t\tconst lowerBound = -Math.min(d, seqY.length + (d % 2));\n\t\t\tconst upperBound = Math.min(d, seqX.length + (d % 2));\n\t\t\tfor (k = lowerBound; k <= upperBound; k += 2) {\n\t\t\t\tlet step = 0;\n\t\t\t\t// We can use the X values of (d-1)-lines to compute X value of the longest d-lines.\n\t\t\t\tconst maxXofDLineTop = k === upperBound ? -1 : V.get(k + 1); // We take a vertical non-diagonal (add a symbol in seqX)\n\t\t\t\tconst maxXofDLineLeft = k === lowerBound ? -1 : V.get(k - 1) + 1; // We take a horizontal non-diagonal (+1 x) (delete a symbol in seqX)\n\t\t\t\tstep++;\n\t\t\t\tconst x = Math.min(Math.max(maxXofDLineTop, maxXofDLineLeft), seqX.length);\n\t\t\t\tconst y = x - k;\n\t\t\t\tstep++;\n\t\t\t\tif (x > seqX.length || y > seqY.length) {\n\t\t\t\t\t// This diagonal is irrelevant for the result.\n\t\t\t\t\t// TODO: Don't pay the cost for this in the next iteration.\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst newMaxX = getXAfterSnake(x, y);\n\t\t\t\tV.set(k, newMaxX);\n\t\t\t\tconst lastPath = x === maxXofDLineTop ? paths.get(k + 1) : paths.get(k - 1);\n\t\t\t\tpaths.set(k, newMaxX !== x ? new SnakePath(lastPath, x, y, newMaxX - x) : lastPath);\n\n\t\t\t\tif (V.get(k) === seqX.length && V.get(k) - k === seqY.length) {\n\t\t\t\t\tbreak loop;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tlet path = paths.get(k);\n\t\tconst result: SequenceDiff[] = [];\n\t\tlet lastAligningPosS1: number = seqX.length;\n\t\tlet lastAligningPosS2: number = seqY.length;\n\n\t\twhile (true) {\n\t\t\tconst endX = path ? path.x + path.length : 0;\n\t\t\tconst endY = path ? path.y + path.length : 0;\n\n\t\t\tif (endX !== lastAligningPosS1 || endY !== lastAligningPosS2) {\n\t\t\t\tresult.push(new SequenceDiff(\n\t\t\t\t\tnew OffsetRange(endX, lastAligningPosS1),\n\t\t\t\t\tnew OffsetRange(endY, lastAligningPosS2),\n\t\t\t\t));\n\t\t\t}\n\t\t\tif (!path) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tlastAligningPosS1 = path.x;\n\t\t\tlastAligningPosS2 = path.y;\n\n\t\t\tpath = path.prev;\n\t\t}\n\n\t\tresult.reverse();\n\t\treturn new DiffAlgorithmResult(result, false);\n\t}\n}\n\nclass SnakePath {\n\tconstructor(\n\t\tpublic readonly prev: SnakePath | null,\n\t\tpublic readonly x: number,\n\t\tpublic readonly y: number,\n\t\tpublic readonly length: number\n\t) {\n\t}\n}\n\n/**\n * An array that supports fast negative indices.\n*/\nclass FastInt32Array {\n\tprivate positiveArr: Int32Array = new Int32Array(10);\n\tprivate negativeArr: Int32Array = new Int32Array(10);\n\n\tget(idx: number): number {\n\t\tif (idx < 0) {\n\t\t\tidx = -idx - 1;\n\t\t\treturn this.negativeArr[idx];\n\t\t} else {\n\t\t\treturn this.positiveArr[idx];\n\t\t}\n\t}\n\n\tset(idx: number, value: number): void {\n\t\tif (idx < 0) {\n\t\t\tidx = -idx - 1;\n\t\t\tif (idx >= this.negativeArr.length) {\n\t\t\t\tconst arr = this.negativeArr;\n\t\t\t\tthis.negativeArr = new Int32Array(arr.length * 2);\n\t\t\t\tthis.negativeArr.set(arr);\n\t\t\t}\n\t\t\tthis.negativeArr[idx] = value;\n\t\t} else {\n\t\t\tif (idx >= this.positiveArr.length) {\n\t\t\t\tconst arr = this.positiveArr;\n\t\t\t\tthis.positiveArr = new Int32Array(arr.length * 2);\n\t\t\t\tthis.positiveArr.set(arr);\n\t\t\t}\n\t\t\tthis.positiveArr[idx] = value;\n\t\t}\n\t}\n}\n\n/**\n * An array that supports fast negative indices.\n*/\nclass FastArrayNegativeIndices {\n\tprivate readonly positiveArr: T[] = [];\n\tprivate readonly negativeArr: T[] = [];\n\n\tget(idx: number): T {\n\t\tif (idx < 0) {\n\t\t\tidx = -idx - 1;\n\t\t\treturn this.negativeArr[idx];\n\t\t} else {\n\t\t\treturn this.positiveArr[idx];\n\t\t}\n\t}\n\n\tset(idx: number, value: T): void {\n\t\tif (idx < 0) {\n\t\t\tidx = -idx - 1;\n\t\t\tthis.negativeArr[idx] = value;\n\t\t} else {\n\t\t\tthis.positiveArr[idx] = value;\n\t\t}\n\t}\n}\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\nimport { forEachWithNeighbors } from 'vs/base/common/arrays';\nimport { OffsetRange } from 'vs/editor/common/core/offsetRange';\nimport { ISequence, OffsetPair, SequenceDiff } from 'vs/editor/common/diff/defaultLinesDiffComputer/algorithms/diffAlgorithm';\nimport { LineSequence } from 'vs/editor/common/diff/defaultLinesDiffComputer/lineSequence';\nimport { LinesSliceCharSequence } from 'vs/editor/common/diff/defaultLinesDiffComputer/linesSliceCharSequence';\n\nexport function optimizeSequenceDiffs(sequence1: ISequence, sequence2: ISequence, sequenceDiffs: SequenceDiff[]): SequenceDiff[] {\n\tlet result = sequenceDiffs;\n\tresult = joinSequenceDiffsByShifting(sequence1, sequence2, result);\n\t// Sometimes, calling this function twice improves the result.\n\t// Uncomment the second invocation and run the tests to see the difference.\n\tresult = joinSequenceDiffsByShifting(sequence1, sequence2, result);\n\tresult = shiftSequenceDiffs(sequence1, sequence2, result);\n\treturn result;\n}\n\n/**\n * This function fixes issues like this:\n * ```\n * import { Baz, Bar } from \"foo\";\n * ```\n * <->\n * ```\n * import { Baz, Bar, Foo } from \"foo\";\n * ```\n * Computed diff: [ {Add \",\" after Bar}, {Add \"Foo \" after space} }\n * Improved diff: [{Add \", Foo\" after Bar}]\n */\nfunction joinSequenceDiffsByShifting(sequence1: ISequence, sequence2: ISequence, sequenceDiffs: SequenceDiff[]): SequenceDiff[] {\n\tif (sequenceDiffs.length === 0) {\n\t\treturn sequenceDiffs;\n\t}\n\n\tconst result: SequenceDiff[] = [];\n\tresult.push(sequenceDiffs[0]);\n\n\t// First move them all to the left as much as possible and join them if possible\n\tfor (let i = 1; i < sequenceDiffs.length; i++) {\n\t\tconst prevResult = result[result.length - 1];\n\t\tlet cur = sequenceDiffs[i];\n\n\t\tif (cur.seq1Range.isEmpty || cur.seq2Range.isEmpty) {\n\t\t\tconst length = cur.seq1Range.start - prevResult.seq1Range.endExclusive;\n\t\t\tlet d;\n\t\t\tfor (d = 1; d <= length; d++) {\n\t\t\t\tif (\n\t\t\t\t\tsequence1.getElement(cur.seq1Range.start - d) !== sequence1.getElement(cur.seq1Range.endExclusive - d) ||\n\t\t\t\t\tsequence2.getElement(cur.seq2Range.start - d) !== sequence2.getElement(cur.seq2Range.endExclusive - d)) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\td--;\n\n\t\t\tif (d === length) {\n\t\t\t\t// Merge previous and current diff\n\t\t\t\tresult[result.length - 1] = new SequenceDiff(\n\t\t\t\t\tnew OffsetRange(prevResult.seq1Range.start, cur.seq1Range.endExclusive - length),\n\t\t\t\t\tnew OffsetRange(prevResult.seq2Range.start, cur.seq2Range.endExclusive - length),\n\t\t\t\t);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tcur = cur.delta(-d);\n\t\t}\n\n\t\tresult.push(cur);\n\t}\n\n\tconst result2: SequenceDiff[] = [];\n\t// Then move them all to the right and join them again if possible\n\tfor (let i = 0; i < result.length - 1; i++) {\n\t\tconst nextResult = result[i + 1];\n\t\tlet cur = result[i];\n\n\t\tif (cur.seq1Range.isEmpty || cur.seq2Range.isEmpty) {\n\t\t\tconst length = nextResult.seq1Range.start - cur.seq1Range.endExclusive;\n\t\t\tlet d;\n\t\t\tfor (d = 0; d < length; d++) {\n\t\t\t\tif (\n\t\t\t\t\t!sequence1.isStronglyEqual(cur.seq1Range.start + d, cur.seq1Range.endExclusive + d) ||\n\t\t\t\t\t!sequence2.isStronglyEqual(cur.seq2Range.start + d, cur.seq2Range.endExclusive + d)\n\t\t\t\t) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (d === length) {\n\t\t\t\t// Merge previous and current diff, write to result!\n\t\t\t\tresult[i + 1] = new SequenceDiff(\n\t\t\t\t\tnew OffsetRange(cur.seq1Range.start + length, nextResult.seq1Range.endExclusive),\n\t\t\t\t\tnew OffsetRange(cur.seq2Range.start + length, nextResult.seq2Range.endExclusive),\n\t\t\t\t);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (d > 0) {\n\t\t\t\tcur = cur.delta(d);\n\t\t\t}\n\t\t}\n\n\t\tresult2.push(cur);\n\t}\n\n\tif (result.length > 0) {\n\t\tresult2.push(result[result.length - 1]);\n\t}\n\n\treturn result2;\n}\n\n// align character level diffs at whitespace characters\n// import { IBar } from \"foo\";\n// import { I[Arr, I]Bar } from \"foo\";\n// ->\n// import { [IArr, ]IBar } from \"foo\";\n\n// import { ITransaction, observableValue, transaction } from 'vs/base/common/observable';\n// import { ITransaction, observable[FromEvent, observable]Value, transaction } from 'vs/base/common/observable';\n// ->\n// import { ITransaction, [observableFromEvent, ]observableValue, transaction } from 'vs/base/common/observable';\n\n// collectBrackets(level + 1, levelPerBracketType);\n// collectBrackets(level + 1, levelPerBracket[ + 1, levelPerBracket]Type);\n// ->\n// collectBrackets(level + 1, [levelPerBracket + 1, ]levelPerBracketType);\n\nfunction shiftSequenceDiffs(sequence1: ISequence, sequence2: ISequence, sequenceDiffs: SequenceDiff[]): SequenceDiff[] {\n\tif (!sequence1.getBoundaryScore || !sequence2.getBoundaryScore) {\n\t\treturn sequenceDiffs;\n\t}\n\n\tfor (let i = 0; i < sequenceDiffs.length; i++) {\n\t\tconst prevDiff = (i > 0 ? sequenceDiffs[i - 1] : undefined);\n\t\tconst diff = sequenceDiffs[i];\n\t\tconst nextDiff = (i + 1 < sequenceDiffs.length ? sequenceDiffs[i + 1] : undefined);\n\n\t\tconst seq1ValidRange = new OffsetRange(prevDiff ? prevDiff.seq1Range.endExclusive + 1 : 0, nextDiff ? nextDiff.seq1Range.start - 1 : sequence1.length);\n\t\tconst seq2ValidRange = new OffsetRange(prevDiff ? prevDiff.seq2Range.endExclusive + 1 : 0, nextDiff ? nextDiff.seq2Range.start - 1 : sequence2.length);\n\n\t\tif (diff.seq1Range.isEmpty) {\n\t\t\tsequenceDiffs[i] = shiftDiffToBetterPosition(diff, sequence1, sequence2, seq1ValidRange, seq2ValidRange);\n\t\t} else if (diff.seq2Range.isEmpty) {\n\t\t\tsequenceDiffs[i] = shiftDiffToBetterPosition(diff.swap(), sequence2, sequence1, seq2ValidRange, seq1ValidRange).swap();\n\t\t}\n\t}\n\n\treturn sequenceDiffs;\n}\n\nfunction shiftDiffToBetterPosition(diff: SequenceDiff, sequence1: ISequence, sequence2: ISequence, seq1ValidRange: OffsetRange, seq2ValidRange: OffsetRange,) {\n\tconst maxShiftLimit = 100; // To prevent performance issues\n\n\t// don't touch previous or next!\n\tlet deltaBefore = 1;\n\twhile (\n\t\tdiff.seq1Range.start - deltaBefore >= seq1ValidRange.start &&\n\t\tdiff.seq2Range.start - deltaBefore >= seq2ValidRange.start &&\n\t\tsequence2.isStronglyEqual(diff.seq2Range.start - deltaBefore, diff.seq2Range.endExclusive - deltaBefore) && deltaBefore < maxShiftLimit\n\t) {\n\t\tdeltaBefore++;\n\t}\n\tdeltaBefore--;\n\n\tlet deltaAfter = 0;\n\twhile (\n\t\tdiff.seq1Range.start + deltaAfter < seq1ValidRange.endExclusive &&\n\t\tdiff.seq2Range.endExclusive + deltaAfter < seq2ValidRange.endExclusive &&\n\t\tsequence2.isStronglyEqual(diff.seq2Range.start + deltaAfter, diff.seq2Range.endExclusive + deltaAfter) && deltaAfter < maxShiftLimit\n\t) {\n\t\tdeltaAfter++;\n\t}\n\n\tif (deltaBefore === 0 && deltaAfter === 0) {\n\t\treturn diff;\n\t}\n\n\t// Visualize `[sequence1.text, diff.seq1Range.start + deltaAfter]`\n\t// and `[sequence2.text, diff.seq2Range.start + deltaAfter, diff.seq2Range.endExclusive + deltaAfter]`\n\n\tlet bestDelta = 0;\n\tlet bestScore = -1;\n\t// find best scored delta\n\tfor (let delta = -deltaBefore; delta <= deltaAfter; delta++) {\n\t\tconst seq2OffsetStart = diff.seq2Range.start + delta;\n\t\tconst seq2OffsetEndExclusive = diff.seq2Range.endExclusive + delta;\n\t\tconst seq1Offset = diff.seq1Range.start + delta;\n\n\t\tconst score = sequence1.getBoundaryScore!(seq1Offset) + sequence2.getBoundaryScore!(seq2OffsetStart) + sequence2.getBoundaryScore!(seq2OffsetEndExclusive);\n\t\tif (score > bestScore) {\n\t\t\tbestScore = score;\n\t\t\tbestDelta = delta;\n\t\t}\n\t}\n\n\treturn diff.delta(bestDelta);\n}\n\nexport function removeShortMatches(sequence1: ISequence, sequence2: ISequence, sequenceDiffs: SequenceDiff[]): SequenceDiff[] {\n\tconst result: SequenceDiff[] = [];\n\tfor (const s of sequenceDiffs) {\n\t\tconst last = result[result.length - 1];\n\t\tif (!last) {\n\t\t\tresult.push(s);\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (s.seq1Range.start - last.seq1Range.endExclusive <= 2 || s.seq2Range.start - last.seq2Range.endExclusive <= 2) {\n\t\t\tresult[result.length - 1] = new SequenceDiff(last.seq1Range.join(s.seq1Range), last.seq2Range.join(s.seq2Range));\n\t\t} else {\n\t\t\tresult.push(s);\n\t\t}\n\t}\n\n\treturn result;\n}\n\nexport function extendDiffsToEntireWordIfAppropriate(sequence1: LinesSliceCharSequence, sequence2: LinesSliceCharSequence, sequenceDiffs: SequenceDiff[]): SequenceDiff[] {\n\tconst equalMappings = SequenceDiff.invert(sequenceDiffs, sequence1.length);\n\n\tconst additional: SequenceDiff[] = [];\n\n\tlet lastPoint = new OffsetPair(0, 0);\n\n\tfunction scanWord(pair: OffsetPair, equalMapping: SequenceDiff) {\n\t\tif (pair.offset1 < lastPoint.offset1 || pair.offset2 < lastPoint.offset2) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst w1 = sequence1.findWordContaining(pair.offset1);\n\t\tconst w2 = sequence2.findWordContaining(pair.offset2);\n\t\tif (!w1 || !w2) {\n\t\t\treturn;\n\t\t}\n\t\tlet w = new SequenceDiff(w1, w2);\n\t\tconst equalPart = w.intersect(equalMapping)!;\n\n\t\tlet equalChars1 = equalPart.seq1Range.length;\n\t\tlet equalChars2 = equalPart.seq2Range.length;\n\n\t\t// The words do not touch previous equals mappings, as we would have processed them already.\n\t\t// But they might touch the next ones.\n\n\t\twhile (equalMappings.length > 0) {\n\t\t\tconst next = equalMappings[0];\n\t\t\tconst intersects = next.seq1Range.intersects(w.seq1Range) || next.seq2Range.intersects(w.seq2Range);\n\t\t\tif (!intersects) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tconst v1 = sequence1.findWordContaining(next.seq1Range.start);\n\t\t\tconst v2 = sequence2.findWordContaining(next.seq2Range.start);\n\t\t\t// Because there is an intersection, we know that the words are not empty.\n\t\t\tconst v = new SequenceDiff(v1!, v2!);\n\t\t\tconst equalPart = v.intersect(next)!;\n\n\t\t\tequalChars1 += equalPart.seq1Range.length;\n\t\t\tequalChars2 += equalPart.seq2Range.length;\n\n\t\t\tw = w.join(v);\n\n\t\t\tif (w.seq1Range.endExclusive >= next.seq1Range.endExclusive) {\n\t\t\t\t// The word extends beyond the next equal mapping.\n\t\t\t\tequalMappings.shift();\n\t\t\t} else {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (equalChars1 + equalChars2 < (w.seq1Range.length + w.seq2Range.length) * 2 / 3) {\n\t\t\tadditional.push(w);\n\t\t}\n\n\t\tlastPoint = w.getEndExclusives();\n\t}\n\n\twhile (equalMappings.length > 0) {\n\t\tconst next = equalMappings.shift()!;\n\t\tif (next.seq1Range.isEmpty) {\n\t\t\tcontinue;\n\t\t}\n\t\tscanWord(next.getStarts(), next);\n\t\t// The equal parts are not empty, so -1 gives us a character that is equal in both parts.\n\t\tscanWord(next.getEndExclusives().delta(-1), next);\n\t}\n\n\tconst merged = mergeSequenceDiffs(sequenceDiffs, additional);\n\treturn merged;\n}\n\nfunction mergeSequenceDiffs(sequenceDiffs1: SequenceDiff[], sequenceDiffs2: SequenceDiff[]): SequenceDiff[] {\n\tconst result: SequenceDiff[] = [];\n\n\twhile (sequenceDiffs1.length > 0 || sequenceDiffs2.length > 0) {\n\t\tconst sd1 = sequenceDiffs1[0];\n\t\tconst sd2 = sequenceDiffs2[0];\n\n\t\tlet next: SequenceDiff;\n\t\tif (sd1 && (!sd2 || sd1.seq1Range.start < sd2.seq1Range.start)) {\n\t\t\tnext = sequenceDiffs1.shift()!;\n\t\t} else {\n\t\t\tnext = sequenceDiffs2.shift()!;\n\t\t}\n\n\t\tif (result.length > 0 && result[result.length - 1].seq1Range.endExclusive >= next.seq1Range.start) {\n\t\t\tresult[result.length - 1] = result[result.length - 1].join(next);\n\t\t} else {\n\t\t\tresult.push(next);\n\t\t}\n\t}\n\n\treturn result;\n}\n\nexport function removeVeryShortMatchingLinesBetweenDiffs(sequence1: LineSequence, _sequence2: LineSequence, sequenceDiffs: SequenceDiff[]): SequenceDiff[] {\n\tlet diffs = sequenceDiffs;\n\tif (diffs.length === 0) {\n\t\treturn diffs;\n\t}\n\n\tlet counter = 0;\n\tlet shouldRepeat: boolean;\n\tdo {\n\t\tshouldRepeat = false;\n\n\t\tconst result: SequenceDiff[] = [\n\t\t\tdiffs[0]\n\t\t];\n\n\t\tfor (let i = 1; i < diffs.length; i++) {\n\t\t\tconst cur = diffs[i];\n\t\t\tconst lastResult = result[result.length - 1];\n\n\t\t\tfunction shouldJoinDiffs(before: SequenceDiff, after: SequenceDiff): boolean {\n\t\t\t\tconst unchangedRange = new OffsetRange(lastResult.seq1Range.endExclusive, cur.seq1Range.start);\n\n\t\t\t\tconst unchangedText = sequence1.getText(unchangedRange);\n\t\t\t\tconst unchangedTextWithoutWs = unchangedText.replace(/\\s/g, '');\n\t\t\t\tif (unchangedTextWithoutWs.length <= 4\n\t\t\t\t\t&& (before.seq1Range.length + before.seq2Range.length > 5 || after.seq1Range.length + after.seq2Range.length > 5)) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tconst shouldJoin = shouldJoinDiffs(lastResult, cur);\n\t\t\tif (shouldJoin) {\n\t\t\t\tshouldRepeat = true;\n\t\t\t\tresult[result.length - 1] = result[result.length - 1].join(cur);\n\t\t\t} else {\n\t\t\t\tresult.push(cur);\n\t\t\t}\n\t\t}\n\n\t\tdiffs = result;\n\t} while (counter++ < 10 && shouldRepeat);\n\n\treturn diffs;\n}\n\nexport function removeVeryShortMatchingTextBetweenLongDiffs(sequence1: LinesSliceCharSequence, sequence2: LinesSliceCharSequence, sequenceDiffs: SequenceDiff[]): SequenceDiff[] {\n\tlet diffs = sequenceDiffs;\n\tif (diffs.length === 0) {\n\t\treturn diffs;\n\t}\n\n\tlet counter = 0;\n\tlet shouldRepeat: boolean;\n\tdo {\n\t\tshouldRepeat = false;\n\n\t\tconst result: SequenceDiff[] = [\n\t\t\tdiffs[0]\n\t\t];\n\n\t\tfor (let i = 1; i < diffs.length; i++) {\n\t\t\tconst cur = diffs[i];\n\t\t\tconst lastResult = result[result.length - 1];\n\n\t\t\tfunction shouldJoinDiffs(before: SequenceDiff, after: SequenceDiff): boolean {\n\t\t\t\tconst unchangedRange = new OffsetRange(lastResult.seq1Range.endExclusive, cur.seq1Range.start);\n\n\t\t\t\tconst unchangedLineCount = sequence1.countLinesIn(unchangedRange);\n\t\t\t\tif (unchangedLineCount > 5 || unchangedRange.length > 500) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tconst unchangedText = sequence1.getText(unchangedRange).trim();\n\t\t\t\tif (unchangedText.length > 20 || unchangedText.split(/\\r\\n|\\r|\\n/).length > 1) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tconst beforeLineCount1 = sequence1.countLinesIn(before.seq1Range);\n\t\t\t\tconst beforeSeq1Length = before.seq1Range.length;\n\t\t\t\tconst beforeLineCount2 = sequence2.countLinesIn(before.seq2Range);\n\t\t\t\tconst beforeSeq2Length = before.seq2Range.length;\n\n\t\t\t\tconst afterLineCount1 = sequence1.countLinesIn(after.seq1Range);\n\t\t\t\tconst afterSeq1Length = after.seq1Range.length;\n\t\t\t\tconst afterLineCount2 = sequence2.countLinesIn(after.seq2Range);\n\t\t\t\tconst afterSeq2Length = after.seq2Range.length;\n\n\t\t\t\t// TODO: Maybe a neural net can be used to derive the result from these numbers\n\n\t\t\t\tconst max = 2 * 40 + 50;\n\t\t\t\tfunction cap(v: number): number {\n\t\t\t\t\treturn Math.min(v, max);\n\t\t\t\t}\n\n\t\t\t\tif (Math.pow(Math.pow(cap(beforeLineCount1 * 40 + beforeSeq1Length), 1.5) + Math.pow(cap(beforeLineCount2 * 40 + beforeSeq2Length), 1.5), 1.5)\n\t\t\t\t\t+ Math.pow(Math.pow(cap(afterLineCount1 * 40 + afterSeq1Length), 1.5) + Math.pow(cap(afterLineCount2 * 40 + afterSeq2Length), 1.5), 1.5) > ((max ** 1.5) ** 1.5) * 1.3) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tconst shouldJoin = shouldJoinDiffs(lastResult, cur);\n\t\t\tif (shouldJoin) {\n\t\t\t\tshouldRepeat = true;\n\t\t\t\tresult[result.length - 1] = result[result.length - 1].join(cur);\n\t\t\t} else {\n\t\t\t\tresult.push(cur);\n\t\t\t}\n\t\t}\n\n\t\tdiffs = result;\n\t} while (counter++ < 10 && shouldRepeat);\n\n\tconst newDiffs: SequenceDiff[] = [];\n\n\t// Remove short suffixes/prefixes\n\tforEachWithNeighbors(diffs, (prev, cur, next) => {\n\t\tlet newDiff = cur;\n\n\t\tfunction shouldMarkAsChanged(text: string): boolean {\n\t\t\treturn text.length > 0 && text.trim().length <= 3 && cur.seq1Range.length + cur.seq2Range.length > 100;\n\t\t}\n\n\t\tconst fullRange1 = sequence1.extendToFullLines(cur.seq1Range);\n\t\tconst prefix = sequence1.getText(new OffsetRange(fullRange1.start, cur.seq1Range.start));\n\t\tif (shouldMarkAsChanged(prefix)) {\n\t\t\tnewDiff = newDiff.deltaStart(-prefix.length);\n\t\t}\n\t\tconst suffix = sequence1.getText(new OffsetRange(cur.seq1Range.endExclusive, fullRange1.endExclusive));\n\t\tif (shouldMarkAsChanged(suffix)) {\n\t\t\tnewDiff = newDiff.deltaEnd(suffix.length);\n\t\t}\n\n\t\tconst availableSpace = SequenceDiff.fromOffsetPairs(\n\t\t\tprev ? prev.getEndExclusives() : OffsetPair.zero,\n\t\t\tnext ? next.getStarts() : OffsetPair.max,\n\t\t);\n\t\tconst result = newDiff.intersect(availableSpace)!;\n\t\tif (newDiffs.length > 0 && result.getStarts().equals(newDiffs[newDiffs.length - 1].getEndExclusives())) {\n\t\t\tnewDiffs[newDiffs.length - 1] = newDiffs[newDiffs.length - 1].join(result);\n\t\t} else {\n\t\t\tnewDiffs.push(result);\n\t\t}\n\t});\n\n\treturn newDiffs;\n}\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\nimport { CharCode } from 'vs/base/common/charCode';\nimport { OffsetRange } from 'vs/editor/common/core/offsetRange';\nimport { ISequence } from 'vs/editor/common/diff/defaultLinesDiffComputer/algorithms/diffAlgorithm';\n\nexport class LineSequence implements ISequence {\n\tconstructor(\n\t\tprivate readonly trimmedHash: number[],\n\t\tprivate readonly lines: string[]\n\t) { }\n\n\tgetElement(offset: number): number {\n\t\treturn this.trimmedHash[offset];\n\t}\n\n\tget length(): number {\n\t\treturn this.trimmedHash.length;\n\t}\n\n\tgetBoundaryScore(length: number): number {\n\t\tconst indentationBefore = length === 0 ? 0 : getIndentation(this.lines[length - 1]);\n\t\tconst indentationAfter = length === this.lines.length ? 0 : getIndentation(this.lines[length]);\n\t\treturn 1000 - (indentationBefore + indentationAfter);\n\t}\n\n\tgetText(range: OffsetRange): string {\n\t\treturn this.lines.slice(range.start, range.endExclusive).join('\\n');\n\t}\n\n\tisStronglyEqual(offset1: number, offset2: number): boolean {\n\t\treturn this.lines[offset1] === this.lines[offset2];\n\t}\n}\n\nfunction getIndentation(str: string): number {\n\tlet i = 0;\n\twhile (i < str.length && (str.charCodeAt(i) === CharCode.Space || str.charCodeAt(i) === CharCode.Tab)) {\n\t\ti++;\n\t}\n\treturn i;\n}\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\nimport { CharCode } from 'vs/base/common/charCode';\nimport { LineRange } from 'vs/editor/common/core/lineRange';\nimport { DetailedLineRangeMapping } from 'vs/editor/common/diff/rangeMapping';\n\nexport class Array2D {\n\tprivate readonly array: T[] = [];\n\n\tconstructor(public readonly width: number, public readonly height: number) {\n\t\tthis.array = new Array(width * height);\n\t}\n\n\tget(x: number, y: number): T {\n\t\treturn this.array[x + y * this.width];\n\t}\n\n\tset(x: number, y: number, value: T): void {\n\t\tthis.array[x + y * this.width] = value;\n\t}\n}\n\nexport function isSpace(charCode: number): boolean {\n\treturn charCode === CharCode.Space || charCode === CharCode.Tab;\n}\n\nexport class LineRangeFragment {\n\tprivate static chrKeys = new Map();\n\n\tprivate static getKey(chr: string): number {\n\t\tlet key = this.chrKeys.get(chr);\n\t\tif (key === undefined) {\n\t\t\tkey = this.chrKeys.size;\n\t\t\tthis.chrKeys.set(chr, key);\n\t\t}\n\t\treturn key;\n\t}\n\n\tprivate readonly totalCount: number;\n\tprivate readonly histogram: number[] = [];\n\tconstructor(\n\t\tpublic readonly range: LineRange,\n\t\tpublic readonly lines: string[],\n\t\tpublic readonly source: DetailedLineRangeMapping,\n\t) {\n\t\tlet counter = 0;\n\t\tfor (let i = range.startLineNumber - 1; i < range.endLineNumberExclusive - 1; i++) {\n\t\t\tconst line = lines[i];\n\t\t\tfor (let j = 0; j < line.length; j++) {\n\t\t\t\tcounter++;\n\t\t\t\tconst chr = line[j];\n\t\t\t\tconst key = LineRangeFragment.getKey(chr);\n\t\t\t\tthis.histogram[key] = (this.histogram[key] || 0) + 1;\n\t\t\t}\n\t\t\tcounter++;\n\t\t\tconst key = LineRangeFragment.getKey('\\n');\n\t\t\tthis.histogram[key] = (this.histogram[key] || 0) + 1;\n\t\t}\n\n\t\tthis.totalCount = counter;\n\t}\n\n\tpublic computeSimilarity(other: LineRangeFragment): number {\n\t\tlet sumDifferences = 0;\n\t\tconst maxLength = Math.max(this.histogram.length, other.histogram.length);\n\t\tfor (let i = 0; i < maxLength; i++) {\n\t\t\tsumDifferences += Math.abs((this.histogram[i] ?? 0) - (other.histogram[i] ?? 0));\n\t\t}\n\t\treturn 1 - (sumDifferences / (this.totalCount + other.totalCount));\n\t}\n}\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\nimport { OffsetRange } from 'vs/editor/common/core/offsetRange';\nimport { IDiffAlgorithm, SequenceDiff, ISequence, ITimeout, InfiniteTimeout, DiffAlgorithmResult } from 'vs/editor/common/diff/defaultLinesDiffComputer/algorithms/diffAlgorithm';\nimport { Array2D } from 'vs/editor/common/diff/defaultLinesDiffComputer/utils';\n\n/**\n * A O(MN) diffing algorithm that supports a score function.\n * The algorithm can be improved by processing the 2d array diagonally.\n*/\nexport class DynamicProgrammingDiffing implements IDiffAlgorithm {\n\tcompute(sequence1: ISequence, sequence2: ISequence, timeout: ITimeout = InfiniteTimeout.instance, equalityScore?: (offset1: number, offset2: number) => number): DiffAlgorithmResult {\n\t\tif (sequence1.length === 0 || sequence2.length === 0) {\n\t\t\treturn DiffAlgorithmResult.trivial(sequence1, sequence2);\n\t\t}\n\n\t\t/**\n\t\t * lcsLengths.get(i, j): Length of the longest common subsequence of sequence1.substring(0, i + 1) and sequence2.substring(0, j + 1).\n\t\t */\n\t\tconst lcsLengths = new Array2D(sequence1.length, sequence2.length);\n\t\tconst directions = new Array2D(sequence1.length, sequence2.length);\n\t\tconst lengths = new Array2D(sequence1.length, sequence2.length);\n\n\t\t// ==== Initializing lcsLengths ====\n\t\tfor (let s1 = 0; s1 < sequence1.length; s1++) {\n\t\t\tfor (let s2 = 0; s2 < sequence2.length; s2++) {\n\t\t\t\tif (!timeout.isValid()) {\n\t\t\t\t\treturn DiffAlgorithmResult.trivialTimedOut(sequence1, sequence2);\n\t\t\t\t}\n\n\t\t\t\tconst horizontalLen = s1 === 0 ? 0 : lcsLengths.get(s1 - 1, s2);\n\t\t\t\tconst verticalLen = s2 === 0 ? 0 : lcsLengths.get(s1, s2 - 1);\n\n\t\t\t\tlet extendedSeqScore: number;\n\t\t\t\tif (sequence1.getElement(s1) === sequence2.getElement(s2)) {\n\t\t\t\t\tif (s1 === 0 || s2 === 0) {\n\t\t\t\t\t\textendedSeqScore = 0;\n\t\t\t\t\t} else {\n\t\t\t\t\t\textendedSeqScore = lcsLengths.get(s1 - 1, s2 - 1);\n\t\t\t\t\t}\n\t\t\t\t\tif (s1 > 0 && s2 > 0 && directions.get(s1 - 1, s2 - 1) === 3) {\n\t\t\t\t\t\t// Prefer consecutive diagonals\n\t\t\t\t\t\textendedSeqScore += lengths.get(s1 - 1, s2 - 1);\n\t\t\t\t\t}\n\t\t\t\t\textendedSeqScore += (equalityScore ? equalityScore(s1, s2) : 1);\n\t\t\t\t} else {\n\t\t\t\t\textendedSeqScore = -1;\n\t\t\t\t}\n\n\t\t\t\tconst newValue = Math.max(horizontalLen, verticalLen, extendedSeqScore);\n\n\t\t\t\tif (newValue === extendedSeqScore) {\n\t\t\t\t\t// Prefer diagonals\n\t\t\t\t\tconst prevLen = s1 > 0 && s2 > 0 ? lengths.get(s1 - 1, s2 - 1) : 0;\n\t\t\t\t\tlengths.set(s1, s2, prevLen + 1);\n\t\t\t\t\tdirections.set(s1, s2, 3);\n\t\t\t\t} else if (newValue === horizontalLen) {\n\t\t\t\t\tlengths.set(s1, s2, 0);\n\t\t\t\t\tdirections.set(s1, s2, 1);\n\t\t\t\t} else if (newValue === verticalLen) {\n\t\t\t\t\tlengths.set(s1, s2, 0);\n\t\t\t\t\tdirections.set(s1, s2, 2);\n\t\t\t\t}\n\n\t\t\t\tlcsLengths.set(s1, s2, newValue);\n\t\t\t}\n\t\t}\n\n\t\t// ==== Backtracking ====\n\t\tconst result: SequenceDiff[] = [];\n\t\tlet lastAligningPosS1: number = sequence1.length;\n\t\tlet lastAligningPosS2: number = sequence2.length;\n\n\t\tfunction reportDecreasingAligningPositions(s1: number, s2: number): void {\n\t\t\tif (s1 + 1 !== lastAligningPosS1 || s2 + 1 !== lastAligningPosS2) {\n\t\t\t\tresult.push(new SequenceDiff(\n\t\t\t\t\tnew OffsetRange(s1 + 1, lastAligningPosS1),\n\t\t\t\t\tnew OffsetRange(s2 + 1, lastAligningPosS2),\n\t\t\t\t));\n\t\t\t}\n\t\t\tlastAligningPosS1 = s1;\n\t\t\tlastAligningPosS2 = s2;\n\t\t}\n\n\t\tlet s1 = sequence1.length - 1;\n\t\tlet s2 = sequence2.length - 1;\n\t\twhile (s1 >= 0 && s2 >= 0) {\n\t\t\tif (directions.get(s1, s2) === 3) {\n\t\t\t\treportDecreasingAligningPositions(s1, s2);\n\t\t\t\ts1--;\n\t\t\t\ts2--;\n\t\t\t} else {\n\t\t\t\tif (directions.get(s1, s2) === 1) {\n\t\t\t\t\ts1--;\n\t\t\t\t} else {\n\t\t\t\t\ts2--;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treportDecreasingAligningPositions(-1, -1);\n\t\tresult.reverse();\n\t\treturn new DiffAlgorithmResult(result, false);\n\t}\n}\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\nimport { findLastIdxMonotonous, findLastMonotonous, findFirstMonotonous } from 'vs/base/common/arraysFind';\nimport { CharCode } from 'vs/base/common/charCode';\nimport { OffsetRange } from 'vs/editor/common/core/offsetRange';\nimport { Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\nimport { ISequence } from 'vs/editor/common/diff/defaultLinesDiffComputer/algorithms/diffAlgorithm';\nimport { isSpace } from 'vs/editor/common/diff/defaultLinesDiffComputer/utils';\n\nexport class LinesSliceCharSequence implements ISequence {\n\tprivate readonly elements: number[] = [];\n\tprivate readonly firstCharOffsetByLine: number[] = [];\n\tpublic readonly lineRange: OffsetRange;\n\t// To account for trimming\n\tprivate readonly additionalOffsetByLine: number[] = [];\n\n\tconstructor(public readonly lines: string[], lineRange: OffsetRange, public readonly considerWhitespaceChanges: boolean) {\n\t\t// This slice has to have lineRange.length many \\n! (otherwise diffing against an empty slice will be problematic)\n\t\t// (Unless it covers the entire document, in that case the other slice also has to cover the entire document ands it's okay)\n\n\t\t// If the slice covers the end, but does not start at the beginning, we include just the \\n of the previous line.\n\t\tlet trimFirstLineFully = false;\n\t\tif (lineRange.start > 0 && lineRange.endExclusive >= lines.length) {\n\t\t\tlineRange = new OffsetRange(lineRange.start - 1, lineRange.endExclusive);\n\t\t\ttrimFirstLineFully = true;\n\t\t}\n\n\t\tthis.lineRange = lineRange;\n\n\t\tthis.firstCharOffsetByLine[0] = 0;\n\t\tfor (let i = this.lineRange.start; i < this.lineRange.endExclusive; i++) {\n\t\t\tlet line = lines[i];\n\t\t\tlet offset = 0;\n\t\t\tif (trimFirstLineFully) {\n\t\t\t\toffset = line.length;\n\t\t\t\tline = '';\n\t\t\t\ttrimFirstLineFully = false;\n\t\t\t} else if (!considerWhitespaceChanges) {\n\t\t\t\tconst trimmedStartLine = line.trimStart();\n\t\t\t\toffset = line.length - trimmedStartLine.length;\n\t\t\t\tline = trimmedStartLine.trimEnd();\n\t\t\t}\n\n\t\t\tthis.additionalOffsetByLine.push(offset);\n\n\t\t\tfor (let i = 0; i < line.length; i++) {\n\t\t\t\tthis.elements.push(line.charCodeAt(i));\n\t\t\t}\n\n\t\t\t// Don't add an \\n that does not exist in the document.\n\t\t\tif (i < lines.length - 1) {\n\t\t\t\tthis.elements.push('\\n'.charCodeAt(0));\n\t\t\t\tthis.firstCharOffsetByLine[i - this.lineRange.start + 1] = this.elements.length;\n\t\t\t}\n\t\t}\n\t\t// To account for the last line\n\t\tthis.additionalOffsetByLine.push(0);\n\t}\n\n\ttoString() {\n\t\treturn `Slice: \"${this.text}\"`;\n\t}\n\n\tget text(): string {\n\t\treturn this.getText(new OffsetRange(0, this.length));\n\t}\n\n\tgetText(range: OffsetRange): string {\n\t\treturn this.elements.slice(range.start, range.endExclusive).map(e => String.fromCharCode(e)).join('');\n\t}\n\n\tgetElement(offset: number): number {\n\t\treturn this.elements[offset];\n\t}\n\n\tget length(): number {\n\t\treturn this.elements.length;\n\t}\n\n\tpublic getBoundaryScore(length: number): number {\n\t\t// a b c , d e f\n\t\t// 11 0 0 12 15 6 13 0 0 11\n\n\t\tconst prevCategory = getCategory(length > 0 ? this.elements[length - 1] : -1);\n\t\tconst nextCategory = getCategory(length < this.elements.length ? this.elements[length] : -1);\n\n\t\tif (prevCategory === CharBoundaryCategory.LineBreakCR && nextCategory === CharBoundaryCategory.LineBreakLF) {\n\t\t\t// don't break between \\r and \\n\n\t\t\treturn 0;\n\t\t}\n\t\tif (prevCategory === CharBoundaryCategory.LineBreakLF) {\n\t\t\t// prefer the linebreak before the change\n\t\t\treturn 150;\n\t\t}\n\n\t\tlet score = 0;\n\t\tif (prevCategory !== nextCategory) {\n\t\t\tscore += 10;\n\t\t\tif (prevCategory === CharBoundaryCategory.WordLower && nextCategory === CharBoundaryCategory.WordUpper) {\n\t\t\t\tscore += 1;\n\t\t\t}\n\t\t}\n\n\t\tscore += getCategoryBoundaryScore(prevCategory);\n\t\tscore += getCategoryBoundaryScore(nextCategory);\n\n\t\treturn score;\n\t}\n\n\tpublic translateOffset(offset: number): Position {\n\t\t// find smallest i, so that lineBreakOffsets[i] <= offset using binary search\n\t\tif (this.lineRange.isEmpty) {\n\t\t\treturn new Position(this.lineRange.start + 1, 1);\n\t\t}\n\n\t\tconst i = findLastIdxMonotonous(this.firstCharOffsetByLine, (value) => value <= offset);\n\t\treturn new Position(this.lineRange.start + i + 1, offset - this.firstCharOffsetByLine[i] + this.additionalOffsetByLine[i] + 1);\n\t}\n\n\tpublic translateRange(range: OffsetRange): Range {\n\t\treturn Range.fromPositions(this.translateOffset(range.start), this.translateOffset(range.endExclusive));\n\t}\n\n\t/**\n\t * Finds the word that contains the character at the given offset\n\t */\n\tpublic findWordContaining(offset: number): OffsetRange | undefined {\n\t\tif (offset < 0 || offset >= this.elements.length) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (!isWordChar(this.elements[offset])) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\t// find start\n\t\tlet start = offset;\n\t\twhile (start > 0 && isWordChar(this.elements[start - 1])) {\n\t\t\tstart--;\n\t\t}\n\n\t\t// find end\n\t\tlet end = offset;\n\t\twhile (end < this.elements.length && isWordChar(this.elements[end])) {\n\t\t\tend++;\n\t\t}\n\n\t\treturn new OffsetRange(start, end);\n\t}\n\n\tpublic countLinesIn(range: OffsetRange): number {\n\t\treturn this.translateOffset(range.endExclusive).lineNumber - this.translateOffset(range.start).lineNumber;\n\t}\n\n\tpublic isStronglyEqual(offset1: number, offset2: number): boolean {\n\t\treturn this.elements[offset1] === this.elements[offset2];\n\t}\n\n\tpublic extendToFullLines(range: OffsetRange): OffsetRange {\n\t\tconst start = findLastMonotonous(this.firstCharOffsetByLine, x => x <= range.start) ?? 0;\n\t\tconst end = findFirstMonotonous(this.firstCharOffsetByLine, x => range.endExclusive <= x) ?? this.elements.length;\n\t\treturn new OffsetRange(start, end);\n\t}\n}\n\nfunction isWordChar(charCode: number): boolean {\n\treturn charCode >= CharCode.a && charCode <= CharCode.z\n\t\t|| charCode >= CharCode.A && charCode <= CharCode.Z\n\t\t|| charCode >= CharCode.Digit0 && charCode <= CharCode.Digit9;\n}\n\nconst enum CharBoundaryCategory {\n\tWordLower,\n\tWordUpper,\n\tWordNumber,\n\tEnd,\n\tOther,\n\tSeparator,\n\tSpace,\n\tLineBreakCR,\n\tLineBreakLF,\n}\n\nconst score: Record = {\n\t[CharBoundaryCategory.WordLower]: 0,\n\t[CharBoundaryCategory.WordUpper]: 0,\n\t[CharBoundaryCategory.WordNumber]: 0,\n\t[CharBoundaryCategory.End]: 10,\n\t[CharBoundaryCategory.Other]: 2,\n\t[CharBoundaryCategory.Separator]: 30,\n\t[CharBoundaryCategory.Space]: 3,\n\t[CharBoundaryCategory.LineBreakCR]: 10,\n\t[CharBoundaryCategory.LineBreakLF]: 10,\n};\n\nfunction getCategoryBoundaryScore(category: CharBoundaryCategory): number {\n\treturn score[category];\n}\n\nfunction getCategory(charCode: number): CharBoundaryCategory {\n\tif (charCode === CharCode.LineFeed) {\n\t\treturn CharBoundaryCategory.LineBreakLF;\n\t} else if (charCode === CharCode.CarriageReturn) {\n\t\treturn CharBoundaryCategory.LineBreakCR;\n\t} else if (isSpace(charCode)) {\n\t\treturn CharBoundaryCategory.Space;\n\t} else if (charCode >= CharCode.a && charCode <= CharCode.z) {\n\t\treturn CharBoundaryCategory.WordLower;\n\t} else if (charCode >= CharCode.A && charCode <= CharCode.Z) {\n\t\treturn CharBoundaryCategory.WordUpper;\n\t} else if (charCode >= CharCode.Digit0 && charCode <= CharCode.Digit9) {\n\t\treturn CharBoundaryCategory.WordNumber;\n\t} else if (charCode === -1) {\n\t\treturn CharBoundaryCategory.End;\n\t} else if (charCode === CharCode.Comma || charCode === CharCode.Semicolon) {\n\t\treturn CharBoundaryCategory.Separator;\n\t} else {\n\t\treturn CharBoundaryCategory.Other;\n\t}\n}\n\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\nimport { DetailedLineRangeMapping, LineRangeMapping } from './rangeMapping';\n\nexport interface ILinesDiffComputer {\n\tcomputeDiff(originalLines: string[], modifiedLines: string[], options: ILinesDiffComputerOptions): LinesDiff;\n}\n\nexport interface ILinesDiffComputerOptions {\n\treadonly ignoreTrimWhitespace: boolean;\n\treadonly maxComputationTimeMs: number;\n\treadonly computeMoves: boolean;\n}\n\nexport class LinesDiff {\n\tconstructor(\n\t\treadonly changes: readonly DetailedLineRangeMapping[],\n\n\t\t/**\n\t\t * Sorted by original line ranges.\n\t\t * The original line ranges and the modified line ranges must be disjoint (but can be touching).\n\t\t */\n\t\treadonly moves: readonly MovedText[],\n\n\t\t/**\n\t\t * Indicates if the time out was reached.\n\t\t * In that case, the diffs might be an approximation and the user should be asked to rerun the diff with more time.\n\t\t */\n\t\treadonly hitTimeout: boolean,\n\t) {\n\t}\n}\n\nexport class MovedText {\n\tpublic readonly lineRangeMapping: LineRangeMapping;\n\n\t/**\n\t * The diff from the original text to the moved text.\n\t * Must be contained in the original/modified line range.\n\t * Can be empty if the text didn't change (only moved).\n\t */\n\tpublic readonly changes: readonly DetailedLineRangeMapping[];\n\n\tconstructor(\n\t\tlineRangeMapping: LineRangeMapping,\n\t\tchanges: readonly DetailedLineRangeMapping[],\n\t) {\n\t\tthis.lineRangeMapping = lineRangeMapping;\n\t\tthis.changes = changes;\n\t}\n}\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\nimport { BugIndicatingError } from 'vs/base/common/errors';\nimport { LineRange } from 'vs/editor/common/core/lineRange';\nimport { Range } from 'vs/editor/common/core/range';\nimport { AbstractText, SingleTextEdit } from 'vs/editor/common/core/textEdit';\n\n/**\n * Maps a line range in the original text model to a line range in the modified text model.\n */\nexport class LineRangeMapping {\n\tpublic static inverse(mapping: readonly LineRangeMapping[], originalLineCount: number, modifiedLineCount: number): LineRangeMapping[] {\n\t\tconst result: LineRangeMapping[] = [];\n\t\tlet lastOriginalEndLineNumber = 1;\n\t\tlet lastModifiedEndLineNumber = 1;\n\n\t\tfor (const m of mapping) {\n\t\t\tconst r = new LineRangeMapping(\n\t\t\t\tnew LineRange(lastOriginalEndLineNumber, m.original.startLineNumber),\n\t\t\t\tnew LineRange(lastModifiedEndLineNumber, m.modified.startLineNumber),\n\t\t\t);\n\t\t\tif (!r.modified.isEmpty) {\n\t\t\t\tresult.push(r);\n\t\t\t}\n\t\t\tlastOriginalEndLineNumber = m.original.endLineNumberExclusive;\n\t\t\tlastModifiedEndLineNumber = m.modified.endLineNumberExclusive;\n\t\t}\n\t\tconst r = new LineRangeMapping(\n\t\t\tnew LineRange(lastOriginalEndLineNumber, originalLineCount + 1),\n\t\t\tnew LineRange(lastModifiedEndLineNumber, modifiedLineCount + 1),\n\t\t);\n\t\tif (!r.modified.isEmpty) {\n\t\t\tresult.push(r);\n\t\t}\n\t\treturn result;\n\t}\n\n\tpublic static clip(mapping: readonly LineRangeMapping[], originalRange: LineRange, modifiedRange: LineRange): LineRangeMapping[] {\n\t\tconst result: LineRangeMapping[] = [];\n\t\tfor (const m of mapping) {\n\t\t\tconst original = m.original.intersect(originalRange);\n\t\t\tconst modified = m.modified.intersect(modifiedRange);\n\t\t\tif (original && !original.isEmpty && modified && !modified.isEmpty) {\n\t\t\t\tresult.push(new LineRangeMapping(original, modified));\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * The line range in the original text model.\n\t */\n\tpublic readonly original: LineRange;\n\n\t/**\n\t * The line range in the modified text model.\n\t */\n\tpublic readonly modified: LineRange;\n\n\tconstructor(\n\t\toriginalRange: LineRange,\n\t\tmodifiedRange: LineRange\n\t) {\n\t\tthis.original = originalRange;\n\t\tthis.modified = modifiedRange;\n\t}\n\n\n\tpublic toString(): string {\n\t\treturn `{${this.original.toString()}->${this.modified.toString()}}`;\n\t}\n\n\tpublic flip(): LineRangeMapping {\n\t\treturn new LineRangeMapping(this.modified, this.original);\n\t}\n\n\tpublic join(other: LineRangeMapping): LineRangeMapping {\n\t\treturn new LineRangeMapping(\n\t\t\tthis.original.join(other.original),\n\t\t\tthis.modified.join(other.modified)\n\t\t);\n\t}\n\n\t/**\n\t * This method assumes that the LineRangeMapping describes a valid diff!\n\t * I.e. if one range is empty, the other range cannot be the entire document.\n\t * It avoids various problems when the line range points to non-existing line-numbers.\n\t*/\n\tpublic toRangeMapping(): RangeMapping {\n\t\tconst origInclusiveRange = this.original.toInclusiveRange();\n\t\tconst modInclusiveRange = this.modified.toInclusiveRange();\n\t\tif (origInclusiveRange && modInclusiveRange) {\n\t\t\treturn new RangeMapping(origInclusiveRange, modInclusiveRange);\n\t\t} else if (this.original.startLineNumber === 1 || this.modified.startLineNumber === 1) {\n\t\t\tif (!(this.modified.startLineNumber === 1 && this.original.startLineNumber === 1)) {\n\t\t\t\t// If one line range starts at 1, the other one must start at 1 as well.\n\t\t\t\tthrow new BugIndicatingError('not a valid diff');\n\t\t\t}\n\n\t\t\t// Because one range is empty and both ranges start at line 1, none of the ranges can cover all lines.\n\t\t\t// Thus, `endLineNumberExclusive` is a valid line number.\n\t\t\treturn new RangeMapping(\n\t\t\t\tnew Range(this.original.startLineNumber, 1, this.original.endLineNumberExclusive, 1),\n\t\t\t\tnew Range(this.modified.startLineNumber, 1, this.modified.endLineNumberExclusive, 1),\n\t\t\t);\n\t\t} else {\n\t\t\t// We can assume here that both startLineNumbers are greater than 1.\n\t\t\treturn new RangeMapping(\n\t\t\t\tnew Range(this.original.startLineNumber - 1, Number.MAX_SAFE_INTEGER, this.original.endLineNumberExclusive - 1, Number.MAX_SAFE_INTEGER),\n\t\t\t\tnew Range(this.modified.startLineNumber - 1, Number.MAX_SAFE_INTEGER, this.modified.endLineNumberExclusive - 1, Number.MAX_SAFE_INTEGER),\n\t\t\t);\n\t\t}\n\t}\n}\n\n/**\n * Maps a line range in the original text model to a line range in the modified text model.\n * Also contains inner range mappings.\n */\nexport class DetailedLineRangeMapping extends LineRangeMapping {\n\tpublic static fromRangeMappings(rangeMappings: RangeMapping[]): DetailedLineRangeMapping {\n\t\tconst originalRange = LineRange.join(rangeMappings.map(r => LineRange.fromRangeInclusive(r.originalRange)));\n\t\tconst modifiedRange = LineRange.join(rangeMappings.map(r => LineRange.fromRangeInclusive(r.modifiedRange)));\n\t\treturn new DetailedLineRangeMapping(originalRange, modifiedRange, rangeMappings);\n\t}\n\n\t/**\n\t * If inner changes have not been computed, this is set to undefined.\n\t * Otherwise, it represents the character-level diff in this line range.\n\t * The original range of each range mapping should be contained in the original line range (same for modified), exceptions are new-lines.\n\t * Must not be an empty array.\n\t */\n\tpublic readonly innerChanges: RangeMapping[] | undefined;\n\n\tconstructor(\n\t\toriginalRange: LineRange,\n\t\tmodifiedRange: LineRange,\n\t\tinnerChanges: RangeMapping[] | undefined\n\t) {\n\t\tsuper(originalRange, modifiedRange);\n\t\tthis.innerChanges = innerChanges;\n\t}\n\n\tpublic override flip(): DetailedLineRangeMapping {\n\t\treturn new DetailedLineRangeMapping(this.modified, this.original, this.innerChanges?.map(c => c.flip()));\n\t}\n\n\tpublic withInnerChangesFromLineRanges(): DetailedLineRangeMapping {\n\t\treturn new DetailedLineRangeMapping(this.original, this.modified, [this.toRangeMapping()]);\n\t}\n}\n\n/**\n * Maps a range in the original text model to a range in the modified text model.\n */\nexport class RangeMapping {\n\t/**\n\t * The original range.\n\t */\n\treadonly originalRange: Range;\n\n\t/**\n\t * The modified range.\n\t */\n\treadonly modifiedRange: Range;\n\n\tconstructor(\n\t\toriginalRange: Range,\n\t\tmodifiedRange: Range\n\t) {\n\t\tthis.originalRange = originalRange;\n\t\tthis.modifiedRange = modifiedRange;\n\t}\n\n\tpublic toString(): string {\n\t\treturn `{${this.originalRange.toString()}->${this.modifiedRange.toString()}}`;\n\t}\n\n\tpublic flip(): RangeMapping {\n\t\treturn new RangeMapping(this.modifiedRange, this.originalRange);\n\t}\n\n\t/**\n\t * Creates a single text edit that describes the change from the original to the modified text.\n\t*/\n\tpublic toTextEdit(modified: AbstractText): SingleTextEdit {\n\t\tconst newText = modified.getValueOfRange(this.modifiedRange);\n\t\treturn new SingleTextEdit(this.originalRange, newText);\n\t}\n}\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\nimport { ITimeout, SequenceDiff } from 'vs/editor/common/diff/defaultLinesDiffComputer/algorithms/diffAlgorithm';\nimport { DetailedLineRangeMapping, LineRangeMapping } from '../rangeMapping';\nimport { pushMany, compareBy, numberComparator, reverseOrder } from 'vs/base/common/arrays';\nimport { MonotonousArray, findLastMonotonous } from 'vs/base/common/arraysFind';\nimport { SetMap } from 'vs/base/common/map';\nimport { LineRange, LineRangeSet } from 'vs/editor/common/core/lineRange';\nimport { OffsetRange } from 'vs/editor/common/core/offsetRange';\nimport { LinesSliceCharSequence } from 'vs/editor/common/diff/defaultLinesDiffComputer/linesSliceCharSequence';\nimport { LineRangeFragment, isSpace } from 'vs/editor/common/diff/defaultLinesDiffComputer/utils';\nimport { MyersDiffAlgorithm } from 'vs/editor/common/diff/defaultLinesDiffComputer/algorithms/myersDiffAlgorithm';\n\nexport function computeMovedLines(\n\tchanges: DetailedLineRangeMapping[],\n\toriginalLines: string[],\n\tmodifiedLines: string[],\n\thashedOriginalLines: number[],\n\thashedModifiedLines: number[],\n\ttimeout: ITimeout\n): LineRangeMapping[] {\n\tlet { moves, excludedChanges } = computeMovesFromSimpleDeletionsToSimpleInsertions(changes, originalLines, modifiedLines, timeout);\n\n\tif (!timeout.isValid()) { return []; }\n\n\tconst filteredChanges = changes.filter(c => !excludedChanges.has(c));\n\tconst unchangedMoves = computeUnchangedMoves(filteredChanges, hashedOriginalLines, hashedModifiedLines, originalLines, modifiedLines, timeout);\n\tpushMany(moves, unchangedMoves);\n\n\tmoves = joinCloseConsecutiveMoves(moves);\n\t// Ignore too short moves\n\tmoves = moves.filter(current => {\n\t\tconst lines = current.original.toOffsetRange().slice(originalLines).map(l => l.trim());\n\t\tconst originalText = lines.join('\\n');\n\t\treturn originalText.length >= 15 && countWhere(lines, l => l.length >= 2) >= 2;\n\t});\n\tmoves = removeMovesInSameDiff(changes, moves);\n\n\treturn moves;\n}\n\nfunction countWhere(arr: T[], predicate: (t: T) => boolean): number {\n\tlet count = 0;\n\tfor (const t of arr) {\n\t\tif (predicate(t)) {\n\t\t\tcount++;\n\t\t}\n\t}\n\treturn count;\n}\n\nfunction computeMovesFromSimpleDeletionsToSimpleInsertions(\n\tchanges: DetailedLineRangeMapping[],\n\toriginalLines: string[],\n\tmodifiedLines: string[],\n\ttimeout: ITimeout,\n) {\n\tconst moves: LineRangeMapping[] = [];\n\n\tconst deletions = changes\n\t\t.filter(c => c.modified.isEmpty && c.original.length >= 3)\n\t\t.map(d => new LineRangeFragment(d.original, originalLines, d));\n\tconst insertions = new Set(changes\n\t\t.filter(c => c.original.isEmpty && c.modified.length >= 3)\n\t\t.map(d => new LineRangeFragment(d.modified, modifiedLines, d)));\n\n\tconst excludedChanges = new Set();\n\n\tfor (const deletion of deletions) {\n\t\tlet highestSimilarity = -1;\n\t\tlet best: LineRangeFragment | undefined;\n\t\tfor (const insertion of insertions) {\n\t\t\tconst similarity = deletion.computeSimilarity(insertion);\n\t\t\tif (similarity > highestSimilarity) {\n\t\t\t\thighestSimilarity = similarity;\n\t\t\t\tbest = insertion;\n\t\t\t}\n\t\t}\n\n\t\tif (highestSimilarity > 0.90 && best) {\n\t\t\tinsertions.delete(best);\n\t\t\tmoves.push(new LineRangeMapping(deletion.range, best.range));\n\t\t\texcludedChanges.add(deletion.source);\n\t\t\texcludedChanges.add(best.source);\n\t\t}\n\n\t\tif (!timeout.isValid()) {\n\t\t\treturn { moves, excludedChanges };\n\t\t}\n\t}\n\n\treturn { moves, excludedChanges };\n}\n\nfunction computeUnchangedMoves(\n\tchanges: DetailedLineRangeMapping[],\n\thashedOriginalLines: number[],\n\thashedModifiedLines: number[],\n\toriginalLines: string[],\n\tmodifiedLines: string[],\n\ttimeout: ITimeout,\n) {\n\tconst moves: LineRangeMapping[] = [];\n\n\tconst original3LineHashes = new SetMap();\n\n\tfor (const change of changes) {\n\t\tfor (let i = change.original.startLineNumber; i < change.original.endLineNumberExclusive - 2; i++) {\n\t\t\tconst key = `${hashedOriginalLines[i - 1]}:${hashedOriginalLines[i + 1 - 1]}:${hashedOriginalLines[i + 2 - 1]}`;\n\t\t\toriginal3LineHashes.add(key, { range: new LineRange(i, i + 3) });\n\t\t}\n\t}\n\n\tinterface PossibleMapping {\n\t\tmodifiedLineRange: LineRange;\n\t\toriginalLineRange: LineRange;\n\t}\n\n\tconst possibleMappings: PossibleMapping[] = [];\n\n\tchanges.sort(compareBy(c => c.modified.startLineNumber, numberComparator));\n\n\tfor (const change of changes) {\n\t\tlet lastMappings: PossibleMapping[] = [];\n\t\tfor (let i = change.modified.startLineNumber; i < change.modified.endLineNumberExclusive - 2; i++) {\n\t\t\tconst key = `${hashedModifiedLines[i - 1]}:${hashedModifiedLines[i + 1 - 1]}:${hashedModifiedLines[i + 2 - 1]}`;\n\t\t\tconst currentModifiedRange = new LineRange(i, i + 3);\n\n\t\t\tconst nextMappings: PossibleMapping[] = [];\n\t\t\toriginal3LineHashes.forEach(key, ({ range }) => {\n\t\t\t\tfor (const lastMapping of lastMappings) {\n\t\t\t\t\t// does this match extend some last match?\n\t\t\t\t\tif (lastMapping.originalLineRange.endLineNumberExclusive + 1 === range.endLineNumberExclusive &&\n\t\t\t\t\t\tlastMapping.modifiedLineRange.endLineNumberExclusive + 1 === currentModifiedRange.endLineNumberExclusive) {\n\t\t\t\t\t\tlastMapping.originalLineRange = new LineRange(lastMapping.originalLineRange.startLineNumber, range.endLineNumberExclusive);\n\t\t\t\t\t\tlastMapping.modifiedLineRange = new LineRange(lastMapping.modifiedLineRange.startLineNumber, currentModifiedRange.endLineNumberExclusive);\n\t\t\t\t\t\tnextMappings.push(lastMapping);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst mapping: PossibleMapping = {\n\t\t\t\t\tmodifiedLineRange: currentModifiedRange,\n\t\t\t\t\toriginalLineRange: range,\n\t\t\t\t};\n\t\t\t\tpossibleMappings.push(mapping);\n\t\t\t\tnextMappings.push(mapping);\n\t\t\t});\n\t\t\tlastMappings = nextMappings;\n\t\t}\n\n\t\tif (!timeout.isValid()) {\n\t\t\treturn [];\n\t\t}\n\t}\n\n\tpossibleMappings.sort(reverseOrder(compareBy(m => m.modifiedLineRange.length, numberComparator)));\n\n\tconst modifiedSet = new LineRangeSet();\n\tconst originalSet = new LineRangeSet();\n\n\tfor (const mapping of possibleMappings) {\n\n\t\tconst diffOrigToMod = mapping.modifiedLineRange.startLineNumber - mapping.originalLineRange.startLineNumber;\n\t\tconst modifiedSections = modifiedSet.subtractFrom(mapping.modifiedLineRange);\n\t\tconst originalTranslatedSections = originalSet.subtractFrom(mapping.originalLineRange).getWithDelta(diffOrigToMod);\n\n\t\tconst modifiedIntersectedSections = modifiedSections.getIntersection(originalTranslatedSections);\n\n\t\tfor (const s of modifiedIntersectedSections.ranges) {\n\t\t\tif (s.length < 3) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst modifiedLineRange = s;\n\t\t\tconst originalLineRange = s.delta(-diffOrigToMod);\n\n\t\t\tmoves.push(new LineRangeMapping(originalLineRange, modifiedLineRange));\n\n\t\t\tmodifiedSet.addRange(modifiedLineRange);\n\t\t\toriginalSet.addRange(originalLineRange);\n\t\t}\n\t}\n\n\tmoves.sort(compareBy(m => m.original.startLineNumber, numberComparator));\n\n\tconst monotonousChanges = new MonotonousArray(changes);\n\tfor (let i = 0; i < moves.length; i++) {\n\t\tconst move = moves[i];\n\t\tconst firstTouchingChangeOrig = monotonousChanges.findLastMonotonous(c => c.original.startLineNumber <= move.original.startLineNumber)!;\n\t\tconst firstTouchingChangeMod = findLastMonotonous(changes, c => c.modified.startLineNumber <= move.modified.startLineNumber)!;\n\t\tconst linesAbove = Math.max(\n\t\t\tmove.original.startLineNumber - firstTouchingChangeOrig.original.startLineNumber,\n\t\t\tmove.modified.startLineNumber - firstTouchingChangeMod.modified.startLineNumber\n\t\t);\n\n\t\tconst lastTouchingChangeOrig = monotonousChanges.findLastMonotonous(c => c.original.startLineNumber < move.original.endLineNumberExclusive)!;\n\t\tconst lastTouchingChangeMod = findLastMonotonous(changes, c => c.modified.startLineNumber < move.modified.endLineNumberExclusive)!;\n\t\tconst linesBelow = Math.max(\n\t\t\tlastTouchingChangeOrig.original.endLineNumberExclusive - move.original.endLineNumberExclusive,\n\t\t\tlastTouchingChangeMod.modified.endLineNumberExclusive - move.modified.endLineNumberExclusive\n\t\t);\n\n\t\tlet extendToTop: number;\n\t\tfor (extendToTop = 0; extendToTop < linesAbove; extendToTop++) {\n\t\t\tconst origLine = move.original.startLineNumber - extendToTop - 1;\n\t\t\tconst modLine = move.modified.startLineNumber - extendToTop - 1;\n\t\t\tif (origLine > originalLines.length || modLine > modifiedLines.length) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (modifiedSet.contains(modLine) || originalSet.contains(origLine)) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (!areLinesSimilar(originalLines[origLine - 1], modifiedLines[modLine - 1], timeout)) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (extendToTop > 0) {\n\t\t\toriginalSet.addRange(new LineRange(move.original.startLineNumber - extendToTop, move.original.startLineNumber));\n\t\t\tmodifiedSet.addRange(new LineRange(move.modified.startLineNumber - extendToTop, move.modified.startLineNumber));\n\t\t}\n\n\t\tlet extendToBottom: number;\n\t\tfor (extendToBottom = 0; extendToBottom < linesBelow; extendToBottom++) {\n\t\t\tconst origLine = move.original.endLineNumberExclusive + extendToBottom;\n\t\t\tconst modLine = move.modified.endLineNumberExclusive + extendToBottom;\n\t\t\tif (origLine > originalLines.length || modLine > modifiedLines.length) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (modifiedSet.contains(modLine) || originalSet.contains(origLine)) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (!areLinesSimilar(originalLines[origLine - 1], modifiedLines[modLine - 1], timeout)) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (extendToBottom > 0) {\n\t\t\toriginalSet.addRange(new LineRange(move.original.endLineNumberExclusive, move.original.endLineNumberExclusive + extendToBottom));\n\t\t\tmodifiedSet.addRange(new LineRange(move.modified.endLineNumberExclusive, move.modified.endLineNumberExclusive + extendToBottom));\n\t\t}\n\n\t\tif (extendToTop > 0 || extendToBottom > 0) {\n\t\t\tmoves[i] = new LineRangeMapping(\n\t\t\t\tnew LineRange(move.original.startLineNumber - extendToTop, move.original.endLineNumberExclusive + extendToBottom),\n\t\t\t\tnew LineRange(move.modified.startLineNumber - extendToTop, move.modified.endLineNumberExclusive + extendToBottom),\n\t\t\t);\n\t\t}\n\t}\n\n\treturn moves;\n}\n\nfunction areLinesSimilar(line1: string, line2: string, timeout: ITimeout): boolean {\n\tif (line1.trim() === line2.trim()) { return true; }\n\tif (line1.length > 300 && line2.length > 300) { return false; }\n\n\tconst myersDiffingAlgorithm = new MyersDiffAlgorithm();\n\tconst result = myersDiffingAlgorithm.compute(\n\t\tnew LinesSliceCharSequence([line1], new OffsetRange(0, 1), false),\n\t\tnew LinesSliceCharSequence([line2], new OffsetRange(0, 1), false),\n\t\ttimeout\n\t);\n\tlet commonNonSpaceCharCount = 0;\n\tconst inverted = SequenceDiff.invert(result.diffs, line1.length);\n\tfor (const seq of inverted) {\n\t\tseq.seq1Range.forEach(idx => {\n\t\t\tif (!isSpace(line1.charCodeAt(idx))) {\n\t\t\t\tcommonNonSpaceCharCount++;\n\t\t\t}\n\t\t});\n\t}\n\n\tfunction countNonWsChars(str: string): number {\n\t\tlet count = 0;\n\t\tfor (let i = 0; i < line1.length; i++) {\n\t\t\tif (!isSpace(str.charCodeAt(i))) {\n\t\t\t\tcount++;\n\t\t\t}\n\t\t}\n\t\treturn count;\n\t}\n\n\tconst longerLineLength = countNonWsChars(line1.length > line2.length ? line1 : line2);\n\tconst r = commonNonSpaceCharCount / longerLineLength > 0.6 && longerLineLength > 10;\n\treturn r;\n}\n\nfunction joinCloseConsecutiveMoves(moves: LineRangeMapping[]): LineRangeMapping[] {\n\tif (moves.length === 0) {\n\t\treturn moves;\n\t}\n\n\tmoves.sort(compareBy(m => m.original.startLineNumber, numberComparator));\n\n\tconst result = [moves[0]];\n\tfor (let i = 1; i < moves.length; i++) {\n\t\tconst last = result[result.length - 1];\n\t\tconst current = moves[i];\n\n\t\tconst originalDist = current.original.startLineNumber - last.original.endLineNumberExclusive;\n\t\tconst modifiedDist = current.modified.startLineNumber - last.modified.endLineNumberExclusive;\n\t\tconst currentMoveAfterLast = originalDist >= 0 && modifiedDist >= 0;\n\n\t\tif (currentMoveAfterLast && originalDist + modifiedDist <= 2) {\n\t\t\tresult[result.length - 1] = last.join(current);\n\t\t\tcontinue;\n\t\t}\n\n\t\tresult.push(current);\n\t}\n\treturn result;\n}\n\nfunction removeMovesInSameDiff(changes: DetailedLineRangeMapping[], moves: LineRangeMapping[]) {\n\tconst changesMonotonous = new MonotonousArray(changes);\n\tmoves = moves.filter(m => {\n\t\tconst diffBeforeEndOfMoveOriginal = changesMonotonous.findLastMonotonous(c => c.original.startLineNumber < m.original.endLineNumberExclusive)\n\t\t\t|| new LineRangeMapping(new LineRange(1, 1), new LineRange(1, 1));\n\t\tconst diffBeforeEndOfMoveModified = findLastMonotonous(changes, c => c.modified.startLineNumber < m.modified.endLineNumberExclusive);\n\n\t\tconst differentDiffs = diffBeforeEndOfMoveOriginal !== diffBeforeEndOfMoveModified;\n\t\treturn differentDiffs;\n\t});\n\treturn moves;\n}\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\nimport { equals, groupAdjacentBy } from 'vs/base/common/arrays';\nimport { assertFn, checkAdjacentItems } from 'vs/base/common/assert';\nimport { LineRange } from 'vs/editor/common/core/lineRange';\nimport { OffsetRange } from 'vs/editor/common/core/offsetRange';\nimport { Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\nimport { DateTimeout, ITimeout, InfiniteTimeout, SequenceDiff } from 'vs/editor/common/diff/defaultLinesDiffComputer/algorithms/diffAlgorithm';\nimport { DynamicProgrammingDiffing } from 'vs/editor/common/diff/defaultLinesDiffComputer/algorithms/dynamicProgrammingDiffing';\nimport { MyersDiffAlgorithm } from 'vs/editor/common/diff/defaultLinesDiffComputer/algorithms/myersDiffAlgorithm';\nimport { computeMovedLines } from 'vs/editor/common/diff/defaultLinesDiffComputer/computeMovedLines';\nimport { extendDiffsToEntireWordIfAppropriate, optimizeSequenceDiffs, removeShortMatches, removeVeryShortMatchingLinesBetweenDiffs, removeVeryShortMatchingTextBetweenLongDiffs } from 'vs/editor/common/diff/defaultLinesDiffComputer/heuristicSequenceOptimizations';\nimport { LineSequence } from 'vs/editor/common/diff/defaultLinesDiffComputer/lineSequence';\nimport { LinesSliceCharSequence } from 'vs/editor/common/diff/defaultLinesDiffComputer/linesSliceCharSequence';\nimport { ILinesDiffComputer, ILinesDiffComputerOptions, LinesDiff, MovedText } from 'vs/editor/common/diff/linesDiffComputer';\nimport { DetailedLineRangeMapping, RangeMapping } from '../rangeMapping';\n\nexport class DefaultLinesDiffComputer implements ILinesDiffComputer {\n\tprivate readonly dynamicProgrammingDiffing = new DynamicProgrammingDiffing();\n\tprivate readonly myersDiffingAlgorithm = new MyersDiffAlgorithm();\n\n\tcomputeDiff(originalLines: string[], modifiedLines: string[], options: ILinesDiffComputerOptions): LinesDiff {\n\t\tif (originalLines.length <= 1 && equals(originalLines, modifiedLines, (a, b) => a === b)) {\n\t\t\treturn new LinesDiff([], [], false);\n\t\t}\n\n\t\tif (originalLines.length === 1 && originalLines[0].length === 0 || modifiedLines.length === 1 && modifiedLines[0].length === 0) {\n\t\t\treturn new LinesDiff([\n\t\t\t\tnew DetailedLineRangeMapping(\n\t\t\t\t\tnew LineRange(1, originalLines.length + 1),\n\t\t\t\t\tnew LineRange(1, modifiedLines.length + 1),\n\t\t\t\t\t[\n\t\t\t\t\t\tnew RangeMapping(\n\t\t\t\t\t\t\tnew Range(1, 1, originalLines.length, originalLines[originalLines.length - 1].length + 1),\n\t\t\t\t\t\t\tnew Range(1, 1, modifiedLines.length, modifiedLines[modifiedLines.length - 1].length + 1),\n\t\t\t\t\t\t)\n\t\t\t\t\t]\n\t\t\t\t)\n\t\t\t], [], false);\n\t\t}\n\n\t\tconst timeout = options.maxComputationTimeMs === 0 ? InfiniteTimeout.instance : new DateTimeout(options.maxComputationTimeMs);\n\t\tconst considerWhitespaceChanges = !options.ignoreTrimWhitespace;\n\n\t\tconst perfectHashes = new Map();\n\t\tfunction getOrCreateHash(text: string): number {\n\t\t\tlet hash = perfectHashes.get(text);\n\t\t\tif (hash === undefined) {\n\t\t\t\thash = perfectHashes.size;\n\t\t\t\tperfectHashes.set(text, hash);\n\t\t\t}\n\t\t\treturn hash;\n\t\t}\n\n\t\tconst originalLinesHashes = originalLines.map((l) => getOrCreateHash(l.trim()));\n\t\tconst modifiedLinesHashes = modifiedLines.map((l) => getOrCreateHash(l.trim()));\n\n\t\tconst sequence1 = new LineSequence(originalLinesHashes, originalLines);\n\t\tconst sequence2 = new LineSequence(modifiedLinesHashes, modifiedLines);\n\n\t\tconst lineAlignmentResult = (() => {\n\t\t\tif (sequence1.length + sequence2.length < 1700) {\n\t\t\t\t// Use the improved algorithm for small files\n\t\t\t\treturn this.dynamicProgrammingDiffing.compute(\n\t\t\t\t\tsequence1,\n\t\t\t\t\tsequence2,\n\t\t\t\t\ttimeout,\n\t\t\t\t\t(offset1, offset2) =>\n\t\t\t\t\t\toriginalLines[offset1] === modifiedLines[offset2]\n\t\t\t\t\t\t\t? modifiedLines[offset2].length === 0\n\t\t\t\t\t\t\t\t? 0.1\n\t\t\t\t\t\t\t\t: 1 + Math.log(1 + modifiedLines[offset2].length)\n\t\t\t\t\t\t\t: 0.99\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn this.myersDiffingAlgorithm.compute(\n\t\t\t\tsequence1,\n\t\t\t\tsequence2\n\t\t\t);\n\t\t})();\n\n\t\tlet lineAlignments = lineAlignmentResult.diffs;\n\t\tlet hitTimeout = lineAlignmentResult.hitTimeout;\n\t\tlineAlignments = optimizeSequenceDiffs(sequence1, sequence2, lineAlignments);\n\t\tlineAlignments = removeVeryShortMatchingLinesBetweenDiffs(sequence1, sequence2, lineAlignments);\n\n\t\tconst alignments: RangeMapping[] = [];\n\n\t\tconst scanForWhitespaceChanges = (equalLinesCount: number) => {\n\t\t\tif (!considerWhitespaceChanges) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tfor (let i = 0; i < equalLinesCount; i++) {\n\t\t\t\tconst seq1Offset = seq1LastStart + i;\n\t\t\t\tconst seq2Offset = seq2LastStart + i;\n\t\t\t\tif (originalLines[seq1Offset] !== modifiedLines[seq2Offset]) {\n\t\t\t\t\t// This is because of whitespace changes, diff these lines\n\t\t\t\t\tconst characterDiffs = this.refineDiff(originalLines, modifiedLines, new SequenceDiff(\n\t\t\t\t\t\tnew OffsetRange(seq1Offset, seq1Offset + 1),\n\t\t\t\t\t\tnew OffsetRange(seq2Offset, seq2Offset + 1),\n\t\t\t\t\t), timeout, considerWhitespaceChanges);\n\t\t\t\t\tfor (const a of characterDiffs.mappings) {\n\t\t\t\t\t\talignments.push(a);\n\t\t\t\t\t}\n\t\t\t\t\tif (characterDiffs.hitTimeout) {\n\t\t\t\t\t\thitTimeout = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tlet seq1LastStart = 0;\n\t\tlet seq2LastStart = 0;\n\n\t\tfor (const diff of lineAlignments) {\n\t\t\tassertFn(() => diff.seq1Range.start - seq1LastStart === diff.seq2Range.start - seq2LastStart);\n\n\t\t\tconst equalLinesCount = diff.seq1Range.start - seq1LastStart;\n\n\t\t\tscanForWhitespaceChanges(equalLinesCount);\n\n\t\t\tseq1LastStart = diff.seq1Range.endExclusive;\n\t\t\tseq2LastStart = diff.seq2Range.endExclusive;\n\n\t\t\tconst characterDiffs = this.refineDiff(originalLines, modifiedLines, diff, timeout, considerWhitespaceChanges);\n\t\t\tif (characterDiffs.hitTimeout) {\n\t\t\t\thitTimeout = true;\n\t\t\t}\n\t\t\tfor (const a of characterDiffs.mappings) {\n\t\t\t\talignments.push(a);\n\t\t\t}\n\t\t}\n\n\t\tscanForWhitespaceChanges(originalLines.length - seq1LastStart);\n\n\t\tconst changes = lineRangeMappingFromRangeMappings(alignments, originalLines, modifiedLines);\n\n\t\tlet moves: MovedText[] = [];\n\t\tif (options.computeMoves) {\n\t\t\tmoves = this.computeMoves(changes, originalLines, modifiedLines, originalLinesHashes, modifiedLinesHashes, timeout, considerWhitespaceChanges);\n\t\t}\n\n\t\t// Make sure all ranges are valid\n\t\tassertFn(() => {\n\t\t\tfunction validatePosition(pos: Position, lines: string[]): boolean {\n\t\t\t\tif (pos.lineNumber < 1 || pos.lineNumber > lines.length) { return false; }\n\t\t\t\tconst line = lines[pos.lineNumber - 1];\n\t\t\t\tif (pos.column < 1 || pos.column > line.length + 1) { return false; }\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tfunction validateRange(range: LineRange, lines: string[]): boolean {\n\t\t\t\tif (range.startLineNumber < 1 || range.startLineNumber > lines.length + 1) { return false; }\n\t\t\t\tif (range.endLineNumberExclusive < 1 || range.endLineNumberExclusive > lines.length + 1) { return false; }\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tfor (const c of changes) {\n\t\t\t\tif (!c.innerChanges) { return false; }\n\t\t\t\tfor (const ic of c.innerChanges) {\n\t\t\t\t\tconst valid = validatePosition(ic.modifiedRange.getStartPosition(), modifiedLines) && validatePosition(ic.modifiedRange.getEndPosition(), modifiedLines) &&\n\t\t\t\t\t\tvalidatePosition(ic.originalRange.getStartPosition(), originalLines) && validatePosition(ic.originalRange.getEndPosition(), originalLines);\n\t\t\t\t\tif (!valid) { return false; }\n\t\t\t\t}\n\t\t\t\tif (!validateRange(c.modified, modifiedLines) || !validateRange(c.original, originalLines)) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t});\n\n\t\treturn new LinesDiff(changes, moves, hitTimeout);\n\t}\n\n\tprivate computeMoves(\n\t\tchanges: DetailedLineRangeMapping[],\n\t\toriginalLines: string[],\n\t\tmodifiedLines: string[],\n\t\thashedOriginalLines: number[],\n\t\thashedModifiedLines: number[],\n\t\ttimeout: ITimeout,\n\t\tconsiderWhitespaceChanges: boolean,\n\t): MovedText[] {\n\t\tconst moves = computeMovedLines(\n\t\t\tchanges,\n\t\t\toriginalLines,\n\t\t\tmodifiedLines,\n\t\t\thashedOriginalLines,\n\t\t\thashedModifiedLines,\n\t\t\ttimeout,\n\t\t);\n\t\tconst movesWithDiffs = moves.map(m => {\n\t\t\tconst moveChanges = this.refineDiff(originalLines, modifiedLines, new SequenceDiff(\n\t\t\t\tm.original.toOffsetRange(),\n\t\t\t\tm.modified.toOffsetRange(),\n\t\t\t), timeout, considerWhitespaceChanges);\n\t\t\tconst mappings = lineRangeMappingFromRangeMappings(moveChanges.mappings, originalLines, modifiedLines, true);\n\t\t\treturn new MovedText(m, mappings);\n\t\t});\n\t\treturn movesWithDiffs;\n\t}\n\n\tprivate refineDiff(originalLines: string[], modifiedLines: string[], diff: SequenceDiff, timeout: ITimeout, considerWhitespaceChanges: boolean): { mappings: RangeMapping[]; hitTimeout: boolean } {\n\t\tconst slice1 = new LinesSliceCharSequence(originalLines, diff.seq1Range, considerWhitespaceChanges);\n\t\tconst slice2 = new LinesSliceCharSequence(modifiedLines, diff.seq2Range, considerWhitespaceChanges);\n\n\t\tconst diffResult = slice1.length + slice2.length < 500\n\t\t\t? this.dynamicProgrammingDiffing.compute(slice1, slice2, timeout)\n\t\t\t: this.myersDiffingAlgorithm.compute(slice1, slice2, timeout);\n\n\t\tlet diffs = diffResult.diffs;\n\t\tdiffs = optimizeSequenceDiffs(slice1, slice2, diffs);\n\t\tdiffs = extendDiffsToEntireWordIfAppropriate(slice1, slice2, diffs);\n\t\tdiffs = removeShortMatches(slice1, slice2, diffs);\n\t\tdiffs = removeVeryShortMatchingTextBetweenLongDiffs(slice1, slice2, diffs);\n\n\t\tconst result = diffs.map(\n\t\t\t(d) =>\n\t\t\t\tnew RangeMapping(\n\t\t\t\t\tslice1.translateRange(d.seq1Range),\n\t\t\t\t\tslice2.translateRange(d.seq2Range)\n\t\t\t\t)\n\t\t);\n\n\t\t// Assert: result applied on original should be the same as diff applied to original\n\n\t\treturn {\n\t\t\tmappings: result,\n\t\t\thitTimeout: diffResult.hitTimeout,\n\t\t};\n\t}\n}\n\nexport function lineRangeMappingFromRangeMappings(alignments: RangeMapping[], originalLines: string[], modifiedLines: string[], dontAssertStartLine: boolean = false): DetailedLineRangeMapping[] {\n\tconst changes: DetailedLineRangeMapping[] = [];\n\tfor (const g of groupAdjacentBy(\n\t\talignments.map(a => getLineRangeMapping(a, originalLines, modifiedLines)),\n\t\t(a1, a2) =>\n\t\t\ta1.original.overlapOrTouch(a2.original)\n\t\t\t|| a1.modified.overlapOrTouch(a2.modified)\n\t)) {\n\t\tconst first = g[0];\n\t\tconst last = g[g.length - 1];\n\n\t\tchanges.push(new DetailedLineRangeMapping(\n\t\t\tfirst.original.join(last.original),\n\t\t\tfirst.modified.join(last.modified),\n\t\t\tg.map(a => a.innerChanges![0]),\n\t\t));\n\t}\n\n\tassertFn(() => {\n\t\tif (!dontAssertStartLine && changes.length > 0) {\n\t\t\tif (changes[0].modified.startLineNumber !== changes[0].original.startLineNumber) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (modifiedLines.length - changes[changes.length - 1].modified.endLineNumberExclusive !== originalLines.length - changes[changes.length - 1].original.endLineNumberExclusive) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn checkAdjacentItems(changes,\n\t\t\t(m1, m2) => m2.original.startLineNumber - m1.original.endLineNumberExclusive === m2.modified.startLineNumber - m1.modified.endLineNumberExclusive &&\n\t\t\t\t// There has to be an unchanged line in between (otherwise both diffs should have been joined)\n\t\t\t\tm1.original.endLineNumberExclusive < m2.original.startLineNumber &&\n\t\t\t\tm1.modified.endLineNumberExclusive < m2.modified.startLineNumber,\n\t\t);\n\t});\n\n\treturn changes;\n}\n\nexport function getLineRangeMapping(rangeMapping: RangeMapping, originalLines: string[], modifiedLines: string[]): DetailedLineRangeMapping {\n\tlet lineStartDelta = 0;\n\tlet lineEndDelta = 0;\n\n\t// rangeMapping describes the edit that replaces `rangeMapping.originalRange` with `newText := getText(modifiedLines, rangeMapping.modifiedRange)`.\n\n\t// original: ]xxx \\n <- this line is not modified\n\t// modified: ]xx \\n\n\tif (rangeMapping.modifiedRange.endColumn === 1 && rangeMapping.originalRange.endColumn === 1\n\t\t&& rangeMapping.originalRange.startLineNumber + lineStartDelta <= rangeMapping.originalRange.endLineNumber\n\t\t&& rangeMapping.modifiedRange.startLineNumber + lineStartDelta <= rangeMapping.modifiedRange.endLineNumber) {\n\t\t// We can only do this if the range is not empty yet\n\t\tlineEndDelta = -1;\n\t}\n\n\t// original: xxx[ \\n <- this line is not modified\n\t// modified: xxx[ \\n\n\tif (rangeMapping.modifiedRange.startColumn - 1 >= modifiedLines[rangeMapping.modifiedRange.startLineNumber - 1].length\n\t\t&& rangeMapping.originalRange.startColumn - 1 >= originalLines[rangeMapping.originalRange.startLineNumber - 1].length\n\t\t&& rangeMapping.originalRange.startLineNumber <= rangeMapping.originalRange.endLineNumber + lineEndDelta\n\t\t&& rangeMapping.modifiedRange.startLineNumber <= rangeMapping.modifiedRange.endLineNumber + lineEndDelta) {\n\t\t// We can only do this if the range is not empty yet\n\t\tlineStartDelta = 1;\n\t}\n\n\tconst originalLineRange = new LineRange(\n\t\trangeMapping.originalRange.startLineNumber + lineStartDelta,\n\t\trangeMapping.originalRange.endLineNumber + 1 + lineEndDelta\n\t);\n\tconst modifiedLineRange = new LineRange(\n\t\trangeMapping.modifiedRange.startLineNumber + lineStartDelta,\n\t\trangeMapping.modifiedRange.endLineNumber + 1 + lineEndDelta\n\t);\n\n\treturn new DetailedLineRangeMapping(originalLineRange, modifiedLineRange, [rangeMapping]);\n}\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\nimport { CharCode } from 'vs/base/common/charCode';\nimport { IDiffChange, ISequence, LcsDiff, IDiffResult } from 'vs/base/common/diff/diff';\nimport { ILinesDiffComputer, ILinesDiffComputerOptions, LinesDiff } from 'vs/editor/common/diff/linesDiffComputer';\nimport { RangeMapping, DetailedLineRangeMapping } from './rangeMapping';\nimport * as strings from 'vs/base/common/strings';\nimport { Range } from 'vs/editor/common/core/range';\nimport { assertFn, checkAdjacentItems } from 'vs/base/common/assert';\nimport { LineRange } from 'vs/editor/common/core/lineRange';\n\nconst MINIMUM_MATCHING_CHARACTER_LENGTH = 3;\n\nexport class LegacyLinesDiffComputer implements ILinesDiffComputer {\n\tcomputeDiff(originalLines: string[], modifiedLines: string[], options: ILinesDiffComputerOptions): LinesDiff {\n\t\tconst diffComputer = new DiffComputer(originalLines, modifiedLines, {\n\t\t\tmaxComputationTime: options.maxComputationTimeMs,\n\t\t\tshouldIgnoreTrimWhitespace: options.ignoreTrimWhitespace,\n\t\t\tshouldComputeCharChanges: true,\n\t\t\tshouldMakePrettyDiff: true,\n\t\t\tshouldPostProcessCharChanges: true,\n\t\t});\n\t\tconst result = diffComputer.computeDiff();\n\t\tconst changes: DetailedLineRangeMapping[] = [];\n\t\tlet lastChange: DetailedLineRangeMapping | null = null;\n\n\n\t\tfor (const c of result.changes) {\n\t\t\tlet originalRange: LineRange;\n\t\t\tif (c.originalEndLineNumber === 0) {\n\t\t\t\t// Insertion\n\t\t\t\toriginalRange = new LineRange(c.originalStartLineNumber + 1, c.originalStartLineNumber + 1);\n\t\t\t} else {\n\t\t\t\toriginalRange = new LineRange(c.originalStartLineNumber, c.originalEndLineNumber + 1);\n\t\t\t}\n\n\t\t\tlet modifiedRange: LineRange;\n\t\t\tif (c.modifiedEndLineNumber === 0) {\n\t\t\t\t// Deletion\n\t\t\t\tmodifiedRange = new LineRange(c.modifiedStartLineNumber + 1, c.modifiedStartLineNumber + 1);\n\t\t\t} else {\n\t\t\t\tmodifiedRange = new LineRange(c.modifiedStartLineNumber, c.modifiedEndLineNumber + 1);\n\t\t\t}\n\n\t\t\tlet change = new DetailedLineRangeMapping(originalRange, modifiedRange, c.charChanges?.map(c => new RangeMapping(\n\t\t\t\tnew Range(c.originalStartLineNumber, c.originalStartColumn, c.originalEndLineNumber, c.originalEndColumn),\n\t\t\t\tnew Range(c.modifiedStartLineNumber, c.modifiedStartColumn, c.modifiedEndLineNumber, c.modifiedEndColumn),\n\t\t\t)));\n\t\t\tif (lastChange) {\n\t\t\t\tif (lastChange.modified.endLineNumberExclusive === change.modified.startLineNumber\n\t\t\t\t\t|| lastChange.original.endLineNumberExclusive === change.original.startLineNumber) {\n\t\t\t\t\t// join touching diffs. Probably moving diffs up/down in the algorithm causes touching diffs.\n\t\t\t\t\tchange = new DetailedLineRangeMapping(\n\t\t\t\t\t\tlastChange.original.join(change.original),\n\t\t\t\t\t\tlastChange.modified.join(change.modified),\n\t\t\t\t\t\tlastChange.innerChanges && change.innerChanges ?\n\t\t\t\t\t\t\tlastChange.innerChanges.concat(change.innerChanges) : undefined\n\t\t\t\t\t);\n\t\t\t\t\tchanges.pop();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tchanges.push(change);\n\t\t\tlastChange = change;\n\t\t}\n\n\t\tassertFn(() => {\n\t\t\treturn checkAdjacentItems(changes,\n\t\t\t\t(m1, m2) => m2.original.startLineNumber - m1.original.endLineNumberExclusive === m2.modified.startLineNumber - m1.modified.endLineNumberExclusive &&\n\t\t\t\t\t// There has to be an unchanged line in between (otherwise both diffs should have been joined)\n\t\t\t\t\tm1.original.endLineNumberExclusive < m2.original.startLineNumber &&\n\t\t\t\t\tm1.modified.endLineNumberExclusive < m2.modified.startLineNumber,\n\t\t\t);\n\t\t});\n\n\t\treturn new LinesDiff(changes, [], result.quitEarly);\n\t}\n}\n\n/**\n * A change\n */\nexport interface IChange {\n\treadonly originalStartLineNumber: number;\n\treadonly originalEndLineNumber: number;\n\treadonly modifiedStartLineNumber: number;\n\treadonly modifiedEndLineNumber: number;\n}\n\n/**\n * A character level change.\n */\nexport interface ICharChange extends IChange {\n\treadonly originalStartColumn: number;\n\treadonly originalEndColumn: number;\n\treadonly modifiedStartColumn: number;\n\treadonly modifiedEndColumn: number;\n}\n\n/**\n * A line change\n */\nexport interface ILineChange extends IChange {\n\treadonly charChanges: ICharChange[] | undefined;\n}\n\nexport interface IDiffComputerResult {\n\tquitEarly: boolean;\n\tchanges: ILineChange[];\n}\n\nfunction computeDiff(originalSequence: ISequence, modifiedSequence: ISequence, continueProcessingPredicate: () => boolean, pretty: boolean): IDiffResult {\n\tconst diffAlgo = new LcsDiff(originalSequence, modifiedSequence, continueProcessingPredicate);\n\treturn diffAlgo.ComputeDiff(pretty);\n}\n\nclass LineSequence implements ISequence {\n\n\tpublic readonly lines: string[];\n\tprivate readonly _startColumns: number[];\n\tprivate readonly _endColumns: number[];\n\n\tconstructor(lines: string[]) {\n\t\tconst startColumns: number[] = [];\n\t\tconst endColumns: number[] = [];\n\t\tfor (let i = 0, length = lines.length; i < length; i++) {\n\t\t\tstartColumns[i] = getFirstNonBlankColumn(lines[i], 1);\n\t\t\tendColumns[i] = getLastNonBlankColumn(lines[i], 1);\n\t\t}\n\t\tthis.lines = lines;\n\t\tthis._startColumns = startColumns;\n\t\tthis._endColumns = endColumns;\n\t}\n\n\tpublic getElements(): Int32Array | number[] | string[] {\n\t\tconst elements: string[] = [];\n\t\tfor (let i = 0, len = this.lines.length; i < len; i++) {\n\t\t\telements[i] = this.lines[i].substring(this._startColumns[i] - 1, this._endColumns[i] - 1);\n\t\t}\n\t\treturn elements;\n\t}\n\n\tpublic getStrictElement(index: number): string {\n\t\treturn this.lines[index];\n\t}\n\n\tpublic getStartLineNumber(i: number): number {\n\t\treturn i + 1;\n\t}\n\n\tpublic getEndLineNumber(i: number): number {\n\t\treturn i + 1;\n\t}\n\n\tpublic createCharSequence(shouldIgnoreTrimWhitespace: boolean, startIndex: number, endIndex: number): CharSequence {\n\t\tconst charCodes: number[] = [];\n\t\tconst lineNumbers: number[] = [];\n\t\tconst columns: number[] = [];\n\t\tlet len = 0;\n\t\tfor (let index = startIndex; index <= endIndex; index++) {\n\t\t\tconst lineContent = this.lines[index];\n\t\t\tconst startColumn = (shouldIgnoreTrimWhitespace ? this._startColumns[index] : 1);\n\t\t\tconst endColumn = (shouldIgnoreTrimWhitespace ? this._endColumns[index] : lineContent.length + 1);\n\t\t\tfor (let col = startColumn; col < endColumn; col++) {\n\t\t\t\tcharCodes[len] = lineContent.charCodeAt(col - 1);\n\t\t\t\tlineNumbers[len] = index + 1;\n\t\t\t\tcolumns[len] = col;\n\t\t\t\tlen++;\n\t\t\t}\n\t\t\tif (!shouldIgnoreTrimWhitespace && index < endIndex) {\n\t\t\t\t// Add \\n if trim whitespace is not ignored\n\t\t\t\tcharCodes[len] = CharCode.LineFeed;\n\t\t\t\tlineNumbers[len] = index + 1;\n\t\t\t\tcolumns[len] = lineContent.length + 1;\n\t\t\t\tlen++;\n\t\t\t}\n\t\t}\n\t\treturn new CharSequence(charCodes, lineNumbers, columns);\n\t}\n}\n\nclass CharSequence implements ISequence {\n\n\tprivate readonly _charCodes: number[];\n\tprivate readonly _lineNumbers: number[];\n\tprivate readonly _columns: number[];\n\n\tconstructor(charCodes: number[], lineNumbers: number[], columns: number[]) {\n\t\tthis._charCodes = charCodes;\n\t\tthis._lineNumbers = lineNumbers;\n\t\tthis._columns = columns;\n\t}\n\n\tpublic toString() {\n\t\treturn (\n\t\t\t'[' + this._charCodes.map((s, idx) => (s === CharCode.LineFeed ? '\\\\n' : String.fromCharCode(s)) + `-(${this._lineNumbers[idx]},${this._columns[idx]})`).join(', ') + ']'\n\t\t);\n\t}\n\n\tprivate _assertIndex(index: number, arr: number[]): void {\n\t\tif (index < 0 || index >= arr.length) {\n\t\t\tthrow new Error(`Illegal index`);\n\t\t}\n\t}\n\n\tpublic getElements(): Int32Array | number[] | string[] {\n\t\treturn this._charCodes;\n\t}\n\n\tpublic getStartLineNumber(i: number): number {\n\t\tif (i > 0 && i === this._lineNumbers.length) {\n\t\t\t// the start line number of the element after the last element\n\t\t\t// is the end line number of the last element\n\t\t\treturn this.getEndLineNumber(i - 1);\n\t\t}\n\t\tthis._assertIndex(i, this._lineNumbers);\n\n\t\treturn this._lineNumbers[i];\n\t}\n\n\tpublic getEndLineNumber(i: number): number {\n\t\tif (i === -1) {\n\t\t\t// the end line number of the element before the first element\n\t\t\t// is the start line number of the first element\n\t\t\treturn this.getStartLineNumber(i + 1);\n\t\t}\n\t\tthis._assertIndex(i, this._lineNumbers);\n\n\t\tif (this._charCodes[i] === CharCode.LineFeed) {\n\t\t\treturn this._lineNumbers[i] + 1;\n\t\t}\n\t\treturn this._lineNumbers[i];\n\t}\n\n\tpublic getStartColumn(i: number): number {\n\t\tif (i > 0 && i === this._columns.length) {\n\t\t\t// the start column of the element after the last element\n\t\t\t// is the end column of the last element\n\t\t\treturn this.getEndColumn(i - 1);\n\t\t}\n\t\tthis._assertIndex(i, this._columns);\n\t\treturn this._columns[i];\n\t}\n\n\tpublic getEndColumn(i: number): number {\n\t\tif (i === -1) {\n\t\t\t// the end column of the element before the first element\n\t\t\t// is the start column of the first element\n\t\t\treturn this.getStartColumn(i + 1);\n\t\t}\n\t\tthis._assertIndex(i, this._columns);\n\n\t\tif (this._charCodes[i] === CharCode.LineFeed) {\n\t\t\treturn 1;\n\t\t}\n\t\treturn this._columns[i] + 1;\n\t}\n}\n\nclass CharChange implements ICharChange {\n\n\tpublic originalStartLineNumber: number;\n\tpublic originalStartColumn: number;\n\tpublic originalEndLineNumber: number;\n\tpublic originalEndColumn: number;\n\n\tpublic modifiedStartLineNumber: number;\n\tpublic modifiedStartColumn: number;\n\tpublic modifiedEndLineNumber: number;\n\tpublic modifiedEndColumn: number;\n\n\tconstructor(\n\t\toriginalStartLineNumber: number,\n\t\toriginalStartColumn: number,\n\t\toriginalEndLineNumber: number,\n\t\toriginalEndColumn: number,\n\t\tmodifiedStartLineNumber: number,\n\t\tmodifiedStartColumn: number,\n\t\tmodifiedEndLineNumber: number,\n\t\tmodifiedEndColumn: number\n\t) {\n\t\tthis.originalStartLineNumber = originalStartLineNumber;\n\t\tthis.originalStartColumn = originalStartColumn;\n\t\tthis.originalEndLineNumber = originalEndLineNumber;\n\t\tthis.originalEndColumn = originalEndColumn;\n\t\tthis.modifiedStartLineNumber = modifiedStartLineNumber;\n\t\tthis.modifiedStartColumn = modifiedStartColumn;\n\t\tthis.modifiedEndLineNumber = modifiedEndLineNumber;\n\t\tthis.modifiedEndColumn = modifiedEndColumn;\n\t}\n\n\tpublic static createFromDiffChange(diffChange: IDiffChange, originalCharSequence: CharSequence, modifiedCharSequence: CharSequence): CharChange {\n\t\tconst originalStartLineNumber = originalCharSequence.getStartLineNumber(diffChange.originalStart);\n\t\tconst originalStartColumn = originalCharSequence.getStartColumn(diffChange.originalStart);\n\t\tconst originalEndLineNumber = originalCharSequence.getEndLineNumber(diffChange.originalStart + diffChange.originalLength - 1);\n\t\tconst originalEndColumn = originalCharSequence.getEndColumn(diffChange.originalStart + diffChange.originalLength - 1);\n\n\t\tconst modifiedStartLineNumber = modifiedCharSequence.getStartLineNumber(diffChange.modifiedStart);\n\t\tconst modifiedStartColumn = modifiedCharSequence.getStartColumn(diffChange.modifiedStart);\n\t\tconst modifiedEndLineNumber = modifiedCharSequence.getEndLineNumber(diffChange.modifiedStart + diffChange.modifiedLength - 1);\n\t\tconst modifiedEndColumn = modifiedCharSequence.getEndColumn(diffChange.modifiedStart + diffChange.modifiedLength - 1);\n\n\t\treturn new CharChange(\n\t\t\toriginalStartLineNumber, originalStartColumn, originalEndLineNumber, originalEndColumn,\n\t\t\tmodifiedStartLineNumber, modifiedStartColumn, modifiedEndLineNumber, modifiedEndColumn,\n\t\t);\n\t}\n}\n\nfunction postProcessCharChanges(rawChanges: IDiffChange[]): IDiffChange[] {\n\tif (rawChanges.length <= 1) {\n\t\treturn rawChanges;\n\t}\n\n\tconst result = [rawChanges[0]];\n\tlet prevChange = result[0];\n\n\tfor (let i = 1, len = rawChanges.length; i < len; i++) {\n\t\tconst currChange = rawChanges[i];\n\n\t\tconst originalMatchingLength = currChange.originalStart - (prevChange.originalStart + prevChange.originalLength);\n\t\tconst modifiedMatchingLength = currChange.modifiedStart - (prevChange.modifiedStart + prevChange.modifiedLength);\n\t\t// Both of the above should be equal, but the continueProcessingPredicate may prevent this from being true\n\t\tconst matchingLength = Math.min(originalMatchingLength, modifiedMatchingLength);\n\n\t\tif (matchingLength < MINIMUM_MATCHING_CHARACTER_LENGTH) {\n\t\t\t// Merge the current change into the previous one\n\t\t\tprevChange.originalLength = (currChange.originalStart + currChange.originalLength) - prevChange.originalStart;\n\t\t\tprevChange.modifiedLength = (currChange.modifiedStart + currChange.modifiedLength) - prevChange.modifiedStart;\n\t\t} else {\n\t\t\t// Add the current change\n\t\t\tresult.push(currChange);\n\t\t\tprevChange = currChange;\n\t\t}\n\t}\n\n\treturn result;\n}\n\nclass LineChange implements ILineChange {\n\tpublic originalStartLineNumber: number;\n\tpublic originalEndLineNumber: number;\n\tpublic modifiedStartLineNumber: number;\n\tpublic modifiedEndLineNumber: number;\n\tpublic charChanges: CharChange[] | undefined;\n\n\tconstructor(\n\t\toriginalStartLineNumber: number,\n\t\toriginalEndLineNumber: number,\n\t\tmodifiedStartLineNumber: number,\n\t\tmodifiedEndLineNumber: number,\n\t\tcharChanges: CharChange[] | undefined\n\t) {\n\t\tthis.originalStartLineNumber = originalStartLineNumber;\n\t\tthis.originalEndLineNumber = originalEndLineNumber;\n\t\tthis.modifiedStartLineNumber = modifiedStartLineNumber;\n\t\tthis.modifiedEndLineNumber = modifiedEndLineNumber;\n\t\tthis.charChanges = charChanges;\n\t}\n\n\tpublic static createFromDiffResult(shouldIgnoreTrimWhitespace: boolean, diffChange: IDiffChange, originalLineSequence: LineSequence, modifiedLineSequence: LineSequence, continueCharDiff: () => boolean, shouldComputeCharChanges: boolean, shouldPostProcessCharChanges: boolean): LineChange {\n\t\tlet originalStartLineNumber: number;\n\t\tlet originalEndLineNumber: number;\n\t\tlet modifiedStartLineNumber: number;\n\t\tlet modifiedEndLineNumber: number;\n\t\tlet charChanges: CharChange[] | undefined = undefined;\n\n\t\tif (diffChange.originalLength === 0) {\n\t\t\toriginalStartLineNumber = originalLineSequence.getStartLineNumber(diffChange.originalStart) - 1;\n\t\t\toriginalEndLineNumber = 0;\n\t\t} else {\n\t\t\toriginalStartLineNumber = originalLineSequence.getStartLineNumber(diffChange.originalStart);\n\t\t\toriginalEndLineNumber = originalLineSequence.getEndLineNumber(diffChange.originalStart + diffChange.originalLength - 1);\n\t\t}\n\n\t\tif (diffChange.modifiedLength === 0) {\n\t\t\tmodifiedStartLineNumber = modifiedLineSequence.getStartLineNumber(diffChange.modifiedStart) - 1;\n\t\t\tmodifiedEndLineNumber = 0;\n\t\t} else {\n\t\t\tmodifiedStartLineNumber = modifiedLineSequence.getStartLineNumber(diffChange.modifiedStart);\n\t\t\tmodifiedEndLineNumber = modifiedLineSequence.getEndLineNumber(diffChange.modifiedStart + diffChange.modifiedLength - 1);\n\t\t}\n\n\t\tif (shouldComputeCharChanges && diffChange.originalLength > 0 && diffChange.originalLength < 20 && diffChange.modifiedLength > 0 && diffChange.modifiedLength < 20 && continueCharDiff()) {\n\t\t\t// Compute character changes for diff chunks of at most 20 lines...\n\t\t\tconst originalCharSequence = originalLineSequence.createCharSequence(shouldIgnoreTrimWhitespace, diffChange.originalStart, diffChange.originalStart + diffChange.originalLength - 1);\n\t\t\tconst modifiedCharSequence = modifiedLineSequence.createCharSequence(shouldIgnoreTrimWhitespace, diffChange.modifiedStart, diffChange.modifiedStart + diffChange.modifiedLength - 1);\n\n\t\t\tif (originalCharSequence.getElements().length > 0 && modifiedCharSequence.getElements().length > 0) {\n\t\t\t\tlet rawChanges = computeDiff(originalCharSequence, modifiedCharSequence, continueCharDiff, true).changes;\n\n\t\t\t\tif (shouldPostProcessCharChanges) {\n\t\t\t\t\trawChanges = postProcessCharChanges(rawChanges);\n\t\t\t\t}\n\n\t\t\t\tcharChanges = [];\n\t\t\t\tfor (let i = 0, length = rawChanges.length; i < length; i++) {\n\t\t\t\t\tcharChanges.push(CharChange.createFromDiffChange(rawChanges[i], originalCharSequence, modifiedCharSequence));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn new LineChange(originalStartLineNumber, originalEndLineNumber, modifiedStartLineNumber, modifiedEndLineNumber, charChanges);\n\t}\n}\n\nexport interface IDiffComputerOpts {\n\tshouldComputeCharChanges: boolean;\n\tshouldPostProcessCharChanges: boolean;\n\tshouldIgnoreTrimWhitespace: boolean;\n\tshouldMakePrettyDiff: boolean;\n\tmaxComputationTime: number;\n}\n\nexport class DiffComputer {\n\n\tprivate readonly shouldComputeCharChanges: boolean;\n\tprivate readonly shouldPostProcessCharChanges: boolean;\n\tprivate readonly shouldIgnoreTrimWhitespace: boolean;\n\tprivate readonly shouldMakePrettyDiff: boolean;\n\tprivate readonly originalLines: string[];\n\tprivate readonly modifiedLines: string[];\n\tprivate readonly original: LineSequence;\n\tprivate readonly modified: LineSequence;\n\tprivate readonly continueLineDiff: () => boolean;\n\tprivate readonly continueCharDiff: () => boolean;\n\n\tconstructor(originalLines: string[], modifiedLines: string[], opts: IDiffComputerOpts) {\n\t\tthis.shouldComputeCharChanges = opts.shouldComputeCharChanges;\n\t\tthis.shouldPostProcessCharChanges = opts.shouldPostProcessCharChanges;\n\t\tthis.shouldIgnoreTrimWhitespace = opts.shouldIgnoreTrimWhitespace;\n\t\tthis.shouldMakePrettyDiff = opts.shouldMakePrettyDiff;\n\t\tthis.originalLines = originalLines;\n\t\tthis.modifiedLines = modifiedLines;\n\t\tthis.original = new LineSequence(originalLines);\n\t\tthis.modified = new LineSequence(modifiedLines);\n\n\t\tthis.continueLineDiff = createContinueProcessingPredicate(opts.maxComputationTime);\n\t\tthis.continueCharDiff = createContinueProcessingPredicate(opts.maxComputationTime === 0 ? 0 : Math.min(opts.maxComputationTime, 5000)); // never run after 5s for character changes...\n\t}\n\n\tpublic computeDiff(): IDiffComputerResult {\n\n\t\tif (this.original.lines.length === 1 && this.original.lines[0].length === 0) {\n\t\t\t// empty original => fast path\n\t\t\tif (this.modified.lines.length === 1 && this.modified.lines[0].length === 0) {\n\t\t\t\treturn {\n\t\t\t\t\tquitEarly: false,\n\t\t\t\t\tchanges: []\n\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tquitEarly: false,\n\t\t\t\tchanges: [{\n\t\t\t\t\toriginalStartLineNumber: 1,\n\t\t\t\t\toriginalEndLineNumber: 1,\n\t\t\t\t\tmodifiedStartLineNumber: 1,\n\t\t\t\t\tmodifiedEndLineNumber: this.modified.lines.length,\n\t\t\t\t\tcharChanges: undefined\n\t\t\t\t}]\n\t\t\t};\n\t\t}\n\n\t\tif (this.modified.lines.length === 1 && this.modified.lines[0].length === 0) {\n\t\t\t// empty modified => fast path\n\t\t\treturn {\n\t\t\t\tquitEarly: false,\n\t\t\t\tchanges: [{\n\t\t\t\t\toriginalStartLineNumber: 1,\n\t\t\t\t\toriginalEndLineNumber: this.original.lines.length,\n\t\t\t\t\tmodifiedStartLineNumber: 1,\n\t\t\t\t\tmodifiedEndLineNumber: 1,\n\t\t\t\t\tcharChanges: undefined\n\t\t\t\t}]\n\t\t\t};\n\t\t}\n\n\t\tconst diffResult = computeDiff(this.original, this.modified, this.continueLineDiff, this.shouldMakePrettyDiff);\n\t\tconst rawChanges = diffResult.changes;\n\t\tconst quitEarly = diffResult.quitEarly;\n\n\t\t// The diff is always computed with ignoring trim whitespace\n\t\t// This ensures we get the prettiest diff\n\n\t\tif (this.shouldIgnoreTrimWhitespace) {\n\t\t\tconst lineChanges: LineChange[] = [];\n\t\t\tfor (let i = 0, length = rawChanges.length; i < length; i++) {\n\t\t\t\tlineChanges.push(LineChange.createFromDiffResult(this.shouldIgnoreTrimWhitespace, rawChanges[i], this.original, this.modified, this.continueCharDiff, this.shouldComputeCharChanges, this.shouldPostProcessCharChanges));\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tquitEarly: quitEarly,\n\t\t\t\tchanges: lineChanges\n\t\t\t};\n\t\t}\n\n\t\t// Need to post-process and introduce changes where the trim whitespace is different\n\t\t// Note that we are looping starting at -1 to also cover the lines before the first change\n\t\tconst result: LineChange[] = [];\n\n\t\tlet originalLineIndex = 0;\n\t\tlet modifiedLineIndex = 0;\n\t\tfor (let i = -1 /* !!!! */, len = rawChanges.length; i < len; i++) {\n\t\t\tconst nextChange = (i + 1 < len ? rawChanges[i + 1] : null);\n\t\t\tconst originalStop = (nextChange ? nextChange.originalStart : this.originalLines.length);\n\t\t\tconst modifiedStop = (nextChange ? nextChange.modifiedStart : this.modifiedLines.length);\n\n\t\t\twhile (originalLineIndex < originalStop && modifiedLineIndex < modifiedStop) {\n\t\t\t\tconst originalLine = this.originalLines[originalLineIndex];\n\t\t\t\tconst modifiedLine = this.modifiedLines[modifiedLineIndex];\n\n\t\t\t\tif (originalLine !== modifiedLine) {\n\t\t\t\t\t// These lines differ only in trim whitespace\n\n\t\t\t\t\t// Check the leading whitespace\n\t\t\t\t\t{\n\t\t\t\t\t\tlet originalStartColumn = getFirstNonBlankColumn(originalLine, 1);\n\t\t\t\t\t\tlet modifiedStartColumn = getFirstNonBlankColumn(modifiedLine, 1);\n\t\t\t\t\t\twhile (originalStartColumn > 1 && modifiedStartColumn > 1) {\n\t\t\t\t\t\t\tconst originalChar = originalLine.charCodeAt(originalStartColumn - 2);\n\t\t\t\t\t\t\tconst modifiedChar = modifiedLine.charCodeAt(modifiedStartColumn - 2);\n\t\t\t\t\t\t\tif (originalChar !== modifiedChar) {\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\toriginalStartColumn--;\n\t\t\t\t\t\t\tmodifiedStartColumn--;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (originalStartColumn > 1 || modifiedStartColumn > 1) {\n\t\t\t\t\t\t\tthis._pushTrimWhitespaceCharChange(result,\n\t\t\t\t\t\t\t\toriginalLineIndex + 1, 1, originalStartColumn,\n\t\t\t\t\t\t\t\tmodifiedLineIndex + 1, 1, modifiedStartColumn\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Check the trailing whitespace\n\t\t\t\t\t{\n\t\t\t\t\t\tlet originalEndColumn = getLastNonBlankColumn(originalLine, 1);\n\t\t\t\t\t\tlet modifiedEndColumn = getLastNonBlankColumn(modifiedLine, 1);\n\t\t\t\t\t\tconst originalMaxColumn = originalLine.length + 1;\n\t\t\t\t\t\tconst modifiedMaxColumn = modifiedLine.length + 1;\n\t\t\t\t\t\twhile (originalEndColumn < originalMaxColumn && modifiedEndColumn < modifiedMaxColumn) {\n\t\t\t\t\t\t\tconst originalChar = originalLine.charCodeAt(originalEndColumn - 1);\n\t\t\t\t\t\t\tconst modifiedChar = originalLine.charCodeAt(modifiedEndColumn - 1);\n\t\t\t\t\t\t\tif (originalChar !== modifiedChar) {\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\toriginalEndColumn++;\n\t\t\t\t\t\t\tmodifiedEndColumn++;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (originalEndColumn < originalMaxColumn || modifiedEndColumn < modifiedMaxColumn) {\n\t\t\t\t\t\t\tthis._pushTrimWhitespaceCharChange(result,\n\t\t\t\t\t\t\t\toriginalLineIndex + 1, originalEndColumn, originalMaxColumn,\n\t\t\t\t\t\t\t\tmodifiedLineIndex + 1, modifiedEndColumn, modifiedMaxColumn\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\toriginalLineIndex++;\n\t\t\t\tmodifiedLineIndex++;\n\t\t\t}\n\n\t\t\tif (nextChange) {\n\t\t\t\t// Emit the actual change\n\t\t\t\tresult.push(LineChange.createFromDiffResult(this.shouldIgnoreTrimWhitespace, nextChange, this.original, this.modified, this.continueCharDiff, this.shouldComputeCharChanges, this.shouldPostProcessCharChanges));\n\n\t\t\t\toriginalLineIndex += nextChange.originalLength;\n\t\t\t\tmodifiedLineIndex += nextChange.modifiedLength;\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tquitEarly: quitEarly,\n\t\t\tchanges: result\n\t\t};\n\t}\n\n\tprivate _pushTrimWhitespaceCharChange(\n\t\tresult: LineChange[],\n\t\toriginalLineNumber: number, originalStartColumn: number, originalEndColumn: number,\n\t\tmodifiedLineNumber: number, modifiedStartColumn: number, modifiedEndColumn: number\n\t): void {\n\t\tif (this._mergeTrimWhitespaceCharChange(result, originalLineNumber, originalStartColumn, originalEndColumn, modifiedLineNumber, modifiedStartColumn, modifiedEndColumn)) {\n\t\t\t// Merged into previous\n\t\t\treturn;\n\t\t}\n\n\t\tlet charChanges: CharChange[] | undefined = undefined;\n\t\tif (this.shouldComputeCharChanges) {\n\t\t\tcharChanges = [new CharChange(\n\t\t\t\toriginalLineNumber, originalStartColumn, originalLineNumber, originalEndColumn,\n\t\t\t\tmodifiedLineNumber, modifiedStartColumn, modifiedLineNumber, modifiedEndColumn\n\t\t\t)];\n\t\t}\n\t\tresult.push(new LineChange(\n\t\t\toriginalLineNumber, originalLineNumber,\n\t\t\tmodifiedLineNumber, modifiedLineNumber,\n\t\t\tcharChanges\n\t\t));\n\t}\n\n\tprivate _mergeTrimWhitespaceCharChange(\n\t\tresult: LineChange[],\n\t\toriginalLineNumber: number, originalStartColumn: number, originalEndColumn: number,\n\t\tmodifiedLineNumber: number, modifiedStartColumn: number, modifiedEndColumn: number\n\t): boolean {\n\t\tconst len = result.length;\n\t\tif (len === 0) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst prevChange = result[len - 1];\n\n\t\tif (prevChange.originalEndLineNumber === 0 || prevChange.modifiedEndLineNumber === 0) {\n\t\t\t// Don't merge with inserts/deletes\n\t\t\treturn false;\n\t\t}\n\n\t\tif (prevChange.originalEndLineNumber === originalLineNumber && prevChange.modifiedEndLineNumber === modifiedLineNumber) {\n\t\t\tif (this.shouldComputeCharChanges && prevChange.charChanges) {\n\t\t\t\tprevChange.charChanges.push(new CharChange(\n\t\t\t\t\toriginalLineNumber, originalStartColumn, originalLineNumber, originalEndColumn,\n\t\t\t\t\tmodifiedLineNumber, modifiedStartColumn, modifiedLineNumber, modifiedEndColumn\n\t\t\t\t));\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t\tif (prevChange.originalEndLineNumber + 1 === originalLineNumber && prevChange.modifiedEndLineNumber + 1 === modifiedLineNumber) {\n\t\t\tprevChange.originalEndLineNumber = originalLineNumber;\n\t\t\tprevChange.modifiedEndLineNumber = modifiedLineNumber;\n\t\t\tif (this.shouldComputeCharChanges && prevChange.charChanges) {\n\t\t\t\tprevChange.charChanges.push(new CharChange(\n\t\t\t\t\toriginalLineNumber, originalStartColumn, originalLineNumber, originalEndColumn,\n\t\t\t\t\tmodifiedLineNumber, modifiedStartColumn, modifiedLineNumber, modifiedEndColumn\n\t\t\t\t));\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n}\n\nfunction getFirstNonBlankColumn(txt: string, defaultValue: number): number {\n\tconst r = strings.firstNonWhitespaceIndex(txt);\n\tif (r === -1) {\n\t\treturn defaultValue;\n\t}\n\treturn r + 1;\n}\n\nfunction getLastNonBlankColumn(txt: string, defaultValue: number): number {\n\tconst r = strings.lastNonWhitespaceIndex(txt);\n\tif (r === -1) {\n\t\treturn defaultValue;\n\t}\n\treturn r + 2;\n}\n\nfunction createContinueProcessingPredicate(maximumRuntime: number): () => boolean {\n\tif (maximumRuntime === 0) {\n\t\treturn () => true;\n\t}\n\n\tconst startTime = Date.now();\n\treturn () => {\n\t\treturn Date.now() - startTime < maximumRuntime;\n\t};\n}\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\nimport { LegacyLinesDiffComputer } from 'vs/editor/common/diff/legacyLinesDiffComputer';\nimport { DefaultLinesDiffComputer } from 'vs/editor/common/diff/defaultLinesDiffComputer/defaultLinesDiffComputer';\nimport { ILinesDiffComputer } from 'vs/editor/common/diff/linesDiffComputer';\n\nexport const linesDiffComputers = {\n\tgetLegacy: () => new LegacyLinesDiffComputer(),\n\tgetDefault: () => new DefaultLinesDiffComputer(),\n} satisfies Record ILinesDiffComputer>;\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\nimport { IEditorAction } from 'vs/editor/common/editorCommon';\nimport { ICommandMetadata } from 'vs/platform/commands/common/commands';\nimport { ContextKeyExpression, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';\n\nexport class InternalEditorAction implements IEditorAction {\n\n\tconstructor(\n\t\tpublic readonly id: string,\n\t\tpublic readonly label: string,\n\t\tpublic readonly alias: string,\n\t\tpublic readonly metadata: ICommandMetadata | undefined,\n\t\tprivate readonly _precondition: ContextKeyExpression | undefined,\n\t\tprivate readonly _run: (args: unknown) => Promise,\n\t\tprivate readonly _contextKeyService: IContextKeyService\n\t) { }\n\n\tpublic isSupported(): boolean {\n\t\treturn this._contextKeyService.contextMatchesRules(this._precondition);\n\t}\n\n\tpublic run(args: unknown): Promise {\n\t\tif (!this.isSupported()) {\n\t\t\treturn Promise.resolve(undefined);\n\t\t}\n\n\t\treturn this._run(args);\n\t}\n}\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\nimport { Event } from 'vs/base/common/event';\nimport { IDisposable } from 'vs/base/common/lifecycle';\nimport { URI } from 'vs/base/common/uri';\nimport { IEditorOptions } from 'vs/editor/common/config/editorOptions';\nimport { IDimension } from 'vs/editor/common/core/dimension';\nimport { IPosition, Position } from 'vs/editor/common/core/position';\nimport { IRange, Range } from 'vs/editor/common/core/range';\nimport { ISelection, Selection } from 'vs/editor/common/core/selection';\nimport { IModelDecoration, IModelDecorationsChangeAccessor, IModelDeltaDecoration, ITextModel, IValidEditOperation } from 'vs/editor/common/model';\nimport { IModelDecorationsChangedEvent } from 'vs/editor/common/textModelEvents';\nimport { ICommandMetadata } from 'vs/platform/commands/common/commands';\n\n/**\n * A builder and helper for edit operations for a command.\n */\nexport interface IEditOperationBuilder {\n\t/**\n\t * Add a new edit operation (a replace operation).\n\t * @param range The range to replace (delete). May be empty to represent a simple insert.\n\t * @param text The text to replace with. May be null to represent a simple delete.\n\t */\n\taddEditOperation(range: IRange, text: string | null, forceMoveMarkers?: boolean): void;\n\n\t/**\n\t * Add a new edit operation (a replace operation).\n\t * The inverse edits will be accessible in `ICursorStateComputerData.getInverseEditOperations()`\n\t * @param range The range to replace (delete). May be empty to represent a simple insert.\n\t * @param text The text to replace with. May be null to represent a simple delete.\n\t */\n\taddTrackedEditOperation(range: IRange, text: string | null, forceMoveMarkers?: boolean): void;\n\n\t/**\n\t * Track `selection` when applying edit operations.\n\t * A best effort will be made to not grow/expand the selection.\n\t * An empty selection will clamp to a nearby character.\n\t * @param selection The selection to track.\n\t * @param trackPreviousOnEmpty If set, and the selection is empty, indicates whether the selection\n\t * should clamp to the previous or the next character.\n\t * @return A unique identifier.\n\t */\n\ttrackSelection(selection: Selection, trackPreviousOnEmpty?: boolean): string;\n}\n\n/**\n * A helper for computing cursor state after a command.\n */\nexport interface ICursorStateComputerData {\n\t/**\n\t * Get the inverse edit operations of the added edit operations.\n\t */\n\tgetInverseEditOperations(): IValidEditOperation[];\n\t/**\n\t * Get a previously tracked selection.\n\t * @param id The unique identifier returned by `trackSelection`.\n\t * @return The selection.\n\t */\n\tgetTrackedSelection(id: string): Selection;\n}\n\n/**\n * A command that modifies text / cursor state on a model.\n */\nexport interface ICommand {\n\n\t/**\n\t * Signal that this command is inserting automatic whitespace that should be trimmed if possible.\n\t * @internal\n\t */\n\treadonly insertsAutoWhitespace?: boolean;\n\n\t/**\n\t * Get the edit operations needed to execute this command.\n\t * @param model The model the command will execute on.\n\t * @param builder A helper to collect the needed edit operations and to track selections.\n\t */\n\tgetEditOperations(model: ITextModel, builder: IEditOperationBuilder): void;\n\n\t/**\n\t * Compute the cursor state after the edit operations were applied.\n\t * @param model The model the command has executed on.\n\t * @param helper A helper to get inverse edit operations and to get previously tracked selections.\n\t * @return The cursor state after the command executed.\n\t */\n\tcomputeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection;\n}\n\n/**\n * A model for the diff editor.\n */\nexport interface IDiffEditorModel {\n\t/**\n\t * Original model.\n\t */\n\toriginal: ITextModel;\n\t/**\n\t * Modified model.\n\t */\n\tmodified: ITextModel;\n}\n\nexport interface IDiffEditorViewModel extends IDisposable {\n\treadonly model: IDiffEditorModel;\n\n\twaitForDiff(): Promise;\n}\n\n/**\n * An event describing that an editor has had its model reset (i.e. `editor.setModel()`).\n */\nexport interface IModelChangedEvent {\n\t/**\n\t * The `uri` of the previous model or null.\n\t */\n\treadonly oldModelUrl: URI | null;\n\t/**\n\t * The `uri` of the new model or null.\n\t */\n\treadonly newModelUrl: URI | null;\n}\n\n// --- view\n\nexport interface IScrollEvent {\n\treadonly scrollTop: number;\n\treadonly scrollLeft: number;\n\treadonly scrollWidth: number;\n\treadonly scrollHeight: number;\n\n\treadonly scrollTopChanged: boolean;\n\treadonly scrollLeftChanged: boolean;\n\treadonly scrollWidthChanged: boolean;\n\treadonly scrollHeightChanged: boolean;\n}\n\nexport interface IContentSizeChangedEvent {\n\treadonly contentWidth: number;\n\treadonly contentHeight: number;\n\n\treadonly contentWidthChanged: boolean;\n\treadonly contentHeightChanged: boolean;\n}\n\nexport interface INewScrollPosition {\n\tscrollLeft?: number;\n\tscrollTop?: number;\n}\n\nexport interface IEditorAction {\n\treadonly id: string;\n\treadonly label: string;\n\treadonly alias: string;\n\treadonly metadata: ICommandMetadata | undefined;\n\tisSupported(): boolean;\n\trun(args?: unknown): Promise;\n}\n\nexport type IEditorModel = ITextModel | IDiffEditorModel | IDiffEditorViewModel;\n\n/**\n * A (serializable) state of the cursors.\n */\nexport interface ICursorState {\n\tinSelectionMode: boolean;\n\tselectionStart: IPosition;\n\tposition: IPosition;\n}\n/**\n * A (serializable) state of the view.\n */\nexport interface IViewState {\n\t/** written by previous versions */\n\tscrollTop?: number;\n\t/** written by previous versions */\n\tscrollTopWithoutViewZones?: number;\n\tscrollLeft: number;\n\tfirstPosition: IPosition;\n\tfirstPositionDeltaTop: number;\n}\n/**\n * A (serializable) state of the code editor.\n */\nexport interface ICodeEditorViewState {\n\tcursorState: ICursorState[];\n\tviewState: IViewState;\n\tcontributionsState: { [id: string]: any };\n}\n/**\n * (Serializable) View state for the diff editor.\n */\nexport interface IDiffEditorViewState {\n\toriginal: ICodeEditorViewState | null;\n\tmodified: ICodeEditorViewState | null;\n\tmodelState?: unknown;\n}\n/**\n * An editor view state.\n */\nexport type IEditorViewState = ICodeEditorViewState | IDiffEditorViewState;\n\nexport const enum ScrollType {\n\tSmooth = 0,\n\tImmediate = 1,\n}\n\n/**\n * An editor.\n */\nexport interface IEditor {\n\t/**\n\t * An event emitted when the editor has been disposed.\n\t * @event\n\t */\n\tonDidDispose(listener: () => void): IDisposable;\n\n\t/**\n\t * Dispose the editor.\n\t */\n\tdispose(): void;\n\n\t/**\n\t * Get a unique id for this editor instance.\n\t */\n\tgetId(): string;\n\n\t/**\n\t * Get the editor type. Please see `EditorType`.\n\t * This is to avoid an instanceof check\n\t */\n\tgetEditorType(): string;\n\n\t/**\n\t * Update the editor's options after the editor has been created.\n\t */\n\tupdateOptions(newOptions: IEditorOptions): void;\n\n\t/**\n\t * Instructs the editor to remeasure its container. This method should\n\t * be called when the container of the editor gets resized.\n\t *\n\t * If a dimension is passed in, the passed in value will be used.\n\t *\n\t * By default, this will also render the editor immediately.\n\t * If you prefer to delay rendering to the next animation frame, use postponeRendering == true.\n\t */\n\tlayout(dimension?: IDimension, postponeRendering?: boolean): void;\n\n\t/**\n\t * Brings browser focus to the editor text\n\t */\n\tfocus(): void;\n\n\t/**\n\t * Returns true if the text inside this editor is focused (i.e. cursor is blinking).\n\t */\n\thasTextFocus(): boolean;\n\n\t/**\n\t * Returns all actions associated with this editor.\n\t */\n\tgetSupportedActions(): IEditorAction[];\n\n\t/**\n\t * Saves current view state of the editor in a serializable object.\n\t */\n\tsaveViewState(): IEditorViewState | null;\n\n\t/**\n\t * Restores the view state of the editor from a serializable object generated by `saveViewState`.\n\t */\n\trestoreViewState(state: IEditorViewState | null): void;\n\n\t/**\n\t * Given a position, returns a column number that takes tab-widths into account.\n\t */\n\tgetVisibleColumnFromPosition(position: IPosition): number;\n\n\t/**\n\t * Returns the primary position of the cursor.\n\t */\n\tgetPosition(): Position | null;\n\n\t/**\n\t * Set the primary position of the cursor. This will remove any secondary cursors.\n\t * @param position New primary cursor's position\n\t * @param source Source of the call that caused the position\n\t */\n\tsetPosition(position: IPosition, source?: string): void;\n\n\t/**\n\t * Scroll vertically as necessary and reveal a line.\n\t */\n\trevealLine(lineNumber: number, scrollType?: ScrollType): void;\n\n\t/**\n\t * Scroll vertically as necessary and reveal a line centered vertically.\n\t */\n\trevealLineInCenter(lineNumber: number, scrollType?: ScrollType): void;\n\n\t/**\n\t * Scroll vertically as necessary and reveal a line centered vertically only if it lies outside the viewport.\n\t */\n\trevealLineInCenterIfOutsideViewport(lineNumber: number, scrollType?: ScrollType): void;\n\n\t/**\n\t * Scroll vertically as necessary and reveal a line close to the top of the viewport,\n\t * optimized for viewing a code definition.\n\t */\n\trevealLineNearTop(lineNumber: number, scrollType?: ScrollType): void;\n\n\t/**\n\t * Scroll vertically or horizontally as necessary and reveal a position.\n\t */\n\trevealPosition(position: IPosition, scrollType?: ScrollType): void;\n\n\t/**\n\t * Scroll vertically or horizontally as necessary and reveal a position centered vertically.\n\t */\n\trevealPositionInCenter(position: IPosition, scrollType?: ScrollType): void;\n\n\t/**\n\t * Scroll vertically or horizontally as necessary and reveal a position centered vertically only if it lies outside the viewport.\n\t */\n\trevealPositionInCenterIfOutsideViewport(position: IPosition, scrollType?: ScrollType): void;\n\n\t/**\n\t * Scroll vertically or horizontally as necessary and reveal a position close to the top of the viewport,\n\t * optimized for viewing a code definition.\n\t */\n\trevealPositionNearTop(position: IPosition, scrollType?: ScrollType): void;\n\n\t/**\n\t * Returns the primary selection of the editor.\n\t */\n\tgetSelection(): Selection | null;\n\n\t/**\n\t * Returns all the selections of the editor.\n\t */\n\tgetSelections(): Selection[] | null;\n\n\t/**\n\t * Set the primary selection of the editor. This will remove any secondary cursors.\n\t * @param selection The new selection\n\t * @param source Source of the call that caused the selection\n\t */\n\tsetSelection(selection: IRange, source?: string): void;\n\t/**\n\t * Set the primary selection of the editor. This will remove any secondary cursors.\n\t * @param selection The new selection\n\t * @param source Source of the call that caused the selection\n\t */\n\tsetSelection(selection: Range, source?: string): void;\n\t/**\n\t * Set the primary selection of the editor. This will remove any secondary cursors.\n\t * @param selection The new selection\n\t * @param source Source of the call that caused the selection\n\t */\n\tsetSelection(selection: ISelection, source?: string): void;\n\t/**\n\t * Set the primary selection of the editor. This will remove any secondary cursors.\n\t * @param selection The new selection\n\t * @param source Source of the call that caused the selection\n\t */\n\tsetSelection(selection: Selection, source?: string): void;\n\n\t/**\n\t * Set the selections for all the cursors of the editor.\n\t * Cursors will be removed or added, as necessary.\n\t * @param selections The new selection\n\t * @param source Source of the call that caused the selection\n\t */\n\tsetSelections(selections: readonly ISelection[], source?: string): void;\n\n\t/**\n\t * Scroll vertically as necessary and reveal lines.\n\t */\n\trevealLines(startLineNumber: number, endLineNumber: number, scrollType?: ScrollType): void;\n\n\t/**\n\t * Scroll vertically as necessary and reveal lines centered vertically.\n\t */\n\trevealLinesInCenter(lineNumber: number, endLineNumber: number, scrollType?: ScrollType): void;\n\n\t/**\n\t * Scroll vertically as necessary and reveal lines centered vertically only if it lies outside the viewport.\n\t */\n\trevealLinesInCenterIfOutsideViewport(lineNumber: number, endLineNumber: number, scrollType?: ScrollType): void;\n\n\t/**\n\t * Scroll vertically as necessary and reveal lines close to the top of the viewport,\n\t * optimized for viewing a code definition.\n\t */\n\trevealLinesNearTop(lineNumber: number, endLineNumber: number, scrollType?: ScrollType): void;\n\n\t/**\n\t * Scroll vertically or horizontally as necessary and reveal a range.\n\t */\n\trevealRange(range: IRange, scrollType?: ScrollType): void;\n\n\t/**\n\t * Scroll vertically or horizontally as necessary and reveal a range centered vertically.\n\t */\n\trevealRangeInCenter(range: IRange, scrollType?: ScrollType): void;\n\n\t/**\n\t * Scroll vertically or horizontally as necessary and reveal a range at the top of the viewport.\n\t */\n\trevealRangeAtTop(range: IRange, scrollType?: ScrollType): void;\n\n\t/**\n\t * Scroll vertically or horizontally as necessary and reveal a range centered vertically only if it lies outside the viewport.\n\t */\n\trevealRangeInCenterIfOutsideViewport(range: IRange, scrollType?: ScrollType): void;\n\n\t/**\n\t * Scroll vertically or horizontally as necessary and reveal a range close to the top of the viewport,\n\t * optimized for viewing a code definition.\n\t */\n\trevealRangeNearTop(range: IRange, scrollType?: ScrollType): void;\n\n\t/**\n\t * Scroll vertically or horizontally as necessary and reveal a range close to the top of the viewport,\n\t * optimized for viewing a code definition. Only if it lies outside the viewport.\n\t */\n\trevealRangeNearTopIfOutsideViewport(range: IRange, scrollType?: ScrollType): void;\n\n\t/**\n\t * Directly trigger a handler or an editor action.\n\t * @param source The source of the call.\n\t * @param handlerId The id of the handler or the id of a contribution.\n\t * @param payload Extra data to be sent to the handler.\n\t */\n\ttrigger(source: string | null | undefined, handlerId: string, payload: any): void;\n\n\t/**\n\t * Gets the current model attached to this editor.\n\t */\n\tgetModel(): IEditorModel | null;\n\n\t/**\n\t * Sets the current model attached to this editor.\n\t * If the previous model was created by the editor via the value key in the options\n\t * literal object, it will be destroyed. Otherwise, if the previous model was set\n\t * via setModel, or the model key in the options literal object, the previous model\n\t * will not be destroyed.\n\t * It is safe to call setModel(null) to simply detach the current model from the editor.\n\t */\n\tsetModel(model: IEditorModel | null): void;\n\n\t/**\n\t * Create a collection of decorations. All decorations added through this collection\n\t * will get the ownerId of the editor (meaning they will not show up in other editors).\n\t * These decorations will be automatically cleared when the editor's model changes.\n\t */\n\tcreateDecorationsCollection(decorations?: IModelDeltaDecoration[]): IEditorDecorationsCollection;\n\n\t/**\n\t * Change the decorations. All decorations added through this changeAccessor\n\t * will get the ownerId of the editor (meaning they will not show up in other\n\t * editors).\n\t * @see {@link ITextModel.changeDecorations}\n\t * @internal\n\t */\n\tchangeDecorations(callback: (changeAccessor: IModelDecorationsChangeAccessor) => any): any;\n}\n\n/**\n * A diff editor.\n *\n * @internal\n */\nexport interface IDiffEditor extends IEditor {\n\n\t/**\n\t * Type the getModel() of IEditor.\n\t */\n\tgetModel(): IDiffEditorModel | null;\n}\n\n/**\n * @internal\n */\nexport interface ICompositeCodeEditor {\n\n\t/**\n\t * An event that signals that the active editor has changed\n\t */\n\treadonly onDidChangeActiveEditor: Event;\n\n\t/**\n\t * The active code editor iff any\n\t */\n\treadonly activeCodeEditor: IEditor | undefined;\n\t// readonly editors: readonly ICodeEditor[] maybe supported with uris\n}\n\n/**\n * A collection of decorations\n */\nexport interface IEditorDecorationsCollection {\n\t/**\n\t * An event emitted when decorations change in the editor,\n\t * but the change is not caused by us setting or clearing the collection.\n\t */\n\tonDidChange: Event;\n\t/**\n\t * Get the decorations count.\n\t */\n\tlength: number;\n\t/**\n\t * Get the range for a decoration.\n\t */\n\tgetRange(index: number): Range | null;\n\t/**\n\t * Get all ranges for decorations.\n\t */\n\tgetRanges(): Range[];\n\t/**\n\t * Determine if a decoration is in this collection.\n\t */\n\thas(decoration: IModelDecoration): boolean;\n\t/**\n\t * Replace all previous decorations with `newDecorations`.\n\t */\n\tset(newDecorations: readonly IModelDeltaDecoration[]): string[];\n\t/**\n\t * Append `newDecorations` to this collection.\n\t */\n\tappend(newDecorations: readonly IModelDeltaDecoration[]): string[];\n\t/**\n\t * Remove all previous decorations.\n\t */\n\tclear(): void;\n}\n\n/**\n * An editor contribution that gets created every time a new editor gets created and gets disposed when the editor gets disposed.\n */\nexport interface IEditorContribution {\n\t/**\n\t * Dispose this contribution.\n\t */\n\tdispose(): void;\n\t/**\n\t * Store view state.\n\t */\n\tsaveViewState?(): any;\n\t/**\n\t * Restore view state.\n\t */\n\trestoreViewState?(state: any): void;\n}\n\n/**\n * A diff editor contribution that gets created every time a new diffeditor gets created and gets disposed when the diff editor gets disposed.\n * @internal\n */\nexport interface IDiffEditorContribution {\n\t/**\n\t * Dispose this contribution.\n\t */\n\tdispose(): void;\n}\n\n/**\n * The type of the `IEditor`.\n */\nexport const EditorType = {\n\tICodeEditor: 'vs.editor.ICodeEditor',\n\tIDiffEditor: 'vs.editor.IDiffEditor'\n};\n\n/**\n * Built-in commands.\n * @internal\n */\nexport const enum Handler {\n\tCompositionStart = 'compositionStart',\n\tCompositionEnd = 'compositionEnd',\n\tType = 'type',\n\tReplacePreviousChar = 'replacePreviousChar',\n\tCompositionType = 'compositionType',\n\tPaste = 'paste',\n\tCut = 'cut',\n}\n\n/**\n * @internal\n */\nexport interface TypePayload {\n\ttext: string;\n}\n\n/**\n * @internal\n */\nexport interface ReplacePreviousCharPayload {\n\ttext: string;\n\treplaceCharCnt: number;\n}\n\n/**\n * @internal\n */\nexport interface CompositionTypePayload {\n\ttext: string;\n\treplacePrevCharCnt: number;\n\treplaceNextCharCnt: number;\n\tpositionDelta: number;\n}\n\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\nimport { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';\nimport { IMouseEvent, IMouseWheelEvent } from 'vs/base/browser/mouseEvent';\nimport { Event } from 'vs/base/common/event';\nimport { IEditorConstructionOptions } from 'vs/editor/browser/config/editorConfiguration';\nimport { ConfigurationChangedEvent, EditorLayoutInfo, EditorOption, FindComputedEditorOptionValueById, IComputedEditorOptions, IDiffEditorOptions, IEditorOptions, OverviewRulerPosition } from 'vs/editor/common/config/editorOptions';\nimport { IDimension } from 'vs/editor/common/core/dimension';\nimport { IPosition, Position } from 'vs/editor/common/core/position';\nimport { IRange, Range } from 'vs/editor/common/core/range';\nimport { Selection } from 'vs/editor/common/core/selection';\nimport { IWordAtPosition } from 'vs/editor/common/core/wordHelper';\nimport { ICursorPositionChangedEvent, ICursorSelectionChangedEvent } from 'vs/editor/common/cursorEvents';\nimport { ILineChange } from 'vs/editor/common/diff/legacyLinesDiffComputer';\nimport * as editorCommon from 'vs/editor/common/editorCommon';\nimport { GlyphMarginLane, ICursorStateComputer, IIdentifiedSingleEditOperation, IModelDecoration, IModelDeltaDecoration, ITextModel, PositionAffinity } from 'vs/editor/common/model';\nimport { InjectedText } from 'vs/editor/common/modelLineProjectionData';\nimport { IModelContentChangedEvent, IModelDecorationsChangedEvent, IModelLanguageChangedEvent, IModelLanguageConfigurationChangedEvent, IModelOptionsChangedEvent, IModelTokensChangedEvent } from 'vs/editor/common/textModelEvents';\nimport { IViewModel } from 'vs/editor/common/viewModel';\nimport { OverviewRulerZone } from 'vs/editor/common/viewModel/overviewZoneManager';\nimport { MenuId } from 'vs/platform/actions/common/actions';\nimport { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';\n\n/**\n * A view zone is a full horizontal rectangle that 'pushes' text down.\n * The editor reserves space for view zones when rendering.\n */\nexport interface IViewZone {\n\t/**\n\t * The line number after which this zone should appear.\n\t * Use 0 to place a view zone before the first line number.\n\t */\n\tafterLineNumber: number;\n\t/**\n\t * The column after which this zone should appear.\n\t * If not set, the maxLineColumn of `afterLineNumber` will be used.\n\t * This is relevant for wrapped lines.\n\t */\n\tafterColumn?: number;\n\t/**\n\t * If the `afterColumn` has multiple view columns, the affinity specifies which one to use. Defaults to `none`.\n\t*/\n\tafterColumnAffinity?: PositionAffinity;\n\t/**\n\t * Render the zone even when its line is hidden.\n\t */\n\tshowInHiddenAreas?: boolean;\n\t/**\n\t * Tiebreaker that is used when multiple view zones want to be after the same line.\n\t * Defaults to `afterColumn` otherwise 10000;\n\t */\n\tordinal?: number;\n\t/**\n\t * Suppress mouse down events.\n\t * If set, the editor will attach a mouse down listener to the view zone and .preventDefault on it.\n\t * Defaults to false\n\t */\n\tsuppressMouseDown?: boolean;\n\t/**\n\t * The height in lines of the view zone.\n\t * If specified, `heightInPx` will be used instead of this.\n\t * If neither `heightInPx` nor `heightInLines` is specified, a default of `heightInLines` = 1 will be chosen.\n\t */\n\theightInLines?: number;\n\t/**\n\t * The height in px of the view zone.\n\t * If this is set, the editor will give preference to it rather than `heightInLines` above.\n\t * If neither `heightInPx` nor `heightInLines` is specified, a default of `heightInLines` = 1 will be chosen.\n\t */\n\theightInPx?: number;\n\t/**\n\t * The minimum width in px of the view zone.\n\t * If this is set, the editor will ensure that the scroll width is >= than this value.\n\t */\n\tminWidthInPx?: number;\n\t/**\n\t * The dom node of the view zone\n\t */\n\tdomNode: HTMLElement;\n\t/**\n\t * An optional dom node for the view zone that will be placed in the margin area.\n\t */\n\tmarginDomNode?: HTMLElement | null;\n\t/**\n\t * Callback which gives the relative top of the view zone as it appears (taking scrolling into account).\n\t */\n\tonDomNodeTop?: (top: number) => void;\n\t/**\n\t * Callback which gives the height in pixels of the view zone.\n\t */\n\tonComputedHeight?: (height: number) => void;\n}\n/**\n * An accessor that allows for zones to be added or removed.\n */\nexport interface IViewZoneChangeAccessor {\n\t/**\n\t * Create a new view zone.\n\t * @param zone Zone to create\n\t * @return A unique identifier to the view zone.\n\t */\n\taddZone(zone: IViewZone): string;\n\t/**\n\t * Remove a zone\n\t * @param id A unique identifier to the view zone, as returned by the `addZone` call.\n\t */\n\tremoveZone(id: string): void;\n\t/**\n\t * Change a zone's position.\n\t * The editor will rescan the `afterLineNumber` and `afterColumn` properties of a view zone.\n\t */\n\tlayoutZone(id: string): void;\n}\n\n/**\n * A positioning preference for rendering content widgets.\n */\nexport const enum ContentWidgetPositionPreference {\n\t/**\n\t * Place the content widget exactly at a position\n\t */\n\tEXACT,\n\t/**\n\t * Place the content widget above a position\n\t */\n\tABOVE,\n\t/**\n\t * Place the content widget below a position\n\t */\n\tBELOW\n}\n/**\n * A position for rendering content widgets.\n */\nexport interface IContentWidgetPosition {\n\t/**\n\t * Desired position which serves as an anchor for placing the content widget.\n\t * The widget will be placed above, at, or below the specified position, based on the\n\t * provided preference. The widget will always touch this position.\n\t *\n\t * Given sufficient horizontal space, the widget will be placed to the right of the\n\t * passed in position. This can be tweaked by providing a `secondaryPosition`.\n\t *\n\t * @see preference\n\t * @see secondaryPosition\n\t */\n\tposition: IPosition | null;\n\t/**\n\t * Optionally, a secondary position can be provided to further define the placing of\n\t * the content widget. The secondary position must have the same line number as the\n\t * primary position. If possible, the widget will be placed such that it also touches\n\t * the secondary position.\n\t */\n\tsecondaryPosition?: IPosition | null;\n\t/**\n\t * Placement preference for position, in order of preference.\n\t */\n\tpreference: ContentWidgetPositionPreference[];\n\n\t/**\n\t * Placement preference when multiple view positions refer to the same (model) position.\n\t * This plays a role when injected text is involved.\n\t*/\n\tpositionAffinity?: PositionAffinity;\n}\n/**\n * A content widget renders inline with the text and can be easily placed 'near' an editor position.\n */\nexport interface IContentWidget {\n\t/**\n\t * Render this content widget in a location where it could overflow the editor's view dom node.\n\t */\n\tallowEditorOverflow?: boolean;\n\t/**\n\t * Call preventDefault() on mousedown events that target the content widget.\n\t */\n\tsuppressMouseDown?: boolean;\n\t/**\n\t * Get a unique identifier of the content widget.\n\t */\n\tgetId(): string;\n\t/**\n\t * Get the dom node of the content widget.\n\t */\n\tgetDomNode(): HTMLElement;\n\t/**\n\t * Get the placement of the content widget.\n\t * If null is returned, the content widget will be placed off screen.\n\t */\n\tgetPosition(): IContentWidgetPosition | null;\n\t/**\n\t * Optional function that is invoked before rendering\n\t * the content widget. If a dimension is returned the editor will\n\t * attempt to use it.\n\t */\n\tbeforeRender?(): IDimension | null;\n\t/**\n\t * Optional function that is invoked after rendering the content\n\t * widget. Is being invoked with the selected position preference\n\t * or `null` if not rendered.\n\t */\n\tafterRender?(position: ContentWidgetPositionPreference | null): void;\n}\n\n/**\n * A positioning preference for rendering overlay widgets.\n */\nexport const enum OverlayWidgetPositionPreference {\n\t/**\n\t * Position the overlay widget in the top right corner\n\t */\n\tTOP_RIGHT_CORNER,\n\n\t/**\n\t * Position the overlay widget in the bottom right corner\n\t */\n\tBOTTOM_RIGHT_CORNER,\n\n\t/**\n\t * Position the overlay widget in the top center\n\t */\n\tTOP_CENTER\n}\n\n\n/**\n * Represents editor-relative coordinates of an overlay widget.\n */\nexport interface IOverlayWidgetPositionCoordinates {\n\t/**\n\t * The top position for the overlay widget, relative to the editor.\n\t */\n\ttop: number;\n\t/**\n\t * The left position for the overlay widget, relative to the editor.\n\t */\n\tleft: number;\n}\n\n/**\n * A position for rendering overlay widgets.\n */\nexport interface IOverlayWidgetPosition {\n\t/**\n\t * The position preference for the overlay widget.\n\t */\n\tpreference: OverlayWidgetPositionPreference | IOverlayWidgetPositionCoordinates | null;\n\n\t/**\n\t * When set, stacks with other overlay widgets with the same preference,\n\t * in an order determined by the ordinal value.\n\t */\n\tstackOridinal?: number;\n}\n/**\n * An overlay widgets renders on top of the text.\n */\nexport interface IOverlayWidget {\n\t/**\n\t * Event fired when the widget layout changes.\n\t */\n\tonDidLayout?: Event;\n\t/**\n\t * Render this overlay widget in a location where it could overflow the editor's view dom node.\n\t */\n\tallowEditorOverflow?: boolean;\n\t/**\n\t * Get a unique identifier of the overlay widget.\n\t */\n\tgetId(): string;\n\t/**\n\t * Get the dom node of the overlay widget.\n\t */\n\tgetDomNode(): HTMLElement;\n\t/**\n\t * Get the placement of the overlay widget.\n\t * If null is returned, the overlay widget is responsible to place itself.\n\t */\n\tgetPosition(): IOverlayWidgetPosition | null;\n\t/**\n\t * The editor will ensure that the scroll width is >= than this value.\n\t */\n\tgetMinContentWidthInPx?(): number;\n}\n\n/**\n * A glyph margin widget renders in the editor glyph margin.\n */\nexport interface IGlyphMarginWidget {\n\t/**\n\t * Get a unique identifier of the glyph widget.\n\t */\n\tgetId(): string;\n\t/**\n\t * Get the dom node of the glyph widget.\n\t */\n\tgetDomNode(): HTMLElement;\n\t/**\n\t * Get the placement of the glyph widget.\n\t */\n\tgetPosition(): IGlyphMarginWidgetPosition;\n}\n\n/**\n * A position for rendering glyph margin widgets.\n */\nexport interface IGlyphMarginWidgetPosition {\n\t/**\n\t * The glyph margin lane where the widget should be shown.\n\t */\n\tlane: GlyphMarginLane;\n\t/**\n\t * The priority order of the widget, used for determining which widget\n\t * to render when there are multiple.\n\t */\n\tzIndex: number;\n\t/**\n\t * The editor range that this widget applies to.\n\t */\n\trange: IRange;\n}\n\n/**\n * Type of hit element with the mouse in the editor.\n */\nexport const enum MouseTargetType {\n\t/**\n\t * Mouse is on top of an unknown element.\n\t */\n\tUNKNOWN,\n\t/**\n\t * Mouse is on top of the textarea used for input.\n\t */\n\tTEXTAREA,\n\t/**\n\t * Mouse is on top of the glyph margin\n\t */\n\tGUTTER_GLYPH_MARGIN,\n\t/**\n\t * Mouse is on top of the line numbers\n\t */\n\tGUTTER_LINE_NUMBERS,\n\t/**\n\t * Mouse is on top of the line decorations\n\t */\n\tGUTTER_LINE_DECORATIONS,\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,\n\t/**\n\t * Mouse is on top of text in the content.\n\t */\n\tCONTENT_TEXT,\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,\n\t/**\n\t * Mouse is on top of a view zone in the content.\n\t */\n\tCONTENT_VIEW_ZONE,\n\t/**\n\t * Mouse is on top of a content widget.\n\t */\n\tCONTENT_WIDGET,\n\t/**\n\t * Mouse is on top of the decorations overview ruler.\n\t */\n\tOVERVIEW_RULER,\n\t/**\n\t * Mouse is on top of a scrollbar.\n\t */\n\tSCROLLBAR,\n\t/**\n\t * Mouse is on top of an overlay widget.\n\t */\n\tOVERLAY_WIDGET,\n\t/**\n\t * Mouse is outside of the editor.\n\t */\n\tOUTSIDE_EDITOR,\n}\nexport interface IBaseMouseTarget {\n\t/**\n\t * The target element\n\t */\n\treadonly element: HTMLElement | null;\n\t/**\n\t * The 'approximate' editor position\n\t */\n\treadonly position: Position | null;\n\t/**\n\t * Desired mouse column (e.g. when position.column gets clamped to text length -- clicking after text on a line).\n\t */\n\treadonly mouseColumn: number;\n\t/**\n\t * The 'approximate' editor range\n\t */\n\treadonly range: Range | null;\n}\nexport interface IMouseTargetUnknown extends IBaseMouseTarget {\n\treadonly type: MouseTargetType.UNKNOWN;\n}\nexport interface IMouseTargetTextarea extends IBaseMouseTarget {\n\treadonly type: MouseTargetType.TEXTAREA;\n\treadonly position: null;\n\treadonly range: null;\n}\nexport interface IMouseTargetMarginData {\n\treadonly isAfterLines: boolean;\n\treadonly glyphMarginLeft: number;\n\treadonly glyphMarginWidth: number;\n\treadonly glyphMarginLane?: GlyphMarginLane;\n\treadonly lineNumbersWidth: number;\n\treadonly offsetX: number;\n}\nexport interface IMouseTargetMargin extends IBaseMouseTarget {\n\treadonly type: MouseTargetType.GUTTER_GLYPH_MARGIN | MouseTargetType.GUTTER_LINE_NUMBERS | MouseTargetType.GUTTER_LINE_DECORATIONS;\n\treadonly position: Position;\n\treadonly range: Range;\n\treadonly detail: IMouseTargetMarginData;\n}\nexport interface IMouseTargetViewZoneData {\n\treadonly viewZoneId: string;\n\treadonly positionBefore: Position | null;\n\treadonly positionAfter: Position | null;\n\treadonly position: Position;\n\treadonly afterLineNumber: number;\n}\nexport interface IMouseTargetViewZone extends IBaseMouseTarget {\n\treadonly type: MouseTargetType.GUTTER_VIEW_ZONE | MouseTargetType.CONTENT_VIEW_ZONE;\n\treadonly position: Position;\n\treadonly range: Range;\n\treadonly detail: IMouseTargetViewZoneData;\n}\nexport interface IMouseTargetContentTextData {\n\treadonly mightBeForeignElement: boolean;\n\t/**\n\t * @internal\n\t */\n\treadonly injectedText: InjectedText | null;\n}\nexport interface IMouseTargetContentText extends IBaseMouseTarget {\n\treadonly type: MouseTargetType.CONTENT_TEXT;\n\treadonly position: Position;\n\treadonly range: Range;\n\treadonly detail: IMouseTargetContentTextData;\n}\nexport interface IMouseTargetContentEmptyData {\n\treadonly isAfterLines: boolean;\n\treadonly horizontalDistanceToText?: number;\n}\nexport interface IMouseTargetContentEmpty extends IBaseMouseTarget {\n\treadonly type: MouseTargetType.CONTENT_EMPTY;\n\treadonly position: Position;\n\treadonly range: Range;\n\treadonly detail: IMouseTargetContentEmptyData;\n}\nexport interface IMouseTargetContentWidget extends IBaseMouseTarget {\n\treadonly type: MouseTargetType.CONTENT_WIDGET;\n\treadonly position: null;\n\treadonly range: null;\n\treadonly detail: string;\n}\nexport interface IMouseTargetOverlayWidget extends IBaseMouseTarget {\n\treadonly type: MouseTargetType.OVERLAY_WIDGET;\n\treadonly position: null;\n\treadonly range: null;\n\treadonly detail: string;\n}\nexport interface IMouseTargetScrollbar extends IBaseMouseTarget {\n\treadonly type: MouseTargetType.SCROLLBAR;\n\treadonly position: Position;\n\treadonly range: Range;\n}\nexport interface IMouseTargetOverviewRuler extends IBaseMouseTarget {\n\treadonly type: MouseTargetType.OVERVIEW_RULER;\n}\nexport interface IMouseTargetOutsideEditor extends IBaseMouseTarget {\n\treadonly type: MouseTargetType.OUTSIDE_EDITOR;\n\treadonly outsidePosition: 'above' | 'below' | 'left' | 'right';\n\treadonly outsideDistance: number;\n}\n/**\n * Target hit with the mouse in the editor.\n */\nexport type IMouseTarget = (\n\tIMouseTargetUnknown\n\t| IMouseTargetTextarea\n\t| IMouseTargetMargin\n\t| IMouseTargetViewZone\n\t| IMouseTargetContentText\n\t| IMouseTargetContentEmpty\n\t| IMouseTargetContentWidget\n\t| IMouseTargetOverlayWidget\n\t| IMouseTargetScrollbar\n\t| IMouseTargetOverviewRuler\n\t| IMouseTargetOutsideEditor\n);\n/**\n * A mouse event originating from the editor.\n */\nexport interface IEditorMouseEvent {\n\treadonly event: IMouseEvent;\n\treadonly target: IMouseTarget;\n}\nexport interface IPartialEditorMouseEvent {\n\treadonly event: IMouseEvent;\n\treadonly target: IMouseTarget | null;\n}\n\n/**\n * A paste event originating from the editor.\n */\nexport interface IPasteEvent {\n\treadonly range: Range;\n\treadonly languageId: string | null;\n\treadonly clipboardEvent?: ClipboardEvent;\n}\n\n/**\n * @internal\n */\nexport interface PastePayload {\n\ttext: string;\n\tpasteOnNewLine: boolean;\n\tmulticursorText: string[] | null;\n\tmode: string | null;\n\tclipboardEvent?: ClipboardEvent;\n}\n\n/**\n * An overview ruler\n * @internal\n */\nexport interface IOverviewRuler {\n\tgetDomNode(): HTMLElement;\n\tdispose(): void;\n\tsetZones(zones: OverviewRulerZone[]): void;\n\tsetLayout(position: OverviewRulerPosition): void;\n}\n\n/**\n * Editor aria options.\n * @internal\n */\nexport interface IEditorAriaOptions {\n\tactiveDescendant: string | undefined;\n\trole?: string;\n}\n\nexport interface IDiffEditorConstructionOptions extends IDiffEditorOptions, IEditorConstructionOptions {\n\t/**\n\t * Place overflow widgets inside an external DOM node.\n\t * Defaults to an internal DOM node.\n\t */\n\toverflowWidgetsDomNode?: HTMLElement;\n\n\t/**\n\t * Aria label for original editor.\n\t */\n\toriginalAriaLabel?: string;\n\n\t/**\n\t * Aria label for modified editor.\n\t */\n\tmodifiedAriaLabel?: string;\n}\n\n/**\n * A rich code editor.\n */\nexport interface ICodeEditor extends editorCommon.IEditor {\n\t/**\n\t * This editor is used as an alternative to an box, i.e. as a simple widget.\n\t * @internal\n\t */\n\treadonly isSimpleWidget: boolean;\n\t/**\n\t * The context menu ID that should be used to lookup context menu actions.\n\t * @internal\n\t */\n\treadonly contextMenuId: MenuId;\n\t/**\n\t * An event emitted when the content of the current model has changed.\n\t * @event\n\t */\n\treadonly onDidChangeModelContent: Event;\n\t/**\n\t * An event emitted when the language of the current model has changed.\n\t * @event\n\t */\n\treadonly onDidChangeModelLanguage: Event;\n\t/**\n\t * An event emitted when the language configuration of the current model has changed.\n\t * @event\n\t */\n\treadonly onDidChangeModelLanguageConfiguration: Event;\n\t/**\n\t * An event emitted when the options of the current model has changed.\n\t * @event\n\t */\n\treadonly onDidChangeModelOptions: Event;\n\t/**\n\t * An event emitted when the configuration of the editor has changed. (e.g. `editor.updateOptions()`)\n\t * @event\n\t */\n\treadonly onDidChangeConfiguration: Event;\n\t/**\n\t * An event emitted when the cursor position has changed.\n\t * @event\n\t */\n\treadonly onDidChangeCursorPosition: Event;\n\t/**\n\t * An event emitted when the cursor selection has changed.\n\t * @event\n\t */\n\treadonly onDidChangeCursorSelection: Event;\n\t/**\n\t * An event emitted when the model of this editor is about to change (e.g. from `editor.setModel()`).\n\t * @event\n\t */\n\treadonly onWillChangeModel: Event;\n\t/**\n\t * An event emitted when the model of this editor has changed (e.g. `editor.setModel()`).\n\t * @event\n\t */\n\treadonly onDidChangeModel: Event;\n\t/**\n\t * An event emitted when the decorations of the current model have changed.\n\t * @event\n\t */\n\treadonly onDidChangeModelDecorations: Event;\n\t/**\n\t * An event emitted when the tokens of the current model have changed.\n\t * @internal\n\t */\n\treadonly onDidChangeModelTokens: Event;\n\t/**\n\t * An event emitted when the text inside this editor gained focus (i.e. cursor starts blinking).\n\t * @event\n\t */\n\treadonly onDidFocusEditorText: Event;\n\t/**\n\t * An event emitted when the text inside this editor lost focus (i.e. cursor stops blinking).\n\t * @event\n\t */\n\treadonly onDidBlurEditorText: Event;\n\t/**\n\t * An event emitted when the text inside this editor or an editor widget gained focus.\n\t * @event\n\t */\n\treadonly onDidFocusEditorWidget: Event;\n\t/**\n\t * An event emitted when the text inside this editor or an editor widget lost focus.\n\t * @event\n\t */\n\treadonly onDidBlurEditorWidget: Event;\n\t/**\n\t * An event emitted before interpreting typed characters (on the keyboard).\n\t * @event\n\t * @internal\n\t */\n\treadonly onWillType: Event;\n\t/**\n\t * An event emitted after interpreting typed characters (on the keyboard).\n\t * @event\n\t * @internal\n\t */\n\treadonly onDidType: Event;\n\t/**\n\t * An event emitted after composition has started.\n\t */\n\treadonly onDidCompositionStart: Event;\n\t/**\n\t * An event emitted after composition has ended.\n\t */\n\treadonly onDidCompositionEnd: Event;\n\t/**\n\t * An event emitted when editing failed because the editor is read-only.\n\t * @event\n\t */\n\treadonly onDidAttemptReadOnlyEdit: Event;\n\t/**\n\t * An event emitted when users paste text in the editor.\n\t * @event\n\t */\n\treadonly onDidPaste: Event;\n\t/**\n\t * An event emitted on a \"mouseup\".\n\t * @event\n\t */\n\treadonly onMouseUp: Event;\n\t/**\n\t * An event emitted on a \"mousedown\".\n\t * @event\n\t */\n\treadonly onMouseDown: Event;\n\t/**\n\t * An event emitted on a \"mousedrag\".\n\t * @internal\n\t * @event\n\t */\n\treadonly onMouseDrag: Event;\n\t/**\n\t * An event emitted on a \"mousedrop\".\n\t * @internal\n\t * @event\n\t */\n\treadonly onMouseDrop: Event;\n\t/**\n\t * An event emitted on a \"mousedropcanceled\".\n\t * @internal\n\t * @event\n\t */\n\treadonly onMouseDropCanceled: Event;\n\t/**\n\t * An event emitted when content is dropped into the editor.\n\t * @internal\n\t * @event\n\t */\n\treadonly onDropIntoEditor: Event<{ readonly position: IPosition; readonly event: DragEvent }>;\n\t/**\n\t * An event emitted on a \"contextmenu\".\n\t * @event\n\t */\n\treadonly onContextMenu: Event;\n\t/**\n\t * An event emitted on a \"mousemove\".\n\t * @event\n\t */\n\treadonly onMouseMove: Event;\n\t/**\n\t * An event emitted on a \"mouseleave\".\n\t * @event\n\t */\n\treadonly onMouseLeave: Event;\n\t/**\n\t * An event emitted on a \"mousewheel\"\n\t * @event\n\t * @internal\n\t */\n\treadonly onMouseWheel: Event;\n\t/**\n\t * An event emitted on a \"keyup\".\n\t * @event\n\t */\n\treadonly onKeyUp: Event;\n\t/**\n\t * An event emitted on a \"keydown\".\n\t * @event\n\t */\n\treadonly onKeyDown: Event;\n\t/**\n\t * An event emitted when the layout of the editor has changed.\n\t * @event\n\t */\n\treadonly onDidLayoutChange: Event;\n\t/**\n\t * An event emitted when the content width or content height in the editor has changed.\n\t * @event\n\t */\n\treadonly onDidContentSizeChange: Event;\n\t/**\n\t * An event emitted when the scroll in the editor has changed.\n\t * @event\n\t */\n\treadonly onDidScrollChange: Event;\n\n\t/**\n\t * An event emitted when hidden areas change in the editor (e.g. due to folding).\n\t * @event\n\t */\n\treadonly onDidChangeHiddenAreas: Event;\n\n\t/**\n\t * Some editor operations fire multiple events at once.\n\t * To allow users to react to multiple events fired by a single operation,\n\t * the editor fires a begin update before the operation and an end update after the operation.\n\t * Whenever the editor fires `onBeginUpdate`, it will also fire `onEndUpdate` once the operation finishes.\n\t * Note that not all operations are bracketed by `onBeginUpdate` and `onEndUpdate`.\n\t*/\n\treadonly onBeginUpdate: Event;\n\n\t/**\n\t * Fires after the editor completes the operation it fired `onBeginUpdate` for.\n\t*/\n\treadonly onEndUpdate: Event;\n\n\t/**\n\t * Saves current view state of the editor in a serializable object.\n\t */\n\tsaveViewState(): editorCommon.ICodeEditorViewState | null;\n\n\t/**\n\t * Restores the view state of the editor from a serializable object generated by `saveViewState`.\n\t */\n\trestoreViewState(state: editorCommon.ICodeEditorViewState | null): void;\n\n\t/**\n\t * Returns true if the text inside this editor or an editor widget has focus.\n\t */\n\thasWidgetFocus(): boolean;\n\n\t/**\n\t * Get a contribution of this editor.\n\t * @id Unique identifier of the contribution.\n\t * @return The contribution or null if contribution not found.\n\t */\n\tgetContribution(id: string): T | null;\n\n\t/**\n\t * Execute `fn` with the editor's services.\n\t * @internal\n\t */\n\tinvokeWithinContext(fn: (accessor: ServicesAccessor) => T): T;\n\n\t/**\n\t * Type the getModel() of IEditor.\n\t */\n\tgetModel(): ITextModel | null;\n\n\t/**\n\t * Sets the current model attached to this editor.\n\t * If the previous model was created by the editor via the value key in the options\n\t * literal object, it will be destroyed. Otherwise, if the previous model was set\n\t * via setModel, or the model key in the options literal object, the previous model\n\t * will not be destroyed.\n\t * It is safe to call setModel(null) to simply detach the current model from the editor.\n\t */\n\tsetModel(model: ITextModel | null): void;\n\n\t/**\n\t * Gets all the editor computed options.\n\t */\n\tgetOptions(): IComputedEditorOptions;\n\n\t/**\n\t * Gets a specific editor option.\n\t */\n\tgetOption(id: T): FindComputedEditorOptionValueById;\n\n\t/**\n\t * Returns the editor's configuration (without any validation or defaults).\n\t */\n\tgetRawOptions(): IEditorOptions;\n\n\t/**\n\t * @internal\n\t */\n\tgetOverflowWidgetsDomNode(): HTMLElement | undefined;\n\n\t/**\n\t * @internal\n\t */\n\tgetConfiguredWordAtPosition(position: Position): IWordAtPosition | null;\n\n\t/**\n\t * Get value of the current model attached to this editor.\n\t * @see {@link ITextModel.getValue}\n\t */\n\tgetValue(options?: { preserveBOM: boolean; lineEnding: string }): string;\n\n\t/**\n\t * Set the value of the current model attached to this editor.\n\t * @see {@link ITextModel.setValue}\n\t */\n\tsetValue(newValue: string): void;\n\n\t/**\n\t * Get the width of the editor's content.\n\t * This is information that is \"erased\" when computing `scrollWidth = Math.max(contentWidth, width)`\n\t */\n\tgetContentWidth(): number;\n\t/**\n\t * Get the scrollWidth of the editor's viewport.\n\t */\n\tgetScrollWidth(): number;\n\t/**\n\t * Get the scrollLeft of the editor's viewport.\n\t */\n\tgetScrollLeft(): number;\n\n\t/**\n\t * Get the height of the editor's content.\n\t * This is information that is \"erased\" when computing `scrollHeight = Math.max(contentHeight, height)`\n\t */\n\tgetContentHeight(): number;\n\t/**\n\t * Get the scrollHeight of the editor's viewport.\n\t */\n\tgetScrollHeight(): number;\n\t/**\n\t * Get the scrollTop of the editor's viewport.\n\t */\n\tgetScrollTop(): number;\n\n\t/**\n\t * Change the scrollLeft of the editor's viewport.\n\t */\n\tsetScrollLeft(newScrollLeft: number, scrollType?: editorCommon.ScrollType): void;\n\t/**\n\t * Change the scrollTop of the editor's viewport.\n\t */\n\tsetScrollTop(newScrollTop: number, scrollType?: editorCommon.ScrollType): void;\n\t/**\n\t * Change the scroll position of the editor's viewport.\n\t */\n\tsetScrollPosition(position: editorCommon.INewScrollPosition, scrollType?: editorCommon.ScrollType): void;\n\t/**\n\t * Check if the editor is currently scrolling towards a different scroll position.\n\t */\n\thasPendingScrollAnimation(): boolean;\n\n\t/**\n\t * Get an action that is a contribution to this editor.\n\t * @id Unique identifier of the contribution.\n\t * @return The action or null if action not found.\n\t */\n\tgetAction(id: string): editorCommon.IEditorAction | null;\n\n\t/**\n\t * Execute a command on the editor.\n\t * The edits will land on the undo-redo stack, but no \"undo stop\" will be pushed.\n\t * @param source The source of the call.\n\t * @param command The command to execute\n\t */\n\texecuteCommand(source: string | null | undefined, command: editorCommon.ICommand): void;\n\n\t/**\n\t * Create an \"undo stop\" in the undo-redo stack.\n\t */\n\tpushUndoStop(): boolean;\n\n\t/**\n\t * Remove the \"undo stop\" in the undo-redo stack.\n\t */\n\tpopUndoStop(): boolean;\n\n\t/**\n\t * Execute edits on the editor.\n\t * The edits will land on the undo-redo stack, but no \"undo stop\" will be pushed.\n\t * @param source The source of the call.\n\t * @param edits The edits to execute.\n\t * @param endCursorState Cursor state after the edits were applied.\n\t */\n\texecuteEdits(source: string | null | undefined, edits: IIdentifiedSingleEditOperation[], endCursorState?: ICursorStateComputer | Selection[]): boolean;\n\n\t/**\n\t * Execute multiple (concomitant) commands on the editor.\n\t * @param source The source of the call.\n\t * @param command The commands to execute\n\t */\n\texecuteCommands(source: string | null | undefined, commands: (editorCommon.ICommand | null)[]): void;\n\n\t/**\n\t * @internal\n\t */\n\t_getViewModel(): IViewModel | null;\n\n\t/**\n\t * Get all the decorations on a line (filtering out decorations from other editors).\n\t */\n\tgetLineDecorations(lineNumber: number): IModelDecoration[] | null;\n\n\t/**\n\t * Get all the decorations for a range (filtering out decorations from other editors).\n\t */\n\tgetDecorationsInRange(range: Range): IModelDecoration[] | null;\n\n\t/**\n\t * All decorations added through this call will get the ownerId of this editor.\n\t * @deprecated Use `createDecorationsCollection`\n\t * @see createDecorationsCollection\n\t */\n\tdeltaDecorations(oldDecorations: string[], newDecorations: IModelDeltaDecoration[]): string[];\n\n\t/**\n\t * Remove previously added decorations.\n\t */\n\tremoveDecorations(decorationIds: string[]): void;\n\n\t/**\n\t * @internal\n\t */\n\tremoveDecorationsByType(decorationTypeKey: string): void;\n\n\t/**\n\t * Get the layout info for the editor.\n\t */\n\tgetLayoutInfo(): EditorLayoutInfo;\n\n\t/**\n\t * Returns the ranges that are currently visible.\n\t * Does not account for horizontal scrolling.\n\t */\n\tgetVisibleRanges(): Range[];\n\n\t/**\n\t * @internal\n\t */\n\tgetVisibleRangesPlusViewportAboveBelow(): Range[];\n\n\t/**\n\t * Get the vertical position (top offset) for the line's top w.r.t. to the first line.\n\t */\n\tgetTopForLineNumber(lineNumber: number, includeViewZones?: boolean): number;\n\n\t/**\n\t * Get the vertical position (top offset) for the line's bottom w.r.t. to the first line.\n\t */\n\tgetBottomForLineNumber(lineNumber: number): number;\n\n\t/**\n\t * Get the vertical position (top offset) for the position w.r.t. to the first line.\n\t */\n\tgetTopForPosition(lineNumber: number, column: number): number;\n\n\t/**\n\t * Set the model ranges that will be hidden in the view.\n\t * Hidden areas are stored per source.\n\t * @internal\n\t */\n\tsetHiddenAreas(ranges: IRange[], source?: unknown): void;\n\n\t/**\n\t * Sets the editor aria options, primarily the active descendent.\n\t * @internal\n\t */\n\tsetAriaOptions(options: IEditorAriaOptions): void;\n\n\t/**\n\t * Write the screen reader content to be the current selection\n\t */\n\twriteScreenReaderContent(reason: string): void;\n\n\t/**\n\t * Returns the editor's container dom node\n\t */\n\tgetContainerDomNode(): HTMLElement;\n\n\t/**\n\t * Returns the editor's dom node\n\t */\n\tgetDomNode(): HTMLElement | null;\n\n\t/**\n\t * Add a content widget. Widgets must have unique ids, otherwise they will be overwritten.\n\t */\n\taddContentWidget(widget: IContentWidget): void;\n\t/**\n\t * Layout/Reposition a content widget. This is a ping to the editor to call widget.getPosition()\n\t * and update appropriately.\n\t */\n\tlayoutContentWidget(widget: IContentWidget): void;\n\t/**\n\t * Remove a content widget.\n\t */\n\tremoveContentWidget(widget: IContentWidget): void;\n\n\t/**\n\t * Add an overlay widget. Widgets must have unique ids, otherwise they will be overwritten.\n\t */\n\taddOverlayWidget(widget: IOverlayWidget): void;\n\t/**\n\t * Layout/Reposition an overlay widget. This is a ping to the editor to call widget.getPosition()\n\t * and update appropriately.\n\t */\n\tlayoutOverlayWidget(widget: IOverlayWidget): void;\n\t/**\n\t * Remove an overlay widget.\n\t */\n\tremoveOverlayWidget(widget: IOverlayWidget): void;\n\n\t/**\n\t * Add a glyph margin widget. Widgets must have unique ids, otherwise they will be overwritten.\n\t */\n\taddGlyphMarginWidget(widget: IGlyphMarginWidget): void;\n\t/**\n\t * Layout/Reposition a glyph margin widget. This is a ping to the editor to call widget.getPosition()\n\t * and update appropriately.\n\t */\n\tlayoutGlyphMarginWidget(widget: IGlyphMarginWidget): void;\n\t/**\n\t * Remove a glyph margin widget.\n\t */\n\tremoveGlyphMarginWidget(widget: IGlyphMarginWidget): void;\n\n\t/**\n\t * Change the view zones. View zones are lost when a new model is attached to the editor.\n\t */\n\tchangeViewZones(callback: (accessor: IViewZoneChangeAccessor) => void): void;\n\n\t/**\n\t * Get the horizontal position (left offset) for the column w.r.t to the beginning of the line.\n\t * This method works only if the line `lineNumber` is currently rendered (in the editor's viewport).\n\t * Use this method with caution.\n\t */\n\tgetOffsetForColumn(lineNumber: number, column: number): number;\n\n\t/**\n\t * Force an editor render now.\n\t */\n\trender(forceRedraw?: boolean): void;\n\n\t/**\n\t * Get the hit test target at coordinates `clientX` and `clientY`.\n\t * The coordinates are relative to the top-left of the viewport.\n\t *\n\t * @returns Hit test target or null if the coordinates fall outside the editor or the editor has no model.\n\t */\n\tgetTargetAtClientPoint(clientX: number, clientY: number): IMouseTarget | null;\n\n\t/**\n\t * Get the visible position for `position`.\n\t * The result position takes scrolling into account and is relative to the top left corner of the editor.\n\t * Explanation 1: the results of this method will change for the same `position` if the user scrolls the editor.\n\t * Explanation 2: the results of this method will not change if the container of the editor gets repositioned.\n\t * Warning: the results of this method are inaccurate for positions that are outside the current editor viewport.\n\t */\n\tgetScrolledVisiblePosition(position: IPosition): { top: number; left: number; height: number } | null;\n\n\t/**\n\t * Apply the same font settings as the editor to `target`.\n\t */\n\tapplyFontInfo(target: HTMLElement): void;\n\n\t/**\n\t * Check if the current instance has a model attached.\n\t * @internal\n\t */\n\thasModel(): this is IActiveCodeEditor;\n\n\tsetBanner(bannerDomNode: HTMLElement | null, height: number): void;\n\n\t/**\n\t * Is called when the model has been set, view state was restored and options are updated.\n\t * This is the best place to compute data for the viewport (such as tokens).\n\t */\n\thandleInitialized?(): void;\n}\n\n/**\n * @internal\n */\nexport interface IActiveCodeEditor extends ICodeEditor {\n\t/**\n\t * Returns the primary position of the cursor.\n\t */\n\tgetPosition(): Position;\n\n\t/**\n\t * Returns the primary selection of the editor.\n\t */\n\tgetSelection(): Selection;\n\n\t/**\n\t * Returns all the selections of the editor.\n\t */\n\tgetSelections(): Selection[];\n\n\t/**\n\t * Type the getModel() of IEditor.\n\t */\n\tgetModel(): ITextModel;\n\n\t/**\n\t * @internal\n\t */\n\t_getViewModel(): IViewModel;\n\n\t/**\n\t * Get all the decorations on a line (filtering out decorations from other editors).\n\t */\n\tgetLineDecorations(lineNumber: number): IModelDecoration[];\n\n\t/**\n\t * Returns the editor's dom node\n\t */\n\tgetDomNode(): HTMLElement;\n\n\t/**\n\t * Get the visible position for `position`.\n\t * The result position takes scrolling into account and is relative to the top left corner of the editor.\n\t * Explanation 1: the results of this method will change for the same `position` if the user scrolls the editor.\n\t * Explanation 2: the results of this method will not change if the container of the editor gets repositioned.\n\t * Warning: the results of this method are inaccurate for positions that are outside the current editor viewport.\n\t */\n\tgetScrolledVisiblePosition(position: IPosition): { top: number; left: number; height: number };\n}\n\n/**\n * A rich diff editor.\n */\nexport interface IDiffEditor extends editorCommon.IEditor {\n\n\t/**\n\t * @see {@link ICodeEditor.getContainerDomNode}\n\t */\n\tgetContainerDomNode(): HTMLElement;\n\n\t/**\n\t * An event emitted when the diff information computed by this diff editor has been updated.\n\t * @event\n\t */\n\treadonly onDidUpdateDiff: Event;\n\n\t/**\n\t * An event emitted when the diff model is changed (i.e. the diff editor shows new content).\n\t * @event\n\t */\n\treadonly onDidChangeModel: Event;\n\n\t/**\n\t * Saves current view state of the editor in a serializable object.\n\t */\n\tsaveViewState(): editorCommon.IDiffEditorViewState | null;\n\n\t/**\n\t * Restores the view state of the editor from a serializable object generated by `saveViewState`.\n\t */\n\trestoreViewState(state: editorCommon.IDiffEditorViewState | null): void;\n\n\t/**\n\t * Type the getModel() of IEditor.\n\t */\n\tgetModel(): editorCommon.IDiffEditorModel | null;\n\n\tcreateViewModel(model: editorCommon.IDiffEditorModel): editorCommon.IDiffEditorViewModel;\n\n\t/**\n\t * Sets the current model attached to this editor.\n\t * If the previous model was created by the editor via the value key in the options\n\t * literal object, it will be destroyed. Otherwise, if the previous model was set\n\t * via setModel, or the model key in the options literal object, the previous model\n\t * will not be destroyed.\n\t * It is safe to call setModel(null) to simply detach the current model from the editor.\n\t */\n\tsetModel(model: editorCommon.IDiffEditorModel | editorCommon.IDiffEditorViewModel | null): void;\n\n\t/**\n\t * Get the `original` editor.\n\t */\n\tgetOriginalEditor(): ICodeEditor;\n\n\t/**\n\t * Get the `modified` editor.\n\t */\n\tgetModifiedEditor(): ICodeEditor;\n\n\t/**\n\t * Get the computed diff information.\n\t */\n\tgetLineChanges(): ILineChange[] | null;\n\n\t/**\n\t * Update the editor's options after the editor has been created.\n\t */\n\tupdateOptions(newOptions: IDiffEditorOptions): void;\n\n\t/**\n\t * Jumps to the next or previous diff.\n\t */\n\tgoToDiff(target: 'next' | 'previous'): void;\n\n\t/**\n\t * Scrolls to the first diff.\n\t * (Waits until the diff computation finished.)\n\t */\n\trevealFirstDiff(): unknown;\n\n\taccessibleDiffViewerNext(): void;\n\n\taccessibleDiffViewerPrev(): void;\n\n\thandleInitialized(): void;\n}\n\n/**\n *@internal\n */\nexport function isCodeEditor(thing: unknown): thing is ICodeEditor {\n\tif (thing && typeof (thing).getEditorType === 'function') {\n\t\treturn (thing).getEditorType() === editorCommon.EditorType.ICodeEditor;\n\t} else {\n\t\treturn false;\n\t}\n}\n\n/**\n *@internal\n */\nexport function isDiffEditor(thing: unknown): thing is IDiffEditor {\n\tif (thing && typeof (thing).getEditorType === 'function') {\n\t\treturn (thing).getEditorType() === editorCommon.EditorType.IDiffEditor;\n\t} else {\n\t\treturn false;\n\t}\n}\n\n/**\n *@internal\n */\nexport function isCompositeEditor(thing: unknown): thing is editorCommon.ICompositeCodeEditor {\n\treturn !!thing\n\t\t&& typeof thing === 'object'\n\t\t&& typeof (thing).onDidChangeActiveEditor === 'function';\n\n}\n\n/**\n *@internal\n */\nexport function getCodeEditor(thing: unknown): ICodeEditor | null {\n\tif (isCodeEditor(thing)) {\n\t\treturn thing;\n\t}\n\n\tif (isDiffEditor(thing)) {\n\t\treturn thing.getModifiedEditor();\n\t}\n\n\tif (isCompositeEditor(thing) && isCodeEditor(thing.activeCodeEditor)) {\n\t\treturn thing.activeCodeEditor;\n\t}\n\n\treturn null;\n}\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\nimport { BrandedService, IConstructorSignature } from 'vs/platform/instantiation/common/instantiation';\n\n/**\n * A feature that will be loaded when the first code editor is constructed and disposed when the system shuts down.\n */\nexport interface IEditorFeature {\n\t// Marker Interface\n}\n\nexport type EditorFeatureCtor = IConstructorSignature;\n\nconst editorFeatures: EditorFeatureCtor[] = [];\n\n/**\n * Registers an editor feature. Editor features will be instantiated only once, as soon as\n * the first code editor is instantiated.\n */\nexport function registerEditorFeature(ctor: { new(...services: Services): IEditorFeature }): void {\n\teditorFeatures.push(ctor as EditorFeatureCtor);\n}\n\nexport function getEditorFeatures(): Iterable {\n\treturn editorFeatures.slice(0);\n}\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\nimport { IColorTheme } from 'vs/platform/theme/common/themeService';\nimport { ColorIdentifier } from 'vs/platform/theme/common/colorRegistry';\nimport { Color } from 'vs/base/common/color';\nimport { ColorScheme } from 'vs/platform/theme/common/theme';\n\nexport class EditorTheme {\n\n\tprivate _theme: IColorTheme;\n\n\tpublic get type(): ColorScheme {\n\t\treturn this._theme.type;\n\t}\n\n\tpublic get value(): IColorTheme {\n\t\treturn this._theme;\n\t}\n\n\tconstructor(theme: IColorTheme) {\n\t\tthis._theme = theme;\n\t}\n\n\tpublic update(theme: IColorTheme): void {\n\t\tthis._theme = theme;\n\t}\n\n\tpublic getColor(color: ColorIdentifier): Color | undefined {\n\t\treturn this._theme.getColor(color);\n\t}\n}\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 * Open ended enum at runtime\n */\nexport const enum LanguageId {\n\tNull = 0,\n\tPlainText = 1\n}\n\n/**\n * A font style. Values are 2^x such that a bit mask can be used.\n */\nexport const enum FontStyle {\n\tNotSet = -1,\n\tNone = 0,\n\tItalic = 1,\n\tBold = 2,\n\tUnderline = 4,\n\tStrikethrough = 8,\n}\n\n/**\n * Open ended enum at runtime\n */\nexport const enum ColorId {\n\tNone = 0,\n\tDefaultForeground = 1,\n\tDefaultBackground = 2\n}\n\n/**\n * A standard token type.\n */\nexport const enum StandardTokenType {\n\tOther = 0,\n\tComment = 1,\n\tString = 2,\n\tRegEx = 3\n}\n\n/**\n * Helpers to manage the \"collapsed\" metadata of an entire StackElement stack.\n * The following assumptions have been made:\n * - languageId < 256 => needs 8 bits\n * - unique color count < 512 => needs 9 bits\n *\n * The binary format is:\n * - -------------------------------------------\n * 3322 2222 2222 1111 1111 1100 0000 0000\n * 1098 7654 3210 9876 5432 1098 7654 3210\n * - -------------------------------------------\n * xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx\n * bbbb bbbb ffff ffff fFFF FBTT LLLL LLLL\n * - -------------------------------------------\n * - L = LanguageId (8 bits)\n * - T = StandardTokenType (2 bits)\n * - B = Balanced bracket (1 bit)\n * - F = FontStyle (4 bits)\n * - f = foreground color (9 bits)\n * - b = background color (9 bits)\n *\n */\nexport const enum MetadataConsts {\n\tLANGUAGEID_MASK = 0b00000000000000000000000011111111,\n\tTOKEN_TYPE_MASK = 0b00000000000000000000001100000000,\n\tBALANCED_BRACKETS_MASK = 0b00000000000000000000010000000000,\n\tFONT_STYLE_MASK = 0b00000000000000000111100000000000,\n\tFOREGROUND_MASK = 0b00000000111111111000000000000000,\n\tBACKGROUND_MASK = 0b11111111000000000000000000000000,\n\n\tITALIC_MASK = 0b00000000000000000000100000000000,\n\tBOLD_MASK = 0b00000000000000000001000000000000,\n\tUNDERLINE_MASK = 0b00000000000000000010000000000000,\n\tSTRIKETHROUGH_MASK = 0b00000000000000000100000000000000,\n\n\t// Semantic tokens cannot set the language id, so we can\n\t// use the first 8 bits for control purposes\n\tSEMANTIC_USE_ITALIC = 0b00000000000000000000000000000001,\n\tSEMANTIC_USE_BOLD = 0b00000000000000000000000000000010,\n\tSEMANTIC_USE_UNDERLINE = 0b00000000000000000000000000000100,\n\tSEMANTIC_USE_STRIKETHROUGH = 0b00000000000000000000000000001000,\n\tSEMANTIC_USE_FOREGROUND = 0b00000000000000000000000000010000,\n\tSEMANTIC_USE_BACKGROUND = 0b00000000000000000000000000100000,\n\n\tLANGUAGEID_OFFSET = 0,\n\tTOKEN_TYPE_OFFSET = 8,\n\tBALANCED_BRACKETS_OFFSET = 10,\n\tFONT_STYLE_OFFSET = 11,\n\tFOREGROUND_OFFSET = 15,\n\tBACKGROUND_OFFSET = 24\n}\n\n/**\n */\nexport class TokenMetadata {\n\n\tpublic static getLanguageId(metadata: number): LanguageId {\n\t\treturn (metadata & MetadataConsts.LANGUAGEID_MASK) >>> MetadataConsts.LANGUAGEID_OFFSET;\n\t}\n\n\tpublic static getTokenType(metadata: number): StandardTokenType {\n\t\treturn (metadata & MetadataConsts.TOKEN_TYPE_MASK) >>> MetadataConsts.TOKEN_TYPE_OFFSET;\n\t}\n\n\tpublic static containsBalancedBrackets(metadata: number): boolean {\n\t\treturn (metadata & MetadataConsts.BALANCED_BRACKETS_MASK) !== 0;\n\t}\n\n\tpublic static getFontStyle(metadata: number): FontStyle {\n\t\treturn (metadata & MetadataConsts.FONT_STYLE_MASK) >>> MetadataConsts.FONT_STYLE_OFFSET;\n\t}\n\n\tpublic static getForeground(metadata: number): ColorId {\n\t\treturn (metadata & MetadataConsts.FOREGROUND_MASK) >>> MetadataConsts.FOREGROUND_OFFSET;\n\t}\n\n\tpublic static getBackground(metadata: number): ColorId {\n\t\treturn (metadata & MetadataConsts.BACKGROUND_MASK) >>> MetadataConsts.BACKGROUND_OFFSET;\n\t}\n\n\tpublic static getClassNameFromMetadata(metadata: number): string {\n\t\tconst foreground = this.getForeground(metadata);\n\t\tlet className = 'mtk' + foreground;\n\n\t\tconst fontStyle = this.getFontStyle(metadata);\n\t\tif (fontStyle & FontStyle.Italic) {\n\t\t\tclassName += ' mtki';\n\t\t}\n\t\tif (fontStyle & FontStyle.Bold) {\n\t\t\tclassName += ' mtkb';\n\t\t}\n\t\tif (fontStyle & FontStyle.Underline) {\n\t\t\tclassName += ' mtku';\n\t\t}\n\t\tif (fontStyle & FontStyle.Strikethrough) {\n\t\t\tclassName += ' mtks';\n\t\t}\n\n\t\treturn className;\n\t}\n\n\tpublic static getInlineStyleFromMetadata(metadata: number, colorMap: string[]): string {\n\t\tconst foreground = this.getForeground(metadata);\n\t\tconst fontStyle = this.getFontStyle(metadata);\n\n\t\tlet result = `color: ${colorMap[foreground]};`;\n\t\tif (fontStyle & FontStyle.Italic) {\n\t\t\tresult += 'font-style: italic;';\n\t\t}\n\t\tif (fontStyle & FontStyle.Bold) {\n\t\t\tresult += 'font-weight: bold;';\n\t\t}\n\t\tlet textDecoration = '';\n\t\tif (fontStyle & FontStyle.Underline) {\n\t\t\ttextDecoration += ' underline';\n\t\t}\n\t\tif (fontStyle & FontStyle.Strikethrough) {\n\t\t\ttextDecoration += ' line-through';\n\t\t}\n\t\tif (textDecoration) {\n\t\t\tresult += `text-decoration:${textDecoration};`;\n\n\t\t}\n\t\treturn result;\n\t}\n\n\tpublic static getPresentationFromMetadata(metadata: number): ITokenPresentation {\n\t\tconst foreground = this.getForeground(metadata);\n\t\tconst fontStyle = this.getFontStyle(metadata);\n\n\t\treturn {\n\t\t\tforeground: foreground,\n\t\t\titalic: Boolean(fontStyle & FontStyle.Italic),\n\t\t\tbold: Boolean(fontStyle & FontStyle.Bold),\n\t\t\tunderline: Boolean(fontStyle & FontStyle.Underline),\n\t\t\tstrikethrough: Boolean(fontStyle & FontStyle.Strikethrough),\n\t\t};\n\t}\n}\n\n/**\n */\nexport interface ITokenPresentation {\n\tforeground: ColorId;\n\titalic: boolean;\n\tbold: boolean;\n\tunderline: boolean;\n\tstrikethrough: boolean;\n}\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 *--------------------------------------------------------------------------------------------*/\nimport { Color, HSLA } from 'vs/base/common/color';\nimport { IPosition } from 'vs/editor/common/core/position';\nimport { IRange } from 'vs/editor/common/core/range';\nimport { IColor, IColorInformation } from 'vs/editor/common/languages';\n\nexport interface IDocumentColorComputerTarget {\n\tgetValue(): string;\n\tpositionAt(offset: number): IPosition;\n\tfindMatches(regex: RegExp): RegExpMatchArray[];\n}\n\nfunction _parseCaptureGroups(captureGroups: IterableIterator) {\n\tconst values = [];\n\tfor (const captureGroup of captureGroups) {\n\t\tconst parsedNumber = Number(captureGroup);\n\t\tif (parsedNumber || parsedNumber === 0 && captureGroup.replace(/\\s/g, '') !== '') {\n\t\t\tvalues.push(parsedNumber);\n\t\t}\n\t}\n\treturn values;\n}\n\nfunction _toIColor(r: number, g: number, b: number, a: number): IColor {\n\treturn {\n\t\tred: r / 255,\n\t\tblue: b / 255,\n\t\tgreen: g / 255,\n\t\talpha: a\n\t};\n}\n\nfunction _findRange(model: IDocumentColorComputerTarget, match: RegExpMatchArray): IRange | undefined {\n\tconst index = match.index;\n\tconst length = match[0].length;\n\tif (!index) {\n\t\treturn;\n\t}\n\tconst startPosition = model.positionAt(index);\n\tconst range: IRange = {\n\t\tstartLineNumber: startPosition.lineNumber,\n\t\tstartColumn: startPosition.column,\n\t\tendLineNumber: startPosition.lineNumber,\n\t\tendColumn: startPosition.column + length\n\t};\n\treturn range;\n}\n\nfunction _findHexColorInformation(range: IRange | undefined, hexValue: string) {\n\tif (!range) {\n\t\treturn;\n\t}\n\tconst parsedHexColor = Color.Format.CSS.parseHex(hexValue);\n\tif (!parsedHexColor) {\n\t\treturn;\n\t}\n\treturn {\n\t\trange: range,\n\t\tcolor: _toIColor(parsedHexColor.rgba.r, parsedHexColor.rgba.g, parsedHexColor.rgba.b, parsedHexColor.rgba.a)\n\t};\n}\n\nfunction _findRGBColorInformation(range: IRange | undefined, matches: RegExpMatchArray[], isAlpha: boolean) {\n\tif (!range || matches.length !== 1) {\n\t\treturn;\n\t}\n\tconst match = matches[0]!;\n\tconst captureGroups = match.values();\n\tconst parsedRegex = _parseCaptureGroups(captureGroups);\n\treturn {\n\t\trange: range,\n\t\tcolor: _toIColor(parsedRegex[0], parsedRegex[1], parsedRegex[2], isAlpha ? parsedRegex[3] : 1)\n\t};\n}\n\nfunction _findHSLColorInformation(range: IRange | undefined, matches: RegExpMatchArray[], isAlpha: boolean) {\n\tif (!range || matches.length !== 1) {\n\t\treturn;\n\t}\n\tconst match = matches[0]!;\n\tconst captureGroups = match.values();\n\tconst parsedRegex = _parseCaptureGroups(captureGroups);\n\tconst colorEquivalent = new Color(new HSLA(parsedRegex[0], parsedRegex[1] / 100, parsedRegex[2] / 100, isAlpha ? parsedRegex[3] : 1));\n\treturn {\n\t\trange: range,\n\t\tcolor: _toIColor(colorEquivalent.rgba.r, colorEquivalent.rgba.g, colorEquivalent.rgba.b, colorEquivalent.rgba.a)\n\t};\n}\n\nfunction _findMatches(model: IDocumentColorComputerTarget | string, regex: RegExp): RegExpMatchArray[] {\n\tif (typeof model === 'string') {\n\t\treturn [...model.matchAll(regex)];\n\t} else {\n\t\treturn model.findMatches(regex);\n\t}\n}\n\nfunction computeColors(model: IDocumentColorComputerTarget): IColorInformation[] {\n\tconst result: IColorInformation[] = [];\n\t// Early validation for RGB and HSL\n\tconst initialValidationRegex = /\\b(rgb|rgba|hsl|hsla)(\\([0-9\\s,.\\%]*\\))|(#)([A-Fa-f0-9]{3})\\b|(#)([A-Fa-f0-9]{4})\\b|(#)([A-Fa-f0-9]{6})\\b|(#)([A-Fa-f0-9]{8})\\b/gm;\n\tconst initialValidationMatches = _findMatches(model, initialValidationRegex);\n\n\t// Potential colors have been found, validate the parameters\n\tif (initialValidationMatches.length > 0) {\n\t\tfor (const initialMatch of initialValidationMatches) {\n\t\t\tconst initialCaptureGroups = initialMatch.filter(captureGroup => captureGroup !== undefined);\n\t\t\tconst colorScheme = initialCaptureGroups[1];\n\t\t\tconst colorParameters = initialCaptureGroups[2];\n\t\t\tif (!colorParameters) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tlet colorInformation;\n\t\t\tif (colorScheme === 'rgb') {\n\t\t\t\tconst regexParameters = /^\\(\\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\\s*,\\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\\s*,\\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\\s*\\)$/gm;\n\t\t\t\tcolorInformation = _findRGBColorInformation(_findRange(model, initialMatch), _findMatches(colorParameters, regexParameters), false);\n\t\t\t} else if (colorScheme === 'rgba') {\n\t\t\t\tconst regexParameters = /^\\(\\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\\s*,\\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\\s*,\\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\\s*,\\s*(0[.][0-9]+|[.][0-9]+|[01][.]|[01])\\s*\\)$/gm;\n\t\t\t\tcolorInformation = _findRGBColorInformation(_findRange(model, initialMatch), _findMatches(colorParameters, regexParameters), true);\n\t\t\t} else if (colorScheme === 'hsl') {\n\t\t\t\tconst regexParameters = /^\\(\\s*(36[0]|3[0-5][0-9]|[12][0-9][0-9]|[1-9]?[0-9])\\s*,\\s*(100|\\d{1,2}[.]\\d*|\\d{1,2})%\\s*,\\s*(100|\\d{1,2}[.]\\d*|\\d{1,2})%\\s*\\)$/gm;\n\t\t\t\tcolorInformation = _findHSLColorInformation(_findRange(model, initialMatch), _findMatches(colorParameters, regexParameters), false);\n\t\t\t} else if (colorScheme === 'hsla') {\n\t\t\t\tconst regexParameters = /^\\(\\s*(36[0]|3[0-5][0-9]|[12][0-9][0-9]|[1-9]?[0-9])\\s*,\\s*(100|\\d{1,2}[.]\\d*|\\d{1,2})%\\s*,\\s*(100|\\d{1,2}[.]\\d*|\\d{1,2})%\\s*,\\s*(0[.][0-9]+|[.][0-9]+|[01][.]|[01])\\s*\\)$/gm;\n\t\t\t\tcolorInformation = _findHSLColorInformation(_findRange(model, initialMatch), _findMatches(colorParameters, regexParameters), true);\n\t\t\t} else if (colorScheme === '#') {\n\t\t\t\tcolorInformation = _findHexColorInformation(_findRange(model, initialMatch), colorScheme + colorParameters);\n\t\t\t}\n\t\t\tif (colorInformation) {\n\t\t\t\tresult.push(colorInformation);\n\t\t\t}\n\t\t}\n\t}\n\treturn result;\n}\n\n/**\n * Returns an array of all default document colors in the provided document\n */\nexport function computeDefaultDocumentColors(model: IDocumentColorComputerTarget): IColorInformation[] {\n\tif (!model || typeof model.getValue !== 'function' || typeof model.positionAt !== 'function') {\n\t\t// Unknown caller!\n\t\treturn [];\n\t}\n\treturn computeColors(model);\n}\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\nimport { CharCode } from 'vs/base/common/charCode';\nimport { StandardTokenType } from 'vs/editor/common/encodedTokenAttributes';\nimport { ScopedLineTokens } from 'vs/editor/common/languages/supports';\n\n/**\n * Describes how comments for a language work.\n */\nexport interface CommentRule {\n\t/**\n\t * The line comment token, like `// this is a comment`\n\t */\n\tlineComment?: string | null;\n\t/**\n\t * The block comment character pair, like `/* block comment */`\n\t */\n\tblockComment?: CharacterPair | null;\n}\n\n/**\n * The language configuration interface defines the contract between extensions and\n * various editor features, like automatic bracket insertion, automatic indentation etc.\n */\nexport interface LanguageConfiguration {\n\t/**\n\t * The language's comment settings.\n\t */\n\tcomments?: CommentRule;\n\t/**\n\t * The language's brackets.\n\t * This configuration implicitly affects pressing Enter around these brackets.\n\t */\n\tbrackets?: CharacterPair[];\n\t/**\n\t * The language's word definition.\n\t * If the language supports Unicode identifiers (e.g. JavaScript), it is preferable\n\t * to provide a word definition that uses exclusion of known separators.\n\t * e.g.: A regex that matches anything except known separators (and dot is allowed to occur in a floating point number):\n\t * /(-?\\d*\\.\\d\\w*)|([^\\`\\~\\!\\@\\#\\%\\^\\&\\*\\(\\)\\-\\=\\+\\[\\{\\]\\}\\\\\\|\\;\\:\\'\\\"\\,\\.\\<\\>\\/\\?\\s]+)/g\n\t */\n\twordPattern?: RegExp;\n\t/**\n\t * The language's indentation settings.\n\t */\n\tindentationRules?: IndentationRule;\n\t/**\n\t * The language's rules to be evaluated when pressing Enter.\n\t */\n\tonEnterRules?: OnEnterRule[];\n\t/**\n\t * The language's auto closing pairs. The 'close' character is automatically inserted with the\n\t * 'open' character is typed. If not set, the configured brackets will be used.\n\t */\n\tautoClosingPairs?: IAutoClosingPairConditional[];\n\t/**\n\t * The language's surrounding pairs. When the 'open' character is typed on a selection, the\n\t * selected string is surrounded by the open and close characters. If not set, the autoclosing pairs\n\t * settings will be used.\n\t */\n\tsurroundingPairs?: IAutoClosingPair[];\n\t/**\n\t * Defines a list of bracket pairs that are colorized depending on their nesting level.\n\t * If not set, the configured brackets will be used.\n\t*/\n\tcolorizedBracketPairs?: CharacterPair[];\n\t/**\n\t * Defines what characters must be after the cursor for bracket or quote autoclosing to occur when using the \\'languageDefined\\' autoclosing setting.\n\t *\n\t * This is typically the set of characters which can not start an expression, such as whitespace, closing brackets, non-unary operators, etc.\n\t */\n\tautoCloseBefore?: string;\n\n\t/**\n\t * The language's folding rules.\n\t */\n\tfolding?: FoldingRules;\n\n\t/**\n\t * **Deprecated** Do not use.\n\t *\n\t * @deprecated Will be replaced by a better API soon.\n\t */\n\t__electricCharacterSupport?: {\n\t\tdocComment?: IDocComment;\n\t};\n}\n\n/**\n * @internal\n */\ntype OrUndefined = { [P in keyof T]: T[P] | undefined };\n\n/**\n * @internal\n */\nexport type ExplicitLanguageConfiguration = OrUndefined>;\n\n/**\n * Describes indentation rules for a language.\n */\nexport interface IndentationRule {\n\t/**\n\t * If a line matches this pattern, then all the lines after it should be unindented once (until another rule matches).\n\t */\n\tdecreaseIndentPattern: RegExp;\n\t/**\n\t * If a line matches this pattern, then all the lines after it should be indented once (until another rule matches).\n\t */\n\tincreaseIndentPattern: RegExp;\n\t/**\n\t * If a line matches this pattern, then **only the next line** after it should be indented once.\n\t */\n\tindentNextLinePattern?: RegExp | null;\n\t/**\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.\n\t */\n\tunIndentedLinePattern?: RegExp | null;\n\n}\n\n/**\n * Describes language specific folding markers such as '#region' and '#endregion'.\n * The start and end regexes will be tested against the contents of all lines and must be designed efficiently:\n * - the regex should start with '^'\n * - regexp flags (i, g) are ignored\n */\nexport interface FoldingMarkers {\n\tstart: RegExp;\n\tend: RegExp;\n}\n\n/**\n * Describes folding rules for a language.\n */\nexport interface FoldingRules {\n\t/**\n\t * Used by the indentation based strategy to decide whether empty lines belong to the previous or the next block.\n\t * A language adheres to the off-side rule if blocks in that language are expressed by their indentation.\n\t * See [wikipedia](https://en.wikipedia.org/wiki/Off-side_rule) for more information.\n\t * If not set, `false` is used and empty lines belong to the previous block.\n\t */\n\toffSide?: boolean;\n\n\t/**\n\t * Region markers used by the language.\n\t */\n\tmarkers?: FoldingMarkers;\n}\n\n/**\n * Describes a rule to be evaluated when pressing Enter.\n */\nexport interface OnEnterRule {\n\t/**\n\t * This rule will only execute if the text before the cursor matches this regular expression.\n\t */\n\tbeforeText: RegExp;\n\t/**\n\t * This rule will only execute if the text after the cursor matches this regular expression.\n\t */\n\tafterText?: RegExp;\n\t/**\n\t * This rule will only execute if the text above the this line matches this regular expression.\n\t */\n\tpreviousLineText?: RegExp;\n\t/**\n\t * The action to execute.\n\t */\n\taction: EnterAction;\n}\n\n/**\n * Definition of documentation comments (e.g. Javadoc/JSdoc)\n */\nexport interface IDocComment {\n\t/**\n\t * The string that starts a doc comment (e.g. '/**')\n\t */\n\topen: string;\n\t/**\n\t * The string that appears on the last line and closes the doc comment (e.g. ' * /').\n\t */\n\tclose?: string;\n}\n\n/**\n * A tuple of two characters, like a pair of\n * opening and closing brackets.\n */\nexport type CharacterPair = [string, string];\n\nexport interface IAutoClosingPair {\n\topen: string;\n\tclose: string;\n}\n\nexport interface IAutoClosingPairConditional extends IAutoClosingPair {\n\tnotIn?: string[];\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 * Describes what to do when pressing Enter.\n */\nexport interface EnterAction {\n\t/**\n\t * Describe what to do with the indentation.\n\t */\n\tindentAction: IndentAction;\n\t/**\n\t * Describes text to be appended after the new line and after the indentation.\n\t */\n\tappendText?: string;\n\t/**\n\t * Describes the number of characters to remove from the new line's indentation.\n\t */\n\tremoveText?: number;\n}\n\n/**\n * @internal\n */\nexport interface CompleteEnterAction {\n\t/**\n\t * Describe what to do with the indentation.\n\t */\n\tindentAction: IndentAction;\n\t/**\n\t * Describes text to be appended after the new line and after the indentation.\n\t */\n\tappendText: string;\n\t/**\n\t * Describes the number of characters to remove from the new line's indentation.\n\t */\n\tremoveText: number;\n\t/**\n\t * The line's indentation minus removeText\n\t */\n\tindentation: string;\n}\n\n/**\n * @internal\n */\nexport class StandardAutoClosingPairConditional {\n\n\treadonly open: string;\n\treadonly close: string;\n\tprivate readonly _inString: boolean;\n\tprivate readonly _inComment: boolean;\n\tprivate readonly _inRegEx: boolean;\n\tprivate _neutralCharacter: string | null = null;\n\tprivate _neutralCharacterSearched: boolean = false;\n\n\tconstructor(source: IAutoClosingPairConditional) {\n\t\tthis.open = source.open;\n\t\tthis.close = source.close;\n\n\t\t// initially allowed in all tokens\n\t\tthis._inString = true;\n\t\tthis._inComment = true;\n\t\tthis._inRegEx = true;\n\n\t\tif (Array.isArray(source.notIn)) {\n\t\t\tfor (let i = 0, len = source.notIn.length; i < len; i++) {\n\t\t\t\tconst notIn: string = source.notIn[i];\n\t\t\t\tswitch (notIn) {\n\t\t\t\t\tcase 'string':\n\t\t\t\t\t\tthis._inString = false;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'comment':\n\t\t\t\t\t\tthis._inComment = false;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'regex':\n\t\t\t\t\t\tthis._inRegEx = false;\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic isOK(standardToken: StandardTokenType): boolean {\n\t\tswitch (standardToken) {\n\t\t\tcase StandardTokenType.Other:\n\t\t\t\treturn true;\n\t\t\tcase StandardTokenType.Comment:\n\t\t\t\treturn this._inComment;\n\t\t\tcase StandardTokenType.String:\n\t\t\t\treturn this._inString;\n\t\t\tcase StandardTokenType.RegEx:\n\t\t\t\treturn this._inRegEx;\n\t\t}\n\t}\n\n\tpublic shouldAutoClose(context: ScopedLineTokens, column: number): boolean {\n\t\t// Always complete on empty line\n\t\tif (context.getTokenCount() === 0) {\n\t\t\treturn true;\n\t\t}\n\n\t\tconst tokenIndex = context.findTokenIndexAtOffset(column - 2);\n\t\tconst standardTokenType = context.getStandardTokenType(tokenIndex);\n\t\treturn this.isOK(standardTokenType);\n\t}\n\n\tprivate _findNeutralCharacterInRange(fromCharCode: number, toCharCode: number): string | null {\n\t\tfor (let charCode = fromCharCode; charCode <= toCharCode; charCode++) {\n\t\t\tconst character = String.fromCharCode(charCode);\n\t\t\tif (!this.open.includes(character) && !this.close.includes(character)) {\n\t\t\t\treturn character;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * Find a character in the range [0-9a-zA-Z] that does not appear in the open or close\n\t */\n\tpublic findNeutralCharacter(): string | null {\n\t\tif (!this._neutralCharacterSearched) {\n\t\t\tthis._neutralCharacterSearched = true;\n\t\t\tif (!this._neutralCharacter) {\n\t\t\t\tthis._neutralCharacter = this._findNeutralCharacterInRange(CharCode.Digit0, CharCode.Digit9);\n\t\t\t}\n\t\t\tif (!this._neutralCharacter) {\n\t\t\t\tthis._neutralCharacter = this._findNeutralCharacterInRange(CharCode.a, CharCode.z);\n\t\t\t}\n\t\t\tif (!this._neutralCharacter) {\n\t\t\t\tthis._neutralCharacter = this._findNeutralCharacterInRange(CharCode.A, CharCode.Z);\n\t\t\t}\n\t\t}\n\t\treturn this._neutralCharacter;\n\t}\n}\n\n/**\n * @internal\n */\nexport class AutoClosingPairs {\n\t// it is useful to be able to get pairs using either end of open and close\n\n\t/** Key is first character of open */\n\tpublic readonly autoClosingPairsOpenByStart: Map;\n\t/** Key is last character of open */\n\tpublic readonly autoClosingPairsOpenByEnd: Map;\n\t/** Key is first character of close */\n\tpublic readonly autoClosingPairsCloseByStart: Map;\n\t/** Key is last character of close */\n\tpublic readonly autoClosingPairsCloseByEnd: Map;\n\t/** Key is close. Only has pairs that are a single character */\n\tpublic readonly autoClosingPairsCloseSingleChar: Map;\n\n\tconstructor(autoClosingPairs: StandardAutoClosingPairConditional[]) {\n\t\tthis.autoClosingPairsOpenByStart = new Map();\n\t\tthis.autoClosingPairsOpenByEnd = new Map();\n\t\tthis.autoClosingPairsCloseByStart = new Map();\n\t\tthis.autoClosingPairsCloseByEnd = new Map();\n\t\tthis.autoClosingPairsCloseSingleChar = new Map();\n\t\tfor (const pair of autoClosingPairs) {\n\t\t\tappendEntry(this.autoClosingPairsOpenByStart, pair.open.charAt(0), pair);\n\t\t\tappendEntry(this.autoClosingPairsOpenByEnd, pair.open.charAt(pair.open.length - 1), pair);\n\t\t\tappendEntry(this.autoClosingPairsCloseByStart, pair.close.charAt(0), pair);\n\t\t\tappendEntry(this.autoClosingPairsCloseByEnd, pair.close.charAt(pair.close.length - 1), pair);\n\t\t\tif (pair.close.length === 1 && pair.open.length === 1) {\n\t\t\t\tappendEntry(this.autoClosingPairsCloseSingleChar, pair.close, pair);\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction appendEntry(target: Map, key: K, value: V): void {\n\tif (target.has(key)) {\n\t\ttarget.get(key)!.push(value);\n\t} else {\n\t\ttarget.set(key, [value]);\n\t}\n}\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\nimport { CharCode } from 'vs/base/common/charCode';\nimport { CharacterClassifier } from 'vs/editor/common/core/characterClassifier';\nimport { ILink } from 'vs/editor/common/languages';\n\nexport interface ILinkComputerTarget {\n\tgetLineCount(): number;\n\tgetLineContent(lineNumber: number): string;\n}\n\nexport const enum State {\n\tInvalid = 0,\n\tStart = 1,\n\tH = 2,\n\tHT = 3,\n\tHTT = 4,\n\tHTTP = 5,\n\tF = 6,\n\tFI = 7,\n\tFIL = 8,\n\tBeforeColon = 9,\n\tAfterColon = 10,\n\tAlmostThere = 11,\n\tEnd = 12,\n\tAccept = 13,\n\tLastKnownState = 14 // marker, custom states may follow\n}\n\nexport type Edge = [State, number, State];\n\nclass Uint8Matrix {\n\n\tprivate readonly _data: Uint8Array;\n\tpublic readonly rows: number;\n\tpublic readonly cols: number;\n\n\tconstructor(rows: number, cols: number, defaultValue: number) {\n\t\tconst data = new Uint8Array(rows * cols);\n\t\tfor (let i = 0, len = rows * cols; i < len; i++) {\n\t\t\tdata[i] = defaultValue;\n\t\t}\n\n\t\tthis._data = data;\n\t\tthis.rows = rows;\n\t\tthis.cols = cols;\n\t}\n\n\tpublic get(row: number, col: number): number {\n\t\treturn this._data[row * this.cols + col];\n\t}\n\n\tpublic set(row: number, col: number, value: number): void {\n\t\tthis._data[row * this.cols + col] = value;\n\t}\n}\n\nexport class StateMachine {\n\n\tprivate readonly _states: Uint8Matrix;\n\tprivate readonly _maxCharCode: number;\n\n\tconstructor(edges: Edge[]) {\n\t\tlet maxCharCode = 0;\n\t\tlet maxState = State.Invalid;\n\t\tfor (let i = 0, len = edges.length; i < len; i++) {\n\t\t\tconst [from, chCode, to] = edges[i];\n\t\t\tif (chCode > maxCharCode) {\n\t\t\t\tmaxCharCode = chCode;\n\t\t\t}\n\t\t\tif (from > maxState) {\n\t\t\t\tmaxState = from;\n\t\t\t}\n\t\t\tif (to > maxState) {\n\t\t\t\tmaxState = to;\n\t\t\t}\n\t\t}\n\n\t\tmaxCharCode++;\n\t\tmaxState++;\n\n\t\tconst states = new Uint8Matrix(maxState, maxCharCode, State.Invalid);\n\t\tfor (let i = 0, len = edges.length; i < len; i++) {\n\t\t\tconst [from, chCode, to] = edges[i];\n\t\t\tstates.set(from, chCode, to);\n\t\t}\n\n\t\tthis._states = states;\n\t\tthis._maxCharCode = maxCharCode;\n\t}\n\n\tpublic nextState(currentState: State, chCode: number): State {\n\t\tif (chCode < 0 || chCode >= this._maxCharCode) {\n\t\t\treturn State.Invalid;\n\t\t}\n\t\treturn this._states.get(currentState, chCode);\n\t}\n}\n\n// State machine for http:// or https:// or file://\nlet _stateMachine: StateMachine | null = null;\nfunction getStateMachine(): StateMachine {\n\tif (_stateMachine === null) {\n\t\t_stateMachine = new StateMachine([\n\t\t\t[State.Start, CharCode.h, State.H],\n\t\t\t[State.Start, CharCode.H, State.H],\n\t\t\t[State.Start, CharCode.f, State.F],\n\t\t\t[State.Start, CharCode.F, State.F],\n\n\t\t\t[State.H, CharCode.t, State.HT],\n\t\t\t[State.H, CharCode.T, State.HT],\n\n\t\t\t[State.HT, CharCode.t, State.HTT],\n\t\t\t[State.HT, CharCode.T, State.HTT],\n\n\t\t\t[State.HTT, CharCode.p, State.HTTP],\n\t\t\t[State.HTT, CharCode.P, State.HTTP],\n\n\t\t\t[State.HTTP, CharCode.s, State.BeforeColon],\n\t\t\t[State.HTTP, CharCode.S, State.BeforeColon],\n\t\t\t[State.HTTP, CharCode.Colon, State.AfterColon],\n\n\t\t\t[State.F, CharCode.i, State.FI],\n\t\t\t[State.F, CharCode.I, State.FI],\n\n\t\t\t[State.FI, CharCode.l, State.FIL],\n\t\t\t[State.FI, CharCode.L, State.FIL],\n\n\t\t\t[State.FIL, CharCode.e, State.BeforeColon],\n\t\t\t[State.FIL, CharCode.E, State.BeforeColon],\n\n\t\t\t[State.BeforeColon, CharCode.Colon, State.AfterColon],\n\n\t\t\t[State.AfterColon, CharCode.Slash, State.AlmostThere],\n\n\t\t\t[State.AlmostThere, CharCode.Slash, State.End],\n\t\t]);\n\t}\n\treturn _stateMachine;\n}\n\n\nconst enum CharacterClass {\n\tNone = 0,\n\tForceTermination = 1,\n\tCannotEndIn = 2\n}\n\nlet _classifier: CharacterClassifier | null = null;\nfunction getClassifier(): CharacterClassifier {\n\tif (_classifier === null) {\n\t\t_classifier = new CharacterClassifier(CharacterClass.None);\n\n\t\t// allow-any-unicode-next-line\n\t\tconst FORCE_TERMINATION_CHARACTERS = ' \\t<>\\'\\\"、。。、,.:;‘〈「『〔([{「」}])〕』」〉’`~…';\n\t\tfor (let i = 0; i < FORCE_TERMINATION_CHARACTERS.length; i++) {\n\t\t\t_classifier.set(FORCE_TERMINATION_CHARACTERS.charCodeAt(i), CharacterClass.ForceTermination);\n\t\t}\n\n\t\tconst CANNOT_END_WITH_CHARACTERS = '.,;:';\n\t\tfor (let i = 0; i < CANNOT_END_WITH_CHARACTERS.length; i++) {\n\t\t\t_classifier.set(CANNOT_END_WITH_CHARACTERS.charCodeAt(i), CharacterClass.CannotEndIn);\n\t\t}\n\t}\n\treturn _classifier;\n}\n\nexport class LinkComputer {\n\n\tprivate static _createLink(classifier: CharacterClassifier, line: string, lineNumber: number, linkBeginIndex: number, linkEndIndex: number): ILink {\n\t\t// Do not allow to end link in certain characters...\n\t\tlet lastIncludedCharIndex = linkEndIndex - 1;\n\t\tdo {\n\t\t\tconst chCode = line.charCodeAt(lastIncludedCharIndex);\n\t\t\tconst chClass = classifier.get(chCode);\n\t\t\tif (chClass !== CharacterClass.CannotEndIn) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tlastIncludedCharIndex--;\n\t\t} while (lastIncludedCharIndex > linkBeginIndex);\n\n\t\t// Handle links enclosed in parens, square brackets and curlys.\n\t\tif (linkBeginIndex > 0) {\n\t\t\tconst charCodeBeforeLink = line.charCodeAt(linkBeginIndex - 1);\n\t\t\tconst lastCharCodeInLink = line.charCodeAt(lastIncludedCharIndex);\n\n\t\t\tif (\n\t\t\t\t(charCodeBeforeLink === CharCode.OpenParen && lastCharCodeInLink === CharCode.CloseParen)\n\t\t\t\t|| (charCodeBeforeLink === CharCode.OpenSquareBracket && lastCharCodeInLink === CharCode.CloseSquareBracket)\n\t\t\t\t|| (charCodeBeforeLink === CharCode.OpenCurlyBrace && lastCharCodeInLink === CharCode.CloseCurlyBrace)\n\t\t\t) {\n\t\t\t\t// Do not end in ) if ( is before the link start\n\t\t\t\t// Do not end in ] if [ is before the link start\n\t\t\t\t// Do not end in } if { is before the link start\n\t\t\t\tlastIncludedCharIndex--;\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\trange: {\n\t\t\t\tstartLineNumber: lineNumber,\n\t\t\t\tstartColumn: linkBeginIndex + 1,\n\t\t\t\tendLineNumber: lineNumber,\n\t\t\t\tendColumn: lastIncludedCharIndex + 2\n\t\t\t},\n\t\t\turl: line.substring(linkBeginIndex, lastIncludedCharIndex + 1)\n\t\t};\n\t}\n\n\tpublic static computeLinks(model: ILinkComputerTarget, stateMachine: StateMachine = getStateMachine()): ILink[] {\n\t\tconst classifier = getClassifier();\n\n\t\tconst result: ILink[] = [];\n\t\tfor (let i = 1, lineCount = model.getLineCount(); i <= lineCount; i++) {\n\t\t\tconst line = model.getLineContent(i);\n\t\t\tconst len = line.length;\n\n\t\t\tlet j = 0;\n\t\t\tlet linkBeginIndex = 0;\n\t\t\tlet linkBeginChCode = 0;\n\t\t\tlet state = State.Start;\n\t\t\tlet hasOpenParens = false;\n\t\t\tlet hasOpenSquareBracket = false;\n\t\t\tlet inSquareBrackets = false;\n\t\t\tlet hasOpenCurlyBracket = false;\n\n\t\t\twhile (j < len) {\n\n\t\t\t\tlet resetStateMachine = false;\n\t\t\t\tconst chCode = line.charCodeAt(j);\n\n\t\t\t\tif (state === State.Accept) {\n\t\t\t\t\tlet chClass: CharacterClass;\n\t\t\t\t\tswitch (chCode) {\n\t\t\t\t\t\tcase CharCode.OpenParen:\n\t\t\t\t\t\t\thasOpenParens = true;\n\t\t\t\t\t\t\tchClass = CharacterClass.None;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase CharCode.CloseParen:\n\t\t\t\t\t\t\tchClass = (hasOpenParens ? CharacterClass.None : CharacterClass.ForceTermination);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase CharCode.OpenSquareBracket:\n\t\t\t\t\t\t\tinSquareBrackets = true;\n\t\t\t\t\t\t\thasOpenSquareBracket = true;\n\t\t\t\t\t\t\tchClass = CharacterClass.None;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase CharCode.CloseSquareBracket:\n\t\t\t\t\t\t\tinSquareBrackets = false;\n\t\t\t\t\t\t\tchClass = (hasOpenSquareBracket ? CharacterClass.None : CharacterClass.ForceTermination);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase CharCode.OpenCurlyBrace:\n\t\t\t\t\t\t\thasOpenCurlyBracket = true;\n\t\t\t\t\t\t\tchClass = CharacterClass.None;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase CharCode.CloseCurlyBrace:\n\t\t\t\t\t\t\tchClass = (hasOpenCurlyBracket ? CharacterClass.None : CharacterClass.ForceTermination);\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t// The following three rules make it that ' or \" or ` are allowed inside links\n\t\t\t\t\t\t// only if the link is wrapped by some other quote character\n\t\t\t\t\t\tcase CharCode.SingleQuote:\n\t\t\t\t\t\tcase CharCode.DoubleQuote:\n\t\t\t\t\t\tcase CharCode.BackTick:\n\t\t\t\t\t\t\tif (linkBeginChCode === chCode) {\n\t\t\t\t\t\t\t\tchClass = CharacterClass.ForceTermination;\n\t\t\t\t\t\t\t} else if (linkBeginChCode === CharCode.SingleQuote || linkBeginChCode === CharCode.DoubleQuote || linkBeginChCode === CharCode.BackTick) {\n\t\t\t\t\t\t\t\tchClass = CharacterClass.None;\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tchClass = CharacterClass.ForceTermination;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase CharCode.Asterisk:\n\t\t\t\t\t\t\t// `*` terminates a link if the link began with `*`\n\t\t\t\t\t\t\tchClass = (linkBeginChCode === CharCode.Asterisk) ? CharacterClass.ForceTermination : CharacterClass.None;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase CharCode.Pipe:\n\t\t\t\t\t\t\t// `|` terminates a link if the link began with `|`\n\t\t\t\t\t\t\tchClass = (linkBeginChCode === CharCode.Pipe) ? CharacterClass.ForceTermination : CharacterClass.None;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase CharCode.Space:\n\t\t\t\t\t\t\t// ` ` allow space in between [ and ]\n\t\t\t\t\t\t\tchClass = (inSquareBrackets ? CharacterClass.None : CharacterClass.ForceTermination);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\tchClass = classifier.get(chCode);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Check if character terminates link\n\t\t\t\t\tif (chClass === CharacterClass.ForceTermination) {\n\t\t\t\t\t\tresult.push(LinkComputer._createLink(classifier, line, i, linkBeginIndex, j));\n\t\t\t\t\t\tresetStateMachine = true;\n\t\t\t\t\t}\n\t\t\t\t} else if (state === State.End) {\n\n\t\t\t\t\tlet chClass: CharacterClass;\n\t\t\t\t\tif (chCode === CharCode.OpenSquareBracket) {\n\t\t\t\t\t\t// Allow for the authority part to contain ipv6 addresses which contain [ and ]\n\t\t\t\t\t\thasOpenSquareBracket = true;\n\t\t\t\t\t\tchClass = CharacterClass.None;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tchClass = classifier.get(chCode);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Check if character terminates link\n\t\t\t\t\tif (chClass === CharacterClass.ForceTermination) {\n\t\t\t\t\t\tresetStateMachine = true;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tstate = State.Accept;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tstate = stateMachine.nextState(state, chCode);\n\t\t\t\t\tif (state === State.Invalid) {\n\t\t\t\t\t\tresetStateMachine = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (resetStateMachine) {\n\t\t\t\t\tstate = State.Start;\n\t\t\t\t\thasOpenParens = false;\n\t\t\t\t\thasOpenSquareBracket = false;\n\t\t\t\t\thasOpenCurlyBracket = false;\n\n\t\t\t\t\t// Record where the link started\n\t\t\t\t\tlinkBeginIndex = j + 1;\n\t\t\t\t\tlinkBeginChCode = chCode;\n\t\t\t\t}\n\n\t\t\t\tj++;\n\t\t\t}\n\n\t\t\tif (state === State.Accept) {\n\t\t\t\tresult.push(LinkComputer._createLink(classifier, line, i, linkBeginIndex, len));\n\t\t\t}\n\n\t\t}\n\n\t\treturn result;\n\t}\n}\n\n/**\n * Returns an array of all links contains in the provided\n * document. *Note* that this operation is computational\n * expensive and should not run in the UI thread.\n */\nexport function computeLinks(model: ILinkComputerTarget | null): ILink[] {\n\tif (!model || typeof model.getLineCount !== 'function' || typeof model.getLineContent !== 'function') {\n\t\t// Unknown caller!\n\t\treturn [];\n\t}\n\treturn LinkComputer.computeLinks(model);\n}\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\nimport { LineTokens } from 'vs/editor/common/tokens/lineTokens';\nimport { StandardTokenType } from 'vs/editor/common/encodedTokenAttributes';\n\nexport function createScopedLineTokens(context: LineTokens, offset: number): ScopedLineTokens {\n\tconst tokenCount = context.getCount();\n\tconst tokenIndex = context.findTokenIndexAtOffset(offset);\n\tconst desiredLanguageId = context.getLanguageId(tokenIndex);\n\n\tlet lastTokenIndex = tokenIndex;\n\twhile (lastTokenIndex + 1 < tokenCount && context.getLanguageId(lastTokenIndex + 1) === desiredLanguageId) {\n\t\tlastTokenIndex++;\n\t}\n\n\tlet firstTokenIndex = tokenIndex;\n\twhile (firstTokenIndex > 0 && context.getLanguageId(firstTokenIndex - 1) === desiredLanguageId) {\n\t\tfirstTokenIndex--;\n\t}\n\n\treturn new ScopedLineTokens(\n\t\tcontext,\n\t\tdesiredLanguageId,\n\t\tfirstTokenIndex,\n\t\tlastTokenIndex + 1,\n\t\tcontext.getStartOffset(firstTokenIndex),\n\t\tcontext.getEndOffset(lastTokenIndex)\n\t);\n}\n\nexport class ScopedLineTokens {\n\t_scopedLineTokensBrand: void = undefined;\n\n\tpublic readonly languageId: string;\n\tprivate readonly _actual: LineTokens;\n\tprivate readonly _firstTokenIndex: number;\n\tprivate readonly _lastTokenIndex: number;\n\tpublic readonly firstCharOffset: number;\n\tprivate readonly _lastCharOffset: number;\n\n\tconstructor(\n\t\tactual: LineTokens,\n\t\tlanguageId: string,\n\t\tfirstTokenIndex: number,\n\t\tlastTokenIndex: number,\n\t\tfirstCharOffset: number,\n\t\tlastCharOffset: number\n\t) {\n\t\tthis._actual = actual;\n\t\tthis.languageId = languageId;\n\t\tthis._firstTokenIndex = firstTokenIndex;\n\t\tthis._lastTokenIndex = lastTokenIndex;\n\t\tthis.firstCharOffset = firstCharOffset;\n\t\tthis._lastCharOffset = lastCharOffset;\n\t}\n\n\tpublic getLineContent(): string {\n\t\tconst actualLineContent = this._actual.getLineContent();\n\t\treturn actualLineContent.substring(this.firstCharOffset, this._lastCharOffset);\n\t}\n\n\tpublic getActualLineContentBefore(offset: number): string {\n\t\tconst actualLineContent = this._actual.getLineContent();\n\t\treturn actualLineContent.substring(0, this.firstCharOffset + offset);\n\t}\n\n\tpublic getTokenCount(): number {\n\t\treturn this._lastTokenIndex - this._firstTokenIndex;\n\t}\n\n\tpublic findTokenIndexAtOffset(offset: number): number {\n\t\treturn this._actual.findTokenIndexAtOffset(offset + this.firstCharOffset) - this._firstTokenIndex;\n\t}\n\n\tpublic getStandardTokenType(tokenIndex: number): StandardTokenType {\n\t\treturn this._actual.getStandardTokenType(tokenIndex + this._firstTokenIndex);\n\t}\n}\n\nconst enum IgnoreBracketsInTokens {\n\tvalue = StandardTokenType.Comment | StandardTokenType.String | StandardTokenType.RegEx\n}\n\nexport function ignoreBracketsInToken(standardTokenType: StandardTokenType): boolean {\n\treturn (standardTokenType & IgnoreBracketsInTokens.value) !== 0;\n}\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\nimport { ConfigurationChangedEvent, EditorAutoClosingEditStrategy, EditorAutoClosingStrategy, EditorAutoIndentStrategy, EditorAutoSurroundStrategy, EditorOption } from 'vs/editor/common/config/editorOptions';\nimport { LineTokens } from 'vs/editor/common/tokens/lineTokens';\nimport { Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\nimport { ISelection, Selection } from 'vs/editor/common/core/selection';\nimport { ICommand } from 'vs/editor/common/editorCommon';\nimport { IEditorConfiguration } from 'vs/editor/common/config/editorConfiguration';\nimport { PositionAffinity, TextModelResolvedOptions } from 'vs/editor/common/model';\nimport { AutoClosingPairs } from 'vs/editor/common/languages/languageConfiguration';\nimport { ILanguageConfigurationService } from 'vs/editor/common/languages/languageConfigurationRegistry';\nimport { createScopedLineTokens } from 'vs/editor/common/languages/supports';\nimport { IElectricAction } from 'vs/editor/common/languages/supports/electricCharacter';\nimport { CursorColumns } from 'vs/editor/common/core/cursorColumns';\nimport { normalizeIndentation } from 'vs/editor/common/core/indentation';\n\nexport interface IColumnSelectData {\n\tisReal: boolean;\n\tfromViewLineNumber: number;\n\tfromViewVisualColumn: number;\n\ttoViewLineNumber: number;\n\ttoViewVisualColumn: number;\n}\n\n/**\n * This is an operation type that will be recorded for undo/redo purposes.\n * The goal is to introduce an undo stop when the controller switches between different operation types.\n */\nexport const enum EditOperationType {\n\tOther = 0,\n\tDeletingLeft = 2,\n\tDeletingRight = 3,\n\tTypingOther = 4,\n\tTypingFirstSpace = 5,\n\tTypingConsecutiveSpace = 6,\n}\n\nexport interface CharacterMap {\n\t[char: string]: string;\n}\n\nconst autoCloseAlways = () => true;\nconst autoCloseNever = () => false;\nconst autoCloseBeforeWhitespace = (chr: string) => (chr === ' ' || chr === '\\t');\n\nexport class CursorConfiguration {\n\t_cursorMoveConfigurationBrand: void = undefined;\n\n\tpublic readonly readOnly: boolean;\n\tpublic readonly tabSize: number;\n\tpublic readonly indentSize: number;\n\tpublic readonly insertSpaces: boolean;\n\tpublic readonly stickyTabStops: boolean;\n\tpublic readonly pageSize: number;\n\tpublic readonly lineHeight: number;\n\tpublic readonly typicalHalfwidthCharacterWidth: number;\n\tpublic readonly useTabStops: boolean;\n\tpublic readonly wordSeparators: string;\n\tpublic readonly emptySelectionClipboard: boolean;\n\tpublic readonly copyWithSyntaxHighlighting: boolean;\n\tpublic readonly multiCursorMergeOverlapping: boolean;\n\tpublic readonly multiCursorPaste: 'spread' | 'full';\n\tpublic readonly multiCursorLimit: number;\n\tpublic readonly autoClosingBrackets: EditorAutoClosingStrategy;\n\tpublic readonly autoClosingComments: EditorAutoClosingStrategy;\n\tpublic readonly autoClosingQuotes: EditorAutoClosingStrategy;\n\tpublic readonly autoClosingDelete: EditorAutoClosingEditStrategy;\n\tpublic readonly autoClosingOvertype: EditorAutoClosingEditStrategy;\n\tpublic readonly autoSurround: EditorAutoSurroundStrategy;\n\tpublic readonly autoIndent: EditorAutoIndentStrategy;\n\tpublic readonly autoClosingPairs: AutoClosingPairs;\n\tpublic readonly surroundingPairs: CharacterMap;\n\tpublic readonly blockCommentStartToken: string | null;\n\tpublic readonly shouldAutoCloseBefore: { quote: (ch: string) => boolean; bracket: (ch: string) => boolean; comment: (ch: string) => boolean };\n\tpublic readonly wordSegmenterLocales: string[];\n\n\tprivate readonly _languageId: string;\n\tprivate _electricChars: { [key: string]: boolean } | null;\n\n\tpublic static shouldRecreate(e: ConfigurationChangedEvent): boolean {\n\t\treturn (\n\t\t\te.hasChanged(EditorOption.layoutInfo)\n\t\t\t|| e.hasChanged(EditorOption.wordSeparators)\n\t\t\t|| e.hasChanged(EditorOption.emptySelectionClipboard)\n\t\t\t|| e.hasChanged(EditorOption.multiCursorMergeOverlapping)\n\t\t\t|| e.hasChanged(EditorOption.multiCursorPaste)\n\t\t\t|| e.hasChanged(EditorOption.multiCursorLimit)\n\t\t\t|| e.hasChanged(EditorOption.autoClosingBrackets)\n\t\t\t|| e.hasChanged(EditorOption.autoClosingComments)\n\t\t\t|| e.hasChanged(EditorOption.autoClosingQuotes)\n\t\t\t|| e.hasChanged(EditorOption.autoClosingDelete)\n\t\t\t|| e.hasChanged(EditorOption.autoClosingOvertype)\n\t\t\t|| e.hasChanged(EditorOption.autoSurround)\n\t\t\t|| e.hasChanged(EditorOption.useTabStops)\n\t\t\t|| e.hasChanged(EditorOption.fontInfo)\n\t\t\t|| e.hasChanged(EditorOption.readOnly)\n\t\t\t|| e.hasChanged(EditorOption.wordSegmenterLocales)\n\t\t);\n\t}\n\n\tconstructor(\n\t\tlanguageId: string,\n\t\tmodelOptions: TextModelResolvedOptions,\n\t\tconfiguration: IEditorConfiguration,\n\t\tpublic readonly languageConfigurationService: ILanguageConfigurationService\n\t) {\n\t\tthis._languageId = languageId;\n\n\t\tconst options = configuration.options;\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\n\t\tconst fontInfo = options.get(EditorOption.fontInfo);\n\n\t\tthis.readOnly = options.get(EditorOption.readOnly);\n\t\tthis.tabSize = modelOptions.tabSize;\n\t\tthis.indentSize = modelOptions.indentSize;\n\t\tthis.insertSpaces = modelOptions.insertSpaces;\n\t\tthis.stickyTabStops = options.get(EditorOption.stickyTabStops);\n\t\tthis.lineHeight = fontInfo.lineHeight;\n\t\tthis.typicalHalfwidthCharacterWidth = fontInfo.typicalHalfwidthCharacterWidth;\n\t\tthis.pageSize = Math.max(1, Math.floor(layoutInfo.height / this.lineHeight) - 2);\n\t\tthis.useTabStops = options.get(EditorOption.useTabStops);\n\t\tthis.wordSeparators = options.get(EditorOption.wordSeparators);\n\t\tthis.emptySelectionClipboard = options.get(EditorOption.emptySelectionClipboard);\n\t\tthis.copyWithSyntaxHighlighting = options.get(EditorOption.copyWithSyntaxHighlighting);\n\t\tthis.multiCursorMergeOverlapping = options.get(EditorOption.multiCursorMergeOverlapping);\n\t\tthis.multiCursorPaste = options.get(EditorOption.multiCursorPaste);\n\t\tthis.multiCursorLimit = options.get(EditorOption.multiCursorLimit);\n\t\tthis.autoClosingBrackets = options.get(EditorOption.autoClosingBrackets);\n\t\tthis.autoClosingComments = options.get(EditorOption.autoClosingComments);\n\t\tthis.autoClosingQuotes = options.get(EditorOption.autoClosingQuotes);\n\t\tthis.autoClosingDelete = options.get(EditorOption.autoClosingDelete);\n\t\tthis.autoClosingOvertype = options.get(EditorOption.autoClosingOvertype);\n\t\tthis.autoSurround = options.get(EditorOption.autoSurround);\n\t\tthis.autoIndent = options.get(EditorOption.autoIndent);\n\t\tthis.wordSegmenterLocales = options.get(EditorOption.wordSegmenterLocales);\n\n\t\tthis.surroundingPairs = {};\n\t\tthis._electricChars = null;\n\n\t\tthis.shouldAutoCloseBefore = {\n\t\t\tquote: this._getShouldAutoClose(languageId, this.autoClosingQuotes, true),\n\t\t\tcomment: this._getShouldAutoClose(languageId, this.autoClosingComments, false),\n\t\t\tbracket: this._getShouldAutoClose(languageId, this.autoClosingBrackets, false),\n\t\t};\n\n\t\tthis.autoClosingPairs = this.languageConfigurationService.getLanguageConfiguration(languageId).getAutoClosingPairs();\n\n\t\tconst surroundingPairs = this.languageConfigurationService.getLanguageConfiguration(languageId).getSurroundingPairs();\n\t\tif (surroundingPairs) {\n\t\t\tfor (const pair of surroundingPairs) {\n\t\t\t\tthis.surroundingPairs[pair.open] = pair.close;\n\t\t\t}\n\t\t}\n\n\t\tconst commentsConfiguration = this.languageConfigurationService.getLanguageConfiguration(languageId).comments;\n\t\tthis.blockCommentStartToken = commentsConfiguration?.blockCommentStartToken ?? null;\n\t}\n\n\tpublic get electricChars() {\n\t\tif (!this._electricChars) {\n\t\t\tthis._electricChars = {};\n\t\t\tconst electricChars = this.languageConfigurationService.getLanguageConfiguration(this._languageId).electricCharacter?.getElectricCharacters();\n\t\t\tif (electricChars) {\n\t\t\t\tfor (const char of electricChars) {\n\t\t\t\t\tthis._electricChars[char] = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn this._electricChars;\n\t}\n\n\t/**\n\t * Should return opening bracket type to match indentation with\n\t */\n\tpublic onElectricCharacter(character: string, context: LineTokens, column: number): IElectricAction | null {\n\t\tconst scopedLineTokens = createScopedLineTokens(context, column - 1);\n\t\tconst electricCharacterSupport = this.languageConfigurationService.getLanguageConfiguration(scopedLineTokens.languageId).electricCharacter;\n\t\tif (!electricCharacterSupport) {\n\t\t\treturn null;\n\t\t}\n\t\treturn electricCharacterSupport.onElectricCharacter(character, scopedLineTokens, column - scopedLineTokens.firstCharOffset);\n\t}\n\n\tpublic normalizeIndentation(str: string): string {\n\t\treturn normalizeIndentation(str, this.indentSize, this.insertSpaces);\n\t}\n\n\tprivate _getShouldAutoClose(languageId: string, autoCloseConfig: EditorAutoClosingStrategy, forQuotes: boolean): (ch: string) => boolean {\n\t\tswitch (autoCloseConfig) {\n\t\t\tcase 'beforeWhitespace':\n\t\t\t\treturn autoCloseBeforeWhitespace;\n\t\t\tcase 'languageDefined':\n\t\t\t\treturn this._getLanguageDefinedShouldAutoClose(languageId, forQuotes);\n\t\t\tcase 'always':\n\t\t\t\treturn autoCloseAlways;\n\t\t\tcase 'never':\n\t\t\t\treturn autoCloseNever;\n\t\t}\n\t}\n\n\tprivate _getLanguageDefinedShouldAutoClose(languageId: string, forQuotes: boolean): (ch: string) => boolean {\n\t\tconst autoCloseBeforeSet = this.languageConfigurationService.getLanguageConfiguration(languageId).getAutoCloseBeforeSet(forQuotes);\n\t\treturn c => autoCloseBeforeSet.indexOf(c) !== -1;\n\t}\n\n\t/**\n\t * Returns a visible column from a column.\n\t * @see {@link CursorColumns}\n\t */\n\tpublic visibleColumnFromColumn(model: ICursorSimpleModel, position: Position): number {\n\t\treturn CursorColumns.visibleColumnFromColumn(model.getLineContent(position.lineNumber), position.column, this.tabSize);\n\t}\n\n\t/**\n\t * Returns a visible column from a column.\n\t * @see {@link CursorColumns}\n\t */\n\tpublic columnFromVisibleColumn(model: ICursorSimpleModel, lineNumber: number, visibleColumn: number): number {\n\t\tconst result = CursorColumns.columnFromVisibleColumn(model.getLineContent(lineNumber), visibleColumn, this.tabSize);\n\n\t\tconst minColumn = model.getLineMinColumn(lineNumber);\n\t\tif (result < minColumn) {\n\t\t\treturn minColumn;\n\t\t}\n\n\t\tconst maxColumn = model.getLineMaxColumn(lineNumber);\n\t\tif (result > maxColumn) {\n\t\t\treturn maxColumn;\n\t\t}\n\n\t\treturn result;\n\t}\n}\n\n/**\n * Represents a simple model (either the model or the view model).\n */\nexport interface ICursorSimpleModel {\n\tgetLineCount(): number;\n\tgetLineContent(lineNumber: number): string;\n\tgetLineMinColumn(lineNumber: number): number;\n\tgetLineMaxColumn(lineNumber: number): number;\n\tgetLineFirstNonWhitespaceColumn(lineNumber: number): number;\n\tnormalizePosition(position: Position, affinity: PositionAffinity): Position;\n\n\t/**\n\t * Gets the column at which indentation stops at a given line.\n\t * @internal\n\t */\n\tgetLineIndentColumn(lineNumber: number): number;\n}\n\nexport type PartialCursorState = CursorState | PartialModelCursorState | PartialViewCursorState;\n\nexport class CursorState {\n\t_cursorStateBrand: void = undefined;\n\n\tpublic static fromModelState(modelState: SingleCursorState): PartialModelCursorState {\n\t\treturn new PartialModelCursorState(modelState);\n\t}\n\n\tpublic static fromViewState(viewState: SingleCursorState): PartialViewCursorState {\n\t\treturn new PartialViewCursorState(viewState);\n\t}\n\n\tpublic static fromModelSelection(modelSelection: ISelection): PartialModelCursorState {\n\t\tconst selection = Selection.liftSelection(modelSelection);\n\t\tconst modelState = new SingleCursorState(\n\t\t\tRange.fromPositions(selection.getSelectionStart()),\n\t\t\tSelectionStartKind.Simple, 0,\n\t\t\tselection.getPosition(), 0\n\t\t);\n\t\treturn CursorState.fromModelState(modelState);\n\t}\n\n\tpublic static fromModelSelections(modelSelections: readonly ISelection[]): PartialModelCursorState[] {\n\t\tconst states: PartialModelCursorState[] = [];\n\t\tfor (let i = 0, len = modelSelections.length; i < len; i++) {\n\t\t\tstates[i] = this.fromModelSelection(modelSelections[i]);\n\t\t}\n\t\treturn states;\n\t}\n\n\treadonly modelState: SingleCursorState;\n\treadonly viewState: SingleCursorState;\n\n\tconstructor(modelState: SingleCursorState, viewState: SingleCursorState) {\n\t\tthis.modelState = modelState;\n\t\tthis.viewState = viewState;\n\t}\n\n\tpublic equals(other: CursorState): boolean {\n\t\treturn (this.viewState.equals(other.viewState) && this.modelState.equals(other.modelState));\n\t}\n}\n\nexport class PartialModelCursorState {\n\treadonly modelState: SingleCursorState;\n\treadonly viewState: null;\n\n\tconstructor(modelState: SingleCursorState) {\n\t\tthis.modelState = modelState;\n\t\tthis.viewState = null;\n\t}\n}\n\nexport class PartialViewCursorState {\n\treadonly modelState: null;\n\treadonly viewState: SingleCursorState;\n\n\tconstructor(viewState: SingleCursorState) {\n\t\tthis.modelState = null;\n\t\tthis.viewState = viewState;\n\t}\n}\n\nexport const enum SelectionStartKind {\n\tSimple,\n\tWord,\n\tLine\n}\n\n/**\n * Represents the cursor state on either the model or on the view model.\n */\nexport class SingleCursorState {\n\t_singleCursorStateBrand: void = undefined;\n\n\tpublic readonly selection: Selection;\n\n\tconstructor(\n\t\tpublic readonly selectionStart: Range,\n\t\tpublic readonly selectionStartKind: SelectionStartKind,\n\t\tpublic readonly selectionStartLeftoverVisibleColumns: number,\n\t\tpublic readonly position: Position,\n\t\tpublic readonly leftoverVisibleColumns: number,\n\t) {\n\t\tthis.selection = SingleCursorState._computeSelection(this.selectionStart, this.position);\n\t}\n\n\tpublic equals(other: SingleCursorState) {\n\t\treturn (\n\t\t\tthis.selectionStartLeftoverVisibleColumns === other.selectionStartLeftoverVisibleColumns\n\t\t\t&& this.leftoverVisibleColumns === other.leftoverVisibleColumns\n\t\t\t&& this.selectionStartKind === other.selectionStartKind\n\t\t\t&& this.position.equals(other.position)\n\t\t\t&& this.selectionStart.equalsRange(other.selectionStart)\n\t\t);\n\t}\n\n\tpublic hasSelection(): boolean {\n\t\treturn (!this.selection.isEmpty() || !this.selectionStart.isEmpty());\n\t}\n\n\tpublic move(inSelectionMode: boolean, lineNumber: number, column: number, leftoverVisibleColumns: number): SingleCursorState {\n\t\tif (inSelectionMode) {\n\t\t\t// move just position\n\t\t\treturn new SingleCursorState(\n\t\t\t\tthis.selectionStart,\n\t\t\t\tthis.selectionStartKind,\n\t\t\t\tthis.selectionStartLeftoverVisibleColumns,\n\t\t\t\tnew Position(lineNumber, column),\n\t\t\t\tleftoverVisibleColumns\n\t\t\t);\n\t\t} else {\n\t\t\t// move everything\n\t\t\treturn new SingleCursorState(\n\t\t\t\tnew Range(lineNumber, column, lineNumber, column),\n\t\t\t\tSelectionStartKind.Simple,\n\t\t\t\tleftoverVisibleColumns,\n\t\t\t\tnew Position(lineNumber, column),\n\t\t\t\tleftoverVisibleColumns\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate static _computeSelection(selectionStart: Range, position: Position): Selection {\n\t\tif (selectionStart.isEmpty() || !position.isBeforeOrEqual(selectionStart.getStartPosition())) {\n\t\t\treturn Selection.fromPositions(selectionStart.getStartPosition(), position);\n\t\t} else {\n\t\t\treturn Selection.fromPositions(selectionStart.getEndPosition(), position);\n\t\t}\n\t}\n}\n\nexport class EditOperationResult {\n\t_editOperationResultBrand: void = undefined;\n\n\treadonly type: EditOperationType;\n\treadonly commands: Array;\n\treadonly shouldPushStackElementBefore: boolean;\n\treadonly shouldPushStackElementAfter: boolean;\n\n\tconstructor(\n\t\ttype: EditOperationType,\n\t\tcommands: Array,\n\t\topts: {\n\t\t\tshouldPushStackElementBefore: boolean;\n\t\t\tshouldPushStackElementAfter: boolean;\n\t\t}\n\t) {\n\t\tthis.type = type;\n\t\tthis.commands = commands;\n\t\tthis.shouldPushStackElementBefore = opts.shouldPushStackElementBefore;\n\t\tthis.shouldPushStackElementAfter = opts.shouldPushStackElementAfter;\n\t}\n}\n\nexport function isQuote(ch: string): boolean {\n\treturn (ch === '\\'' || ch === '\"' || ch === '`');\n}\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\nimport { CursorConfiguration, ICursorSimpleModel, SingleCursorState, IColumnSelectData, SelectionStartKind } from 'vs/editor/common/cursorCommon';\nimport { Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\n\nexport class ColumnSelection {\n\n\tpublic static columnSelect(config: CursorConfiguration, model: ICursorSimpleModel, fromLineNumber: number, fromVisibleColumn: number, toLineNumber: number, toVisibleColumn: number): IColumnSelectResult {\n\t\tconst lineCount = Math.abs(toLineNumber - fromLineNumber) + 1;\n\t\tconst reversed = (fromLineNumber > toLineNumber);\n\t\tconst isRTL = (fromVisibleColumn > toVisibleColumn);\n\t\tconst isLTR = (fromVisibleColumn < toVisibleColumn);\n\n\t\tconst result: SingleCursorState[] = [];\n\n\t\t// console.log(`fromVisibleColumn: ${fromVisibleColumn}, toVisibleColumn: ${toVisibleColumn}`);\n\n\t\tfor (let i = 0; i < lineCount; i++) {\n\t\t\tconst lineNumber = fromLineNumber + (reversed ? -i : i);\n\n\t\t\tconst startColumn = config.columnFromVisibleColumn(model, lineNumber, fromVisibleColumn);\n\t\t\tconst endColumn = config.columnFromVisibleColumn(model, lineNumber, toVisibleColumn);\n\t\t\tconst visibleStartColumn = config.visibleColumnFromColumn(model, new Position(lineNumber, startColumn));\n\t\t\tconst visibleEndColumn = config.visibleColumnFromColumn(model, new Position(lineNumber, endColumn));\n\n\t\t\t// console.log(`lineNumber: ${lineNumber}: visibleStartColumn: ${visibleStartColumn}, visibleEndColumn: ${visibleEndColumn}`);\n\n\t\t\tif (isLTR) {\n\t\t\t\tif (visibleStartColumn > toVisibleColumn) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (visibleEndColumn < fromVisibleColumn) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (isRTL) {\n\t\t\t\tif (visibleEndColumn > fromVisibleColumn) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (visibleStartColumn < toVisibleColumn) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tresult.push(new SingleCursorState(\n\t\t\t\tnew Range(lineNumber, startColumn, lineNumber, startColumn), SelectionStartKind.Simple, 0,\n\t\t\t\tnew Position(lineNumber, endColumn), 0\n\t\t\t));\n\t\t}\n\n\t\tif (result.length === 0) {\n\t\t\t// We are after all the lines, so add cursor at the end of each line\n\t\t\tfor (let i = 0; i < lineCount; i++) {\n\t\t\t\tconst lineNumber = fromLineNumber + (reversed ? -i : i);\n\t\t\t\tconst maxColumn = model.getLineMaxColumn(lineNumber);\n\n\t\t\t\tresult.push(new SingleCursorState(\n\t\t\t\t\tnew Range(lineNumber, maxColumn, lineNumber, maxColumn), SelectionStartKind.Simple, 0,\n\t\t\t\t\tnew Position(lineNumber, maxColumn), 0\n\t\t\t\t));\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tviewStates: result,\n\t\t\treversed: reversed,\n\t\t\tfromLineNumber: fromLineNumber,\n\t\t\tfromVisualColumn: fromVisibleColumn,\n\t\t\ttoLineNumber: toLineNumber,\n\t\t\ttoVisualColumn: toVisibleColumn\n\t\t};\n\t}\n\n\tpublic static columnSelectLeft(config: CursorConfiguration, model: ICursorSimpleModel, prevColumnSelectData: IColumnSelectData): IColumnSelectResult {\n\t\tlet toViewVisualColumn = prevColumnSelectData.toViewVisualColumn;\n\t\tif (toViewVisualColumn > 0) {\n\t\t\ttoViewVisualColumn--;\n\t\t}\n\n\t\treturn ColumnSelection.columnSelect(config, model, prevColumnSelectData.fromViewLineNumber, prevColumnSelectData.fromViewVisualColumn, prevColumnSelectData.toViewLineNumber, toViewVisualColumn);\n\t}\n\n\tpublic static columnSelectRight(config: CursorConfiguration, model: ICursorSimpleModel, prevColumnSelectData: IColumnSelectData): IColumnSelectResult {\n\t\tlet maxVisualViewColumn = 0;\n\t\tconst minViewLineNumber = Math.min(prevColumnSelectData.fromViewLineNumber, prevColumnSelectData.toViewLineNumber);\n\t\tconst maxViewLineNumber = Math.max(prevColumnSelectData.fromViewLineNumber, prevColumnSelectData.toViewLineNumber);\n\t\tfor (let lineNumber = minViewLineNumber; lineNumber <= maxViewLineNumber; lineNumber++) {\n\t\t\tconst lineMaxViewColumn = model.getLineMaxColumn(lineNumber);\n\t\t\tconst lineMaxVisualViewColumn = config.visibleColumnFromColumn(model, new Position(lineNumber, lineMaxViewColumn));\n\t\t\tmaxVisualViewColumn = Math.max(maxVisualViewColumn, lineMaxVisualViewColumn);\n\t\t}\n\n\t\tlet toViewVisualColumn = prevColumnSelectData.toViewVisualColumn;\n\t\tif (toViewVisualColumn < maxVisualViewColumn) {\n\t\t\ttoViewVisualColumn++;\n\t\t}\n\n\t\treturn this.columnSelect(config, model, prevColumnSelectData.fromViewLineNumber, prevColumnSelectData.fromViewVisualColumn, prevColumnSelectData.toViewLineNumber, toViewVisualColumn);\n\t}\n\n\tpublic static columnSelectUp(config: CursorConfiguration, model: ICursorSimpleModel, prevColumnSelectData: IColumnSelectData, isPaged: boolean): IColumnSelectResult {\n\t\tconst linesCount = isPaged ? config.pageSize : 1;\n\t\tconst toViewLineNumber = Math.max(1, prevColumnSelectData.toViewLineNumber - linesCount);\n\t\treturn this.columnSelect(config, model, prevColumnSelectData.fromViewLineNumber, prevColumnSelectData.fromViewVisualColumn, toViewLineNumber, prevColumnSelectData.toViewVisualColumn);\n\t}\n\n\tpublic static columnSelectDown(config: CursorConfiguration, model: ICursorSimpleModel, prevColumnSelectData: IColumnSelectData, isPaged: boolean): IColumnSelectResult {\n\t\tconst linesCount = isPaged ? config.pageSize : 1;\n\t\tconst toViewLineNumber = Math.min(model.getLineCount(), prevColumnSelectData.toViewLineNumber + linesCount);\n\t\treturn this.columnSelect(config, model, prevColumnSelectData.fromViewLineNumber, prevColumnSelectData.fromViewVisualColumn, toViewLineNumber, prevColumnSelectData.toViewVisualColumn);\n\t}\n}\n\nexport interface IColumnSelectResult {\n\tviewStates: SingleCursorState[];\n\treversed: boolean;\n\tfromLineNumber: number;\n\tfromVisualColumn: number;\n\ttoLineNumber: number;\n\ttoVisualColumn: number;\n}\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\nimport * as strings from 'vs/base/common/strings';\nimport { Constants } from 'vs/base/common/uint';\nimport { CursorColumns } from 'vs/editor/common/core/cursorColumns';\nimport { Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\nimport { AtomicTabMoveOperations, Direction } from 'vs/editor/common/cursor/cursorAtomicMoveOperations';\nimport { CursorConfiguration, ICursorSimpleModel, SelectionStartKind, SingleCursorState } from 'vs/editor/common/cursorCommon';\nimport { PositionAffinity } from 'vs/editor/common/model';\n\nexport class CursorPosition {\n\t_cursorPositionBrand: void = undefined;\n\n\tpublic readonly lineNumber: number;\n\tpublic readonly column: number;\n\tpublic readonly leftoverVisibleColumns: number;\n\n\tconstructor(lineNumber: number, column: number, leftoverVisibleColumns: number) {\n\t\tthis.lineNumber = lineNumber;\n\t\tthis.column = column;\n\t\tthis.leftoverVisibleColumns = leftoverVisibleColumns;\n\t}\n}\n\nexport class MoveOperations {\n\tpublic static leftPosition(model: ICursorSimpleModel, position: Position): Position {\n\t\tif (position.column > model.getLineMinColumn(position.lineNumber)) {\n\t\t\treturn position.delta(undefined, -strings.prevCharLength(model.getLineContent(position.lineNumber), position.column - 1));\n\t\t} else if (position.lineNumber > 1) {\n\t\t\tconst newLineNumber = position.lineNumber - 1;\n\t\t\treturn new Position(newLineNumber, model.getLineMaxColumn(newLineNumber));\n\t\t} else {\n\t\t\treturn position;\n\t\t}\n\t}\n\n\tprivate static leftPositionAtomicSoftTabs(model: ICursorSimpleModel, position: Position, tabSize: number): Position {\n\t\tif (position.column <= model.getLineIndentColumn(position.lineNumber)) {\n\t\t\tconst minColumn = model.getLineMinColumn(position.lineNumber);\n\t\t\tconst lineContent = model.getLineContent(position.lineNumber);\n\t\t\tconst newPosition = AtomicTabMoveOperations.atomicPosition(lineContent, position.column - 1, tabSize, Direction.Left);\n\t\t\tif (newPosition !== -1 && newPosition + 1 >= minColumn) {\n\t\t\t\treturn new Position(position.lineNumber, newPosition + 1);\n\t\t\t}\n\t\t}\n\t\treturn this.leftPosition(model, position);\n\t}\n\n\tprivate static left(config: CursorConfiguration, model: ICursorSimpleModel, position: Position): CursorPosition {\n\t\tconst pos = config.stickyTabStops\n\t\t\t? MoveOperations.leftPositionAtomicSoftTabs(model, position, config.tabSize)\n\t\t\t: MoveOperations.leftPosition(model, position);\n\t\treturn new CursorPosition(pos.lineNumber, pos.column, 0);\n\t}\n\n\t/**\n\t * @param noOfColumns Must be either `1`\n\t * or `Math.round(viewModel.getLineContent(viewLineNumber).length / 2)` (for half lines).\n\t*/\n\tpublic static moveLeft(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, inSelectionMode: boolean, noOfColumns: number): SingleCursorState {\n\t\tlet lineNumber: number,\n\t\t\tcolumn: number;\n\n\t\tif (cursor.hasSelection() && !inSelectionMode) {\n\t\t\t// If the user has a selection and does not want to extend it,\n\t\t\t// put the cursor at the beginning of the selection.\n\t\t\tlineNumber = cursor.selection.startLineNumber;\n\t\t\tcolumn = cursor.selection.startColumn;\n\t\t} else {\n\t\t\t// This has no effect if noOfColumns === 1.\n\t\t\t// It is ok to do so in the half-line scenario.\n\t\t\tconst pos = cursor.position.delta(undefined, -(noOfColumns - 1));\n\t\t\t// We clip the position before normalization, as normalization is not defined\n\t\t\t// for possibly negative columns.\n\t\t\tconst normalizedPos = model.normalizePosition(MoveOperations.clipPositionColumn(pos, model), PositionAffinity.Left);\n\t\t\tconst p = MoveOperations.left(config, model, normalizedPos);\n\n\t\t\tlineNumber = p.lineNumber;\n\t\t\tcolumn = p.column;\n\t\t}\n\n\t\treturn cursor.move(inSelectionMode, lineNumber, column, 0);\n\t}\n\n\t/**\n\t * Adjusts the column so that it is within min/max of the line.\n\t*/\n\tprivate static clipPositionColumn(position: Position, model: ICursorSimpleModel): Position {\n\t\treturn new Position(\n\t\t\tposition.lineNumber,\n\t\t\tMoveOperations.clipRange(position.column, model.getLineMinColumn(position.lineNumber),\n\t\t\t\tmodel.getLineMaxColumn(position.lineNumber))\n\t\t);\n\t}\n\n\tprivate static clipRange(value: number, min: number, max: number): number {\n\t\tif (value < min) {\n\t\t\treturn min;\n\t\t}\n\t\tif (value > max) {\n\t\t\treturn max;\n\t\t}\n\t\treturn value;\n\t}\n\n\tpublic static rightPosition(model: ICursorSimpleModel, lineNumber: number, column: number): Position {\n\t\tif (column < model.getLineMaxColumn(lineNumber)) {\n\t\t\tcolumn = column + strings.nextCharLength(model.getLineContent(lineNumber), column - 1);\n\t\t} else if (lineNumber < model.getLineCount()) {\n\t\t\tlineNumber = lineNumber + 1;\n\t\t\tcolumn = model.getLineMinColumn(lineNumber);\n\t\t}\n\t\treturn new Position(lineNumber, column);\n\t}\n\n\tpublic static rightPositionAtomicSoftTabs(model: ICursorSimpleModel, lineNumber: number, column: number, tabSize: number, indentSize: number): Position {\n\t\tif (column < model.getLineIndentColumn(lineNumber)) {\n\t\t\tconst lineContent = model.getLineContent(lineNumber);\n\t\t\tconst newPosition = AtomicTabMoveOperations.atomicPosition(lineContent, column - 1, tabSize, Direction.Right);\n\t\t\tif (newPosition !== -1) {\n\t\t\t\treturn new Position(lineNumber, newPosition + 1);\n\t\t\t}\n\t\t}\n\t\treturn this.rightPosition(model, lineNumber, column);\n\t}\n\n\tpublic static right(config: CursorConfiguration, model: ICursorSimpleModel, position: Position): CursorPosition {\n\t\tconst pos = config.stickyTabStops\n\t\t\t? MoveOperations.rightPositionAtomicSoftTabs(model, position.lineNumber, position.column, config.tabSize, config.indentSize)\n\t\t\t: MoveOperations.rightPosition(model, position.lineNumber, position.column);\n\t\treturn new CursorPosition(pos.lineNumber, pos.column, 0);\n\t}\n\n\tpublic static moveRight(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, inSelectionMode: boolean, noOfColumns: number): SingleCursorState {\n\t\tlet lineNumber: number,\n\t\t\tcolumn: number;\n\n\t\tif (cursor.hasSelection() && !inSelectionMode) {\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\n\t\t\tlineNumber = cursor.selection.endLineNumber;\n\t\t\tcolumn = cursor.selection.endColumn;\n\t\t} else {\n\t\t\tconst pos = cursor.position.delta(undefined, noOfColumns - 1);\n\t\t\tconst normalizedPos = model.normalizePosition(MoveOperations.clipPositionColumn(pos, model), PositionAffinity.Right);\n\t\t\tconst r = MoveOperations.right(config, model, normalizedPos);\n\t\t\tlineNumber = r.lineNumber;\n\t\t\tcolumn = r.column;\n\t\t}\n\n\t\treturn cursor.move(inSelectionMode, lineNumber, column, 0);\n\t}\n\n\tpublic static vertical(config: CursorConfiguration, model: ICursorSimpleModel, lineNumber: number, column: number, leftoverVisibleColumns: number, newLineNumber: number, allowMoveOnEdgeLine: boolean, normalizationAffinity?: PositionAffinity): CursorPosition {\n\t\tconst currentVisibleColumn = CursorColumns.visibleColumnFromColumn(model.getLineContent(lineNumber), column, config.tabSize) + leftoverVisibleColumns;\n\t\tconst lineCount = model.getLineCount();\n\t\tconst wasOnFirstPosition = (lineNumber === 1 && column === 1);\n\t\tconst wasOnLastPosition = (lineNumber === lineCount && column === model.getLineMaxColumn(lineNumber));\n\t\tconst wasAtEdgePosition = (newLineNumber < lineNumber ? wasOnFirstPosition : wasOnLastPosition);\n\n\t\tlineNumber = newLineNumber;\n\t\tif (lineNumber < 1) {\n\t\t\tlineNumber = 1;\n\t\t\tif (allowMoveOnEdgeLine) {\n\t\t\t\tcolumn = model.getLineMinColumn(lineNumber);\n\t\t\t} else {\n\t\t\t\tcolumn = Math.min(model.getLineMaxColumn(lineNumber), column);\n\t\t\t}\n\t\t} else if (lineNumber > lineCount) {\n\t\t\tlineNumber = lineCount;\n\t\t\tif (allowMoveOnEdgeLine) {\n\t\t\t\tcolumn = model.getLineMaxColumn(lineNumber);\n\t\t\t} else {\n\t\t\t\tcolumn = Math.min(model.getLineMaxColumn(lineNumber), column);\n\t\t\t}\n\t\t} else {\n\t\t\tcolumn = config.columnFromVisibleColumn(model, lineNumber, currentVisibleColumn);\n\t\t}\n\n\t\tif (wasAtEdgePosition) {\n\t\t\tleftoverVisibleColumns = 0;\n\t\t} else {\n\t\t\tleftoverVisibleColumns = currentVisibleColumn - CursorColumns.visibleColumnFromColumn(model.getLineContent(lineNumber), column, config.tabSize);\n\t\t}\n\n\t\tif (normalizationAffinity !== undefined) {\n\t\t\tconst position = new Position(lineNumber, column);\n\t\t\tconst newPosition = model.normalizePosition(position, normalizationAffinity);\n\t\t\tleftoverVisibleColumns = leftoverVisibleColumns + (column - newPosition.column);\n\t\t\tlineNumber = newPosition.lineNumber;\n\t\t\tcolumn = newPosition.column;\n\t\t}\n\t\treturn new CursorPosition(lineNumber, column, leftoverVisibleColumns);\n\t}\n\n\tpublic static down(config: CursorConfiguration, model: ICursorSimpleModel, lineNumber: number, column: number, leftoverVisibleColumns: number, count: number, allowMoveOnLastLine: boolean): CursorPosition {\n\t\treturn this.vertical(config, model, lineNumber, column, leftoverVisibleColumns, lineNumber + count, allowMoveOnLastLine, PositionAffinity.RightOfInjectedText);\n\t}\n\n\tpublic static moveDown(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, inSelectionMode: boolean, linesCount: number): SingleCursorState {\n\t\tlet lineNumber: number,\n\t\t\tcolumn: number;\n\n\t\tif (cursor.hasSelection() && !inSelectionMode) {\n\t\t\t// If we are in selection mode, move down acts relative to the end of selection\n\t\t\tlineNumber = cursor.selection.endLineNumber;\n\t\t\tcolumn = cursor.selection.endColumn;\n\t\t} else {\n\t\t\tlineNumber = cursor.position.lineNumber;\n\t\t\tcolumn = cursor.position.column;\n\t\t}\n\n\t\tlet i = 0;\n\t\tlet r: CursorPosition;\n\t\tdo {\n\t\t\tr = MoveOperations.down(config, model, lineNumber + i, column, cursor.leftoverVisibleColumns, linesCount, true);\n\t\t\tconst np = model.normalizePosition(new Position(r.lineNumber, r.column), PositionAffinity.None);\n\t\t\tif (np.lineNumber > lineNumber) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t} while (i++ < 10 && lineNumber + i < model.getLineCount());\n\n\t\treturn cursor.move(inSelectionMode, r.lineNumber, r.column, r.leftoverVisibleColumns);\n\t}\n\n\tpublic static translateDown(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState): SingleCursorState {\n\t\tconst selection = cursor.selection;\n\n\t\tconst selectionStart = MoveOperations.down(config, model, selection.selectionStartLineNumber, selection.selectionStartColumn, cursor.selectionStartLeftoverVisibleColumns, 1, false);\n\t\tconst position = MoveOperations.down(config, model, selection.positionLineNumber, selection.positionColumn, cursor.leftoverVisibleColumns, 1, false);\n\n\t\treturn new SingleCursorState(\n\t\t\tnew Range(selectionStart.lineNumber, selectionStart.column, selectionStart.lineNumber, selectionStart.column),\n\t\t\tSelectionStartKind.Simple,\n\t\t\tselectionStart.leftoverVisibleColumns,\n\t\t\tnew Position(position.lineNumber, position.column),\n\t\t\tposition.leftoverVisibleColumns\n\t\t);\n\t}\n\n\tpublic static up(config: CursorConfiguration, model: ICursorSimpleModel, lineNumber: number, column: number, leftoverVisibleColumns: number, count: number, allowMoveOnFirstLine: boolean): CursorPosition {\n\t\treturn this.vertical(config, model, lineNumber, column, leftoverVisibleColumns, lineNumber - count, allowMoveOnFirstLine, PositionAffinity.LeftOfInjectedText);\n\t}\n\n\tpublic static moveUp(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, inSelectionMode: boolean, linesCount: number): SingleCursorState {\n\t\tlet lineNumber: number,\n\t\t\tcolumn: number;\n\n\t\tif (cursor.hasSelection() && !inSelectionMode) {\n\t\t\t// If we are in selection mode, move up acts relative to the beginning of selection\n\t\t\tlineNumber = cursor.selection.startLineNumber;\n\t\t\tcolumn = cursor.selection.startColumn;\n\t\t} else {\n\t\t\tlineNumber = cursor.position.lineNumber;\n\t\t\tcolumn = cursor.position.column;\n\t\t}\n\n\t\tconst r = MoveOperations.up(config, model, lineNumber, column, cursor.leftoverVisibleColumns, linesCount, true);\n\n\t\treturn cursor.move(inSelectionMode, r.lineNumber, r.column, r.leftoverVisibleColumns);\n\t}\n\n\tpublic static translateUp(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState): SingleCursorState {\n\n\t\tconst selection = cursor.selection;\n\n\t\tconst selectionStart = MoveOperations.up(config, model, selection.selectionStartLineNumber, selection.selectionStartColumn, cursor.selectionStartLeftoverVisibleColumns, 1, false);\n\t\tconst position = MoveOperations.up(config, model, selection.positionLineNumber, selection.positionColumn, cursor.leftoverVisibleColumns, 1, false);\n\n\t\treturn new SingleCursorState(\n\t\t\tnew Range(selectionStart.lineNumber, selectionStart.column, selectionStart.lineNumber, selectionStart.column),\n\t\t\tSelectionStartKind.Simple,\n\t\t\tselectionStart.leftoverVisibleColumns,\n\t\t\tnew Position(position.lineNumber, position.column),\n\t\t\tposition.leftoverVisibleColumns\n\t\t);\n\t}\n\n\tprivate static _isBlankLine(model: ICursorSimpleModel, lineNumber: number): boolean {\n\t\tif (model.getLineFirstNonWhitespaceColumn(lineNumber) === 0) {\n\t\t\t// empty or contains only whitespace\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tpublic static moveToPrevBlankLine(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, inSelectionMode: boolean): SingleCursorState {\n\t\tlet lineNumber = cursor.position.lineNumber;\n\n\t\t// If our current line is blank, move to the previous non-blank line\n\t\twhile (lineNumber > 1 && this._isBlankLine(model, lineNumber)) {\n\t\t\tlineNumber--;\n\t\t}\n\n\t\t// Find the previous blank line\n\t\twhile (lineNumber > 1 && !this._isBlankLine(model, lineNumber)) {\n\t\t\tlineNumber--;\n\t\t}\n\n\t\treturn cursor.move(inSelectionMode, lineNumber, model.getLineMinColumn(lineNumber), 0);\n\t}\n\n\tpublic static moveToNextBlankLine(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, inSelectionMode: boolean): SingleCursorState {\n\t\tconst lineCount = model.getLineCount();\n\t\tlet lineNumber = cursor.position.lineNumber;\n\n\t\t// If our current line is blank, move to the next non-blank line\n\t\twhile (lineNumber < lineCount && this._isBlankLine(model, lineNumber)) {\n\t\t\tlineNumber++;\n\t\t}\n\n\t\t// Find the next blank line\n\t\twhile (lineNumber < lineCount && !this._isBlankLine(model, lineNumber)) {\n\t\t\tlineNumber++;\n\t\t}\n\n\t\treturn cursor.move(inSelectionMode, lineNumber, model.getLineMinColumn(lineNumber), 0);\n\t}\n\n\tpublic static moveToBeginningOfLine(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, inSelectionMode: boolean): SingleCursorState {\n\t\tconst lineNumber = cursor.position.lineNumber;\n\t\tconst minColumn = model.getLineMinColumn(lineNumber);\n\t\tconst firstNonBlankColumn = model.getLineFirstNonWhitespaceColumn(lineNumber) || minColumn;\n\n\t\tlet column: number;\n\n\t\tconst relevantColumnNumber = cursor.position.column;\n\t\tif (relevantColumnNumber === firstNonBlankColumn) {\n\t\t\tcolumn = minColumn;\n\t\t} else {\n\t\t\tcolumn = firstNonBlankColumn;\n\t\t}\n\n\t\treturn cursor.move(inSelectionMode, lineNumber, column, 0);\n\t}\n\n\tpublic static moveToEndOfLine(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, inSelectionMode: boolean, sticky: boolean): SingleCursorState {\n\t\tconst lineNumber = cursor.position.lineNumber;\n\t\tconst maxColumn = model.getLineMaxColumn(lineNumber);\n\t\treturn cursor.move(inSelectionMode, lineNumber, maxColumn, sticky ? Constants.MAX_SAFE_SMALL_INTEGER - maxColumn : 0);\n\t}\n\n\tpublic static moveToBeginningOfBuffer(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, inSelectionMode: boolean): SingleCursorState {\n\t\treturn cursor.move(inSelectionMode, 1, 1, 0);\n\t}\n\n\tpublic static moveToEndOfBuffer(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, inSelectionMode: boolean): SingleCursorState {\n\t\tconst lastLineNumber = model.getLineCount();\n\t\tconst lastColumn = model.getLineMaxColumn(lastLineNumber);\n\n\t\treturn cursor.move(inSelectionMode, lastLineNumber, lastColumn, 0);\n\t}\n}\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\nimport * as strings from 'vs/base/common/strings';\nimport { ReplaceCommand } from 'vs/editor/common/commands/replaceCommand';\nimport { EditorAutoClosingEditStrategy, EditorAutoClosingStrategy } from 'vs/editor/common/config/editorOptions';\nimport { CursorConfiguration, EditOperationResult, EditOperationType, ICursorSimpleModel, isQuote } from 'vs/editor/common/cursorCommon';\nimport { CursorColumns } from 'vs/editor/common/core/cursorColumns';\nimport { MoveOperations } from 'vs/editor/common/cursor/cursorMoveOperations';\nimport { Range } from 'vs/editor/common/core/range';\nimport { Selection } from 'vs/editor/common/core/selection';\nimport { ICommand } from 'vs/editor/common/editorCommon';\nimport { StandardAutoClosingPairConditional } from 'vs/editor/common/languages/languageConfiguration';\nimport { Position } from 'vs/editor/common/core/position';\n\nexport class DeleteOperations {\n\n\tpublic static deleteRight(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ICursorSimpleModel, selections: Selection[]): [boolean, Array] {\n\t\tconst commands: Array = [];\n\t\tlet shouldPushStackElementBefore = (prevEditOperationType !== EditOperationType.DeletingRight);\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\n\t\t\tconst selection = selections[i];\n\n\t\t\tlet deleteSelection: Range = selection;\n\n\t\t\tif (deleteSelection.isEmpty()) {\n\t\t\t\tconst position = selection.getPosition();\n\t\t\t\tconst rightOfPosition = MoveOperations.right(config, model, position);\n\t\t\t\tdeleteSelection = new Range(\n\t\t\t\t\trightOfPosition.lineNumber,\n\t\t\t\t\trightOfPosition.column,\n\t\t\t\t\tposition.lineNumber,\n\t\t\t\t\tposition.column\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (deleteSelection.isEmpty()) {\n\t\t\t\t// Probably at end of file => ignore\n\t\t\t\tcommands[i] = null;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (deleteSelection.startLineNumber !== deleteSelection.endLineNumber) {\n\t\t\t\tshouldPushStackElementBefore = true;\n\t\t\t}\n\n\t\t\tcommands[i] = new ReplaceCommand(deleteSelection, '');\n\t\t}\n\t\treturn [shouldPushStackElementBefore, commands];\n\t}\n\n\tpublic static isAutoClosingPairDelete(\n\t\tautoClosingDelete: EditorAutoClosingEditStrategy,\n\t\tautoClosingBrackets: EditorAutoClosingStrategy,\n\t\tautoClosingQuotes: EditorAutoClosingStrategy,\n\t\tautoClosingPairsOpen: Map,\n\t\tmodel: ICursorSimpleModel,\n\t\tselections: Selection[],\n\t\tautoClosedCharacters: Range[]\n\t): boolean {\n\t\tif (autoClosingBrackets === 'never' && autoClosingQuotes === 'never') {\n\t\t\treturn false;\n\t\t}\n\t\tif (autoClosingDelete === 'never') {\n\t\t\treturn false;\n\t\t}\n\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\n\t\t\tconst selection = selections[i];\n\t\t\tconst position = selection.getPosition();\n\n\t\t\tif (!selection.isEmpty()) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tconst lineText = model.getLineContent(position.lineNumber);\n\t\t\tif (position.column < 2 || position.column >= lineText.length + 1) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tconst character = lineText.charAt(position.column - 2);\n\n\t\t\tconst autoClosingPairCandidates = autoClosingPairsOpen.get(character);\n\t\t\tif (!autoClosingPairCandidates) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (isQuote(character)) {\n\t\t\t\tif (autoClosingQuotes === 'never') {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (autoClosingBrackets === 'never') {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst afterCharacter = lineText.charAt(position.column - 1);\n\n\t\t\tlet foundAutoClosingPair = false;\n\t\t\tfor (const autoClosingPairCandidate of autoClosingPairCandidates) {\n\t\t\t\tif (autoClosingPairCandidate.open === character && autoClosingPairCandidate.close === afterCharacter) {\n\t\t\t\t\tfoundAutoClosingPair = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!foundAutoClosingPair) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// Must delete the pair only if it was automatically inserted by the editor\n\t\t\tif (autoClosingDelete === 'auto') {\n\t\t\t\tlet found = false;\n\t\t\t\tfor (let j = 0, lenJ = autoClosedCharacters.length; j < lenJ; j++) {\n\t\t\t\t\tconst autoClosedCharacter = autoClosedCharacters[j];\n\t\t\t\t\tif (position.lineNumber === autoClosedCharacter.startLineNumber && position.column === autoClosedCharacter.startColumn) {\n\t\t\t\t\t\tfound = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (!found) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tprivate static _runAutoClosingPairDelete(config: CursorConfiguration, model: ICursorSimpleModel, selections: Selection[]): [boolean, ICommand[]] {\n\t\tconst commands: ICommand[] = [];\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\n\t\t\tconst position = selections[i].getPosition();\n\t\t\tconst deleteSelection = new Range(\n\t\t\t\tposition.lineNumber,\n\t\t\t\tposition.column - 1,\n\t\t\t\tposition.lineNumber,\n\t\t\t\tposition.column + 1\n\t\t\t);\n\t\t\tcommands[i] = new ReplaceCommand(deleteSelection, '');\n\t\t}\n\t\treturn [true, commands];\n\t}\n\n\tpublic static deleteLeft(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ICursorSimpleModel, selections: Selection[], autoClosedCharacters: Range[]): [boolean, Array] {\n\t\tif (this.isAutoClosingPairDelete(config.autoClosingDelete, config.autoClosingBrackets, config.autoClosingQuotes, config.autoClosingPairs.autoClosingPairsOpenByEnd, model, selections, autoClosedCharacters)) {\n\t\t\treturn this._runAutoClosingPairDelete(config, model, selections);\n\t\t}\n\n\t\tconst commands: Array = [];\n\t\tlet shouldPushStackElementBefore = (prevEditOperationType !== EditOperationType.DeletingLeft);\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\n\t\t\tconst deleteRange = DeleteOperations.getDeleteRange(selections[i], model, config);\n\n\t\t\t// Ignore empty delete ranges, as they have no effect\n\t\t\t// They happen if the cursor is at the beginning of the file.\n\t\t\tif (deleteRange.isEmpty()) {\n\t\t\t\tcommands[i] = null;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (deleteRange.startLineNumber !== deleteRange.endLineNumber) {\n\t\t\t\tshouldPushStackElementBefore = true;\n\t\t\t}\n\n\t\t\tcommands[i] = new ReplaceCommand(deleteRange, '');\n\t\t}\n\t\treturn [shouldPushStackElementBefore, commands];\n\n\t}\n\n\tprivate static getDeleteRange(selection: Selection, model: ICursorSimpleModel, config: CursorConfiguration,): Range {\n\t\tif (!selection.isEmpty()) {\n\t\t\treturn selection;\n\t\t}\n\n\t\tconst position = selection.getPosition();\n\n\t\t// Unintend when using tab stops and cursor is within indentation\n\t\tif (config.useTabStops && position.column > 1) {\n\t\t\tconst lineContent = model.getLineContent(position.lineNumber);\n\n\t\t\tconst firstNonWhitespaceIndex = strings.firstNonWhitespaceIndex(lineContent);\n\t\t\tconst lastIndentationColumn = (\n\t\t\t\tfirstNonWhitespaceIndex === -1\n\t\t\t\t\t? /* entire string is whitespace */ lineContent.length + 1\n\t\t\t\t\t: firstNonWhitespaceIndex + 1\n\t\t\t);\n\n\t\t\tif (position.column <= lastIndentationColumn) {\n\t\t\t\tconst fromVisibleColumn = config.visibleColumnFromColumn(model, position);\n\t\t\t\tconst toVisibleColumn = CursorColumns.prevIndentTabStop(fromVisibleColumn, config.indentSize);\n\t\t\t\tconst toColumn = config.columnFromVisibleColumn(model, position.lineNumber, toVisibleColumn);\n\t\t\t\treturn new Range(position.lineNumber, toColumn, position.lineNumber, position.column);\n\t\t\t}\n\t\t}\n\n\t\treturn Range.fromPositions(DeleteOperations.getPositionAfterDeleteLeft(position, model), position);\n\t}\n\n\tprivate static getPositionAfterDeleteLeft(position: Position, model: ICursorSimpleModel): Position {\n\t\tif (position.column > 1) {\n\t\t\t// Convert 1-based columns to 0-based offsets and back.\n\t\t\tconst idx = strings.getLeftDeleteOffset(position.column - 1, model.getLineContent(position.lineNumber));\n\t\t\treturn position.with(undefined, idx + 1);\n\t\t} else if (position.lineNumber > 1) {\n\t\t\tconst newLine = position.lineNumber - 1;\n\t\t\treturn new Position(newLine, model.getLineMaxColumn(newLine));\n\t\t} else {\n\t\t\treturn position;\n\t\t}\n\t}\n\n\tpublic static cut(config: CursorConfiguration, model: ICursorSimpleModel, selections: Selection[]): EditOperationResult {\n\t\tconst commands: Array = [];\n\t\tlet lastCutRange: Range | null = null;\n\t\tselections.sort((a, b) => Position.compare(a.getStartPosition(), b.getEndPosition()));\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\n\t\t\tconst selection = selections[i];\n\n\t\t\tif (selection.isEmpty()) {\n\t\t\t\tif (config.emptySelectionClipboard) {\n\t\t\t\t\t// This is a full line cut\n\n\t\t\t\t\tconst position = selection.getPosition();\n\n\t\t\t\t\tlet startLineNumber: number,\n\t\t\t\t\t\tstartColumn: number,\n\t\t\t\t\t\tendLineNumber: number,\n\t\t\t\t\t\tendColumn: number;\n\n\t\t\t\t\tif (position.lineNumber < model.getLineCount()) {\n\t\t\t\t\t\t// Cutting a line in the middle of the model\n\t\t\t\t\t\tstartLineNumber = position.lineNumber;\n\t\t\t\t\t\tstartColumn = 1;\n\t\t\t\t\t\tendLineNumber = position.lineNumber + 1;\n\t\t\t\t\t\tendColumn = 1;\n\t\t\t\t\t} else if (position.lineNumber > 1 && lastCutRange?.endLineNumber !== position.lineNumber) {\n\t\t\t\t\t\t// Cutting the last line & there are more than 1 lines in the model & a previous cut operation does not touch the current cut operation\n\t\t\t\t\t\tstartLineNumber = position.lineNumber - 1;\n\t\t\t\t\t\tstartColumn = model.getLineMaxColumn(position.lineNumber - 1);\n\t\t\t\t\t\tendLineNumber = position.lineNumber;\n\t\t\t\t\t\tendColumn = model.getLineMaxColumn(position.lineNumber);\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Cutting the single line that the model contains\n\t\t\t\t\t\tstartLineNumber = position.lineNumber;\n\t\t\t\t\t\tstartColumn = 1;\n\t\t\t\t\t\tendLineNumber = position.lineNumber;\n\t\t\t\t\t\tendColumn = model.getLineMaxColumn(position.lineNumber);\n\t\t\t\t\t}\n\n\t\t\t\t\tconst deleteSelection = new Range(\n\t\t\t\t\t\tstartLineNumber,\n\t\t\t\t\t\tstartColumn,\n\t\t\t\t\t\tendLineNumber,\n\t\t\t\t\t\tendColumn\n\t\t\t\t\t);\n\t\t\t\t\tlastCutRange = deleteSelection;\n\n\t\t\t\t\tif (!deleteSelection.isEmpty()) {\n\t\t\t\t\t\tcommands[i] = new ReplaceCommand(deleteSelection, '');\n\t\t\t\t\t} else {\n\t\t\t\t\t\tcommands[i] = null;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Cannot cut empty selection\n\t\t\t\t\tcommands[i] = null;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tcommands[i] = new ReplaceCommand(selection, '');\n\t\t\t}\n\t\t}\n\t\treturn new EditOperationResult(EditOperationType.Other, commands, {\n\t\t\tshouldPushStackElementBefore: true,\n\t\t\tshouldPushStackElementAfter: true\n\t\t});\n\t}\n}\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\nimport { CharCode } from 'vs/base/common/charCode';\nimport * as strings from 'vs/base/common/strings';\nimport { EditorAutoClosingEditStrategy, EditorAutoClosingStrategy } from 'vs/editor/common/config/editorOptions';\nimport { CursorConfiguration, ICursorSimpleModel, SelectionStartKind, SingleCursorState } from 'vs/editor/common/cursorCommon';\nimport { DeleteOperations } from 'vs/editor/common/cursor/cursorDeleteOperations';\nimport { WordCharacterClass, WordCharacterClassifier, IntlWordSegmentData, getMapForWordSeparators } from 'vs/editor/common/core/wordCharacterClassifier';\nimport { Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\nimport { Selection } from 'vs/editor/common/core/selection';\nimport { ITextModel } from 'vs/editor/common/model';\nimport { IWordAtPosition } from 'vs/editor/common/core/wordHelper';\nimport { AutoClosingPairs } from 'vs/editor/common/languages/languageConfiguration';\n\ninterface IFindWordResult {\n\t/**\n\t * The index where the word starts.\n\t */\n\tstart: number;\n\t/**\n\t * The index where the word ends.\n\t */\n\tend: number;\n\t/**\n\t * The word type.\n\t */\n\twordType: WordType;\n\t/**\n\t * The reason the word ended.\n\t */\n\tnextCharClass: WordCharacterClass;\n}\n\nconst enum WordType {\n\tNone = 0,\n\tRegular = 1,\n\tSeparator = 2\n}\n\nexport const enum WordNavigationType {\n\tWordStart = 0,\n\tWordStartFast = 1,\n\tWordEnd = 2,\n\tWordAccessibility = 3 // Respect chrome definition of a word\n}\n\nexport interface DeleteWordContext {\n\twordSeparators: WordCharacterClassifier;\n\tmodel: ITextModel;\n\tselection: Selection;\n\twhitespaceHeuristics: boolean;\n\tautoClosingDelete: EditorAutoClosingEditStrategy;\n\tautoClosingBrackets: EditorAutoClosingStrategy;\n\tautoClosingQuotes: EditorAutoClosingStrategy;\n\tautoClosingPairs: AutoClosingPairs;\n\tautoClosedCharacters: Range[];\n}\n\nexport class WordOperations {\n\n\tprivate static _createWord(lineContent: string, wordType: WordType, nextCharClass: WordCharacterClass, start: number, end: number): IFindWordResult {\n\t\t// console.log('WORD ==> ' + start + ' => ' + end + ':::: <<<' + lineContent.substring(start, end) + '>>>');\n\t\treturn { start: start, end: end, wordType: wordType, nextCharClass: nextCharClass };\n\t}\n\n\tprivate static _createIntlWord(intlWord: IntlWordSegmentData, nextCharClass: WordCharacterClass): IFindWordResult {\n\t\t// console.log('INTL WORD ==> ' + intlWord.index + ' => ' + intlWord.index + intlWord.segment.length + ':::: <<<' + intlWord.segment + '>>>');\n\t\treturn { start: intlWord.index, end: intlWord.index + intlWord.segment.length, wordType: WordType.Regular, nextCharClass: nextCharClass };\n\t}\n\n\tprivate static _findPreviousWordOnLine(wordSeparators: WordCharacterClassifier, model: ICursorSimpleModel, position: Position): IFindWordResult | null {\n\t\tconst lineContent = model.getLineContent(position.lineNumber);\n\t\treturn this._doFindPreviousWordOnLine(lineContent, wordSeparators, position);\n\t}\n\n\tprivate static _doFindPreviousWordOnLine(lineContent: string, wordSeparators: WordCharacterClassifier, position: Position): IFindWordResult | null {\n\t\tlet wordType = WordType.None;\n\n\t\tconst previousIntlWord = wordSeparators.findPrevIntlWordBeforeOrAtOffset(lineContent, position.column - 2);\n\n\t\tfor (let chIndex = position.column - 2; chIndex >= 0; chIndex--) {\n\t\t\tconst chCode = lineContent.charCodeAt(chIndex);\n\t\t\tconst chClass = wordSeparators.get(chCode);\n\n\t\t\tif (previousIntlWord && chIndex === previousIntlWord.index) {\n\t\t\t\treturn this._createIntlWord(previousIntlWord, chClass);\n\t\t\t}\n\n\t\t\tif (chClass === WordCharacterClass.Regular) {\n\t\t\t\tif (wordType === WordType.Separator) {\n\t\t\t\t\treturn this._createWord(lineContent, wordType, chClass, chIndex + 1, this._findEndOfWord(lineContent, wordSeparators, wordType, chIndex + 1));\n\t\t\t\t}\n\t\t\t\twordType = WordType.Regular;\n\t\t\t} else if (chClass === WordCharacterClass.WordSeparator) {\n\t\t\t\tif (wordType === WordType.Regular) {\n\t\t\t\t\treturn this._createWord(lineContent, wordType, chClass, chIndex + 1, this._findEndOfWord(lineContent, wordSeparators, wordType, chIndex + 1));\n\t\t\t\t}\n\t\t\t\twordType = WordType.Separator;\n\t\t\t} else if (chClass === WordCharacterClass.Whitespace) {\n\t\t\t\tif (wordType !== WordType.None) {\n\t\t\t\t\treturn this._createWord(lineContent, wordType, chClass, chIndex + 1, this._findEndOfWord(lineContent, wordSeparators, wordType, chIndex + 1));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (wordType !== WordType.None) {\n\t\t\treturn this._createWord(lineContent, wordType, WordCharacterClass.Whitespace, 0, this._findEndOfWord(lineContent, wordSeparators, wordType, 0));\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tprivate static _findEndOfWord(lineContent: string, wordSeparators: WordCharacterClassifier, wordType: WordType, startIndex: number): number {\n\n\t\tconst nextIntlWord = wordSeparators.findNextIntlWordAtOrAfterOffset(lineContent, startIndex);\n\n\t\tconst len = lineContent.length;\n\t\tfor (let chIndex = startIndex; chIndex < len; chIndex++) {\n\t\t\tconst chCode = lineContent.charCodeAt(chIndex);\n\t\t\tconst chClass = wordSeparators.get(chCode);\n\n\t\t\tif (nextIntlWord && chIndex === nextIntlWord.index + nextIntlWord.segment.length) {\n\t\t\t\treturn chIndex;\n\t\t\t}\n\n\t\t\tif (chClass === WordCharacterClass.Whitespace) {\n\t\t\t\treturn chIndex;\n\t\t\t}\n\t\t\tif (wordType === WordType.Regular && chClass === WordCharacterClass.WordSeparator) {\n\t\t\t\treturn chIndex;\n\t\t\t}\n\t\t\tif (wordType === WordType.Separator && chClass === WordCharacterClass.Regular) {\n\t\t\t\treturn chIndex;\n\t\t\t}\n\t\t}\n\t\treturn len;\n\t}\n\n\tprivate static _findNextWordOnLine(wordSeparators: WordCharacterClassifier, model: ICursorSimpleModel, position: Position): IFindWordResult | null {\n\t\tconst lineContent = model.getLineContent(position.lineNumber);\n\t\treturn this._doFindNextWordOnLine(lineContent, wordSeparators, position);\n\t}\n\n\tprivate static _doFindNextWordOnLine(lineContent: string, wordSeparators: WordCharacterClassifier, position: Position): IFindWordResult | null {\n\t\tlet wordType = WordType.None;\n\t\tconst len = lineContent.length;\n\n\t\tconst nextIntlWord = wordSeparators.findNextIntlWordAtOrAfterOffset(lineContent, position.column - 1);\n\n\t\tfor (let chIndex = position.column - 1; chIndex < len; chIndex++) {\n\t\t\tconst chCode = lineContent.charCodeAt(chIndex);\n\t\t\tconst chClass = wordSeparators.get(chCode);\n\n\t\t\tif (nextIntlWord && chIndex === nextIntlWord.index) {\n\t\t\t\treturn this._createIntlWord(nextIntlWord, chClass);\n\t\t\t}\n\n\t\t\tif (chClass === WordCharacterClass.Regular) {\n\t\t\t\tif (wordType === WordType.Separator) {\n\t\t\t\t\treturn this._createWord(lineContent, wordType, chClass, this._findStartOfWord(lineContent, wordSeparators, wordType, chIndex - 1), chIndex);\n\t\t\t\t}\n\t\t\t\twordType = WordType.Regular;\n\t\t\t} else if (chClass === WordCharacterClass.WordSeparator) {\n\t\t\t\tif (wordType === WordType.Regular) {\n\t\t\t\t\treturn this._createWord(lineContent, wordType, chClass, this._findStartOfWord(lineContent, wordSeparators, wordType, chIndex - 1), chIndex);\n\t\t\t\t}\n\t\t\t\twordType = WordType.Separator;\n\t\t\t} else if (chClass === WordCharacterClass.Whitespace) {\n\t\t\t\tif (wordType !== WordType.None) {\n\t\t\t\t\treturn this._createWord(lineContent, wordType, chClass, this._findStartOfWord(lineContent, wordSeparators, wordType, chIndex - 1), chIndex);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (wordType !== WordType.None) {\n\t\t\treturn this._createWord(lineContent, wordType, WordCharacterClass.Whitespace, this._findStartOfWord(lineContent, wordSeparators, wordType, len - 1), len);\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tprivate static _findStartOfWord(lineContent: string, wordSeparators: WordCharacterClassifier, wordType: WordType, startIndex: number): number {\n\n\t\tconst previousIntlWord = wordSeparators.findPrevIntlWordBeforeOrAtOffset(lineContent, startIndex);\n\n\t\tfor (let chIndex = startIndex; chIndex >= 0; chIndex--) {\n\t\t\tconst chCode = lineContent.charCodeAt(chIndex);\n\t\t\tconst chClass = wordSeparators.get(chCode);\n\n\t\t\tif (previousIntlWord && chIndex === previousIntlWord.index) {\n\t\t\t\treturn chIndex;\n\t\t\t}\n\n\t\t\tif (chClass === WordCharacterClass.Whitespace) {\n\t\t\t\treturn chIndex + 1;\n\t\t\t}\n\t\t\tif (wordType === WordType.Regular && chClass === WordCharacterClass.WordSeparator) {\n\t\t\t\treturn chIndex + 1;\n\t\t\t}\n\t\t\tif (wordType === WordType.Separator && chClass === WordCharacterClass.Regular) {\n\t\t\t\treturn chIndex + 1;\n\t\t\t}\n\t\t}\n\t\treturn 0;\n\t}\n\n\tpublic static moveWordLeft(wordSeparators: WordCharacterClassifier, model: ICursorSimpleModel, position: Position, wordNavigationType: WordNavigationType): Position {\n\t\tlet lineNumber = position.lineNumber;\n\t\tlet column = position.column;\n\n\t\tif (column === 1) {\n\t\t\tif (lineNumber > 1) {\n\t\t\t\tlineNumber = lineNumber - 1;\n\t\t\t\tcolumn = model.getLineMaxColumn(lineNumber);\n\t\t\t}\n\t\t}\n\n\t\tlet prevWordOnLine = WordOperations._findPreviousWordOnLine(wordSeparators, model, new Position(lineNumber, column));\n\n\t\tif (wordNavigationType === WordNavigationType.WordStart) {\n\t\t\treturn new Position(lineNumber, prevWordOnLine ? prevWordOnLine.start + 1 : 1);\n\t\t}\n\n\t\tif (wordNavigationType === WordNavigationType.WordStartFast) {\n\t\t\tif (\n\t\t\t\tprevWordOnLine\n\t\t\t\t&& prevWordOnLine.wordType === WordType.Separator\n\t\t\t\t&& prevWordOnLine.end - prevWordOnLine.start === 1\n\t\t\t\t&& prevWordOnLine.nextCharClass === WordCharacterClass.Regular\n\t\t\t) {\n\t\t\t\t// Skip over a word made up of one single separator and followed by a regular character\n\t\t\t\tprevWordOnLine = WordOperations._findPreviousWordOnLine(wordSeparators, model, new Position(lineNumber, prevWordOnLine.start + 1));\n\t\t\t}\n\n\t\t\treturn new Position(lineNumber, prevWordOnLine ? prevWordOnLine.start + 1 : 1);\n\t\t}\n\n\t\tif (wordNavigationType === WordNavigationType.WordAccessibility) {\n\t\t\twhile (\n\t\t\t\tprevWordOnLine\n\t\t\t\t&& prevWordOnLine.wordType === WordType.Separator\n\t\t\t) {\n\t\t\t\t// Skip over words made up of only separators\n\t\t\t\tprevWordOnLine = WordOperations._findPreviousWordOnLine(wordSeparators, model, new Position(lineNumber, prevWordOnLine.start + 1));\n\t\t\t}\n\n\t\t\treturn new Position(lineNumber, prevWordOnLine ? prevWordOnLine.start + 1 : 1);\n\t\t}\n\n\t\t// We are stopping at the ending of words\n\n\t\tif (prevWordOnLine && column <= prevWordOnLine.end + 1) {\n\t\t\tprevWordOnLine = WordOperations._findPreviousWordOnLine(wordSeparators, model, new Position(lineNumber, prevWordOnLine.start + 1));\n\t\t}\n\n\t\treturn new Position(lineNumber, prevWordOnLine ? prevWordOnLine.end + 1 : 1);\n\t}\n\n\tpublic static _moveWordPartLeft(model: ICursorSimpleModel, position: Position): Position {\n\t\tconst lineNumber = position.lineNumber;\n\t\tconst maxColumn = model.getLineMaxColumn(lineNumber);\n\n\t\tif (position.column === 1) {\n\t\t\treturn (lineNumber > 1 ? new Position(lineNumber - 1, model.getLineMaxColumn(lineNumber - 1)) : position);\n\t\t}\n\n\t\tconst lineContent = model.getLineContent(lineNumber);\n\t\tfor (let column = position.column - 1; column > 1; column--) {\n\t\t\tconst left = lineContent.charCodeAt(column - 2);\n\t\t\tconst right = lineContent.charCodeAt(column - 1);\n\n\t\t\tif (left === CharCode.Underline && right !== CharCode.Underline) {\n\t\t\t\t// snake_case_variables\n\t\t\t\treturn new Position(lineNumber, column);\n\t\t\t}\n\n\t\t\tif (left === CharCode.Dash && right !== CharCode.Dash) {\n\t\t\t\t// kebab-case-variables\n\t\t\t\treturn new Position(lineNumber, column);\n\t\t\t}\n\n\t\t\tif ((strings.isLowerAsciiLetter(left) || strings.isAsciiDigit(left)) && strings.isUpperAsciiLetter(right)) {\n\t\t\t\t// camelCaseVariables\n\t\t\t\treturn new Position(lineNumber, column);\n\t\t\t}\n\n\t\t\tif (strings.isUpperAsciiLetter(left) && strings.isUpperAsciiLetter(right)) {\n\t\t\t\t// thisIsACamelCaseWithOneLetterWords\n\t\t\t\tif (column + 1 < maxColumn) {\n\t\t\t\t\tconst rightRight = lineContent.charCodeAt(column);\n\t\t\t\t\tif (strings.isLowerAsciiLetter(rightRight) || strings.isAsciiDigit(rightRight)) {\n\t\t\t\t\t\treturn new Position(lineNumber, column);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn new Position(lineNumber, 1);\n\t}\n\n\tpublic static moveWordRight(wordSeparators: WordCharacterClassifier, model: ICursorSimpleModel, position: Position, wordNavigationType: WordNavigationType): Position {\n\t\tlet lineNumber = position.lineNumber;\n\t\tlet column = position.column;\n\n\t\tlet movedDown = false;\n\t\tif (column === model.getLineMaxColumn(lineNumber)) {\n\t\t\tif (lineNumber < model.getLineCount()) {\n\t\t\t\tmovedDown = true;\n\t\t\t\tlineNumber = lineNumber + 1;\n\t\t\t\tcolumn = 1;\n\t\t\t}\n\t\t}\n\n\t\tlet nextWordOnLine = WordOperations._findNextWordOnLine(wordSeparators, model, new Position(lineNumber, column));\n\n\t\tif (wordNavigationType === WordNavigationType.WordEnd) {\n\t\t\tif (nextWordOnLine && nextWordOnLine.wordType === WordType.Separator) {\n\t\t\t\tif (nextWordOnLine.end - nextWordOnLine.start === 1 && nextWordOnLine.nextCharClass === WordCharacterClass.Regular) {\n\t\t\t\t\t// Skip over a word made up of one single separator and followed by a regular character\n\t\t\t\t\tnextWordOnLine = WordOperations._findNextWordOnLine(wordSeparators, model, new Position(lineNumber, nextWordOnLine.end + 1));\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (nextWordOnLine) {\n\t\t\t\tcolumn = nextWordOnLine.end + 1;\n\t\t\t} else {\n\t\t\t\tcolumn = model.getLineMaxColumn(lineNumber);\n\t\t\t}\n\t\t} else if (wordNavigationType === WordNavigationType.WordAccessibility) {\n\t\t\tif (movedDown) {\n\t\t\t\t// If we move to the next line, pretend that the cursor is right before the first character.\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,\n\t\t\t\t// we need to start before.\n\t\t\t\tcolumn = 0;\n\t\t\t}\n\n\t\t\twhile (\n\t\t\t\tnextWordOnLine\n\t\t\t\t&& (nextWordOnLine.wordType === WordType.Separator\n\t\t\t\t\t|| nextWordOnLine.start + 1 <= column\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\t// Skip over a word made up of one single separator\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.\n\t\t\t\tnextWordOnLine = WordOperations._findNextWordOnLine(wordSeparators, model, new Position(lineNumber, nextWordOnLine.end + 1));\n\t\t\t}\n\n\t\t\tif (nextWordOnLine) {\n\t\t\t\tcolumn = nextWordOnLine.start + 1;\n\t\t\t} else {\n\t\t\t\tcolumn = model.getLineMaxColumn(lineNumber);\n\t\t\t}\n\t\t} else {\n\t\t\tif (nextWordOnLine && !movedDown && column >= nextWordOnLine.start + 1) {\n\t\t\t\tnextWordOnLine = WordOperations._findNextWordOnLine(wordSeparators, model, new Position(lineNumber, nextWordOnLine.end + 1));\n\t\t\t}\n\t\t\tif (nextWordOnLine) {\n\t\t\t\tcolumn = nextWordOnLine.start + 1;\n\t\t\t} else {\n\t\t\t\tcolumn = model.getLineMaxColumn(lineNumber);\n\t\t\t}\n\t\t}\n\n\t\treturn new Position(lineNumber, column);\n\t}\n\n\tpublic static _moveWordPartRight(model: ICursorSimpleModel, position: Position): Position {\n\t\tconst lineNumber = position.lineNumber;\n\t\tconst maxColumn = model.getLineMaxColumn(lineNumber);\n\n\t\tif (position.column === maxColumn) {\n\t\t\treturn (lineNumber < model.getLineCount() ? new Position(lineNumber + 1, 1) : position);\n\t\t}\n\n\t\tconst lineContent = model.getLineContent(lineNumber);\n\t\tfor (let column = position.column + 1; column < maxColumn; column++) {\n\t\t\tconst left = lineContent.charCodeAt(column - 2);\n\t\t\tconst right = lineContent.charCodeAt(column - 1);\n\n\t\t\tif (left !== CharCode.Underline && right === CharCode.Underline) {\n\t\t\t\t// snake_case_variables\n\t\t\t\treturn new Position(lineNumber, column);\n\t\t\t}\n\n\t\t\tif (left !== CharCode.Dash && right === CharCode.Dash) {\n\t\t\t\t// kebab-case-variables\n\t\t\t\treturn new Position(lineNumber, column);\n\t\t\t}\n\n\t\t\tif ((strings.isLowerAsciiLetter(left) || strings.isAsciiDigit(left)) && strings.isUpperAsciiLetter(right)) {\n\t\t\t\t// camelCaseVariables\n\t\t\t\treturn new Position(lineNumber, column);\n\t\t\t}\n\n\t\t\tif (strings.isUpperAsciiLetter(left) && strings.isUpperAsciiLetter(right)) {\n\t\t\t\t// thisIsACamelCaseWithOneLetterWords\n\t\t\t\tif (column + 1 < maxColumn) {\n\t\t\t\t\tconst rightRight = lineContent.charCodeAt(column);\n\t\t\t\t\tif (strings.isLowerAsciiLetter(rightRight) || strings.isAsciiDigit(rightRight)) {\n\t\t\t\t\t\treturn new Position(lineNumber, column);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn new Position(lineNumber, maxColumn);\n\t}\n\n\tprotected static _deleteWordLeftWhitespace(model: ICursorSimpleModel, position: Position): Range | null {\n\t\tconst lineContent = model.getLineContent(position.lineNumber);\n\t\tconst startIndex = position.column - 2;\n\t\tconst lastNonWhitespace = strings.lastNonWhitespaceIndex(lineContent, startIndex);\n\t\tif (lastNonWhitespace + 1 < startIndex) {\n\t\t\treturn new Range(position.lineNumber, lastNonWhitespace + 2, position.lineNumber, position.column);\n\t\t}\n\t\treturn null;\n\t}\n\n\tpublic static deleteWordLeft(ctx: DeleteWordContext, wordNavigationType: WordNavigationType): Range | null {\n\t\tconst wordSeparators = ctx.wordSeparators;\n\t\tconst model = ctx.model;\n\t\tconst selection = ctx.selection;\n\t\tconst whitespaceHeuristics = ctx.whitespaceHeuristics;\n\n\t\tif (!selection.isEmpty()) {\n\t\t\treturn selection;\n\t\t}\n\n\t\tif (DeleteOperations.isAutoClosingPairDelete(ctx.autoClosingDelete, ctx.autoClosingBrackets, ctx.autoClosingQuotes, ctx.autoClosingPairs.autoClosingPairsOpenByEnd, ctx.model, [ctx.selection], ctx.autoClosedCharacters)) {\n\t\t\tconst position = ctx.selection.getPosition();\n\t\t\treturn new Range(position.lineNumber, position.column - 1, position.lineNumber, position.column + 1);\n\t\t}\n\n\t\tconst position = new Position(selection.positionLineNumber, selection.positionColumn);\n\n\t\tlet lineNumber = position.lineNumber;\n\t\tlet column = position.column;\n\n\t\tif (lineNumber === 1 && column === 1) {\n\t\t\t// Ignore deleting at beginning of file\n\t\t\treturn null;\n\t\t}\n\n\t\tif (whitespaceHeuristics) {\n\t\t\tconst r = this._deleteWordLeftWhitespace(model, position);\n\t\t\tif (r) {\n\t\t\t\treturn r;\n\t\t\t}\n\t\t}\n\n\t\tlet prevWordOnLine = WordOperations._findPreviousWordOnLine(wordSeparators, model, position);\n\n\t\tif (wordNavigationType === WordNavigationType.WordStart) {\n\t\t\tif (prevWordOnLine) {\n\t\t\t\tcolumn = prevWordOnLine.start + 1;\n\t\t\t} else {\n\t\t\t\tif (column > 1) {\n\t\t\t\t\tcolumn = 1;\n\t\t\t\t} else {\n\t\t\t\t\tlineNumber--;\n\t\t\t\t\tcolumn = model.getLineMaxColumn(lineNumber);\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tif (prevWordOnLine && column <= prevWordOnLine.end + 1) {\n\t\t\t\tprevWordOnLine = WordOperations._findPreviousWordOnLine(wordSeparators, model, new Position(lineNumber, prevWordOnLine.start + 1));\n\t\t\t}\n\t\t\tif (prevWordOnLine) {\n\t\t\t\tcolumn = prevWordOnLine.end + 1;\n\t\t\t} else {\n\t\t\t\tif (column > 1) {\n\t\t\t\t\tcolumn = 1;\n\t\t\t\t} else {\n\t\t\t\t\tlineNumber--;\n\t\t\t\t\tcolumn = model.getLineMaxColumn(lineNumber);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn new Range(lineNumber, column, position.lineNumber, position.column);\n\t}\n\n\tpublic static deleteInsideWord(wordSeparators: WordCharacterClassifier, model: ITextModel, selection: Selection): Range {\n\t\tif (!selection.isEmpty()) {\n\t\t\treturn selection;\n\t\t}\n\n\t\tconst position = new Position(selection.positionLineNumber, selection.positionColumn);\n\n\t\tconst r = this._deleteInsideWordWhitespace(model, position);\n\t\tif (r) {\n\t\t\treturn r;\n\t\t}\n\n\t\treturn this._deleteInsideWordDetermineDeleteRange(wordSeparators, model, position);\n\t}\n\n\tprivate static _charAtIsWhitespace(str: string, index: number): boolean {\n\t\tconst charCode = str.charCodeAt(index);\n\t\treturn (charCode === CharCode.Space || charCode === CharCode.Tab);\n\t}\n\n\tprivate static _deleteInsideWordWhitespace(model: ICursorSimpleModel, position: Position): Range | null {\n\t\tconst lineContent = model.getLineContent(position.lineNumber);\n\t\tconst lineContentLength = lineContent.length;\n\n\t\tif (lineContentLength === 0) {\n\t\t\t// empty line\n\t\t\treturn null;\n\t\t}\n\n\t\tlet leftIndex = Math.max(position.column - 2, 0);\n\t\tif (!this._charAtIsWhitespace(lineContent, leftIndex)) {\n\t\t\t// touches a non-whitespace character to the left\n\t\t\treturn null;\n\t\t}\n\n\t\tlet rightIndex = Math.min(position.column - 1, lineContentLength - 1);\n\t\tif (!this._charAtIsWhitespace(lineContent, rightIndex)) {\n\t\t\t// touches a non-whitespace character to the right\n\t\t\treturn null;\n\t\t}\n\n\t\t// walk over whitespace to the left\n\t\twhile (leftIndex > 0 && this._charAtIsWhitespace(lineContent, leftIndex - 1)) {\n\t\t\tleftIndex--;\n\t\t}\n\n\t\t// walk over whitespace to the right\n\t\twhile (rightIndex + 1 < lineContentLength && this._charAtIsWhitespace(lineContent, rightIndex + 1)) {\n\t\t\trightIndex++;\n\t\t}\n\n\t\treturn new Range(position.lineNumber, leftIndex + 1, position.lineNumber, rightIndex + 2);\n\t}\n\n\tprivate static _deleteInsideWordDetermineDeleteRange(wordSeparators: WordCharacterClassifier, model: ICursorSimpleModel, position: Position): Range {\n\t\tconst lineContent = model.getLineContent(position.lineNumber);\n\t\tconst lineLength = lineContent.length;\n\t\tif (lineLength === 0) {\n\t\t\t// empty line\n\t\t\tif (position.lineNumber > 1) {\n\t\t\t\treturn new Range(position.lineNumber - 1, model.getLineMaxColumn(position.lineNumber - 1), position.lineNumber, 1);\n\t\t\t} else {\n\t\t\t\tif (position.lineNumber < model.getLineCount()) {\n\t\t\t\t\treturn new Range(position.lineNumber, 1, position.lineNumber + 1, 1);\n\t\t\t\t} else {\n\t\t\t\t\t// empty model\n\t\t\t\t\treturn new Range(position.lineNumber, 1, position.lineNumber, 1);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst touchesWord = (word: IFindWordResult) => {\n\t\t\treturn (word.start + 1 <= position.column && position.column <= word.end + 1);\n\t\t};\n\t\tconst createRangeWithPosition = (startColumn: number, endColumn: number) => {\n\t\t\tstartColumn = Math.min(startColumn, position.column);\n\t\t\tendColumn = Math.max(endColumn, position.column);\n\t\t\treturn new Range(position.lineNumber, startColumn, position.lineNumber, endColumn);\n\t\t};\n\t\tconst deleteWordAndAdjacentWhitespace = (word: IFindWordResult) => {\n\t\t\tlet startColumn = word.start + 1;\n\t\t\tlet endColumn = word.end + 1;\n\t\t\tlet expandedToTheRight = false;\n\t\t\twhile (endColumn - 1 < lineLength && this._charAtIsWhitespace(lineContent, endColumn - 1)) {\n\t\t\t\texpandedToTheRight = true;\n\t\t\t\tendColumn++;\n\t\t\t}\n\t\t\tif (!expandedToTheRight) {\n\t\t\t\twhile (startColumn > 1 && this._charAtIsWhitespace(lineContent, startColumn - 2)) {\n\t\t\t\t\tstartColumn--;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn createRangeWithPosition(startColumn, endColumn);\n\t\t};\n\n\t\tconst prevWordOnLine = WordOperations._findPreviousWordOnLine(wordSeparators, model, position);\n\t\tif (prevWordOnLine && touchesWord(prevWordOnLine)) {\n\t\t\treturn deleteWordAndAdjacentWhitespace(prevWordOnLine);\n\t\t}\n\t\tconst nextWordOnLine = WordOperations._findNextWordOnLine(wordSeparators, model, position);\n\t\tif (nextWordOnLine && touchesWord(nextWordOnLine)) {\n\t\t\treturn deleteWordAndAdjacentWhitespace(nextWordOnLine);\n\t\t}\n\t\tif (prevWordOnLine && nextWordOnLine) {\n\t\t\treturn createRangeWithPosition(prevWordOnLine.end + 1, nextWordOnLine.start + 1);\n\t\t}\n\t\tif (prevWordOnLine) {\n\t\t\treturn createRangeWithPosition(prevWordOnLine.start + 1, prevWordOnLine.end + 1);\n\t\t}\n\t\tif (nextWordOnLine) {\n\t\t\treturn createRangeWithPosition(nextWordOnLine.start + 1, nextWordOnLine.end + 1);\n\t\t}\n\n\t\treturn createRangeWithPosition(1, lineLength + 1);\n\t}\n\n\tpublic static _deleteWordPartLeft(model: ICursorSimpleModel, selection: Selection): Range {\n\t\tif (!selection.isEmpty()) {\n\t\t\treturn selection;\n\t\t}\n\n\t\tconst pos = selection.getPosition();\n\t\tconst toPosition = WordOperations._moveWordPartLeft(model, pos);\n\t\treturn new Range(pos.lineNumber, pos.column, toPosition.lineNumber, toPosition.column);\n\t}\n\n\tprivate static _findFirstNonWhitespaceChar(str: string, startIndex: number): number {\n\t\tconst len = str.length;\n\t\tfor (let chIndex = startIndex; chIndex < len; chIndex++) {\n\t\t\tconst ch = str.charAt(chIndex);\n\t\t\tif (ch !== ' ' && ch !== '\\t') {\n\t\t\t\treturn chIndex;\n\t\t\t}\n\t\t}\n\t\treturn len;\n\t}\n\n\tprotected static _deleteWordRightWhitespace(model: ICursorSimpleModel, position: Position): Range | null {\n\t\tconst lineContent = model.getLineContent(position.lineNumber);\n\t\tconst startIndex = position.column - 1;\n\t\tconst firstNonWhitespace = this._findFirstNonWhitespaceChar(lineContent, startIndex);\n\t\tif (startIndex + 1 < firstNonWhitespace) {\n\t\t\t// bingo\n\t\t\treturn new Range(position.lineNumber, position.column, position.lineNumber, firstNonWhitespace + 1);\n\t\t}\n\t\treturn null;\n\t}\n\n\tpublic static deleteWordRight(ctx: DeleteWordContext, wordNavigationType: WordNavigationType): Range | null {\n\t\tconst wordSeparators = ctx.wordSeparators;\n\t\tconst model = ctx.model;\n\t\tconst selection = ctx.selection;\n\t\tconst whitespaceHeuristics = ctx.whitespaceHeuristics;\n\n\t\tif (!selection.isEmpty()) {\n\t\t\treturn selection;\n\t\t}\n\n\t\tconst position = new Position(selection.positionLineNumber, selection.positionColumn);\n\n\t\tlet lineNumber = position.lineNumber;\n\t\tlet column = position.column;\n\n\t\tconst lineCount = model.getLineCount();\n\t\tconst maxColumn = model.getLineMaxColumn(lineNumber);\n\t\tif (lineNumber === lineCount && column === maxColumn) {\n\t\t\t// Ignore deleting at end of file\n\t\t\treturn null;\n\t\t}\n\n\t\tif (whitespaceHeuristics) {\n\t\t\tconst r = this._deleteWordRightWhitespace(model, position);\n\t\t\tif (r) {\n\t\t\t\treturn r;\n\t\t\t}\n\t\t}\n\n\t\tlet nextWordOnLine = WordOperations._findNextWordOnLine(wordSeparators, model, position);\n\n\t\tif (wordNavigationType === WordNavigationType.WordEnd) {\n\t\t\tif (nextWordOnLine) {\n\t\t\t\tcolumn = nextWordOnLine.end + 1;\n\t\t\t} else {\n\t\t\t\tif (column < maxColumn || lineNumber === lineCount) {\n\t\t\t\t\tcolumn = maxColumn;\n\t\t\t\t} else {\n\t\t\t\t\tlineNumber++;\n\t\t\t\t\tnextWordOnLine = WordOperations._findNextWordOnLine(wordSeparators, model, new Position(lineNumber, 1));\n\t\t\t\t\tif (nextWordOnLine) {\n\t\t\t\t\t\tcolumn = nextWordOnLine.start + 1;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tcolumn = model.getLineMaxColumn(lineNumber);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tif (nextWordOnLine && column >= nextWordOnLine.start + 1) {\n\t\t\t\tnextWordOnLine = WordOperations._findNextWordOnLine(wordSeparators, model, new Position(lineNumber, nextWordOnLine.end + 1));\n\t\t\t}\n\t\t\tif (nextWordOnLine) {\n\t\t\t\tcolumn = nextWordOnLine.start + 1;\n\t\t\t} else {\n\t\t\t\tif (column < maxColumn || lineNumber === lineCount) {\n\t\t\t\t\tcolumn = maxColumn;\n\t\t\t\t} else {\n\t\t\t\t\tlineNumber++;\n\t\t\t\t\tnextWordOnLine = WordOperations._findNextWordOnLine(wordSeparators, model, new Position(lineNumber, 1));\n\t\t\t\t\tif (nextWordOnLine) {\n\t\t\t\t\t\tcolumn = nextWordOnLine.start + 1;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tcolumn = model.getLineMaxColumn(lineNumber);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn new Range(lineNumber, column, position.lineNumber, position.column);\n\t}\n\n\tpublic static _deleteWordPartRight(model: ICursorSimpleModel, selection: Selection): Range {\n\t\tif (!selection.isEmpty()) {\n\t\t\treturn selection;\n\t\t}\n\n\t\tconst pos = selection.getPosition();\n\t\tconst toPosition = WordOperations._moveWordPartRight(model, pos);\n\t\treturn new Range(pos.lineNumber, pos.column, toPosition.lineNumber, toPosition.column);\n\t}\n\n\tprivate static _createWordAtPosition(model: ITextModel, lineNumber: number, word: IFindWordResult): IWordAtPosition {\n\t\tconst range = new Range(lineNumber, word.start + 1, lineNumber, word.end + 1);\n\t\treturn {\n\t\t\tword: model.getValueInRange(range),\n\t\t\tstartColumn: range.startColumn,\n\t\t\tendColumn: range.endColumn\n\t\t};\n\t}\n\n\tpublic static getWordAtPosition(model: ITextModel, _wordSeparators: string, _intlSegmenterLocales: string[], position: Position): IWordAtPosition | null {\n\t\tconst wordSeparators = getMapForWordSeparators(_wordSeparators, _intlSegmenterLocales);\n\t\tconst prevWord = WordOperations._findPreviousWordOnLine(wordSeparators, model, position);\n\t\tif (prevWord && prevWord.wordType === WordType.Regular && prevWord.start <= position.column - 1 && position.column - 1 <= prevWord.end) {\n\t\t\treturn WordOperations._createWordAtPosition(model, position.lineNumber, prevWord);\n\t\t}\n\t\tconst nextWord = WordOperations._findNextWordOnLine(wordSeparators, model, position);\n\t\tif (nextWord && nextWord.wordType === WordType.Regular && nextWord.start <= position.column - 1 && position.column - 1 <= nextWord.end) {\n\t\t\treturn WordOperations._createWordAtPosition(model, position.lineNumber, nextWord);\n\t\t}\n\t\treturn null;\n\t}\n\n\tpublic static word(config: CursorConfiguration, model: ICursorSimpleModel, cursor: SingleCursorState, inSelectionMode: boolean, position: Position): SingleCursorState {\n\t\tconst wordSeparators = getMapForWordSeparators(config.wordSeparators, config.wordSegmenterLocales);\n\t\tconst prevWord = WordOperations._findPreviousWordOnLine(wordSeparators, model, position);\n\t\tconst nextWord = WordOperations._findNextWordOnLine(wordSeparators, model, position);\n\n\t\tif (!inSelectionMode) {\n\t\t\t// Entering word selection for the first time\n\t\t\tlet startColumn: number;\n\t\t\tlet endColumn: number;\n\n\t\t\tif (prevWord && prevWord.wordType === WordType.Regular && prevWord.start <= position.column - 1 && position.column - 1 <= prevWord.end) {\n\t\t\t\t// isTouchingPrevWord\n\t\t\t\tstartColumn = prevWord.start + 1;\n\t\t\t\tendColumn = prevWord.end + 1;\n\t\t\t} else if (nextWord && nextWord.wordType === WordType.Regular && nextWord.start <= position.column - 1 && position.column - 1 <= nextWord.end) {\n\t\t\t\t// isTouchingNextWord\n\t\t\t\tstartColumn = nextWord.start + 1;\n\t\t\t\tendColumn = nextWord.end + 1;\n\t\t\t} else {\n\t\t\t\tif (prevWord) {\n\t\t\t\t\tstartColumn = prevWord.end + 1;\n\t\t\t\t} else {\n\t\t\t\t\tstartColumn = 1;\n\t\t\t\t}\n\t\t\t\tif (nextWord) {\n\t\t\t\t\tendColumn = nextWord.start + 1;\n\t\t\t\t} else {\n\t\t\t\t\tendColumn = model.getLineMaxColumn(position.lineNumber);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn new SingleCursorState(\n\t\t\t\tnew Range(position.lineNumber, startColumn, position.lineNumber, endColumn), SelectionStartKind.Word, 0,\n\t\t\t\tnew Position(position.lineNumber, endColumn), 0\n\t\t\t);\n\t\t}\n\n\t\tlet startColumn: number;\n\t\tlet endColumn: number;\n\n\t\tif (prevWord && prevWord.wordType === WordType.Regular && prevWord.start < position.column - 1 && position.column - 1 < prevWord.end) {\n\t\t\t// isInsidePrevWord\n\t\t\tstartColumn = prevWord.start + 1;\n\t\t\tendColumn = prevWord.end + 1;\n\t\t} else if (nextWord && nextWord.wordType === WordType.Regular && nextWord.start < position.column - 1 && position.column - 1 < nextWord.end) {\n\t\t\t// isInsideNextWord\n\t\t\tstartColumn = nextWord.start + 1;\n\t\t\tendColumn = nextWord.end + 1;\n\t\t} else {\n\t\t\tstartColumn = position.column;\n\t\t\tendColumn = position.column;\n\t\t}\n\n\t\tconst lineNumber = position.lineNumber;\n\t\tlet column: number;\n\t\tif (cursor.selectionStart.containsPosition(position)) {\n\t\t\tcolumn = cursor.selectionStart.endColumn;\n\t\t} else if (position.isBeforeOrEqual(cursor.selectionStart.getStartPosition())) {\n\t\t\tcolumn = startColumn;\n\t\t\tconst possiblePosition = new Position(lineNumber, column);\n\t\t\tif (cursor.selectionStart.containsPosition(possiblePosition)) {\n\t\t\t\tcolumn = cursor.selectionStart.endColumn;\n\t\t\t}\n\t\t} else {\n\t\t\tcolumn = endColumn;\n\t\t\tconst possiblePosition = new Position(lineNumber, column);\n\t\t\tif (cursor.selectionStart.containsPosition(possiblePosition)) {\n\t\t\t\tcolumn = cursor.selectionStart.startColumn;\n\t\t\t}\n\t\t}\n\n\t\treturn cursor.move(true, lineNumber, column, 0);\n\t}\n}\n\nexport class WordPartOperations extends WordOperations {\n\tpublic static deleteWordPartLeft(ctx: DeleteWordContext): Range {\n\t\tconst candidates = enforceDefined([\n\t\t\tWordOperations.deleteWordLeft(ctx, WordNavigationType.WordStart),\n\t\t\tWordOperations.deleteWordLeft(ctx, WordNavigationType.WordEnd),\n\t\t\tWordOperations._deleteWordPartLeft(ctx.model, ctx.selection)\n\t\t]);\n\t\tcandidates.sort(Range.compareRangesUsingEnds);\n\t\treturn candidates[2];\n\t}\n\n\tpublic static deleteWordPartRight(ctx: DeleteWordContext): Range {\n\t\tconst candidates = enforceDefined([\n\t\t\tWordOperations.deleteWordRight(ctx, WordNavigationType.WordStart),\n\t\t\tWordOperations.deleteWordRight(ctx, WordNavigationType.WordEnd),\n\t\t\tWordOperations._deleteWordPartRight(ctx.model, ctx.selection)\n\t\t]);\n\t\tcandidates.sort(Range.compareRangesUsingStarts);\n\t\treturn candidates[0];\n\t}\n\n\tpublic static moveWordPartLeft(wordSeparators: WordCharacterClassifier, model: ICursorSimpleModel, position: Position): Position {\n\t\tconst candidates = enforceDefined([\n\t\t\tWordOperations.moveWordLeft(wordSeparators, model, position, WordNavigationType.WordStart),\n\t\t\tWordOperations.moveWordLeft(wordSeparators, model, position, WordNavigationType.WordEnd),\n\t\t\tWordOperations._moveWordPartLeft(model, position)\n\t\t]);\n\t\tcandidates.sort(Position.compare);\n\t\treturn candidates[2];\n\t}\n\n\tpublic static moveWordPartRight(wordSeparators: WordCharacterClassifier, model: ICursorSimpleModel, position: Position): Position {\n\t\tconst candidates = enforceDefined([\n\t\t\tWordOperations.moveWordRight(wordSeparators, model, position, WordNavigationType.WordStart),\n\t\t\tWordOperations.moveWordRight(wordSeparators, model, position, WordNavigationType.WordEnd),\n\t\t\tWordOperations._moveWordPartRight(model, position)\n\t\t]);\n\t\tcandidates.sort(Position.compare);\n\t\treturn candidates[0];\n\t}\n}\n\nfunction enforceDefined(arr: Array): T[] {\n\treturn arr.filter(el => Boolean(el));\n}\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\nimport * as types from 'vs/base/common/types';\nimport { CursorState, ICursorSimpleModel, PartialCursorState, SelectionStartKind, SingleCursorState } from 'vs/editor/common/cursorCommon';\nimport { MoveOperations } from 'vs/editor/common/cursor/cursorMoveOperations';\nimport { WordOperations } from 'vs/editor/common/cursor/cursorWordOperations';\nimport { IPosition, Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\nimport { ICommandMetadata } from 'vs/platform/commands/common/commands';\nimport { IViewModel } from 'vs/editor/common/viewModel';\n\nexport class CursorMoveCommands {\n\n\tpublic static addCursorDown(viewModel: IViewModel, cursors: CursorState[], useLogicalLine: boolean): PartialCursorState[] {\n\t\tconst result: PartialCursorState[] = [];\n\t\tlet resultLen = 0;\n\t\tfor (let i = 0, len = cursors.length; i < len; i++) {\n\t\t\tconst cursor = cursors[i];\n\t\t\tresult[resultLen++] = new CursorState(cursor.modelState, cursor.viewState);\n\t\t\tif (useLogicalLine) {\n\t\t\t\tresult[resultLen++] = CursorState.fromModelState(MoveOperations.translateDown(viewModel.cursorConfig, viewModel.model, cursor.modelState));\n\t\t\t} else {\n\t\t\t\tresult[resultLen++] = CursorState.fromViewState(MoveOperations.translateDown(viewModel.cursorConfig, viewModel, cursor.viewState));\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tpublic static addCursorUp(viewModel: IViewModel, cursors: CursorState[], useLogicalLine: boolean): PartialCursorState[] {\n\t\tconst result: PartialCursorState[] = [];\n\t\tlet resultLen = 0;\n\t\tfor (let i = 0, len = cursors.length; i < len; i++) {\n\t\t\tconst cursor = cursors[i];\n\t\t\tresult[resultLen++] = new CursorState(cursor.modelState, cursor.viewState);\n\t\t\tif (useLogicalLine) {\n\t\t\t\tresult[resultLen++] = CursorState.fromModelState(MoveOperations.translateUp(viewModel.cursorConfig, viewModel.model, cursor.modelState));\n\t\t\t} else {\n\t\t\t\tresult[resultLen++] = CursorState.fromViewState(MoveOperations.translateUp(viewModel.cursorConfig, viewModel, cursor.viewState));\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tpublic static moveToBeginningOfLine(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean): PartialCursorState[] {\n\t\tconst result: PartialCursorState[] = [];\n\t\tfor (let i = 0, len = cursors.length; i < len; i++) {\n\t\t\tconst cursor = cursors[i];\n\t\t\tresult[i] = this._moveToLineStart(viewModel, cursor, inSelectionMode);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tprivate static _moveToLineStart(viewModel: IViewModel, cursor: CursorState, inSelectionMode: boolean): PartialCursorState {\n\t\tconst currentViewStateColumn = cursor.viewState.position.column;\n\t\tconst currentModelStateColumn = cursor.modelState.position.column;\n\t\tconst isFirstLineOfWrappedLine = currentViewStateColumn === currentModelStateColumn;\n\n\t\tconst currentViewStatelineNumber = cursor.viewState.position.lineNumber;\n\t\tconst firstNonBlankColumn = viewModel.getLineFirstNonWhitespaceColumn(currentViewStatelineNumber);\n\t\tconst isBeginningOfViewLine = currentViewStateColumn === firstNonBlankColumn;\n\n\t\tif (!isFirstLineOfWrappedLine && !isBeginningOfViewLine) {\n\t\t\treturn this._moveToLineStartByView(viewModel, cursor, inSelectionMode);\n\t\t} else {\n\t\t\treturn this._moveToLineStartByModel(viewModel, cursor, inSelectionMode);\n\t\t}\n\t}\n\n\tprivate static _moveToLineStartByView(viewModel: IViewModel, cursor: CursorState, inSelectionMode: boolean): PartialCursorState {\n\t\treturn CursorState.fromViewState(\n\t\t\tMoveOperations.moveToBeginningOfLine(viewModel.cursorConfig, viewModel, cursor.viewState, inSelectionMode)\n\t\t);\n\t}\n\n\tprivate static _moveToLineStartByModel(viewModel: IViewModel, cursor: CursorState, inSelectionMode: boolean): PartialCursorState {\n\t\treturn CursorState.fromModelState(\n\t\t\tMoveOperations.moveToBeginningOfLine(viewModel.cursorConfig, viewModel.model, cursor.modelState, inSelectionMode)\n\t\t);\n\t}\n\n\tpublic static moveToEndOfLine(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean, sticky: boolean): PartialCursorState[] {\n\t\tconst result: PartialCursorState[] = [];\n\t\tfor (let i = 0, len = cursors.length; i < len; i++) {\n\t\t\tconst cursor = cursors[i];\n\t\t\tresult[i] = this._moveToLineEnd(viewModel, cursor, inSelectionMode, sticky);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tprivate static _moveToLineEnd(viewModel: IViewModel, cursor: CursorState, inSelectionMode: boolean, sticky: boolean): PartialCursorState {\n\t\tconst viewStatePosition = cursor.viewState.position;\n\t\tconst viewModelMaxColumn = viewModel.getLineMaxColumn(viewStatePosition.lineNumber);\n\t\tconst isEndOfViewLine = viewStatePosition.column === viewModelMaxColumn;\n\n\t\tconst modelStatePosition = cursor.modelState.position;\n\t\tconst modelMaxColumn = viewModel.model.getLineMaxColumn(modelStatePosition.lineNumber);\n\t\tconst isEndLineOfWrappedLine = viewModelMaxColumn - viewStatePosition.column === modelMaxColumn - modelStatePosition.column;\n\n\t\tif (isEndOfViewLine || isEndLineOfWrappedLine) {\n\t\t\treturn this._moveToLineEndByModel(viewModel, cursor, inSelectionMode, sticky);\n\t\t} else {\n\t\t\treturn this._moveToLineEndByView(viewModel, cursor, inSelectionMode, sticky);\n\t\t}\n\t}\n\n\tprivate static _moveToLineEndByView(viewModel: IViewModel, cursor: CursorState, inSelectionMode: boolean, sticky: boolean): PartialCursorState {\n\t\treturn CursorState.fromViewState(\n\t\t\tMoveOperations.moveToEndOfLine(viewModel.cursorConfig, viewModel, cursor.viewState, inSelectionMode, sticky)\n\t\t);\n\t}\n\n\tprivate static _moveToLineEndByModel(viewModel: IViewModel, cursor: CursorState, inSelectionMode: boolean, sticky: boolean): PartialCursorState {\n\t\treturn CursorState.fromModelState(\n\t\t\tMoveOperations.moveToEndOfLine(viewModel.cursorConfig, viewModel.model, cursor.modelState, inSelectionMode, sticky)\n\t\t);\n\t}\n\n\tpublic static expandLineSelection(viewModel: IViewModel, cursors: CursorState[]): PartialCursorState[] {\n\t\tconst result: PartialCursorState[] = [];\n\t\tfor (let i = 0, len = cursors.length; i < len; i++) {\n\t\t\tconst cursor = cursors[i];\n\n\t\t\tconst startLineNumber = cursor.modelState.selection.startLineNumber;\n\t\t\tconst lineCount = viewModel.model.getLineCount();\n\n\t\t\tlet endLineNumber = cursor.modelState.selection.endLineNumber;\n\t\t\tlet endColumn: number;\n\t\t\tif (endLineNumber === lineCount) {\n\t\t\t\tendColumn = viewModel.model.getLineMaxColumn(lineCount);\n\t\t\t} else {\n\t\t\t\tendLineNumber++;\n\t\t\t\tendColumn = 1;\n\t\t\t}\n\n\t\t\tresult[i] = CursorState.fromModelState(new SingleCursorState(\n\t\t\t\tnew Range(startLineNumber, 1, startLineNumber, 1), SelectionStartKind.Simple, 0,\n\t\t\t\tnew Position(endLineNumber, endColumn), 0\n\t\t\t));\n\t\t}\n\t\treturn result;\n\t}\n\n\tpublic static moveToBeginningOfBuffer(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean): PartialCursorState[] {\n\t\tconst result: PartialCursorState[] = [];\n\t\tfor (let i = 0, len = cursors.length; i < len; i++) {\n\t\t\tconst cursor = cursors[i];\n\t\t\tresult[i] = CursorState.fromModelState(MoveOperations.moveToBeginningOfBuffer(viewModel.cursorConfig, viewModel.model, cursor.modelState, inSelectionMode));\n\t\t}\n\t\treturn result;\n\t}\n\n\tpublic static moveToEndOfBuffer(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean): PartialCursorState[] {\n\t\tconst result: PartialCursorState[] = [];\n\t\tfor (let i = 0, len = cursors.length; i < len; i++) {\n\t\t\tconst cursor = cursors[i];\n\t\t\tresult[i] = CursorState.fromModelState(MoveOperations.moveToEndOfBuffer(viewModel.cursorConfig, viewModel.model, cursor.modelState, inSelectionMode));\n\t\t}\n\t\treturn result;\n\t}\n\n\tpublic static selectAll(viewModel: IViewModel, cursor: CursorState): PartialCursorState {\n\t\tconst lineCount = viewModel.model.getLineCount();\n\t\tconst maxColumn = viewModel.model.getLineMaxColumn(lineCount);\n\n\t\treturn CursorState.fromModelState(new SingleCursorState(\n\t\t\tnew Range(1, 1, 1, 1), SelectionStartKind.Simple, 0,\n\t\t\tnew Position(lineCount, maxColumn), 0\n\t\t));\n\t}\n\n\tpublic static line(viewModel: IViewModel, cursor: CursorState, inSelectionMode: boolean, _position: IPosition, _viewPosition: IPosition | undefined): PartialCursorState {\n\t\tconst position = viewModel.model.validatePosition(_position);\n\t\tconst viewPosition = (\n\t\t\t_viewPosition\n\t\t\t\t? viewModel.coordinatesConverter.validateViewPosition(new Position(_viewPosition.lineNumber, _viewPosition.column), position)\n\t\t\t\t: viewModel.coordinatesConverter.convertModelPositionToViewPosition(position)\n\t\t);\n\n\t\tif (!inSelectionMode) {\n\t\t\t// Entering line selection for the first time\n\t\t\tconst lineCount = viewModel.model.getLineCount();\n\n\t\t\tlet selectToLineNumber = position.lineNumber + 1;\n\t\t\tlet selectToColumn = 1;\n\t\t\tif (selectToLineNumber > lineCount) {\n\t\t\t\tselectToLineNumber = lineCount;\n\t\t\t\tselectToColumn = viewModel.model.getLineMaxColumn(selectToLineNumber);\n\t\t\t}\n\n\t\t\treturn CursorState.fromModelState(new SingleCursorState(\n\t\t\t\tnew Range(position.lineNumber, 1, selectToLineNumber, selectToColumn), SelectionStartKind.Line, 0,\n\t\t\t\tnew Position(selectToLineNumber, selectToColumn), 0\n\t\t\t));\n\t\t}\n\n\t\t// Continuing line selection\n\t\tconst enteringLineNumber = cursor.modelState.selectionStart.getStartPosition().lineNumber;\n\n\t\tif (position.lineNumber < enteringLineNumber) {\n\n\t\t\treturn CursorState.fromViewState(cursor.viewState.move(\n\t\t\t\ttrue, viewPosition.lineNumber, 1, 0\n\t\t\t));\n\n\t\t} else if (position.lineNumber > enteringLineNumber) {\n\n\t\t\tconst lineCount = viewModel.getLineCount();\n\n\t\t\tlet selectToViewLineNumber = viewPosition.lineNumber + 1;\n\t\t\tlet selectToViewColumn = 1;\n\t\t\tif (selectToViewLineNumber > lineCount) {\n\t\t\t\tselectToViewLineNumber = lineCount;\n\t\t\t\tselectToViewColumn = viewModel.getLineMaxColumn(selectToViewLineNumber);\n\t\t\t}\n\n\t\t\treturn CursorState.fromViewState(cursor.viewState.move(\n\t\t\t\ttrue, selectToViewLineNumber, selectToViewColumn, 0\n\t\t\t));\n\n\t\t} else {\n\n\t\t\tconst endPositionOfSelectionStart = cursor.modelState.selectionStart.getEndPosition();\n\t\t\treturn CursorState.fromModelState(cursor.modelState.move(\n\t\t\t\ttrue, endPositionOfSelectionStart.lineNumber, endPositionOfSelectionStart.column, 0\n\t\t\t));\n\n\t\t}\n\t}\n\n\tpublic static word(viewModel: IViewModel, cursor: CursorState, inSelectionMode: boolean, _position: IPosition): PartialCursorState {\n\t\tconst position = viewModel.model.validatePosition(_position);\n\t\treturn CursorState.fromModelState(WordOperations.word(viewModel.cursorConfig, viewModel.model, cursor.modelState, inSelectionMode, position));\n\t}\n\n\tpublic static cancelSelection(viewModel: IViewModel, cursor: CursorState): PartialCursorState {\n\t\tif (!cursor.modelState.hasSelection()) {\n\t\t\treturn new CursorState(cursor.modelState, cursor.viewState);\n\t\t}\n\n\t\tconst lineNumber = cursor.viewState.position.lineNumber;\n\t\tconst column = cursor.viewState.position.column;\n\n\t\treturn CursorState.fromViewState(new SingleCursorState(\n\t\t\tnew Range(lineNumber, column, lineNumber, column), SelectionStartKind.Simple, 0,\n\t\t\tnew Position(lineNumber, column), 0\n\t\t));\n\t}\n\n\tpublic static moveTo(viewModel: IViewModel, cursor: CursorState, inSelectionMode: boolean, _position: IPosition, _viewPosition: IPosition | undefined): PartialCursorState {\n\t\tif (inSelectionMode) {\n\t\t\tif (cursor.modelState.selectionStartKind === SelectionStartKind.Word) {\n\t\t\t\treturn this.word(viewModel, cursor, inSelectionMode, _position);\n\t\t\t}\n\t\t\tif (cursor.modelState.selectionStartKind === SelectionStartKind.Line) {\n\t\t\t\treturn this.line(viewModel, cursor, inSelectionMode, _position, _viewPosition);\n\t\t\t}\n\t\t}\n\t\tconst position = viewModel.model.validatePosition(_position);\n\t\tconst viewPosition = (\n\t\t\t_viewPosition\n\t\t\t\t? viewModel.coordinatesConverter.validateViewPosition(new Position(_viewPosition.lineNumber, _viewPosition.column), position)\n\t\t\t\t: viewModel.coordinatesConverter.convertModelPositionToViewPosition(position)\n\t\t);\n\t\treturn CursorState.fromViewState(cursor.viewState.move(inSelectionMode, viewPosition.lineNumber, viewPosition.column, 0));\n\t}\n\n\tpublic static simpleMove(viewModel: IViewModel, cursors: CursorState[], direction: CursorMove.SimpleMoveDirection, inSelectionMode: boolean, value: number, unit: CursorMove.Unit): PartialCursorState[] | null {\n\t\tswitch (direction) {\n\t\t\tcase CursorMove.Direction.Left: {\n\t\t\t\tif (unit === CursorMove.Unit.HalfLine) {\n\t\t\t\t\t// Move left by half the current line length\n\t\t\t\t\treturn this._moveHalfLineLeft(viewModel, cursors, inSelectionMode);\n\t\t\t\t} else {\n\t\t\t\t\t// Move left by `moveParams.value` columns\n\t\t\t\t\treturn this._moveLeft(viewModel, cursors, inSelectionMode, value);\n\t\t\t\t}\n\t\t\t}\n\t\t\tcase CursorMove.Direction.Right: {\n\t\t\t\tif (unit === CursorMove.Unit.HalfLine) {\n\t\t\t\t\t// Move right by half the current line length\n\t\t\t\t\treturn this._moveHalfLineRight(viewModel, cursors, inSelectionMode);\n\t\t\t\t} else {\n\t\t\t\t\t// Move right by `moveParams.value` columns\n\t\t\t\t\treturn this._moveRight(viewModel, cursors, inSelectionMode, value);\n\t\t\t\t}\n\t\t\t}\n\t\t\tcase CursorMove.Direction.Up: {\n\t\t\t\tif (unit === CursorMove.Unit.WrappedLine) {\n\t\t\t\t\t// Move up by view lines\n\t\t\t\t\treturn this._moveUpByViewLines(viewModel, cursors, inSelectionMode, value);\n\t\t\t\t} else {\n\t\t\t\t\t// Move up by model lines\n\t\t\t\t\treturn this._moveUpByModelLines(viewModel, cursors, inSelectionMode, value);\n\t\t\t\t}\n\t\t\t}\n\t\t\tcase CursorMove.Direction.Down: {\n\t\t\t\tif (unit === CursorMove.Unit.WrappedLine) {\n\t\t\t\t\t// Move down by view lines\n\t\t\t\t\treturn this._moveDownByViewLines(viewModel, cursors, inSelectionMode, value);\n\t\t\t\t} else {\n\t\t\t\t\t// Move down by model lines\n\t\t\t\t\treturn this._moveDownByModelLines(viewModel, cursors, inSelectionMode, value);\n\t\t\t\t}\n\t\t\t}\n\t\t\tcase CursorMove.Direction.PrevBlankLine: {\n\t\t\t\tif (unit === CursorMove.Unit.WrappedLine) {\n\t\t\t\t\treturn cursors.map(cursor => CursorState.fromViewState(MoveOperations.moveToPrevBlankLine(viewModel.cursorConfig, viewModel, cursor.viewState, inSelectionMode)));\n\t\t\t\t} else {\n\t\t\t\t\treturn cursors.map(cursor => CursorState.fromModelState(MoveOperations.moveToPrevBlankLine(viewModel.cursorConfig, viewModel.model, cursor.modelState, inSelectionMode)));\n\t\t\t\t}\n\t\t\t}\n\t\t\tcase CursorMove.Direction.NextBlankLine: {\n\t\t\t\tif (unit === CursorMove.Unit.WrappedLine) {\n\t\t\t\t\treturn cursors.map(cursor => CursorState.fromViewState(MoveOperations.moveToNextBlankLine(viewModel.cursorConfig, viewModel, cursor.viewState, inSelectionMode)));\n\t\t\t\t} else {\n\t\t\t\t\treturn cursors.map(cursor => CursorState.fromModelState(MoveOperations.moveToNextBlankLine(viewModel.cursorConfig, viewModel.model, cursor.modelState, inSelectionMode)));\n\t\t\t\t}\n\t\t\t}\n\t\t\tcase CursorMove.Direction.WrappedLineStart: {\n\t\t\t\t// Move to the beginning of the current view line\n\t\t\t\treturn this._moveToViewMinColumn(viewModel, cursors, inSelectionMode);\n\t\t\t}\n\t\t\tcase CursorMove.Direction.WrappedLineFirstNonWhitespaceCharacter: {\n\t\t\t\t// Move to the first non-whitespace column of the current view line\n\t\t\t\treturn this._moveToViewFirstNonWhitespaceColumn(viewModel, cursors, inSelectionMode);\n\t\t\t}\n\t\t\tcase CursorMove.Direction.WrappedLineColumnCenter: {\n\t\t\t\t// Move to the \"center\" of the current view line\n\t\t\t\treturn this._moveToViewCenterColumn(viewModel, cursors, inSelectionMode);\n\t\t\t}\n\t\t\tcase CursorMove.Direction.WrappedLineEnd: {\n\t\t\t\t// Move to the end of the current view line\n\t\t\t\treturn this._moveToViewMaxColumn(viewModel, cursors, inSelectionMode);\n\t\t\t}\n\t\t\tcase CursorMove.Direction.WrappedLineLastNonWhitespaceCharacter: {\n\t\t\t\t// Move to the last non-whitespace column of the current view line\n\t\t\t\treturn this._moveToViewLastNonWhitespaceColumn(viewModel, cursors, inSelectionMode);\n\t\t\t}\n\t\t\tdefault:\n\t\t\t\treturn null;\n\t\t}\n\n\t}\n\n\tpublic static viewportMove(viewModel: IViewModel, cursors: CursorState[], direction: CursorMove.ViewportDirection, inSelectionMode: boolean, value: number): PartialCursorState[] | null {\n\t\tconst visibleViewRange = viewModel.getCompletelyVisibleViewRange();\n\t\tconst visibleModelRange = viewModel.coordinatesConverter.convertViewRangeToModelRange(visibleViewRange);\n\t\tswitch (direction) {\n\t\t\tcase CursorMove.Direction.ViewPortTop: {\n\t\t\t\t// Move to the nth line start in the viewport (from the top)\n\t\t\t\tconst modelLineNumber = this._firstLineNumberInRange(viewModel.model, visibleModelRange, value);\n\t\t\t\tconst modelColumn = viewModel.model.getLineFirstNonWhitespaceColumn(modelLineNumber);\n\t\t\t\treturn [this._moveToModelPosition(viewModel, cursors[0], inSelectionMode, modelLineNumber, modelColumn)];\n\t\t\t}\n\t\t\tcase CursorMove.Direction.ViewPortBottom: {\n\t\t\t\t// Move to the nth line start in the viewport (from the bottom)\n\t\t\t\tconst modelLineNumber = this._lastLineNumberInRange(viewModel.model, visibleModelRange, value);\n\t\t\t\tconst modelColumn = viewModel.model.getLineFirstNonWhitespaceColumn(modelLineNumber);\n\t\t\t\treturn [this._moveToModelPosition(viewModel, cursors[0], inSelectionMode, modelLineNumber, modelColumn)];\n\t\t\t}\n\t\t\tcase CursorMove.Direction.ViewPortCenter: {\n\t\t\t\t// Move to the line start in the viewport center\n\t\t\t\tconst modelLineNumber = Math.round((visibleModelRange.startLineNumber + visibleModelRange.endLineNumber) / 2);\n\t\t\t\tconst modelColumn = viewModel.model.getLineFirstNonWhitespaceColumn(modelLineNumber);\n\t\t\t\treturn [this._moveToModelPosition(viewModel, cursors[0], inSelectionMode, modelLineNumber, modelColumn)];\n\t\t\t}\n\t\t\tcase CursorMove.Direction.ViewPortIfOutside: {\n\t\t\t\t// Move to a position inside the viewport\n\t\t\t\tconst result: PartialCursorState[] = [];\n\t\t\t\tfor (let i = 0, len = cursors.length; i < len; i++) {\n\t\t\t\t\tconst cursor = cursors[i];\n\t\t\t\t\tresult[i] = this.findPositionInViewportIfOutside(viewModel, cursor, visibleViewRange, inSelectionMode);\n\t\t\t\t}\n\t\t\t\treturn result;\n\t\t\t}\n\t\t\tdefault:\n\t\t\t\treturn null;\n\t\t}\n\t}\n\n\tpublic static findPositionInViewportIfOutside(viewModel: IViewModel, cursor: CursorState, visibleViewRange: Range, inSelectionMode: boolean): PartialCursorState {\n\t\tconst viewLineNumber = cursor.viewState.position.lineNumber;\n\n\t\tif (visibleViewRange.startLineNumber <= viewLineNumber && viewLineNumber <= visibleViewRange.endLineNumber - 1) {\n\t\t\t// Nothing to do, cursor is in viewport\n\t\t\treturn new CursorState(cursor.modelState, cursor.viewState);\n\n\t\t} else {\n\t\t\tlet newViewLineNumber: number;\n\t\t\tif (viewLineNumber > visibleViewRange.endLineNumber - 1) {\n\t\t\t\tnewViewLineNumber = visibleViewRange.endLineNumber - 1;\n\t\t\t} else if (viewLineNumber < visibleViewRange.startLineNumber) {\n\t\t\t\tnewViewLineNumber = visibleViewRange.startLineNumber;\n\t\t\t} else {\n\t\t\t\tnewViewLineNumber = viewLineNumber;\n\t\t\t}\n\t\t\tconst position = MoveOperations.vertical(viewModel.cursorConfig, viewModel, viewLineNumber, cursor.viewState.position.column, cursor.viewState.leftoverVisibleColumns, newViewLineNumber, false);\n\t\t\treturn CursorState.fromViewState(cursor.viewState.move(inSelectionMode, position.lineNumber, position.column, position.leftoverVisibleColumns));\n\t\t}\n\t}\n\n\t/**\n\t * Find the nth line start included in the range (from the start).\n\t */\n\tprivate static _firstLineNumberInRange(model: ICursorSimpleModel, range: Range, count: number): number {\n\t\tlet startLineNumber = range.startLineNumber;\n\t\tif (range.startColumn !== model.getLineMinColumn(startLineNumber)) {\n\t\t\t// Move on to the second line if the first line start is not included in the range\n\t\t\tstartLineNumber++;\n\t\t}\n\n\t\treturn Math.min(range.endLineNumber, startLineNumber + count - 1);\n\t}\n\n\t/**\n\t * Find the nth line start included in the range (from the end).\n\t */\n\tprivate static _lastLineNumberInRange(model: ICursorSimpleModel, range: Range, count: number): number {\n\t\tlet startLineNumber = range.startLineNumber;\n\t\tif (range.startColumn !== model.getLineMinColumn(startLineNumber)) {\n\t\t\t// Move on to the second line if the first line start is not included in the range\n\t\t\tstartLineNumber++;\n\t\t}\n\n\t\treturn Math.max(startLineNumber, range.endLineNumber - count + 1);\n\t}\n\n\tprivate static _moveLeft(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean, noOfColumns: number): PartialCursorState[] {\n\t\treturn cursors.map(cursor =>\n\t\t\tCursorState.fromViewState(\n\t\t\t\tMoveOperations.moveLeft(viewModel.cursorConfig, viewModel, cursor.viewState, inSelectionMode, noOfColumns)\n\t\t\t)\n\t\t);\n\t}\n\n\tprivate static _moveHalfLineLeft(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean): PartialCursorState[] {\n\t\tconst result: PartialCursorState[] = [];\n\t\tfor (let i = 0, len = cursors.length; i < len; i++) {\n\t\t\tconst cursor = cursors[i];\n\t\t\tconst viewLineNumber = cursor.viewState.position.lineNumber;\n\t\t\tconst halfLine = Math.round(viewModel.getLineLength(viewLineNumber) / 2);\n\t\t\tresult[i] = CursorState.fromViewState(MoveOperations.moveLeft(viewModel.cursorConfig, viewModel, cursor.viewState, inSelectionMode, halfLine));\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate static _moveRight(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean, noOfColumns: number): PartialCursorState[] {\n\t\treturn cursors.map(cursor =>\n\t\t\tCursorState.fromViewState(\n\t\t\t\tMoveOperations.moveRight(viewModel.cursorConfig, viewModel, cursor.viewState, inSelectionMode, noOfColumns)\n\t\t\t)\n\t\t);\n\t}\n\n\tprivate static _moveHalfLineRight(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean): PartialCursorState[] {\n\t\tconst result: PartialCursorState[] = [];\n\t\tfor (let i = 0, len = cursors.length; i < len; i++) {\n\t\t\tconst cursor = cursors[i];\n\t\t\tconst viewLineNumber = cursor.viewState.position.lineNumber;\n\t\t\tconst halfLine = Math.round(viewModel.getLineLength(viewLineNumber) / 2);\n\t\t\tresult[i] = CursorState.fromViewState(MoveOperations.moveRight(viewModel.cursorConfig, viewModel, cursor.viewState, inSelectionMode, halfLine));\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate static _moveDownByViewLines(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean, linesCount: number): PartialCursorState[] {\n\t\tconst result: PartialCursorState[] = [];\n\t\tfor (let i = 0, len = cursors.length; i < len; i++) {\n\t\t\tconst cursor = cursors[i];\n\t\t\tresult[i] = CursorState.fromViewState(MoveOperations.moveDown(viewModel.cursorConfig, viewModel, cursor.viewState, inSelectionMode, linesCount));\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate static _moveDownByModelLines(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean, linesCount: number): PartialCursorState[] {\n\t\tconst result: PartialCursorState[] = [];\n\t\tfor (let i = 0, len = cursors.length; i < len; i++) {\n\t\t\tconst cursor = cursors[i];\n\t\t\tresult[i] = CursorState.fromModelState(MoveOperations.moveDown(viewModel.cursorConfig, viewModel.model, cursor.modelState, inSelectionMode, linesCount));\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate static _moveUpByViewLines(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean, linesCount: number): PartialCursorState[] {\n\t\tconst result: PartialCursorState[] = [];\n\t\tfor (let i = 0, len = cursors.length; i < len; i++) {\n\t\t\tconst cursor = cursors[i];\n\t\t\tresult[i] = CursorState.fromViewState(MoveOperations.moveUp(viewModel.cursorConfig, viewModel, cursor.viewState, inSelectionMode, linesCount));\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate static _moveUpByModelLines(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean, linesCount: number): PartialCursorState[] {\n\t\tconst result: PartialCursorState[] = [];\n\t\tfor (let i = 0, len = cursors.length; i < len; i++) {\n\t\t\tconst cursor = cursors[i];\n\t\t\tresult[i] = CursorState.fromModelState(MoveOperations.moveUp(viewModel.cursorConfig, viewModel.model, cursor.modelState, inSelectionMode, linesCount));\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate static _moveToViewPosition(viewModel: IViewModel, cursor: CursorState, inSelectionMode: boolean, toViewLineNumber: number, toViewColumn: number): PartialCursorState {\n\t\treturn CursorState.fromViewState(cursor.viewState.move(inSelectionMode, toViewLineNumber, toViewColumn, 0));\n\t}\n\n\tprivate static _moveToModelPosition(viewModel: IViewModel, cursor: CursorState, inSelectionMode: boolean, toModelLineNumber: number, toModelColumn: number): PartialCursorState {\n\t\treturn CursorState.fromModelState(cursor.modelState.move(inSelectionMode, toModelLineNumber, toModelColumn, 0));\n\t}\n\n\tprivate static _moveToViewMinColumn(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean): PartialCursorState[] {\n\t\tconst result: PartialCursorState[] = [];\n\t\tfor (let i = 0, len = cursors.length; i < len; i++) {\n\t\t\tconst cursor = cursors[i];\n\t\t\tconst viewLineNumber = cursor.viewState.position.lineNumber;\n\t\t\tconst viewColumn = viewModel.getLineMinColumn(viewLineNumber);\n\t\t\tresult[i] = this._moveToViewPosition(viewModel, cursor, inSelectionMode, viewLineNumber, viewColumn);\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate static _moveToViewFirstNonWhitespaceColumn(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean): PartialCursorState[] {\n\t\tconst result: PartialCursorState[] = [];\n\t\tfor (let i = 0, len = cursors.length; i < len; i++) {\n\t\t\tconst cursor = cursors[i];\n\t\t\tconst viewLineNumber = cursor.viewState.position.lineNumber;\n\t\t\tconst viewColumn = viewModel.getLineFirstNonWhitespaceColumn(viewLineNumber);\n\t\t\tresult[i] = this._moveToViewPosition(viewModel, cursor, inSelectionMode, viewLineNumber, viewColumn);\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate static _moveToViewCenterColumn(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean): PartialCursorState[] {\n\t\tconst result: PartialCursorState[] = [];\n\t\tfor (let i = 0, len = cursors.length; i < len; i++) {\n\t\t\tconst cursor = cursors[i];\n\t\t\tconst viewLineNumber = cursor.viewState.position.lineNumber;\n\t\t\tconst viewColumn = Math.round((viewModel.getLineMaxColumn(viewLineNumber) + viewModel.getLineMinColumn(viewLineNumber)) / 2);\n\t\t\tresult[i] = this._moveToViewPosition(viewModel, cursor, inSelectionMode, viewLineNumber, viewColumn);\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate static _moveToViewMaxColumn(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean): PartialCursorState[] {\n\t\tconst result: PartialCursorState[] = [];\n\t\tfor (let i = 0, len = cursors.length; i < len; i++) {\n\t\t\tconst cursor = cursors[i];\n\t\t\tconst viewLineNumber = cursor.viewState.position.lineNumber;\n\t\t\tconst viewColumn = viewModel.getLineMaxColumn(viewLineNumber);\n\t\t\tresult[i] = this._moveToViewPosition(viewModel, cursor, inSelectionMode, viewLineNumber, viewColumn);\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate static _moveToViewLastNonWhitespaceColumn(viewModel: IViewModel, cursors: CursorState[], inSelectionMode: boolean): PartialCursorState[] {\n\t\tconst result: PartialCursorState[] = [];\n\t\tfor (let i = 0, len = cursors.length; i < len; i++) {\n\t\t\tconst cursor = cursors[i];\n\t\t\tconst viewLineNumber = cursor.viewState.position.lineNumber;\n\t\t\tconst viewColumn = viewModel.getLineLastNonWhitespaceColumn(viewLineNumber);\n\t\t\tresult[i] = this._moveToViewPosition(viewModel, cursor, inSelectionMode, viewLineNumber, viewColumn);\n\t\t}\n\t\treturn result;\n\t}\n}\n\nexport namespace CursorMove {\n\n\tconst isCursorMoveArgs = function (arg: any): boolean {\n\t\tif (!types.isObject(arg)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst cursorMoveArg: RawArguments = arg;\n\n\t\tif (!types.isString(cursorMoveArg.to)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (!types.isUndefined(cursorMoveArg.select) && !types.isBoolean(cursorMoveArg.select)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (!types.isUndefined(cursorMoveArg.by) && !types.isString(cursorMoveArg.by)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (!types.isUndefined(cursorMoveArg.value) && !types.isNumber(cursorMoveArg.value)) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t};\n\n\texport const metadata: ICommandMetadata = {\n\t\tdescription: 'Move cursor to a logical position in the view',\n\t\targs: [\n\t\t\t{\n\t\t\t\tname: 'Cursor move argument object',\n\t\t\t\tdescription: `Property-value pairs that can be passed through this argument:\n\t\t\t\t\t* 'to': A mandatory logical position value providing where to move the cursor.\n\t\t\t\t\t\t\\`\\`\\`\n\t\t\t\t\t\t'left', 'right', 'up', 'down', 'prevBlankLine', 'nextBlankLine',\n\t\t\t\t\t\t'wrappedLineStart', 'wrappedLineEnd', 'wrappedLineColumnCenter'\n\t\t\t\t\t\t'wrappedLineFirstNonWhitespaceCharacter', 'wrappedLineLastNonWhitespaceCharacter'\n\t\t\t\t\t\t'viewPortTop', 'viewPortCenter', 'viewPortBottom', 'viewPortIfOutside'\n\t\t\t\t\t\t\\`\\`\\`\n\t\t\t\t\t* 'by': Unit to move. Default is computed based on 'to' value.\n\t\t\t\t\t\t\\`\\`\\`\n\t\t\t\t\t\t'line', 'wrappedLine', 'character', 'halfLine'\n\t\t\t\t\t\t\\`\\`\\`\n\t\t\t\t\t* 'value': Number of units to move. Default is '1'.\n\t\t\t\t\t* 'select': If 'true' makes the selection. Default is 'false'.\n\t\t\t\t`,\n\t\t\t\tconstraint: isCursorMoveArgs,\n\t\t\t\tschema: {\n\t\t\t\t\t'type': 'object',\n\t\t\t\t\t'required': ['to'],\n\t\t\t\t\t'properties': {\n\t\t\t\t\t\t'to': {\n\t\t\t\t\t\t\t'type': 'string',\n\t\t\t\t\t\t\t'enum': ['left', 'right', 'up', 'down', 'prevBlankLine', 'nextBlankLine', 'wrappedLineStart', 'wrappedLineEnd', 'wrappedLineColumnCenter', 'wrappedLineFirstNonWhitespaceCharacter', 'wrappedLineLastNonWhitespaceCharacter', 'viewPortTop', 'viewPortCenter', 'viewPortBottom', 'viewPortIfOutside']\n\t\t\t\t\t\t},\n\t\t\t\t\t\t'by': {\n\t\t\t\t\t\t\t'type': 'string',\n\t\t\t\t\t\t\t'enum': ['line', 'wrappedLine', 'character', 'halfLine']\n\t\t\t\t\t\t},\n\t\t\t\t\t\t'value': {\n\t\t\t\t\t\t\t'type': 'number',\n\t\t\t\t\t\t\t'default': 1\n\t\t\t\t\t\t},\n\t\t\t\t\t\t'select': {\n\t\t\t\t\t\t\t'type': 'boolean',\n\t\t\t\t\t\t\t'default': false\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]\n\t};\n\n\t/**\n\t * Positions in the view for cursor move command.\n\t */\n\texport const RawDirection = {\n\t\tLeft: 'left',\n\t\tRight: 'right',\n\t\tUp: 'up',\n\t\tDown: 'down',\n\n\t\tPrevBlankLine: 'prevBlankLine',\n\t\tNextBlankLine: 'nextBlankLine',\n\n\t\tWrappedLineStart: 'wrappedLineStart',\n\t\tWrappedLineFirstNonWhitespaceCharacter: 'wrappedLineFirstNonWhitespaceCharacter',\n\t\tWrappedLineColumnCenter: 'wrappedLineColumnCenter',\n\t\tWrappedLineEnd: 'wrappedLineEnd',\n\t\tWrappedLineLastNonWhitespaceCharacter: 'wrappedLineLastNonWhitespaceCharacter',\n\n\t\tViewPortTop: 'viewPortTop',\n\t\tViewPortCenter: 'viewPortCenter',\n\t\tViewPortBottom: 'viewPortBottom',\n\n\t\tViewPortIfOutside: 'viewPortIfOutside'\n\t};\n\n\t/**\n\t * Units for Cursor move 'by' argument\n\t */\n\texport const RawUnit = {\n\t\tLine: 'line',\n\t\tWrappedLine: 'wrappedLine',\n\t\tCharacter: 'character',\n\t\tHalfLine: 'halfLine'\n\t};\n\n\t/**\n\t * Arguments for Cursor move command\n\t */\n\texport interface RawArguments {\n\t\tto: string;\n\t\tselect?: boolean;\n\t\tby?: string;\n\t\tvalue?: number;\n\t}\n\n\texport function parse(args: Partial): ParsedArguments | null {\n\t\tif (!args.to) {\n\t\t\t// illegal arguments\n\t\t\treturn null;\n\t\t}\n\n\t\tlet direction: Direction;\n\t\tswitch (args.to) {\n\t\t\tcase RawDirection.Left:\n\t\t\t\tdirection = Direction.Left;\n\t\t\t\tbreak;\n\t\t\tcase RawDirection.Right:\n\t\t\t\tdirection = Direction.Right;\n\t\t\t\tbreak;\n\t\t\tcase RawDirection.Up:\n\t\t\t\tdirection = Direction.Up;\n\t\t\t\tbreak;\n\t\t\tcase RawDirection.Down:\n\t\t\t\tdirection = Direction.Down;\n\t\t\t\tbreak;\n\t\t\tcase RawDirection.PrevBlankLine:\n\t\t\t\tdirection = Direction.PrevBlankLine;\n\t\t\t\tbreak;\n\t\t\tcase RawDirection.NextBlankLine:\n\t\t\t\tdirection = Direction.NextBlankLine;\n\t\t\t\tbreak;\n\t\t\tcase RawDirection.WrappedLineStart:\n\t\t\t\tdirection = Direction.WrappedLineStart;\n\t\t\t\tbreak;\n\t\t\tcase RawDirection.WrappedLineFirstNonWhitespaceCharacter:\n\t\t\t\tdirection = Direction.WrappedLineFirstNonWhitespaceCharacter;\n\t\t\t\tbreak;\n\t\t\tcase RawDirection.WrappedLineColumnCenter:\n\t\t\t\tdirection = Direction.WrappedLineColumnCenter;\n\t\t\t\tbreak;\n\t\t\tcase RawDirection.WrappedLineEnd:\n\t\t\t\tdirection = Direction.WrappedLineEnd;\n\t\t\t\tbreak;\n\t\t\tcase RawDirection.WrappedLineLastNonWhitespaceCharacter:\n\t\t\t\tdirection = Direction.WrappedLineLastNonWhitespaceCharacter;\n\t\t\t\tbreak;\n\t\t\tcase RawDirection.ViewPortTop:\n\t\t\t\tdirection = Direction.ViewPortTop;\n\t\t\t\tbreak;\n\t\t\tcase RawDirection.ViewPortBottom:\n\t\t\t\tdirection = Direction.ViewPortBottom;\n\t\t\t\tbreak;\n\t\t\tcase RawDirection.ViewPortCenter:\n\t\t\t\tdirection = Direction.ViewPortCenter;\n\t\t\t\tbreak;\n\t\t\tcase RawDirection.ViewPortIfOutside:\n\t\t\t\tdirection = Direction.ViewPortIfOutside;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\t// illegal arguments\n\t\t\t\treturn null;\n\t\t}\n\n\t\tlet unit = Unit.None;\n\t\tswitch (args.by) {\n\t\t\tcase RawUnit.Line:\n\t\t\t\tunit = Unit.Line;\n\t\t\t\tbreak;\n\t\t\tcase RawUnit.WrappedLine:\n\t\t\t\tunit = Unit.WrappedLine;\n\t\t\t\tbreak;\n\t\t\tcase RawUnit.Character:\n\t\t\t\tunit = Unit.Character;\n\t\t\t\tbreak;\n\t\t\tcase RawUnit.HalfLine:\n\t\t\t\tunit = Unit.HalfLine;\n\t\t\t\tbreak;\n\t\t}\n\n\t\treturn {\n\t\t\tdirection: direction,\n\t\t\tunit: unit,\n\t\t\tselect: (!!args.select),\n\t\t\tvalue: (args.value || 1)\n\t\t};\n\t}\n\n\texport interface ParsedArguments {\n\t\tdirection: Direction;\n\t\tunit: Unit;\n\t\tselect: boolean;\n\t\tvalue: number;\n\t}\n\n\texport interface SimpleMoveArguments {\n\t\tdirection: SimpleMoveDirection;\n\t\tunit: Unit;\n\t\tselect: boolean;\n\t\tvalue: number;\n\t}\n\n\texport const enum Direction {\n\t\tLeft,\n\t\tRight,\n\t\tUp,\n\t\tDown,\n\t\tPrevBlankLine,\n\t\tNextBlankLine,\n\n\t\tWrappedLineStart,\n\t\tWrappedLineFirstNonWhitespaceCharacter,\n\t\tWrappedLineColumnCenter,\n\t\tWrappedLineEnd,\n\t\tWrappedLineLastNonWhitespaceCharacter,\n\n\t\tViewPortTop,\n\t\tViewPortCenter,\n\t\tViewPortBottom,\n\n\t\tViewPortIfOutside,\n\t}\n\n\texport type SimpleMoveDirection = (\n\t\tDirection.Left\n\t\t| Direction.Right\n\t\t| Direction.Up\n\t\t| Direction.Down\n\t\t| Direction.PrevBlankLine\n\t\t| Direction.NextBlankLine\n\t\t| Direction.WrappedLineStart\n\t\t| Direction.WrappedLineFirstNonWhitespaceCharacter\n\t\t| Direction.WrappedLineColumnCenter\n\t\t| Direction.WrappedLineEnd\n\t\t| Direction.WrappedLineLastNonWhitespaceCharacter\n\t);\n\n\texport type ViewportDirection = (\n\t\tDirection.ViewPortTop\n\t\t| Direction.ViewPortCenter\n\t\t| Direction.ViewPortBottom\n\t\t| Direction.ViewPortIfOutside\n\t);\n\n\texport const enum Unit {\n\t\tNone,\n\t\tLine,\n\t\tWrappedLine,\n\t\tCharacter,\n\t\tHalfLine,\n\t}\n\n}\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\nimport { CursorState, ICursorSimpleModel, SelectionStartKind, SingleCursorState } from 'vs/editor/common/cursorCommon';\nimport { CursorContext } from 'vs/editor/common/cursor/cursorContext';\nimport { Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\nimport { Selection } from 'vs/editor/common/core/selection';\nimport { PositionAffinity, TrackedRangeStickiness } from 'vs/editor/common/model';\n\n/**\n * Represents a single cursor.\n*/\nexport class Cursor {\n\n\tpublic modelState!: SingleCursorState;\n\tpublic viewState!: SingleCursorState;\n\n\tprivate _selTrackedRange: string | null;\n\tprivate _trackSelection: boolean;\n\n\tconstructor(context: CursorContext) {\n\t\tthis._selTrackedRange = null;\n\t\tthis._trackSelection = true;\n\n\t\tthis._setState(\n\t\t\tcontext,\n\t\t\tnew SingleCursorState(new Range(1, 1, 1, 1), SelectionStartKind.Simple, 0, new Position(1, 1), 0),\n\t\t\tnew SingleCursorState(new Range(1, 1, 1, 1), SelectionStartKind.Simple, 0, new Position(1, 1), 0)\n\t\t);\n\t}\n\n\tpublic dispose(context: CursorContext): void {\n\t\tthis._removeTrackedRange(context);\n\t}\n\n\tpublic startTrackingSelection(context: CursorContext): void {\n\t\tthis._trackSelection = true;\n\t\tthis._updateTrackedRange(context);\n\t}\n\n\tpublic stopTrackingSelection(context: CursorContext): void {\n\t\tthis._trackSelection = false;\n\t\tthis._removeTrackedRange(context);\n\t}\n\n\tprivate _updateTrackedRange(context: CursorContext): void {\n\t\tif (!this._trackSelection) {\n\t\t\t// don't track the selection\n\t\t\treturn;\n\t\t}\n\t\tthis._selTrackedRange = context.model._setTrackedRange(this._selTrackedRange, this.modelState.selection, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges);\n\t}\n\n\tprivate _removeTrackedRange(context: CursorContext): void {\n\t\tthis._selTrackedRange = context.model._setTrackedRange(this._selTrackedRange, null, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges);\n\t}\n\n\tpublic asCursorState(): CursorState {\n\t\treturn new CursorState(this.modelState, this.viewState);\n\t}\n\n\tpublic readSelectionFromMarkers(context: CursorContext): Selection {\n\t\tconst range = context.model._getTrackedRange(this._selTrackedRange!)!;\n\n\t\tif (this.modelState.selection.isEmpty() && !range.isEmpty()) {\n\t\t\t// Avoid selecting text when recovering from markers\n\t\t\treturn Selection.fromRange(range.collapseToEnd(), this.modelState.selection.getDirection());\n\t\t}\n\n\t\treturn Selection.fromRange(range, this.modelState.selection.getDirection());\n\t}\n\n\tpublic ensureValidState(context: CursorContext): void {\n\t\tthis._setState(context, this.modelState, this.viewState);\n\t}\n\n\tpublic setState(context: CursorContext, modelState: SingleCursorState | null, viewState: SingleCursorState | null): void {\n\t\tthis._setState(context, modelState, viewState);\n\t}\n\n\tprivate static _validatePositionWithCache(viewModel: ICursorSimpleModel, position: Position, cacheInput: Position, cacheOutput: Position): Position {\n\t\tif (position.equals(cacheInput)) {\n\t\t\treturn cacheOutput;\n\t\t}\n\t\treturn viewModel.normalizePosition(position, PositionAffinity.None);\n\t}\n\n\tprivate static _validateViewState(viewModel: ICursorSimpleModel, viewState: SingleCursorState): SingleCursorState {\n\t\tconst position = viewState.position;\n\t\tconst sStartPosition = viewState.selectionStart.getStartPosition();\n\t\tconst sEndPosition = viewState.selectionStart.getEndPosition();\n\n\t\tconst validPosition = viewModel.normalizePosition(position, PositionAffinity.None);\n\t\tconst validSStartPosition = this._validatePositionWithCache(viewModel, sStartPosition, position, validPosition);\n\t\tconst validSEndPosition = this._validatePositionWithCache(viewModel, sEndPosition, sStartPosition, validSStartPosition);\n\n\t\tif (position.equals(validPosition) && sStartPosition.equals(validSStartPosition) && sEndPosition.equals(validSEndPosition)) {\n\t\t\t// fast path: the state is valid\n\t\t\treturn viewState;\n\t\t}\n\n\t\treturn new SingleCursorState(\n\t\t\tRange.fromPositions(validSStartPosition, validSEndPosition),\n\t\t\tviewState.selectionStartKind,\n\t\t\tviewState.selectionStartLeftoverVisibleColumns + sStartPosition.column - validSStartPosition.column,\n\t\t\tvalidPosition,\n\t\t\tviewState.leftoverVisibleColumns + position.column - validPosition.column,\n\t\t);\n\t}\n\n\tprivate _setState(context: CursorContext, modelState: SingleCursorState | null, viewState: SingleCursorState | null): void {\n\t\tif (viewState) {\n\t\t\tviewState = Cursor._validateViewState(context.viewModel, viewState);\n\t\t}\n\n\t\tif (!modelState) {\n\t\t\tif (!viewState) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// We only have the view state => compute the model state\n\t\t\tconst selectionStart = context.model.validateRange(\n\t\t\t\tcontext.coordinatesConverter.convertViewRangeToModelRange(viewState.selectionStart)\n\t\t\t);\n\n\t\t\tconst position = context.model.validatePosition(\n\t\t\t\tcontext.coordinatesConverter.convertViewPositionToModelPosition(viewState.position)\n\t\t\t);\n\n\t\t\tmodelState = new SingleCursorState(selectionStart, viewState.selectionStartKind, viewState.selectionStartLeftoverVisibleColumns, position, viewState.leftoverVisibleColumns);\n\t\t} else {\n\t\t\t// Validate new model state\n\t\t\tconst selectionStart = context.model.validateRange(modelState.selectionStart);\n\t\t\tconst selectionStartLeftoverVisibleColumns = modelState.selectionStart.equalsRange(selectionStart) ? modelState.selectionStartLeftoverVisibleColumns : 0;\n\n\t\t\tconst position = context.model.validatePosition(\n\t\t\t\tmodelState.position\n\t\t\t);\n\t\t\tconst leftoverVisibleColumns = modelState.position.equals(position) ? modelState.leftoverVisibleColumns : 0;\n\n\t\t\tmodelState = new SingleCursorState(selectionStart, modelState.selectionStartKind, selectionStartLeftoverVisibleColumns, position, leftoverVisibleColumns);\n\t\t}\n\n\t\tif (!viewState) {\n\t\t\t// We only have the model state => compute the view state\n\t\t\tconst viewSelectionStart1 = context.coordinatesConverter.convertModelPositionToViewPosition(new Position(modelState.selectionStart.startLineNumber, modelState.selectionStart.startColumn));\n\t\t\tconst viewSelectionStart2 = context.coordinatesConverter.convertModelPositionToViewPosition(new Position(modelState.selectionStart.endLineNumber, modelState.selectionStart.endColumn));\n\t\t\tconst viewSelectionStart = new Range(viewSelectionStart1.lineNumber, viewSelectionStart1.column, viewSelectionStart2.lineNumber, viewSelectionStart2.column);\n\t\t\tconst viewPosition = context.coordinatesConverter.convertModelPositionToViewPosition(modelState.position);\n\t\t\tviewState = new SingleCursorState(viewSelectionStart, modelState.selectionStartKind, modelState.selectionStartLeftoverVisibleColumns, viewPosition, modelState.leftoverVisibleColumns);\n\t\t} else {\n\t\t\t// Validate new view state\n\t\t\tconst viewSelectionStart = context.coordinatesConverter.validateViewRange(viewState.selectionStart, modelState.selectionStart);\n\t\t\tconst viewPosition = context.coordinatesConverter.validateViewPosition(viewState.position, modelState.position);\n\t\t\tviewState = new SingleCursorState(viewSelectionStart, modelState.selectionStartKind, modelState.selectionStartLeftoverVisibleColumns, viewPosition, modelState.leftoverVisibleColumns);\n\t\t}\n\n\t\tthis.modelState = modelState;\n\t\tthis.viewState = viewState;\n\n\t\tthis._updateTrackedRange(context);\n\t}\n}\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\nimport { compareBy } from 'vs/base/common/arrays';\nimport { findLastMax, findFirstMin } from 'vs/base/common/arraysFind';\nimport { CursorState, PartialCursorState } from 'vs/editor/common/cursorCommon';\nimport { CursorContext } from 'vs/editor/common/cursor/cursorContext';\nimport { Cursor } from 'vs/editor/common/cursor/oneCursor';\nimport { Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\nimport { ISelection, Selection } from 'vs/editor/common/core/selection';\n\nexport class CursorCollection {\n\n\tprivate context: CursorContext;\n\n\t/**\n\t * `cursors[0]` is the primary cursor, thus `cursors.length >= 1` is always true.\n\t * `cursors.slice(1)` are secondary cursors.\n\t*/\n\tprivate cursors: Cursor[];\n\n\t// An index which identifies the last cursor that was added / moved (think Ctrl+drag)\n\t// This index refers to `cursors.slice(1)`, i.e. after removing the primary cursor.\n\tprivate lastAddedCursorIndex: number;\n\n\tconstructor(context: CursorContext) {\n\t\tthis.context = context;\n\t\tthis.cursors = [new Cursor(context)];\n\t\tthis.lastAddedCursorIndex = 0;\n\t}\n\n\tpublic dispose(): void {\n\t\tfor (const cursor of this.cursors) {\n\t\t\tcursor.dispose(this.context);\n\t\t}\n\t}\n\n\tpublic startTrackingSelections(): void {\n\t\tfor (const cursor of this.cursors) {\n\t\t\tcursor.startTrackingSelection(this.context);\n\t\t}\n\t}\n\n\tpublic stopTrackingSelections(): void {\n\t\tfor (const cursor of this.cursors) {\n\t\t\tcursor.stopTrackingSelection(this.context);\n\t\t}\n\t}\n\n\tpublic updateContext(context: CursorContext): void {\n\t\tthis.context = context;\n\t}\n\n\tpublic ensureValidState(): void {\n\t\tfor (const cursor of this.cursors) {\n\t\t\tcursor.ensureValidState(this.context);\n\t\t}\n\t}\n\n\tpublic readSelectionFromMarkers(): Selection[] {\n\t\treturn this.cursors.map(c => c.readSelectionFromMarkers(this.context));\n\t}\n\n\tpublic getAll(): CursorState[] {\n\t\treturn this.cursors.map(c => c.asCursorState());\n\t}\n\n\tpublic getViewPositions(): Position[] {\n\t\treturn this.cursors.map(c => c.viewState.position);\n\t}\n\n\tpublic getTopMostViewPosition(): Position {\n\t\treturn findFirstMin(\n\t\t\tthis.cursors,\n\t\t\tcompareBy(c => c.viewState.position, Position.compare)\n\t\t)!.viewState.position;\n\t}\n\n\tpublic getBottomMostViewPosition(): Position {\n\t\treturn findLastMax(\n\t\t\tthis.cursors,\n\t\t\tcompareBy(c => c.viewState.position, Position.compare)\n\t\t)!.viewState.position;\n\t}\n\n\tpublic getSelections(): Selection[] {\n\t\treturn this.cursors.map(c => c.modelState.selection);\n\t}\n\n\tpublic getViewSelections(): Selection[] {\n\t\treturn this.cursors.map(c => c.viewState.selection);\n\t}\n\n\tpublic setSelections(selections: ISelection[]): void {\n\t\tthis.setStates(CursorState.fromModelSelections(selections));\n\t}\n\n\tpublic getPrimaryCursor(): CursorState {\n\t\treturn this.cursors[0].asCursorState();\n\t}\n\n\tpublic setStates(states: PartialCursorState[] | null): void {\n\t\tif (states === null) {\n\t\t\treturn;\n\t\t}\n\t\tthis.cursors[0].setState(this.context, states[0].modelState, states[0].viewState);\n\t\tthis._setSecondaryStates(states.slice(1));\n\t}\n\n\t/**\n\t * Creates or disposes secondary cursors as necessary to match the number of `secondarySelections`.\n\t */\n\tprivate _setSecondaryStates(secondaryStates: PartialCursorState[]): void {\n\t\tconst secondaryCursorsLength = this.cursors.length - 1;\n\t\tconst secondaryStatesLength = secondaryStates.length;\n\n\t\tif (secondaryCursorsLength < secondaryStatesLength) {\n\t\t\tconst createCnt = secondaryStatesLength - secondaryCursorsLength;\n\t\t\tfor (let i = 0; i < createCnt; i++) {\n\t\t\t\tthis._addSecondaryCursor();\n\t\t\t}\n\t\t} else if (secondaryCursorsLength > secondaryStatesLength) {\n\t\t\tconst removeCnt = secondaryCursorsLength - secondaryStatesLength;\n\t\t\tfor (let i = 0; i < removeCnt; i++) {\n\t\t\t\tthis._removeSecondaryCursor(this.cursors.length - 2);\n\t\t\t}\n\t\t}\n\n\t\tfor (let i = 0; i < secondaryStatesLength; i++) {\n\t\t\tthis.cursors[i + 1].setState(this.context, secondaryStates[i].modelState, secondaryStates[i].viewState);\n\t\t}\n\t}\n\n\tpublic killSecondaryCursors(): void {\n\t\tthis._setSecondaryStates([]);\n\t}\n\n\tprivate _addSecondaryCursor(): void {\n\t\tthis.cursors.push(new Cursor(this.context));\n\t\tthis.lastAddedCursorIndex = this.cursors.length - 1;\n\t}\n\n\tpublic getLastAddedCursorIndex(): number {\n\t\tif (this.cursors.length === 1 || this.lastAddedCursorIndex === 0) {\n\t\t\treturn 0;\n\t\t}\n\t\treturn this.lastAddedCursorIndex;\n\t}\n\n\tprivate _removeSecondaryCursor(removeIndex: number): void {\n\t\tif (this.lastAddedCursorIndex >= removeIndex + 1) {\n\t\t\tthis.lastAddedCursorIndex--;\n\t\t}\n\t\tthis.cursors[removeIndex + 1].dispose(this.context);\n\t\tthis.cursors.splice(removeIndex + 1, 1);\n\t}\n\n\tpublic normalize(): void {\n\t\tif (this.cursors.length === 1) {\n\t\t\treturn;\n\t\t}\n\t\tconst cursors = this.cursors.slice(0);\n\n\t\tinterface SortedCursor {\n\t\t\tindex: number;\n\t\t\tselection: Selection;\n\t\t}\n\t\tconst sortedCursors: SortedCursor[] = [];\n\t\tfor (let i = 0, len = cursors.length; i < len; i++) {\n\t\t\tsortedCursors.push({\n\t\t\t\tindex: i,\n\t\t\t\tselection: cursors[i].modelState.selection,\n\t\t\t});\n\t\t}\n\n\t\tsortedCursors.sort(compareBy(s => s.selection, Range.compareRangesUsingStarts));\n\n\t\tfor (let sortedCursorIndex = 0; sortedCursorIndex < sortedCursors.length - 1; sortedCursorIndex++) {\n\t\t\tconst current = sortedCursors[sortedCursorIndex];\n\t\t\tconst next = sortedCursors[sortedCursorIndex + 1];\n\n\t\t\tconst currentSelection = current.selection;\n\t\t\tconst nextSelection = next.selection;\n\n\t\t\tif (!this.context.cursorConfig.multiCursorMergeOverlapping) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tlet shouldMergeCursors: boolean;\n\t\t\tif (nextSelection.isEmpty() || currentSelection.isEmpty()) {\n\t\t\t\t// Merge touching cursors if one of them is collapsed\n\t\t\t\tshouldMergeCursors = nextSelection.getStartPosition().isBeforeOrEqual(currentSelection.getEndPosition());\n\t\t\t} else {\n\t\t\t\t// Merge only overlapping cursors (i.e. allow touching ranges)\n\t\t\t\tshouldMergeCursors = nextSelection.getStartPosition().isBefore(currentSelection.getEndPosition());\n\t\t\t}\n\n\t\t\tif (shouldMergeCursors) {\n\t\t\t\tconst winnerSortedCursorIndex = current.index < next.index ? sortedCursorIndex : sortedCursorIndex + 1;\n\t\t\t\tconst looserSortedCursorIndex = current.index < next.index ? sortedCursorIndex + 1 : sortedCursorIndex;\n\n\t\t\t\tconst looserIndex = sortedCursors[looserSortedCursorIndex].index;\n\t\t\t\tconst winnerIndex = sortedCursors[winnerSortedCursorIndex].index;\n\n\t\t\t\tconst looserSelection = sortedCursors[looserSortedCursorIndex].selection;\n\t\t\t\tconst winnerSelection = sortedCursors[winnerSortedCursorIndex].selection;\n\n\t\t\t\tif (!looserSelection.equalsSelection(winnerSelection)) {\n\t\t\t\t\tconst resultingRange = looserSelection.plusRange(winnerSelection);\n\t\t\t\t\tconst looserSelectionIsLTR = (looserSelection.selectionStartLineNumber === looserSelection.startLineNumber && looserSelection.selectionStartColumn === looserSelection.startColumn);\n\t\t\t\t\tconst winnerSelectionIsLTR = (winnerSelection.selectionStartLineNumber === winnerSelection.startLineNumber && winnerSelection.selectionStartColumn === winnerSelection.startColumn);\n\n\t\t\t\t\t// Give more importance to the last added cursor (think Ctrl-dragging + hitting another cursor)\n\t\t\t\t\tlet resultingSelectionIsLTR: boolean;\n\t\t\t\t\tif (looserIndex === this.lastAddedCursorIndex) {\n\t\t\t\t\t\tresultingSelectionIsLTR = looserSelectionIsLTR;\n\t\t\t\t\t\tthis.lastAddedCursorIndex = winnerIndex;\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Winner takes it all\n\t\t\t\t\t\tresultingSelectionIsLTR = winnerSelectionIsLTR;\n\t\t\t\t\t}\n\n\t\t\t\t\tlet resultingSelection: Selection;\n\t\t\t\t\tif (resultingSelectionIsLTR) {\n\t\t\t\t\t\tresultingSelection = new Selection(resultingRange.startLineNumber, resultingRange.startColumn, resultingRange.endLineNumber, resultingRange.endColumn);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tresultingSelection = new Selection(resultingRange.endLineNumber, resultingRange.endColumn, resultingRange.startLineNumber, resultingRange.startColumn);\n\t\t\t\t\t}\n\n\t\t\t\t\tsortedCursors[winnerSortedCursorIndex].selection = resultingSelection;\n\t\t\t\t\tconst resultingState = CursorState.fromModelSelection(resultingSelection);\n\t\t\t\t\tcursors[winnerIndex].setState(this.context, resultingState.modelState, resultingState.viewState);\n\t\t\t\t}\n\n\t\t\t\tfor (const sortedCursor of sortedCursors) {\n\t\t\t\t\tif (sortedCursor.index > looserIndex) {\n\t\t\t\t\t\tsortedCursor.index--;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tcursors.splice(looserIndex, 1);\n\t\t\t\tsortedCursors.splice(looserSortedCursorIndex, 1);\n\t\t\t\tthis._removeSecondaryCursor(looserIndex - 1);\n\n\t\t\t\tsortedCursorIndex--;\n\t\t\t}\n\t\t}\n\t}\n}\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\nimport { IAutoClosingPair, StandardAutoClosingPairConditional, LanguageConfiguration } from 'vs/editor/common/languages/languageConfiguration';\n\nexport class CharacterPairSupport {\n\n\tstatic readonly DEFAULT_AUTOCLOSE_BEFORE_LANGUAGE_DEFINED_QUOTES = ';:.,=}])> \\n\\t';\n\tstatic readonly DEFAULT_AUTOCLOSE_BEFORE_LANGUAGE_DEFINED_BRACKETS = '\\'\"`;:.,=}])> \\n\\t';\n\n\tprivate readonly _autoClosingPairs: StandardAutoClosingPairConditional[];\n\tprivate readonly _surroundingPairs: IAutoClosingPair[];\n\tprivate readonly _autoCloseBeforeForQuotes: string;\n\tprivate readonly _autoCloseBeforeForBrackets: string;\n\n\tconstructor(config: LanguageConfiguration) {\n\t\tif (config.autoClosingPairs) {\n\t\t\tthis._autoClosingPairs = config.autoClosingPairs.map(el => new StandardAutoClosingPairConditional(el));\n\t\t} else if (config.brackets) {\n\t\t\tthis._autoClosingPairs = config.brackets.map(b => new StandardAutoClosingPairConditional({ open: b[0], close: b[1] }));\n\t\t} else {\n\t\t\tthis._autoClosingPairs = [];\n\t\t}\n\n\t\tif (config.__electricCharacterSupport && config.__electricCharacterSupport.docComment) {\n\t\t\tconst docComment = config.__electricCharacterSupport.docComment;\n\t\t\t// IDocComment is legacy, only partially supported\n\t\t\tthis._autoClosingPairs.push(new StandardAutoClosingPairConditional({ open: docComment.open, close: docComment.close || '' }));\n\t\t}\n\n\t\tthis._autoCloseBeforeForQuotes = typeof config.autoCloseBefore === 'string' ? config.autoCloseBefore : CharacterPairSupport.DEFAULT_AUTOCLOSE_BEFORE_LANGUAGE_DEFINED_QUOTES;\n\t\tthis._autoCloseBeforeForBrackets = typeof config.autoCloseBefore === 'string' ? config.autoCloseBefore : CharacterPairSupport.DEFAULT_AUTOCLOSE_BEFORE_LANGUAGE_DEFINED_BRACKETS;\n\n\t\tthis._surroundingPairs = config.surroundingPairs || this._autoClosingPairs;\n\t}\n\n\tpublic getAutoClosingPairs(): StandardAutoClosingPairConditional[] {\n\t\treturn this._autoClosingPairs;\n\t}\n\n\tpublic getAutoCloseBeforeSet(forQuotes: boolean): string {\n\t\treturn (forQuotes ? this._autoCloseBeforeForQuotes : this._autoCloseBeforeForBrackets);\n\t}\n\n\tpublic getSurroundingPairs(): IAutoClosingPair[] {\n\t\treturn this._surroundingPairs;\n\t}\n}\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\nimport { IndentationRule } from 'vs/editor/common/languages/languageConfiguration';\n\nexport const enum IndentConsts {\n\tINCREASE_MASK = 0b00000001,\n\tDECREASE_MASK = 0b00000010,\n\tINDENT_NEXTLINE_MASK = 0b00000100,\n\tUNINDENT_MASK = 0b00001000,\n}\n\nfunction resetGlobalRegex(reg: RegExp) {\n\tif (reg.global) {\n\t\treg.lastIndex = 0;\n\t}\n\n\treturn true;\n}\n\nexport class IndentRulesSupport {\n\n\tprivate readonly _indentationRules: IndentationRule;\n\n\tconstructor(indentationRules: IndentationRule) {\n\t\tthis._indentationRules = indentationRules;\n\t}\n\n\tpublic shouldIncrease(text: string): boolean {\n\t\tif (this._indentationRules) {\n\t\t\tif (this._indentationRules.increaseIndentPattern && resetGlobalRegex(this._indentationRules.increaseIndentPattern) && this._indentationRules.increaseIndentPattern.test(text)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\t// if (this._indentationRules.indentNextLinePattern && this._indentationRules.indentNextLinePattern.test(text)) {\n\t\t\t// \treturn true;\n\t\t\t// }\n\t\t}\n\t\treturn false;\n\t}\n\n\tpublic shouldDecrease(text: string): boolean {\n\t\tif (this._indentationRules && this._indentationRules.decreaseIndentPattern && resetGlobalRegex(this._indentationRules.decreaseIndentPattern) && this._indentationRules.decreaseIndentPattern.test(text)) {\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tpublic shouldIndentNextLine(text: string): boolean {\n\t\tif (this._indentationRules && this._indentationRules.indentNextLinePattern && resetGlobalRegex(this._indentationRules.indentNextLinePattern) && this._indentationRules.indentNextLinePattern.test(text)) {\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tpublic shouldIgnore(text: string): boolean {\n\t\t// the text matches `unIndentedLinePattern`\n\t\tif (this._indentationRules && this._indentationRules.unIndentedLinePattern && resetGlobalRegex(this._indentationRules.unIndentedLinePattern) && this._indentationRules.unIndentedLinePattern.test(text)) {\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tpublic getIndentMetadata(text: string): number {\n\t\tlet ret = 0;\n\t\tif (this.shouldIncrease(text)) {\n\t\t\tret += IndentConsts.INCREASE_MASK;\n\t\t}\n\t\tif (this.shouldDecrease(text)) {\n\t\t\tret += IndentConsts.DECREASE_MASK;\n\t\t}\n\t\tif (this.shouldIndentNextLine(text)) {\n\t\t\tret += IndentConsts.INDENT_NEXTLINE_MASK;\n\t\t}\n\t\tif (this.shouldIgnore(text)) {\n\t\t\tret += IndentConsts.UNINDENT_MASK;\n\t\t}\n\t\treturn ret;\n\t}\n}\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\nimport { IRange } from 'vs/editor/common/core/range';\nimport { IInplaceReplaceSupportResult } from 'vs/editor/common/languages';\n\nexport class BasicInplaceReplace {\n\n\tpublic static readonly INSTANCE = new BasicInplaceReplace();\n\n\tpublic navigateValueSet(range1: IRange, text1: string, range2: IRange, text2: string | null, up: boolean): IInplaceReplaceSupportResult | null {\n\n\t\tif (range1 && text1) {\n\t\t\tconst result = this.doNavigateValueSet(text1, up);\n\t\t\tif (result) {\n\t\t\t\treturn {\n\t\t\t\t\trange: range1,\n\t\t\t\t\tvalue: result\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\tif (range2 && text2) {\n\t\t\tconst result = this.doNavigateValueSet(text2, up);\n\t\t\tif (result) {\n\t\t\t\treturn {\n\t\t\t\t\trange: range2,\n\t\t\t\t\tvalue: result\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tprivate doNavigateValueSet(text: string, up: boolean): string | null {\n\t\tconst numberResult = this.numberReplace(text, up);\n\t\tif (numberResult !== null) {\n\t\t\treturn numberResult;\n\t\t}\n\t\treturn this.textReplace(text, up);\n\t}\n\n\tprivate numberReplace(value: string, up: boolean): string | null {\n\t\tconst precision = Math.pow(10, value.length - (value.lastIndexOf('.') + 1));\n\t\tlet n1 = Number(value);\n\t\tconst n2 = parseFloat(value);\n\n\t\tif (!isNaN(n1) && !isNaN(n2) && n1 === n2) {\n\n\t\t\tif (n1 === 0 && !up) {\n\t\t\t\treturn null; // don't do negative\n\t\t\t\t//\t\t\t} else if(n1 === 9 && up) {\n\t\t\t\t//\t\t\t\treturn null; // don't insert 10 into a number\n\t\t\t} else {\n\t\t\t\tn1 = Math.floor(n1 * precision);\n\t\t\t\tn1 += up ? precision : -precision;\n\t\t\t\treturn String(n1 / precision);\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tprivate readonly _defaultValueSet: string[][] = [\n\t\t['true', 'false'],\n\t\t['True', 'False'],\n\t\t['Private', 'Public', 'Friend', 'ReadOnly', 'Partial', 'Protected', 'WriteOnly'],\n\t\t['public', 'protected', 'private'],\n\t];\n\n\tprivate textReplace(value: string, up: boolean): string | null {\n\t\treturn this.valueSetsReplace(this._defaultValueSet, value, up);\n\t}\n\n\tprivate valueSetsReplace(valueSets: string[][], value: string, up: boolean): string | null {\n\t\tlet result: string | null = null;\n\t\tfor (let i = 0, len = valueSets.length; result === null && i < len; i++) {\n\t\t\tresult = this.valueSetReplace(valueSets[i], value, up);\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate valueSetReplace(valueSet: string[], value: string, up: boolean): string | null {\n\t\tlet idx = valueSet.indexOf(value);\n\t\tif (idx >= 0) {\n\t\t\tidx += up ? +1 : -1;\n\t\t\tif (idx < 0) {\n\t\t\t\tidx = valueSet.length - 1;\n\t\t\t} else {\n\t\t\t\tidx %= valueSet.length;\n\t\t\t}\n\t\t\treturn valueSet[idx];\n\t\t}\n\t\treturn null;\n\t}\n}\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\nimport { CachedFunction } from 'vs/base/common/cache';\nimport { LanguageConfiguration } from 'vs/editor/common/languages/languageConfiguration';\n\n/**\n * Captures all bracket related configurations for a single language.\n * Immutable.\n*/\nexport class LanguageBracketsConfiguration {\n\tprivate readonly _openingBrackets: ReadonlyMap;\n\tprivate readonly _closingBrackets: ReadonlyMap;\n\n\tconstructor(\n\t\tpublic readonly languageId: string,\n\t\tconfig: LanguageConfiguration,\n\t) {\n\t\tconst bracketPairs = config.brackets ? filterValidBrackets(config.brackets) : [];\n\t\tconst openingBracketInfos = new CachedFunction((bracket: string) => {\n\t\t\tconst closing = new Set();\n\n\t\t\treturn {\n\t\t\t\tinfo: new OpeningBracketKind(this, bracket, closing),\n\t\t\t\tclosing,\n\t\t\t};\n\t\t});\n\t\tconst closingBracketInfos = new CachedFunction((bracket: string) => {\n\t\t\tconst opening = new Set();\n\t\t\tconst openingColorized = new Set();\n\t\t\treturn {\n\t\t\t\tinfo: new ClosingBracketKind(this, bracket, opening, openingColorized),\n\t\t\t\topening,\n\t\t\t\topeningColorized,\n\t\t\t};\n\t\t});\n\n\t\tfor (const [open, close] of bracketPairs) {\n\t\t\tconst opening = openingBracketInfos.get(open);\n\t\t\tconst closing = closingBracketInfos.get(close);\n\n\t\t\topening.closing.add(closing.info);\n\t\t\tclosing.opening.add(opening.info);\n\t\t}\n\n\t\t// Treat colorized brackets as brackets, and mark them as colorized.\n\t\tconst colorizedBracketPairs = config.colorizedBracketPairs\n\t\t\t? filterValidBrackets(config.colorizedBracketPairs)\n\t\t\t// If not configured: Take all brackets except `<` ... `>`\n\t\t\t// Many languages set < ... > as bracket pair, even though they also use it as comparison operator.\n\t\t\t// This leads to problems when colorizing this bracket, so we exclude it if not explicitly configured otherwise.\n\t\t\t// https://github.com/microsoft/vscode/issues/132476\n\t\t\t: bracketPairs.filter((p) => !(p[0] === '<' && p[1] === '>'));\n\t\tfor (const [open, close] of colorizedBracketPairs) {\n\t\t\tconst opening = openingBracketInfos.get(open);\n\t\t\tconst closing = closingBracketInfos.get(close);\n\n\t\t\topening.closing.add(closing.info);\n\t\t\tclosing.openingColorized.add(opening.info);\n\t\t\tclosing.opening.add(opening.info);\n\t\t}\n\n\t\tthis._openingBrackets = new Map([...openingBracketInfos.cachedValues].map(([k, v]) => [k, v.info]));\n\t\tthis._closingBrackets = new Map([...closingBracketInfos.cachedValues].map(([k, v]) => [k, v.info]));\n\t}\n\n\t/**\n\t * No two brackets have the same bracket text.\n\t*/\n\tpublic get openingBrackets(): readonly OpeningBracketKind[] {\n\t\treturn [...this._openingBrackets.values()];\n\t}\n\n\t/**\n\t * No two brackets have the same bracket text.\n\t*/\n\tpublic get closingBrackets(): readonly ClosingBracketKind[] {\n\t\treturn [...this._closingBrackets.values()];\n\t}\n\n\tpublic getOpeningBracketInfo(bracketText: string): OpeningBracketKind | undefined {\n\t\treturn this._openingBrackets.get(bracketText);\n\t}\n\n\tpublic getClosingBracketInfo(bracketText: string): ClosingBracketKind | undefined {\n\t\treturn this._closingBrackets.get(bracketText);\n\t}\n\n\tpublic getBracketInfo(bracketText: string): BracketKind | undefined {\n\t\treturn this.getOpeningBracketInfo(bracketText) || this.getClosingBracketInfo(bracketText);\n\t}\n}\n\nfunction filterValidBrackets(bracketPairs: [string, string][]): [string, string][] {\n\treturn bracketPairs.filter(([open, close]) => open !== '' && close !== '');\n}\n\nexport type BracketKind = OpeningBracketKind | ClosingBracketKind;\n\nexport class BracketKindBase {\n\tconstructor(\n\t\tprotected readonly config: LanguageBracketsConfiguration,\n\t\tpublic readonly bracketText: string,\n\t) { }\n\n\tpublic get languageId(): string {\n\t\treturn this.config.languageId;\n\t}\n}\n\nexport class OpeningBracketKind extends BracketKindBase {\n\tpublic readonly isOpeningBracket = true;\n\n\tconstructor(\n\t\tconfig: LanguageBracketsConfiguration,\n\t\tbracketText: string,\n\t\tpublic readonly openedBrackets: ReadonlySet,\n\t) {\n\t\tsuper(config, bracketText);\n\t}\n}\n\nexport class ClosingBracketKind extends BracketKindBase {\n\tpublic readonly isOpeningBracket = false;\n\n\tconstructor(\n\t\tconfig: LanguageBracketsConfiguration,\n\t\tbracketText: string,\n\t\t/**\n\t\t * Non empty array of all opening brackets this bracket closes.\n\t\t*/\n\t\tpublic readonly openingBrackets: ReadonlySet,\n\t\tprivate readonly openingColorizedBrackets: ReadonlySet,\n\t) {\n\t\tsuper(config, bracketText);\n\t}\n\n\t/**\n\t * Checks if this bracket closes the given other bracket.\n\t * If the bracket infos come from different configurations, this method will return false.\n\t*/\n\tpublic closes(other: OpeningBracketKind): boolean {\n\t\tif (other['config'] !== this.config) {\n\t\t\treturn false;\n\t\t}\n\t\treturn this.openingBrackets.has(other);\n\t}\n\n\tpublic closesColorized(other: OpeningBracketKind): boolean {\n\t\tif (other['config'] !== this.config) {\n\t\t\treturn false;\n\t\t}\n\t\treturn this.openingColorizedBrackets.has(other);\n\t}\n\n\tpublic getOpeningBrackets(): readonly OpeningBracketKind[] {\n\t\treturn [...this.openingBrackets];\n\t}\n}\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\nimport { onUnexpectedError } from 'vs/base/common/errors';\nimport * as strings from 'vs/base/common/strings';\nimport { CharacterPair, EnterAction, IndentAction, OnEnterRule } from 'vs/editor/common/languages/languageConfiguration';\nimport { EditorAutoIndentStrategy } from 'vs/editor/common/config/editorOptions';\n\nexport interface IOnEnterSupportOptions {\n\tbrackets?: CharacterPair[];\n\tonEnterRules?: OnEnterRule[];\n}\n\ninterface IProcessedBracketPair {\n\topen: string;\n\tclose: string;\n\topenRegExp: RegExp;\n\tcloseRegExp: RegExp;\n}\n\nexport class OnEnterSupport {\n\n\tprivate readonly _brackets: IProcessedBracketPair[];\n\tprivate readonly _regExpRules: OnEnterRule[];\n\n\tconstructor(opts: IOnEnterSupportOptions) {\n\t\topts = opts || {};\n\t\topts.brackets = opts.brackets || [\n\t\t\t['(', ')'],\n\t\t\t['{', '}'],\n\t\t\t['[', ']']\n\t\t];\n\n\t\tthis._brackets = [];\n\t\topts.brackets.forEach((bracket) => {\n\t\t\tconst openRegExp = OnEnterSupport._createOpenBracketRegExp(bracket[0]);\n\t\t\tconst closeRegExp = OnEnterSupport._createCloseBracketRegExp(bracket[1]);\n\t\t\tif (openRegExp && closeRegExp) {\n\t\t\t\tthis._brackets.push({\n\t\t\t\t\topen: bracket[0],\n\t\t\t\t\topenRegExp: openRegExp,\n\t\t\t\t\tclose: bracket[1],\n\t\t\t\t\tcloseRegExp: closeRegExp,\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t\tthis._regExpRules = opts.onEnterRules || [];\n\t}\n\n\tpublic onEnter(autoIndent: EditorAutoIndentStrategy, previousLineText: string, beforeEnterText: string, afterEnterText: string): EnterAction | null {\n\t\t// (1): `regExpRules`\n\t\tif (autoIndent >= EditorAutoIndentStrategy.Advanced) {\n\t\t\tfor (let i = 0, len = this._regExpRules.length; i < len; i++) {\n\t\t\t\tconst rule = this._regExpRules[i];\n\t\t\t\tconst regResult = [{\n\t\t\t\t\treg: rule.beforeText,\n\t\t\t\t\ttext: beforeEnterText\n\t\t\t\t}, {\n\t\t\t\t\treg: rule.afterText,\n\t\t\t\t\ttext: afterEnterText\n\t\t\t\t}, {\n\t\t\t\t\treg: rule.previousLineText,\n\t\t\t\t\ttext: previousLineText\n\t\t\t\t}].every((obj): boolean => {\n\t\t\t\t\tif (!obj.reg) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\n\t\t\t\t\tobj.reg.lastIndex = 0; // To disable the effect of the \"g\" flag.\n\t\t\t\t\treturn obj.reg.test(obj.text);\n\t\t\t\t});\n\n\t\t\t\tif (regResult) {\n\t\t\t\t\treturn rule.action;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// (2): Special indent-outdent\n\t\tif (autoIndent >= EditorAutoIndentStrategy.Brackets) {\n\t\t\tif (beforeEnterText.length > 0 && afterEnterText.length > 0) {\n\t\t\t\tfor (let i = 0, len = this._brackets.length; i < len; i++) {\n\t\t\t\t\tconst bracket = this._brackets[i];\n\t\t\t\t\tif (bracket.openRegExp.test(beforeEnterText) && bracket.closeRegExp.test(afterEnterText)) {\n\t\t\t\t\t\treturn { indentAction: IndentAction.IndentOutdent };\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\n\t\t// (4): Open bracket based logic\n\t\tif (autoIndent >= EditorAutoIndentStrategy.Brackets) {\n\t\t\tif (beforeEnterText.length > 0) {\n\t\t\t\tfor (let i = 0, len = this._brackets.length; i < len; i++) {\n\t\t\t\t\tconst bracket = this._brackets[i];\n\t\t\t\t\tif (bracket.openRegExp.test(beforeEnterText)) {\n\t\t\t\t\t\treturn { indentAction: IndentAction.Indent };\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tprivate static _createOpenBracketRegExp(bracket: string): RegExp | null {\n\t\tlet str = strings.escapeRegExpCharacters(bracket);\n\t\tif (!/\\B/.test(str.charAt(0))) {\n\t\t\tstr = '\\\\b' + str;\n\t\t}\n\t\tstr += '\\\\s*$';\n\t\treturn OnEnterSupport._safeRegExp(str);\n\t}\n\n\tprivate static _createCloseBracketRegExp(bracket: string): RegExp | null {\n\t\tlet str = strings.escapeRegExpCharacters(bracket);\n\t\tif (!/\\B/.test(str.charAt(str.length - 1))) {\n\t\t\tstr = str + '\\\\b';\n\t\t}\n\t\tstr = '^\\\\s*' + str;\n\t\treturn OnEnterSupport._safeRegExp(str);\n\t}\n\n\tprivate static _safeRegExp(def: string): RegExp | null {\n\t\ttry {\n\t\t\treturn new RegExp(def);\n\t\t} catch (err) {\n\t\t\tonUnexpectedError(err);\n\t\t\treturn null;\n\t\t}\n\t}\n}\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\nimport { Color } from 'vs/base/common/color';\nimport { LanguageId, FontStyle, ColorId, StandardTokenType, MetadataConsts } from 'vs/editor/common/encodedTokenAttributes';\n\nexport interface ITokenThemeRule {\n\ttoken: string;\n\tforeground?: string;\n\tbackground?: string;\n\tfontStyle?: string;\n}\n\nexport class ParsedTokenThemeRule {\n\t_parsedThemeRuleBrand: void = undefined;\n\n\treadonly token: string;\n\treadonly index: number;\n\n\t/**\n\t * -1 if not set. An or mask of `FontStyle` otherwise.\n\t */\n\treadonly fontStyle: FontStyle;\n\treadonly foreground: string | null;\n\treadonly background: string | null;\n\n\tconstructor(\n\t\ttoken: string,\n\t\tindex: number,\n\t\tfontStyle: number,\n\t\tforeground: string | null,\n\t\tbackground: string | null,\n\t) {\n\t\tthis.token = token;\n\t\tthis.index = index;\n\t\tthis.fontStyle = fontStyle;\n\t\tthis.foreground = foreground;\n\t\tthis.background = background;\n\t}\n}\n\n/**\n * Parse a raw theme into rules.\n */\nexport function parseTokenTheme(source: ITokenThemeRule[]): ParsedTokenThemeRule[] {\n\tif (!source || !Array.isArray(source)) {\n\t\treturn [];\n\t}\n\tconst result: ParsedTokenThemeRule[] = [];\n\tlet resultLen = 0;\n\tfor (let i = 0, len = source.length; i < len; i++) {\n\t\tconst entry = source[i];\n\n\t\tlet fontStyle: number = FontStyle.NotSet;\n\t\tif (typeof entry.fontStyle === 'string') {\n\t\t\tfontStyle = FontStyle.None;\n\n\t\t\tconst segments = entry.fontStyle.split(' ');\n\t\t\tfor (let j = 0, lenJ = segments.length; j < lenJ; j++) {\n\t\t\t\tconst segment = segments[j];\n\t\t\t\tswitch (segment) {\n\t\t\t\t\tcase 'italic':\n\t\t\t\t\t\tfontStyle = fontStyle | FontStyle.Italic;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'bold':\n\t\t\t\t\t\tfontStyle = fontStyle | FontStyle.Bold;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'underline':\n\t\t\t\t\t\tfontStyle = fontStyle | FontStyle.Underline;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'strikethrough':\n\t\t\t\t\t\tfontStyle = fontStyle | FontStyle.Strikethrough;\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tlet foreground: string | null = null;\n\t\tif (typeof entry.foreground === 'string') {\n\t\t\tforeground = entry.foreground;\n\t\t}\n\n\t\tlet background: string | null = null;\n\t\tif (typeof entry.background === 'string') {\n\t\t\tbackground = entry.background;\n\t\t}\n\n\t\tresult[resultLen++] = new ParsedTokenThemeRule(\n\t\t\tentry.token || '',\n\t\t\ti,\n\t\t\tfontStyle,\n\t\t\tforeground,\n\t\t\tbackground\n\t\t);\n\t}\n\n\treturn result;\n}\n\n/**\n * Resolve rules (i.e. inheritance).\n */\nfunction resolveParsedTokenThemeRules(parsedThemeRules: ParsedTokenThemeRule[], customTokenColors: string[]): TokenTheme {\n\n\t// Sort rules lexicographically, and then by index if necessary\n\tparsedThemeRules.sort((a, b) => {\n\t\tconst r = strcmp(a.token, b.token);\n\t\tif (r !== 0) {\n\t\t\treturn r;\n\t\t}\n\t\treturn a.index - b.index;\n\t});\n\n\t// Determine defaults\n\tlet defaultFontStyle = FontStyle.None;\n\tlet defaultForeground = '000000';\n\tlet defaultBackground = 'ffffff';\n\twhile (parsedThemeRules.length >= 1 && parsedThemeRules[0].token === '') {\n\t\tconst incomingDefaults = parsedThemeRules.shift()!;\n\t\tif (incomingDefaults.fontStyle !== FontStyle.NotSet) {\n\t\t\tdefaultFontStyle = incomingDefaults.fontStyle;\n\t\t}\n\t\tif (incomingDefaults.foreground !== null) {\n\t\t\tdefaultForeground = incomingDefaults.foreground;\n\t\t}\n\t\tif (incomingDefaults.background !== null) {\n\t\t\tdefaultBackground = incomingDefaults.background;\n\t\t}\n\t}\n\tconst colorMap = new ColorMap();\n\n\t// start with token colors from custom token themes\n\tfor (const color of customTokenColors) {\n\t\tcolorMap.getId(color);\n\t}\n\n\n\tconst foregroundColorId = colorMap.getId(defaultForeground);\n\tconst backgroundColorId = colorMap.getId(defaultBackground);\n\n\tconst defaults = new ThemeTrieElementRule(defaultFontStyle, foregroundColorId, backgroundColorId);\n\tconst root = new ThemeTrieElement(defaults);\n\tfor (let i = 0, len = parsedThemeRules.length; i < len; i++) {\n\t\tconst rule = parsedThemeRules[i];\n\t\troot.insert(rule.token, rule.fontStyle, colorMap.getId(rule.foreground), colorMap.getId(rule.background));\n\t}\n\n\treturn new TokenTheme(colorMap, root);\n}\n\nconst colorRegExp = /^#?([0-9A-Fa-f]{6})([0-9A-Fa-f]{2})?$/;\n\nexport class ColorMap {\n\n\tprivate _lastColorId: number;\n\tprivate readonly _id2color: Color[];\n\tprivate readonly _color2id: Map;\n\n\tconstructor() {\n\t\tthis._lastColorId = 0;\n\t\tthis._id2color = [];\n\t\tthis._color2id = new Map();\n\t}\n\n\tpublic getId(color: string | null): ColorId {\n\t\tif (color === null) {\n\t\t\treturn 0;\n\t\t}\n\t\tconst match = color.match(colorRegExp);\n\t\tif (!match) {\n\t\t\tthrow new Error('Illegal value for token color: ' + color);\n\t\t}\n\t\tcolor = match[1].toUpperCase();\n\t\tlet value = this._color2id.get(color);\n\t\tif (value) {\n\t\t\treturn value;\n\t\t}\n\t\tvalue = ++this._lastColorId;\n\t\tthis._color2id.set(color, value);\n\t\tthis._id2color[value] = Color.fromHex('#' + color);\n\t\treturn value;\n\t}\n\n\tpublic getColorMap(): Color[] {\n\t\treturn this._id2color.slice(0);\n\t}\n\n}\n\nexport class TokenTheme {\n\n\tpublic static createFromRawTokenTheme(source: ITokenThemeRule[], customTokenColors: string[]): TokenTheme {\n\t\treturn this.createFromParsedTokenTheme(parseTokenTheme(source), customTokenColors);\n\t}\n\n\tpublic static createFromParsedTokenTheme(source: ParsedTokenThemeRule[], customTokenColors: string[]): TokenTheme {\n\t\treturn resolveParsedTokenThemeRules(source, customTokenColors);\n\t}\n\n\tprivate readonly _colorMap: ColorMap;\n\tprivate readonly _root: ThemeTrieElement;\n\tprivate readonly _cache: Map;\n\n\tconstructor(colorMap: ColorMap, root: ThemeTrieElement) {\n\t\tthis._colorMap = colorMap;\n\t\tthis._root = root;\n\t\tthis._cache = new Map();\n\t}\n\n\tpublic getColorMap(): Color[] {\n\t\treturn this._colorMap.getColorMap();\n\t}\n\n\tpublic _match(token: string): ThemeTrieElementRule {\n\t\treturn this._root.match(token);\n\t}\n\n\tpublic match(languageId: LanguageId, token: string): number {\n\t\t// The cache contains the metadata without the language bits set.\n\t\tlet result = this._cache.get(token);\n\t\tif (typeof result === 'undefined') {\n\t\t\tconst rule = this._match(token);\n\t\t\tconst standardToken = toStandardTokenType(token);\n\t\t\tresult = (\n\t\t\t\trule.metadata\n\t\t\t\t| (standardToken << MetadataConsts.TOKEN_TYPE_OFFSET)\n\t\t\t) >>> 0;\n\t\t\tthis._cache.set(token, result);\n\t\t}\n\n\t\treturn (\n\t\t\tresult\n\t\t\t| (languageId << MetadataConsts.LANGUAGEID_OFFSET)\n\t\t) >>> 0;\n\t}\n}\n\nconst STANDARD_TOKEN_TYPE_REGEXP = /\\b(comment|string|regex|regexp)\\b/;\nexport function toStandardTokenType(tokenType: string): StandardTokenType {\n\tconst m = tokenType.match(STANDARD_TOKEN_TYPE_REGEXP);\n\tif (!m) {\n\t\treturn StandardTokenType.Other;\n\t}\n\tswitch (m[1]) {\n\t\tcase 'comment':\n\t\t\treturn StandardTokenType.Comment;\n\t\tcase 'string':\n\t\t\treturn StandardTokenType.String;\n\t\tcase 'regex':\n\t\t\treturn StandardTokenType.RegEx;\n\t\tcase 'regexp':\n\t\t\treturn StandardTokenType.RegEx;\n\t}\n\tthrow new Error('Unexpected match for standard token type!');\n}\n\nexport function strcmp(a: string, b: string): number {\n\tif (a < b) {\n\t\treturn -1;\n\t}\n\tif (a > b) {\n\t\treturn 1;\n\t}\n\treturn 0;\n}\n\nexport class ThemeTrieElementRule {\n\t_themeTrieElementRuleBrand: void = undefined;\n\n\tprivate _fontStyle: FontStyle;\n\tprivate _foreground: ColorId;\n\tprivate _background: ColorId;\n\tpublic metadata: number;\n\n\tconstructor(fontStyle: FontStyle, foreground: ColorId, background: ColorId) {\n\t\tthis._fontStyle = fontStyle;\n\t\tthis._foreground = foreground;\n\t\tthis._background = background;\n\t\tthis.metadata = (\n\t\t\t(this._fontStyle << MetadataConsts.FONT_STYLE_OFFSET)\n\t\t\t| (this._foreground << MetadataConsts.FOREGROUND_OFFSET)\n\t\t\t| (this._background << MetadataConsts.BACKGROUND_OFFSET)\n\t\t) >>> 0;\n\t}\n\n\tpublic clone(): ThemeTrieElementRule {\n\t\treturn new ThemeTrieElementRule(this._fontStyle, this._foreground, this._background);\n\t}\n\n\tpublic acceptOverwrite(fontStyle: FontStyle, foreground: ColorId, background: ColorId): void {\n\t\tif (fontStyle !== FontStyle.NotSet) {\n\t\t\tthis._fontStyle = fontStyle;\n\t\t}\n\t\tif (foreground !== ColorId.None) {\n\t\t\tthis._foreground = foreground;\n\t\t}\n\t\tif (background !== ColorId.None) {\n\t\t\tthis._background = background;\n\t\t}\n\t\tthis.metadata = (\n\t\t\t(this._fontStyle << MetadataConsts.FONT_STYLE_OFFSET)\n\t\t\t| (this._foreground << MetadataConsts.FOREGROUND_OFFSET)\n\t\t\t| (this._background << MetadataConsts.BACKGROUND_OFFSET)\n\t\t) >>> 0;\n\t}\n}\n\nexport class ThemeTrieElement {\n\t_themeTrieElementBrand: void = undefined;\n\n\tprivate readonly _mainRule: ThemeTrieElementRule;\n\tprivate readonly _children: Map;\n\n\tconstructor(mainRule: ThemeTrieElementRule) {\n\t\tthis._mainRule = mainRule;\n\t\tthis._children = new Map();\n\t}\n\n\tpublic match(token: string): ThemeTrieElementRule {\n\t\tif (token === '') {\n\t\t\treturn this._mainRule;\n\t\t}\n\n\t\tconst dotIndex = token.indexOf('.');\n\t\tlet head: string;\n\t\tlet tail: string;\n\t\tif (dotIndex === -1) {\n\t\t\thead = token;\n\t\t\ttail = '';\n\t\t} else {\n\t\t\thead = token.substring(0, dotIndex);\n\t\t\ttail = token.substring(dotIndex + 1);\n\t\t}\n\n\t\tconst child = this._children.get(head);\n\t\tif (typeof child !== 'undefined') {\n\t\t\treturn child.match(tail);\n\t\t}\n\n\t\treturn this._mainRule;\n\t}\n\n\tpublic insert(token: string, fontStyle: FontStyle, foreground: ColorId, background: ColorId): void {\n\t\tif (token === '') {\n\t\t\t// Merge into the main rule\n\t\t\tthis._mainRule.acceptOverwrite(fontStyle, foreground, background);\n\t\t\treturn;\n\t\t}\n\n\t\tconst dotIndex = token.indexOf('.');\n\t\tlet head: string;\n\t\tlet tail: string;\n\t\tif (dotIndex === -1) {\n\t\t\thead = token;\n\t\t\ttail = '';\n\t\t} else {\n\t\t\thead = token.substring(0, dotIndex);\n\t\t\ttail = token.substring(dotIndex + 1);\n\t\t}\n\n\t\tlet child = this._children.get(head);\n\t\tif (typeof child === 'undefined') {\n\t\t\tchild = new ThemeTrieElement(this._mainRule.clone());\n\t\t\tthis._children.set(head, child);\n\t\t}\n\n\t\tchild.insert(tail, fontStyle, foreground, background);\n\t}\n}\n\nexport function generateTokensCSSForColorMap(colorMap: readonly Color[]): string {\n\tconst rules: string[] = [];\n\tfor (let i = 1, len = colorMap.length; i < len; i++) {\n\t\tconst color = colorMap[i];\n\t\trules[i] = `.mtk${i} { color: ${color}; }`;\n\t}\n\trules.push('.mtki { font-style: italic; }');\n\trules.push('.mtkb { font-weight: bold; }');\n\trules.push('.mtku { text-decoration: underline; text-underline-position: under; }');\n\trules.push('.mtks { text-decoration: line-through; }');\n\trules.push('.mtks.mtku { text-decoration: underline line-through; text-underline-position: under; }');\n\treturn rules.join('\\n');\n}\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\nimport { Event } from 'vs/base/common/event';\nimport { IMarkdownString } from 'vs/base/common/htmlContent';\nimport { IDisposable } from 'vs/base/common/lifecycle';\nimport { equals } from 'vs/base/common/objects';\nimport { ThemeColor } from 'vs/base/common/themables';\nimport { URI } from 'vs/base/common/uri';\nimport { ISingleEditOperation } from 'vs/editor/common/core/editOperation';\nimport { IPosition, Position } from 'vs/editor/common/core/position';\nimport { IRange, Range } from 'vs/editor/common/core/range';\nimport { Selection } from 'vs/editor/common/core/selection';\nimport { TextChange } from 'vs/editor/common/core/textChange';\nimport { WordCharacterClassifier } from 'vs/editor/common/core/wordCharacterClassifier';\nimport { IWordAtPosition } from 'vs/editor/common/core/wordHelper';\nimport { FormattingOptions } from 'vs/editor/common/languages';\nimport { ILanguageSelection } from 'vs/editor/common/languages/language';\nimport { IBracketPairsTextModelPart } from 'vs/editor/common/textModelBracketPairs';\nimport { IModelContentChange, IModelContentChangedEvent, IModelDecorationsChangedEvent, IModelLanguageChangedEvent, IModelLanguageConfigurationChangedEvent, IModelOptionsChangedEvent, IModelTokensChangedEvent, InternalModelContentChangeEvent, ModelInjectedTextChangedEvent } from 'vs/editor/common/textModelEvents';\nimport { IGuidesTextModelPart } from 'vs/editor/common/textModelGuides';\nimport { ITokenizationTextModelPart } from 'vs/editor/common/tokenizationTextModelPart';\nimport { UndoRedoGroup } from 'vs/platform/undoRedo/common/undoRedo';\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\n/**\n * Vertical Lane in the glyph margin of the editor.\n */\nexport enum GlyphMarginLane {\n\tLeft = 1,\n\tCenter = 2,\n\tRight = 3,\n}\n\nexport interface IGlyphMarginLanesModel {\n\t/**\n\t * The number of lanes that should be rendered in the editor.\n\t */\n\treadonly requiredLanes: number;\n\n\t/**\n\t * Gets the lanes that should be rendered starting at a given line number.\n\t */\n\tgetLanesAtLine(lineNumber: number): GlyphMarginLane[];\n\n\t/**\n\t * Resets the model and ensures it can contain at least `maxLine` lines.\n\t */\n\treset(maxLine: number): void;\n\n\t/**\n\t * Registers that a lane should be visible at the Range in the model.\n\t * @param persist - if true, notes that the lane should always be visible,\n\t * even on lines where there's no specific request for that lane.\n\t */\n\tpush(lane: GlyphMarginLane, range: Range, persist?: boolean): void;\n}\n\n/**\n * Position in the minimap to render the decoration.\n */\nexport const enum MinimapPosition {\n\tInline = 1,\n\tGutter = 2\n}\n\n/**\n * Section header style.\n */\nexport const enum MinimapSectionHeaderStyle {\n\tNormal = 1,\n\tUnderlined = 2\n}\n\nexport interface IDecorationOptions {\n\t/**\n\t * CSS color to render.\n\t * e.g.: rgba(100, 100, 100, 0.5) or a color from the color registry\n\t */\n\tcolor: string | ThemeColor | undefined;\n\t/**\n\t * CSS color to render.\n\t * e.g.: rgba(100, 100, 100, 0.5) or a color from the color registry\n\t */\n\tdarkColor?: string | ThemeColor;\n}\n\nexport interface IModelDecorationGlyphMarginOptions {\n\t/**\n\t * The position in the glyph margin.\n\t */\n\tposition: GlyphMarginLane;\n\n\t/**\n\t * Whether the glyph margin lane in {@link position} should be rendered even\n\t * outside of this decoration's range.\n\t */\n\tpersistLane?: boolean;\n}\n\n/**\n * Options for rendering a model decoration in the overview ruler.\n */\nexport interface IModelDecorationOverviewRulerOptions extends IDecorationOptions {\n\t/**\n\t * The position in the overview ruler.\n\t */\n\tposition: OverviewRulerLane;\n}\n\n/**\n * Options for rendering a model decoration in the minimap.\n */\nexport interface IModelDecorationMinimapOptions extends IDecorationOptions {\n\t/**\n\t * The position in the minimap.\n\t */\n\tposition: MinimapPosition;\n\t/**\n\t * If the decoration is for a section header, which header style.\n\t */\n\tsectionHeaderStyle?: MinimapSectionHeaderStyle | null;\n\t/**\n\t * If the decoration is for a section header, the header text.\n\t */\n\tsectionHeaderText?: string | null;\n}\n\n/**\n * Options for a model decoration.\n */\nexport interface IModelDecorationOptions {\n\t/**\n\t * A debug description that can be used for inspecting model decorations.\n\t * @internal\n\t */\n\tdescription: string;\n\t/**\n\t * Customize the growing behavior of the decoration when typing at the edges of the decoration.\n\t * Defaults to TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges\n\t */\n\tstickiness?: TrackedRangeStickiness;\n\t/**\n\t * CSS class name describing the decoration.\n\t */\n\tclassName?: string | null;\n\t/**\n\t * Indicates whether the decoration should span across the entire line when it continues onto the next line.\n\t */\n\tshouldFillLineOnLineBreak?: boolean | null;\n\tblockClassName?: string | null;\n\t/**\n\t * Indicates if this block should be rendered after the last line.\n\t * In this case, the range must be empty and set to the last line.\n\t */\n\tblockIsAfterEnd?: boolean | null;\n\tblockDoesNotCollapse?: boolean | null;\n\tblockPadding?: [top: number, right: number, bottom: number, left: number] | null;\n\n\t/**\n\t * Message to be rendered when hovering over the glyph margin decoration.\n\t */\n\tglyphMarginHoverMessage?: IMarkdownString | IMarkdownString[] | null;\n\t/**\n\t * Array of MarkdownString to render as the decoration message.\n\t */\n\thoverMessage?: IMarkdownString | IMarkdownString[] | null;\n\t/**\n\t * Array of MarkdownString to render as the line number message.\n\t */\n\tlineNumberHoverMessage?: IMarkdownString | IMarkdownString[] | null;\n\t/**\n\t * Should the decoration expand to encompass a whole line.\n\t */\n\tisWholeLine?: boolean;\n\t/**\n\t * Always render the decoration (even when the range it encompasses is collapsed).\n\t */\n\tshowIfCollapsed?: boolean;\n\t/**\n\t * Collapse the decoration if its entire range is being replaced via an edit.\n\t * @internal\n\t */\n\tcollapseOnReplaceEdit?: boolean;\n\t/**\n\t * Specifies the stack order of a decoration.\n\t * A decoration with greater stack order is always in front of a decoration with\n\t * a lower stack order when the decorations are on the same line.\n\t */\n\tzIndex?: number;\n\t/**\n\t * If set, render this decoration in the overview ruler.\n\t */\n\toverviewRuler?: IModelDecorationOverviewRulerOptions | null;\n\t/**\n\t * If set, render this decoration in the minimap.\n\t */\n\tminimap?: IModelDecorationMinimapOptions | null;\n\t/**\n\t * If set, the decoration will be rendered in the glyph margin with this CSS class name.\n\t */\n\tglyphMarginClassName?: string | null;\n\t/**\n\t * If set and the decoration has {@link glyphMarginClassName} set, render this decoration\n\t * with the specified {@link IModelDecorationGlyphMarginOptions} in the glyph margin.\n\t */\n\tglyphMargin?: IModelDecorationGlyphMarginOptions | null;\n\t/**\n\t * If set, the decoration will be rendered in the lines decorations with this CSS class name.\n\t */\n\tlinesDecorationsClassName?: string | null;\n\t/**\n\t * Controls the tooltip text of the line decoration.\n\t */\n\tlinesDecorationsTooltip?: string | null;\n\t/**\n\t * If set, the decoration will be rendered on the line number.\n\t */\n\tlineNumberClassName?: string | null;\n\t/**\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.\n\t */\n\tfirstLineDecorationClassName?: string | null;\n\t/**\n\t * If set, the decoration will be rendered in the margin (covering its full width) with this CSS class name.\n\t */\n\tmarginClassName?: string | null;\n\t/**\n\t * If set, the decoration will be rendered inline with the text with this CSS class name.\n\t * Please use this only for CSS rules that must impact the text. For example, use `className`\n\t * to have a background color decoration.\n\t */\n\tinlineClassName?: string | null;\n\t/**\n\t * If there is an `inlineClassName` which affects letter spacing.\n\t */\n\tinlineClassNameAffectsLetterSpacing?: boolean;\n\t/**\n\t * If set, the decoration will be rendered before the text with this CSS class name.\n\t */\n\tbeforeContentClassName?: string | null;\n\t/**\n\t * If set, the decoration will be rendered after the text with this CSS class name.\n\t */\n\tafterContentClassName?: string | null;\n\t/**\n\t * If set, text will be injected in the view after the range.\n\t */\n\tafter?: InjectedTextOptions | null;\n\n\t/**\n\t * If set, text will be injected in the view before the range.\n\t */\n\tbefore?: InjectedTextOptions | null;\n\n\t/**\n\t * If set, this decoration will not be rendered for comment tokens.\n\t * @internal\n\t*/\n\thideInCommentTokens?: boolean | null;\n\n\t/**\n\t * If set, this decoration will not be rendered for string tokens.\n\t * @internal\n\t*/\n\thideInStringTokens?: boolean | null;\n}\n\n/**\n * Configures text that is injected into the view without changing the underlying document.\n*/\nexport interface InjectedTextOptions {\n\t/**\n\t * Sets the text to inject. Must be a single line.\n\t */\n\treadonly content: string;\n\n\t/**\n\t * If set, the decoration will be rendered inline with the text with this CSS class name.\n\t */\n\treadonly inlineClassName?: string | null;\n\n\t/**\n\t * If there is an `inlineClassName` which affects letter spacing.\n\t */\n\treadonly inlineClassNameAffectsLetterSpacing?: boolean;\n\n\t/**\n\t * This field allows to attach data to this injected text.\n\t * The data can be read when injected texts at a given position are queried.\n\t */\n\treadonly attachedData?: unknown;\n\n\t/**\n\t * Configures cursor stops around injected text.\n\t * Defaults to {@link InjectedTextCursorStops.Both}.\n\t*/\n\treadonly cursorStops?: InjectedTextCursorStops | null;\n}\n\nexport enum InjectedTextCursorStops {\n\tBoth,\n\tRight,\n\tLeft,\n\tNone\n}\n\n/**\n * New model decorations.\n */\nexport interface IModelDeltaDecoration {\n\t/**\n\t * Range that this decoration covers.\n\t */\n\trange: IRange;\n\t/**\n\t * Options associated with this decoration.\n\t */\n\toptions: IModelDecorationOptions;\n}\n\n/**\n * A decoration in the model.\n */\nexport interface IModelDecoration {\n\t/**\n\t * Identifier for a decoration.\n\t */\n\treadonly id: string;\n\t/**\n\t * Identifier for a decoration's owner.\n\t */\n\treadonly ownerId: number;\n\t/**\n\t * Range that this decoration covers.\n\t */\n\treadonly range: Range;\n\t/**\n\t * Options associated with this decoration.\n\t */\n\treadonly options: IModelDecorationOptions;\n}\n\n/**\n * An accessor that can add, change or remove model decorations.\n * @internal\n */\nexport interface IModelDecorationsChangeAccessor {\n\t/**\n\t * Add a new decoration.\n\t * @param range Range that this decoration covers.\n\t * @param options Options associated with this decoration.\n\t * @return An unique identifier associated with this decoration.\n\t */\n\taddDecoration(range: IRange, options: IModelDecorationOptions): string;\n\t/**\n\t * Change the range that an existing decoration covers.\n\t * @param id The unique identifier associated with the decoration.\n\t * @param newRange The new range that this decoration covers.\n\t */\n\tchangeDecoration(id: string, newRange: IRange): void;\n\t/**\n\t * Change the options associated with an existing decoration.\n\t * @param id The unique identifier associated with the decoration.\n\t * @param newOptions The new options associated with this decoration.\n\t */\n\tchangeDecorationOptions(id: string, newOptions: IModelDecorationOptions): void;\n\t/**\n\t * Remove an existing decoration.\n\t * @param id The unique identifier associated with the decoration.\n\t */\n\tremoveDecoration(id: string): void;\n\t/**\n\t * Perform a minimum amount of operations, in order to transform the decorations\n\t * identified by `oldDecorations` to the decorations described by `newDecorations`\n\t * and returns the new identifiers associated with the resulting decorations.\n\t *\n\t * @param oldDecorations Array containing previous decorations identifiers.\n\t * @param newDecorations Array describing what decorations should result after the call.\n\t * @return An array containing the new decorations identifiers.\n\t */\n\tdeltaDecorations(oldDecorations: readonly string[], newDecorations: readonly IModelDeltaDecoration[]): string[];\n}\n\n/**\n * End of line character preference.\n */\nexport const 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 * The default end of line to use when instantiating models.\n */\nexport const 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 * End of line character preference.\n */\nexport const 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 * An identifier for a single edit operation.\n * @internal\n */\nexport interface ISingleEditOperationIdentifier {\n\t/**\n\t * Identifier major\n\t */\n\tmajor: number;\n\t/**\n\t * Identifier minor\n\t */\n\tminor: number;\n}\n\n/**\n * A single edit operation, that has an identifier.\n */\nexport interface IIdentifiedSingleEditOperation extends ISingleEditOperation {\n\t/**\n\t * An identifier associated with this single edit operation.\n\t * @internal\n\t */\n\tidentifier?: ISingleEditOperationIdentifier | null;\n\t/**\n\t * This indicates that this operation is inserting automatic whitespace\n\t * that can be removed on next model edit operation if `config.trimAutoWhitespace` is true.\n\t * @internal\n\t */\n\tisAutoWhitespaceEdit?: boolean;\n\t/**\n\t * This indicates that this operation is in a set of operations that are tracked and should not be \"simplified\".\n\t * @internal\n\t */\n\t_isTracked?: boolean;\n}\n\nexport interface IValidEditOperation {\n\t/**\n\t * An identifier associated with this single edit operation.\n\t * @internal\n\t */\n\tidentifier: ISingleEditOperationIdentifier | null;\n\t/**\n\t * The range to replace. This can be empty to emulate a simple insert.\n\t */\n\trange: Range;\n\t/**\n\t * The text to replace with. This can be empty to emulate a simple delete.\n\t */\n\ttext: string;\n\t/**\n\t * @internal\n\t */\n\ttextChange: TextChange;\n}\n\n/**\n * A callback that can compute the cursor state after applying a series of edit operations.\n */\nexport interface ICursorStateComputer {\n\t/**\n\t * A callback that can compute the resulting cursors state after some edit operations have been executed.\n\t */\n\t(inverseEditOperations: IValidEditOperation[]): Selection[] | null;\n}\n\nexport class TextModelResolvedOptions {\n\t_textModelResolvedOptionsBrand: void = undefined;\n\n\treadonly tabSize: number;\n\treadonly indentSize: number;\n\tprivate readonly _indentSizeIsTabSize: boolean;\n\treadonly insertSpaces: boolean;\n\treadonly defaultEOL: DefaultEndOfLine;\n\treadonly trimAutoWhitespace: boolean;\n\treadonly bracketPairColorizationOptions: BracketPairColorizationOptions;\n\n\tpublic get originalIndentSize(): number | 'tabSize' {\n\t\treturn this._indentSizeIsTabSize ? 'tabSize' : this.indentSize;\n\t}\n\n\t/**\n\t * @internal\n\t */\n\tconstructor(src: {\n\t\ttabSize: number;\n\t\tindentSize: number | 'tabSize';\n\t\tinsertSpaces: boolean;\n\t\tdefaultEOL: DefaultEndOfLine;\n\t\ttrimAutoWhitespace: boolean;\n\t\tbracketPairColorizationOptions: BracketPairColorizationOptions;\n\t}) {\n\t\tthis.tabSize = Math.max(1, src.tabSize | 0);\n\t\tif (src.indentSize === 'tabSize') {\n\t\t\tthis.indentSize = this.tabSize;\n\t\t\tthis._indentSizeIsTabSize = true;\n\t\t} else {\n\t\t\tthis.indentSize = Math.max(1, src.indentSize | 0);\n\t\t\tthis._indentSizeIsTabSize = false;\n\t\t}\n\t\tthis.insertSpaces = Boolean(src.insertSpaces);\n\t\tthis.defaultEOL = src.defaultEOL | 0;\n\t\tthis.trimAutoWhitespace = Boolean(src.trimAutoWhitespace);\n\t\tthis.bracketPairColorizationOptions = src.bracketPairColorizationOptions;\n\t}\n\n\t/**\n\t * @internal\n\t */\n\tpublic equals(other: TextModelResolvedOptions): boolean {\n\t\treturn (\n\t\t\tthis.tabSize === other.tabSize\n\t\t\t&& this._indentSizeIsTabSize === other._indentSizeIsTabSize\n\t\t\t&& this.indentSize === other.indentSize\n\t\t\t&& this.insertSpaces === other.insertSpaces\n\t\t\t&& this.defaultEOL === other.defaultEOL\n\t\t\t&& this.trimAutoWhitespace === other.trimAutoWhitespace\n\t\t\t&& equals(this.bracketPairColorizationOptions, other.bracketPairColorizationOptions)\n\t\t);\n\t}\n\n\t/**\n\t * @internal\n\t */\n\tpublic createChangeEvent(newOpts: TextModelResolvedOptions): IModelOptionsChangedEvent {\n\t\treturn {\n\t\t\ttabSize: this.tabSize !== newOpts.tabSize,\n\t\t\tindentSize: this.indentSize !== newOpts.indentSize,\n\t\t\tinsertSpaces: this.insertSpaces !== newOpts.insertSpaces,\n\t\t\ttrimAutoWhitespace: this.trimAutoWhitespace !== newOpts.trimAutoWhitespace,\n\t\t};\n\t}\n}\n\n/**\n * @internal\n */\nexport interface ITextModelCreationOptions {\n\ttabSize: number;\n\tindentSize: number | 'tabSize';\n\tinsertSpaces: boolean;\n\tdetectIndentation: boolean;\n\ttrimAutoWhitespace: boolean;\n\tdefaultEOL: DefaultEndOfLine;\n\tisForSimpleWidget: boolean;\n\tlargeFileOptimizations: boolean;\n\tbracketPairColorizationOptions: BracketPairColorizationOptions;\n}\n\nexport interface BracketPairColorizationOptions {\n\tenabled: boolean;\n\tindependentColorPoolPerBracketType: boolean;\n}\n\nexport interface ITextModelUpdateOptions {\n\ttabSize?: number;\n\tindentSize?: number | 'tabSize';\n\tinsertSpaces?: boolean;\n\ttrimAutoWhitespace?: boolean;\n\tbracketColorizationOptions?: BracketPairColorizationOptions;\n}\n\nexport class FindMatch {\n\t_findMatchBrand: void = undefined;\n\n\tpublic readonly range: Range;\n\tpublic readonly matches: string[] | null;\n\n\t/**\n\t * @internal\n\t */\n\tconstructor(range: Range, matches: string[] | null) {\n\t\tthis.range = range;\n\t\tthis.matches = matches;\n\t}\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 const enum TrackedRangeStickiness {\n\tAlwaysGrowsWhenTypingAtEdges = 0,\n\tNeverGrowsWhenTypingAtEdges = 1,\n\tGrowsOnlyWhenTypingBefore = 2,\n\tGrowsOnlyWhenTypingAfter = 3,\n}\n\n/**\n * Text snapshot that works like an iterator.\n * Will try to return chunks of roughly ~64KB size.\n * Will return null when finished.\n */\nexport interface ITextSnapshot {\n\tread(): string | null;\n}\n\n/**\n * @internal\n */\nexport function isITextSnapshot(obj: any): obj is ITextSnapshot {\n\treturn (obj && typeof obj.read === 'function');\n}\n\n/**\n * A model.\n */\nexport interface ITextModel {\n\n\t/**\n\t * Gets the resource associated with this editor model.\n\t */\n\treadonly uri: URI;\n\n\t/**\n\t * A unique identifier associated with this model.\n\t */\n\treadonly id: string;\n\n\t/**\n\t * This model is constructed for a simple widget code editor.\n\t * @internal\n\t */\n\treadonly isForSimpleWidget: boolean;\n\n\t/**\n\t * If true, the text model might contain RTL.\n\t * If false, the text model **contains only** contain LTR.\n\t * @internal\n\t */\n\tmightContainRTL(): boolean;\n\n\t/**\n\t * If true, the text model might contain LINE SEPARATOR (LS), PARAGRAPH SEPARATOR (PS).\n\t * If false, the text model definitely does not contain these.\n\t * @internal\n\t */\n\tmightContainUnusualLineTerminators(): boolean;\n\n\t/**\n\t * @internal\n\t */\n\tremoveUnusualLineTerminators(selections?: Selection[]): void;\n\n\t/**\n\t * If true, the text model might contain non basic ASCII.\n\t * If false, the text model **contains only** basic ASCII.\n\t * @internal\n\t */\n\tmightContainNonBasicASCII(): boolean;\n\n\t/**\n\t * Get the resolved options for this model.\n\t */\n\tgetOptions(): TextModelResolvedOptions;\n\n\t/**\n\t * Get the formatting options for this model.\n\t * @internal\n\t */\n\tgetFormattingOptions(): FormattingOptions;\n\n\t/**\n\t * Get the current version id of the model.\n\t * Anytime a change happens to the model (even undo/redo),\n\t * the version id is incremented.\n\t */\n\tgetVersionId(): number;\n\n\t/**\n\t * Get the alternative version id of the model.\n\t * This alternative version id is not always incremented,\n\t * it will return the same values in the case of undo-redo.\n\t */\n\tgetAlternativeVersionId(): number;\n\n\t/**\n\t * Replace the entire text buffer value contained in this model.\n\t */\n\tsetValue(newValue: string | ITextSnapshot): void;\n\n\t/**\n\t * Get the text stored in this model.\n\t * @param eol The end of line character preference. Defaults to `EndOfLinePreference.TextDefined`.\n\t * @param preserverBOM Preserve a BOM character if it was detected when the model was constructed.\n\t * @return The text.\n\t */\n\tgetValue(eol?: EndOfLinePreference, preserveBOM?: boolean): string;\n\n\t/**\n\t * Get the text stored in this model.\n\t * @param preserverBOM Preserve a BOM character if it was detected when the model was constructed.\n\t * @return The text snapshot (it is safe to consume it asynchronously).\n\t */\n\tcreateSnapshot(preserveBOM?: boolean): ITextSnapshot;\n\n\t/**\n\t * Get the length of the text stored in this model.\n\t */\n\tgetValueLength(eol?: EndOfLinePreference, preserveBOM?: boolean): number;\n\n\t/**\n\t * Get the text in a certain range.\n\t * @param range The range describing what text to get.\n\t * @param eol The end of line character preference. This will only be used for multiline ranges. Defaults to `EndOfLinePreference.TextDefined`.\n\t * @return The text.\n\t */\n\tgetValueInRange(range: IRange, eol?: EndOfLinePreference): string;\n\n\t/**\n\t * Get the length of text in a certain range.\n\t * @param range The range describing what text length to get.\n\t * @return The text length.\n\t */\n\tgetValueLengthInRange(range: IRange, eol?: EndOfLinePreference): number;\n\n\t/**\n\t * Get the character count of text in a certain range.\n\t * @param range The range describing what text length to get.\n\t */\n\tgetCharacterCountInRange(range: IRange, eol?: EndOfLinePreference): number;\n\n\t/**\n\t * Splits characters in two buckets. First bucket (A) is of characters that\n\t * sit in lines with length < `LONG_LINE_BOUNDARY`. Second bucket (B) is of\n\t * characters that sit in lines with length >= `LONG_LINE_BOUNDARY`.\n\t * If count(B) > count(A) return true. Returns false otherwise.\n\t * @internal\n\t */\n\tisDominatedByLongLines(): boolean;\n\n\t/**\n\t * Get the number of lines in the model.\n\t */\n\tgetLineCount(): number;\n\n\t/**\n\t * Get the text for a certain line.\n\t */\n\tgetLineContent(lineNumber: number): string;\n\n\t/**\n\t * Get the text length for a certain line.\n\t */\n\tgetLineLength(lineNumber: number): number;\n\n\t/**\n\t * Get the text for all lines.\n\t */\n\tgetLinesContent(): string[];\n\n\t/**\n\t * Get the end of line sequence predominantly used in the text buffer.\n\t * @return EOL char sequence (e.g.: '\\n' or '\\r\\n').\n\t */\n\tgetEOL(): string;\n\n\t/**\n\t * Get the end of line sequence predominantly used in the text buffer.\n\t */\n\tgetEndOfLineSequence(): EndOfLineSequence;\n\n\t/**\n\t * Get the minimum legal column for line at `lineNumber`\n\t */\n\tgetLineMinColumn(lineNumber: number): number;\n\n\t/**\n\t * Get the maximum legal column for line at `lineNumber`\n\t */\n\tgetLineMaxColumn(lineNumber: number): number;\n\n\t/**\n\t * Returns the column before the first non whitespace character for line at `lineNumber`.\n\t * Returns 0 if line is empty or contains only whitespace.\n\t */\n\tgetLineFirstNonWhitespaceColumn(lineNumber: number): number;\n\n\t/**\n\t * Returns the column after the last non whitespace character for line at `lineNumber`.\n\t * Returns 0 if line is empty or contains only whitespace.\n\t */\n\tgetLineLastNonWhitespaceColumn(lineNumber: number): number;\n\n\t/**\n\t * Create a valid position.\n\t */\n\tvalidatePosition(position: IPosition): Position;\n\n\t/**\n\t * Advances the given position by the given offset (negative offsets are also accepted)\n\t * and returns it as a new valid position.\n\t *\n\t * If the offset and position are such that their combination goes beyond the beginning or\n\t * end of the model, throws an exception.\n\t *\n\t * If the offset is such that the new position would be in the middle of a multi-byte\n\t * line terminator, throws an exception.\n\t */\n\tmodifyPosition(position: IPosition, offset: number): Position;\n\n\t/**\n\t * Create a valid range.\n\t */\n\tvalidateRange(range: IRange): Range;\n\n\t/**\n\t * Converts the position to a zero-based offset.\n\t *\n\t * The position will be [adjusted](#TextDocument.validatePosition).\n\t *\n\t * @param position A position.\n\t * @return A valid zero-based offset.\n\t */\n\tgetOffsetAt(position: IPosition): number;\n\n\t/**\n\t * Converts a zero-based offset to a position.\n\t *\n\t * @param offset A zero-based offset.\n\t * @return A valid [position](#Position).\n\t */\n\tgetPositionAt(offset: number): Position;\n\n\t/**\n\t * Get a range covering the entire model.\n\t */\n\tgetFullModelRange(): Range;\n\n\t/**\n\t * Returns if the model was disposed or not.\n\t */\n\tisDisposed(): boolean;\n\n\t/**\n\t * This model is so large that it would not be a good idea to sync it over\n\t * to web workers or other places.\n\t * @internal\n\t */\n\tisTooLargeForSyncing(): boolean;\n\n\t/**\n\t * The file is so large, that even tokenization is disabled.\n\t * @internal\n\t */\n\tisTooLargeForTokenization(): boolean;\n\n\t/**\n\t * The file is so large, that operations on it might be too large for heap\n\t * and can lead to OOM crashes so they should be disabled.\n\t * @internal\n\t */\n\tisTooLargeForHeapOperation(): boolean;\n\n\t/**\n\t * Search the model.\n\t * @param searchString The string used to search. If it is a regular expression, set `isRegex` to true.\n\t * @param searchOnlyEditableRange Limit the searching to only search inside the editable range of the model.\n\t * @param isRegex Used to indicate that `searchString` is a regular expression.\n\t * @param matchCase Force the matching to match lower/upper case exactly.\n\t * @param wordSeparators Force the matching to match entire words only. Pass null otherwise.\n\t * @param captureMatches The result will contain the captured groups.\n\t * @param limitResultCount Limit the number of results\n\t * @return The ranges where the matches are. It is empty if not matches have been found.\n\t */\n\tfindMatches(searchString: string, searchOnlyEditableRange: boolean, isRegex: boolean, matchCase: boolean, wordSeparators: string | null, captureMatches: boolean, limitResultCount?: number): FindMatch[];\n\t/**\n\t * Search the model.\n\t * @param searchString The string used to search. If it is a regular expression, set `isRegex` to true.\n\t * @param searchScope Limit the searching to only search inside these ranges.\n\t * @param isRegex Used to indicate that `searchString` is a regular expression.\n\t * @param matchCase Force the matching to match lower/upper case exactly.\n\t * @param wordSeparators Force the matching to match entire words only. Pass null otherwise.\n\t * @param captureMatches The result will contain the captured groups.\n\t * @param limitResultCount Limit the number of results\n\t * @return The ranges where the matches are. It is empty if no matches have been found.\n\t */\n\tfindMatches(searchString: string, searchScope: IRange | IRange[], isRegex: boolean, matchCase: boolean, wordSeparators: string | null, captureMatches: boolean, limitResultCount?: number): FindMatch[];\n\t/**\n\t * Search the model for the next match. Loops to the beginning of the model if needed.\n\t * @param searchString The string used to search. If it is a regular expression, set `isRegex` to true.\n\t * @param searchStart Start the searching at the specified position.\n\t * @param isRegex Used to indicate that `searchString` is a regular expression.\n\t * @param matchCase Force the matching to match lower/upper case exactly.\n\t * @param wordSeparators Force the matching to match entire words only. Pass null otherwise.\n\t * @param captureMatches The result will contain the captured groups.\n\t * @return The range where the next match is. It is null if no next match has been found.\n\t */\n\tfindNextMatch(searchString: string, searchStart: IPosition, isRegex: boolean, matchCase: boolean, wordSeparators: string | null, captureMatches: boolean): FindMatch | null;\n\t/**\n\t * Search the model for the previous match. Loops to the end of the model if needed.\n\t * @param searchString The string used to search. If it is a regular expression, set `isRegex` to true.\n\t * @param searchStart Start the searching at the specified position.\n\t * @param isRegex Used to indicate that `searchString` is a regular expression.\n\t * @param matchCase Force the matching to match lower/upper case exactly.\n\t * @param wordSeparators Force the matching to match entire words only. Pass null otherwise.\n\t * @param captureMatches The result will contain the captured groups.\n\t * @return The range where the previous match is. It is null if no previous match has been found.\n\t */\n\tfindPreviousMatch(searchString: string, searchStart: IPosition, isRegex: boolean, matchCase: boolean, wordSeparators: string | null, captureMatches: boolean): FindMatch | null;\n\n\n\t/**\n\t * Get the language associated with this model.\n\t */\n\tgetLanguageId(): string;\n\n\t/**\n\t * Set the current language mode associated with the model.\n\t * @param languageId The new language.\n\t * @param source The source of the call that set the language.\n\t * @internal\n\t */\n\tsetLanguage(languageId: string, source?: string): void;\n\n\t/**\n\t * Set the current language mode associated with the model.\n\t * @param languageSelection The new language selection.\n\t * @param source The source of the call that set the language.\n\t * @internal\n\t */\n\tsetLanguage(languageSelection: ILanguageSelection, source?: string): void;\n\n\t/**\n\t * Returns the real (inner-most) language mode at a given position.\n\t * The result might be inaccurate. Use `forceTokenization` to ensure accurate tokens.\n\t * @internal\n\t */\n\tgetLanguageIdAtPosition(lineNumber: number, column: number): string;\n\n\t/**\n\t * Get the word under or besides `position`.\n\t * @param position The position to look for a word.\n\t * @return The word under or besides `position`. Might be null.\n\t */\n\tgetWordAtPosition(position: IPosition): IWordAtPosition | null;\n\n\t/**\n\t * Get the word under or besides `position` trimmed to `position`.column\n\t * @param position The position to look for a word.\n\t * @return The word under or besides `position`. Will never be null.\n\t */\n\tgetWordUntilPosition(position: IPosition): IWordAtPosition;\n\n\t/**\n\t * Change the decorations. The callback will be called with a change accessor\n\t * that becomes invalid as soon as the callback finishes executing.\n\t * This allows for all events to be queued up until the change\n\t * is completed. Returns whatever the callback returns.\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.\n\t * @internal\n\t */\n\tchangeDecorations(callback: (changeAccessor: IModelDecorationsChangeAccessor) => T, ownerId?: number): T | null;\n\n\t/**\n\t * Perform a minimum amount of operations, in order to transform the decorations\n\t * identified by `oldDecorations` to the decorations described by `newDecorations`\n\t * and returns the new identifiers associated with the resulting decorations.\n\t *\n\t * @param oldDecorations Array containing previous decorations identifiers.\n\t * @param newDecorations Array describing what decorations should result after the call.\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.\n\t * @return An array containing the new decorations identifiers.\n\t */\n\tdeltaDecorations(oldDecorations: string[], newDecorations: IModelDeltaDecoration[], ownerId?: number): string[];\n\n\t/**\n\t * Remove all decorations that have been added with this specific ownerId.\n\t * @param ownerId The owner id to search for.\n\t * @internal\n\t */\n\tremoveAllDecorationsWithOwnerId(ownerId: number): void;\n\n\t/**\n\t * Get the options associated with a decoration.\n\t * @param id The decoration id.\n\t * @return The decoration options or null if the decoration was not found.\n\t */\n\tgetDecorationOptions(id: string): IModelDecorationOptions | null;\n\n\t/**\n\t * Get the range associated with a decoration.\n\t * @param id The decoration id.\n\t * @return The decoration range or null if the decoration was not found.\n\t */\n\tgetDecorationRange(id: string): Range | null;\n\n\t/**\n\t * Gets all the decorations for the line `lineNumber` as an array.\n\t * @param lineNumber The line number\n\t * @param ownerId If set, it will ignore decorations belonging to other owners.\n\t * @param filterOutValidation If set, it will ignore decorations specific to validation (i.e. warnings, errors).\n\t * @return An array with the decorations\n\t */\n\tgetLineDecorations(lineNumber: number, ownerId?: number, filterOutValidation?: boolean): IModelDecoration[];\n\n\t/**\n\t * Gets all the decorations for the lines between `startLineNumber` and `endLineNumber` as an array.\n\t * @param startLineNumber The start line number\n\t * @param endLineNumber The end line number\n\t * @param ownerId If set, it will ignore decorations belonging to other owners.\n\t * @param filterOutValidation If set, it will ignore decorations specific to validation (i.e. warnings, errors).\n\t * @return An array with the decorations\n\t */\n\tgetLinesDecorations(startLineNumber: number, endLineNumber: number, ownerId?: number, filterOutValidation?: boolean): IModelDecoration[];\n\n\t/**\n\t * Gets all the decorations in a range as an array. Only `startLineNumber` and `endLineNumber` from `range` are used for filtering.\n\t * So for now it returns all the decorations on the same line as `range`.\n\t * @param range The range to search in\n\t * @param ownerId If set, it will ignore decorations belonging to other owners.\n\t * @param filterOutValidation If set, it will ignore decorations specific to validation (i.e. warnings, errors).\n\t * @param onlyMinimapDecorations If set, it will return only decorations that render in the minimap.\n\t * @param onlyMarginDecorations If set, it will return only decorations that render in the glyph margin.\n\t * @return An array with the decorations\n\t */\n\tgetDecorationsInRange(range: IRange, ownerId?: number, filterOutValidation?: boolean, onlyMinimapDecorations?: boolean, onlyMarginDecorations?: boolean): IModelDecoration[];\n\n\t/**\n\t * Gets all the decorations as an array.\n\t * @param ownerId If set, it will ignore decorations belonging to other owners.\n\t * @param filterOutValidation If set, it will ignore decorations specific to validation (i.e. warnings, errors).\n\t */\n\tgetAllDecorations(ownerId?: number, filterOutValidation?: boolean): IModelDecoration[];\n\n\t/**\n\t * Gets all decorations that render in the glyph margin as an array.\n\t * @param ownerId If set, it will ignore decorations belonging to other owners.\n\t */\n\tgetAllMarginDecorations(ownerId?: number): IModelDecoration[];\n\n\t/**\n\t * Gets all the decorations that should be rendered in the overview ruler as an array.\n\t * @param ownerId If set, it will ignore decorations belonging to other owners.\n\t * @param filterOutValidation If set, it will ignore decorations specific to validation (i.e. warnings, errors).\n\t */\n\tgetOverviewRulerDecorations(ownerId?: number, filterOutValidation?: boolean): IModelDecoration[];\n\n\t/**\n\t * Gets all the decorations that contain injected text.\n\t * @param ownerId If set, it will ignore decorations belonging to other owners.\n\t */\n\tgetInjectedTextDecorations(ownerId?: number): IModelDecoration[];\n\n\t/**\n\t * @internal\n\t */\n\t_getTrackedRange(id: string): Range | null;\n\n\t/**\n\t * @internal\n\t */\n\t_setTrackedRange(id: string | null, newRange: null, newStickiness: TrackedRangeStickiness): null;\n\t/**\n\t * @internal\n\t */\n\t_setTrackedRange(id: string | null, newRange: Range, newStickiness: TrackedRangeStickiness): string;\n\n\t/**\n\t * Normalize a string containing whitespace according to indentation rules (converts to spaces or to tabs).\n\t */\n\tnormalizeIndentation(str: string): string;\n\n\t/**\n\t * Change the options of this model.\n\t */\n\tupdateOptions(newOpts: ITextModelUpdateOptions): void;\n\n\t/**\n\t * Detect the indentation options for this model from its content.\n\t */\n\tdetectIndentation(defaultInsertSpaces: boolean, defaultTabSize: number): void;\n\n\t/**\n\t * Close the current undo-redo element.\n\t * This offers a way to create an undo/redo stop point.\n\t */\n\tpushStackElement(): void;\n\n\t/**\n\t * Open the current undo-redo element.\n\t * This offers a way to remove the current undo/redo stop point.\n\t */\n\tpopStackElement(): void;\n\n\t/**\n\t * Push edit operations, basically editing the model. This is the preferred way\n\t * of editing the model. The edit operations will land on the undo stack.\n\t * @param beforeCursorState The cursor state before the edit operations. This cursor state will be returned when `undo` or `redo` are invoked.\n\t * @param editOperations The edit operations.\n\t * @param cursorStateComputer A callback that can compute the resulting cursors state after the edit operations have been executed.\n\t * @return The cursor state returned by the `cursorStateComputer`.\n\t */\n\tpushEditOperations(beforeCursorState: Selection[] | null, editOperations: IIdentifiedSingleEditOperation[], cursorStateComputer: ICursorStateComputer): Selection[] | null;\n\t/**\n\t * @internal\n\t */\n\tpushEditOperations(beforeCursorState: Selection[] | null, editOperations: IIdentifiedSingleEditOperation[], cursorStateComputer: ICursorStateComputer, group?: UndoRedoGroup): Selection[] | null;\n\n\t/**\n\t * Change the end of line sequence. This is the preferred way of\n\t * changing the eol sequence. This will land on the undo stack.\n\t */\n\tpushEOL(eol: EndOfLineSequence): void;\n\n\t/**\n\t * Edit the model without adding the edits to the undo stack.\n\t * This can have dire consequences on the undo stack! See @pushEditOperations for the preferred way.\n\t * @param operations The edit operations.\n\t * @return If desired, the inverse edit operations, that, when applied, will bring the model back to the previous state.\n\t */\n\tapplyEdits(operations: IIdentifiedSingleEditOperation[]): void;\n\tapplyEdits(operations: IIdentifiedSingleEditOperation[], computeUndoEdits: false): void;\n\tapplyEdits(operations: IIdentifiedSingleEditOperation[], computeUndoEdits: true): IValidEditOperation[];\n\n\t/**\n\t * Change the end of line sequence without recording in the undo stack.\n\t * This can have dire consequences on the undo stack! See @pushEOL for the preferred way.\n\t */\n\tsetEOL(eol: EndOfLineSequence): void;\n\n\t/**\n\t * @internal\n\t */\n\t_applyUndo(changes: TextChange[], eol: EndOfLineSequence, resultingAlternativeVersionId: number, resultingSelection: Selection[] | null): void;\n\n\t/**\n\t * @internal\n\t */\n\t_applyRedo(changes: TextChange[], eol: EndOfLineSequence, resultingAlternativeVersionId: number, resultingSelection: Selection[] | null): void;\n\n\t/**\n\t * Undo edit operations until the previous undo/redo point.\n\t * The inverse edit operations will be pushed on the redo stack.\n\t * @internal\n\t */\n\tundo(): void | Promise;\n\n\t/**\n\t * Is there anything in the undo stack?\n\t * @internal\n\t */\n\tcanUndo(): boolean;\n\n\t/**\n\t * Redo edit operations until the next undo/redo point.\n\t * The inverse edit operations will be pushed on the undo stack.\n\t * @internal\n\t */\n\tredo(): void | Promise;\n\n\t/**\n\t * Is there anything in the redo stack?\n\t * @internal\n\t */\n\tcanRedo(): boolean;\n\n\t/**\n\t * @deprecated Please use `onDidChangeContent` instead.\n\t * An event emitted when the contents of the model have changed.\n\t * @internal\n\t * @event\n\t */\n\treadonly onDidChangeContentOrInjectedText: Event;\n\t/**\n\t * An event emitted when the contents of the model have changed.\n\t * @event\n\t */\n\tonDidChangeContent(listener: (e: IModelContentChangedEvent) => void): IDisposable;\n\t/**\n\t * An event emitted when decorations of the model have changed.\n\t * @event\n\t */\n\treadonly onDidChangeDecorations: Event;\n\t/**\n\t * An event emitted when the model options have changed.\n\t * @event\n\t */\n\treadonly onDidChangeOptions: Event;\n\t/**\n\t * An event emitted when the language associated with the model has changed.\n\t * @event\n\t */\n\treadonly onDidChangeLanguage: Event;\n\t/**\n\t * An event emitted when the language configuration associated with the model has changed.\n\t * @event\n\t */\n\treadonly onDidChangeLanguageConfiguration: Event;\n\t/**\n\t * An event emitted when the tokens associated with the model have changed.\n\t * @event\n\t * @internal\n\t */\n\treadonly onDidChangeTokens: Event;\n\t/**\n\t * An event emitted when the model has been attached to the first editor or detached from the last editor.\n\t * @event\n\t */\n\treadonly onDidChangeAttached: Event;\n\t/**\n\t * An event emitted right before disposing the model.\n\t * @event\n\t */\n\treadonly onWillDispose: Event;\n\n\t/**\n\t * Destroy this model.\n\t */\n\tdispose(): void;\n\n\t/**\n\t * @internal\n\t */\n\tonBeforeAttached(): IAttachedView;\n\n\t/**\n\t * @internal\n\t */\n\tonBeforeDetached(view: IAttachedView): void;\n\n\t/**\n\t * Returns if this model is attached to an editor or not.\n\t */\n\tisAttachedToEditor(): boolean;\n\n\t/**\n\t * Returns the count of editors this model is attached to.\n\t * @internal\n\t */\n\tgetAttachedEditorCount(): number;\n\n\t/**\n\t * Among all positions that are projected to the same position in the underlying text model as\n\t * the given position, select a unique position as indicated by the affinity.\n\t *\n\t * PositionAffinity.Left:\n\t * The normalized position must be equal or left to the requested position.\n\t *\n\t * PositionAffinity.Right:\n\t * The normalized position must be equal or right to the requested position.\n\t *\n\t * @internal\n\t */\n\tnormalizePosition(position: Position, affinity: PositionAffinity): Position;\n\n\t/**\n\t * Gets the column at which indentation stops at a given line.\n\t * @internal\n\t*/\n\tgetLineIndentColumn(lineNumber: number): number;\n\n\t/**\n\t * Returns an object that can be used to query brackets.\n\t * @internal\n\t*/\n\treadonly bracketPairs: IBracketPairsTextModelPart;\n\n\t/**\n\t * Returns an object that can be used to query indent guides.\n\t * @internal\n\t*/\n\treadonly guides: IGuidesTextModelPart;\n\n\t/**\n\t * @internal\n\t */\n\treadonly tokenization: ITokenizationTextModelPart;\n}\n\n/**\n * @internal\n */\nexport interface IAttachedView {\n\t/**\n\t * @param stabilized Indicates if the visible lines are probably going to change soon or can be considered stable.\n\t * Is true on reveal range and false on scroll.\n\t * Tokenizers should tokenize synchronously if stabilized is true.\n\t */\n\tsetVisibleLines(visibleLines: { startLineNumber: number; endLineNumber: number }[], stabilized: boolean): void;\n}\n\nexport const enum PositionAffinity {\n\t/**\n\t * Prefers the left most position.\n\t*/\n\tLeft = 0,\n\n\t/**\n\t * Prefers the right most position.\n\t*/\n\tRight = 1,\n\n\t/**\n\t * No preference.\n\t*/\n\tNone = 2,\n\n\t/**\n\t * If the given position is on injected text, prefers the position left of it.\n\t*/\n\tLeftOfInjectedText = 3,\n\n\t/**\n\t * If the given position is on injected text, prefers the position right of it.\n\t*/\n\tRightOfInjectedText = 4,\n}\n\n/**\n * @internal\n */\nexport interface ITextBufferBuilder {\n}\n\n/**\n * @internal\n */\nexport interface ITextBufferFactory {\n\tcreate(defaultEOL: DefaultEndOfLine): { textBuffer: ITextBuffer; disposable: IDisposable };\n}\n\n/**\n * @internal\n */\nexport class ValidAnnotatedEditOperation implements IIdentifiedSingleEditOperation {\n\tconstructor(\n\t\tpublic readonly identifier: ISingleEditOperationIdentifier | null,\n\t\tpublic readonly range: Range,\n\t\tpublic readonly text: string | null,\n\t\tpublic readonly forceMoveMarkers: boolean,\n\t\tpublic readonly isAutoWhitespaceEdit: boolean,\n\t\tpublic readonly _isTracked: boolean,\n\t) { }\n}\n\n/**\n * @internal\n *\n * `lineNumber` is 1 based.\n */\nexport interface IReadonlyTextBuffer {\n\tmightContainRTL(): boolean;\n\tmightContainUnusualLineTerminators(): boolean;\n\tresetMightContainUnusualLineTerminators(): void;\n\tmightContainNonBasicASCII(): boolean;\n\tgetBOM(): string;\n\tgetEOL(): string;\n\n\tgetOffsetAt(lineNumber: number, column: number): number;\n\tgetPositionAt(offset: number): Position;\n\tgetRangeAt(offset: number, length: number): Range;\n\n\tgetValueInRange(range: Range, eol: EndOfLinePreference): string;\n\tcreateSnapshot(preserveBOM: boolean): ITextSnapshot;\n\tgetValueLengthInRange(range: Range, eol: EndOfLinePreference): number;\n\tgetCharacterCountInRange(range: Range, eol: EndOfLinePreference): number;\n\tgetLength(): number;\n\tgetLineCount(): number;\n\tgetLinesContent(): string[];\n\tgetLineContent(lineNumber: number): string;\n\tgetLineCharCode(lineNumber: number, index: number): number;\n\tgetLineLength(lineNumber: number): number;\n\tgetLineFirstNonWhitespaceColumn(lineNumber: number): number;\n\tgetLineLastNonWhitespaceColumn(lineNumber: number): number;\n\tfindMatchesLineByLine(searchRange: Range, searchData: SearchData, captureMatches: boolean, limitResultCount: number): FindMatch[];\n}\n\n/**\n * @internal\n */\nexport class SearchData {\n\n\t/**\n\t * The regex to search for. Always defined.\n\t */\n\tpublic readonly regex: RegExp;\n\t/**\n\t * The word separator classifier.\n\t */\n\tpublic readonly wordSeparators: WordCharacterClassifier | null;\n\t/**\n\t * The simple string to search for (if possible).\n\t */\n\tpublic readonly simpleSearch: string | null;\n\n\tconstructor(regex: RegExp, wordSeparators: WordCharacterClassifier | null, simpleSearch: string | null) {\n\t\tthis.regex = regex;\n\t\tthis.wordSeparators = wordSeparators;\n\t\tthis.simpleSearch = simpleSearch;\n\t}\n}\n\n/**\n * @internal\n */\nexport interface ITextBuffer extends IReadonlyTextBuffer, IDisposable {\n\tsetEOL(newEOL: '\\r\\n' | '\\n'): void;\n\tapplyEdits(rawOperations: ValidAnnotatedEditOperation[], recordTrimAutoWhitespace: boolean, computeUndoEdits: boolean): ApplyEditsResult;\n}\n\n/**\n * @internal\n */\nexport class ApplyEditsResult {\n\n\tconstructor(\n\t\tpublic readonly reverseEdits: IValidEditOperation[] | null,\n\t\tpublic readonly changes: IInternalModelContentChange[],\n\t\tpublic readonly trimAutoWhitespaceLineNumbers: number[] | null\n\t) { }\n\n}\n\n/**\n * @internal\n */\nexport interface IInternalModelContentChange extends IModelContentChange {\n\trange: Range;\n\tforceMoveMarkers: boolean;\n}\n\n/**\n * @internal\n */\nexport function shouldSynchronizeModel(model: ITextModel): boolean {\n\treturn (\n\t\t!model.isTooLargeForSyncing() && !model.isForSimpleWidget\n\t);\n}\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\nimport { splitLines } from 'vs/base/common/strings';\nimport { Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\nimport { TextLength } from 'vs/editor/common/core/textLength';\n\n/**\n * The end must be greater than or equal to the start.\n*/\nexport function lengthDiff(startLineCount: number, startColumnCount: number, endLineCount: number, endColumnCount: number): Length {\n\treturn (startLineCount !== endLineCount)\n\t\t? toLength(endLineCount - startLineCount, endColumnCount)\n\t\t: toLength(0, endColumnCount - startColumnCount);\n}\n\n/**\n * Represents a non-negative length in terms of line and column count.\n * Does not allocate.\n*/\nexport type Length = { _brand: 'Length' };\n\nexport const lengthZero = 0 as any as Length;\n\nexport function lengthIsZero(length: Length): boolean {\n\treturn length as any as number === 0;\n}\n\n/*\n * We have 52 bits available in a JS number.\n * We use the upper 26 bits to store the line and the lower 26 bits to store the column.\n */\n///*\nconst factor = 2 ** 26;\n/*/\nconst factor = 1000000;\n// */\n\nexport function toLength(lineCount: number, columnCount: number): Length {\n\t// llllllllllllllllllllllllllcccccccccccccccccccccccccc (52 bits)\n\t// line count (26 bits) column count (26 bits)\n\n\t// If there is no overflow (all values/sums below 2^26 = 67108864),\n\t// we have `toLength(lns1, cols1) + toLength(lns2, cols2) = toLength(lns1 + lns2, cols1 + cols2)`.\n\n\treturn (lineCount * factor + columnCount) as any as Length;\n}\n\nexport function lengthToObj(length: Length): TextLength {\n\tconst l = length as any as number;\n\tconst lineCount = Math.floor(l / factor);\n\tconst columnCount = l - lineCount * factor;\n\treturn new TextLength(lineCount, columnCount);\n}\n\nexport function lengthGetLineCount(length: Length): number {\n\treturn Math.floor(length as any as number / factor);\n}\n\n/**\n * Returns the amount of columns of the given length, assuming that it does not span any line.\n*/\nexport function lengthGetColumnCountIfZeroLineCount(length: Length): number {\n\treturn length as any as number;\n}\n\n\n// [10 lines, 5 cols] + [ 0 lines, 3 cols] = [10 lines, 8 cols]\n// [10 lines, 5 cols] + [20 lines, 3 cols] = [30 lines, 3 cols]\nexport function lengthAdd(length1: Length, length2: Length): Length;\nexport function lengthAdd(l1: any, l2: any): Length {\n\tlet r = l1 + l2;\n\tif (l2 >= factor) { r = r - (l1 % factor); }\n\treturn r;\n}\n\nexport function sumLengths(items: readonly T[], lengthFn: (item: T) => Length): Length {\n\treturn items.reduce((a, b) => lengthAdd(a, lengthFn(b)), lengthZero);\n}\n\nexport function lengthEquals(length1: Length, length2: Length): boolean {\n\treturn length1 === length2;\n}\n\n/**\n * Returns a non negative length `result` such that `lengthAdd(length1, result) = length2`, or zero if such length does not exist.\n */\nexport function lengthDiffNonNegative(length1: Length, length2: Length): Length {\n\tconst l1 = length1 as any as number;\n\tconst l2 = length2 as any as number;\n\n\tconst diff = l2 - l1;\n\tif (diff <= 0) {\n\t\t// line-count of length1 is higher than line-count of length2\n\t\t// or they are equal and column-count of length1 is higher than column-count of length2\n\t\treturn lengthZero;\n\t}\n\n\tconst lineCount1 = Math.floor(l1 / factor);\n\tconst lineCount2 = Math.floor(l2 / factor);\n\n\tconst colCount2 = l2 - lineCount2 * factor;\n\n\tif (lineCount1 === lineCount2) {\n\t\tconst colCount1 = l1 - lineCount1 * factor;\n\t\treturn toLength(0, colCount2 - colCount1);\n\t} else {\n\t\treturn toLength(lineCount2 - lineCount1, colCount2);\n\t}\n}\n\nexport function lengthLessThan(length1: Length, length2: Length): boolean {\n\t// First, compare line counts, then column counts.\n\treturn (length1 as any as number) < (length2 as any as number);\n}\n\nexport function lengthLessThanEqual(length1: Length, length2: Length): boolean {\n\treturn (length1 as any as number) <= (length2 as any as number);\n}\n\nexport function lengthGreaterThanEqual(length1: Length, length2: Length): boolean {\n\treturn (length1 as any as number) >= (length2 as any as number);\n}\n\nexport function positionToLength(position: Position): Length {\n\treturn toLength(position.lineNumber - 1, position.column - 1);\n}\n\nexport function lengthsToRange(lengthStart: Length, lengthEnd: Length): Range {\n\tconst l = lengthStart as any as number;\n\tconst lineCount = Math.floor(l / factor);\n\tconst colCount = l - lineCount * factor;\n\n\tconst l2 = lengthEnd as any as number;\n\tconst lineCount2 = Math.floor(l2 / factor);\n\tconst colCount2 = l2 - lineCount2 * factor;\n\n\treturn new Range(lineCount + 1, colCount + 1, lineCount2 + 1, colCount2 + 1);\n}\n\nexport function lengthOfString(str: string): Length {\n\tconst lines = splitLines(str);\n\treturn toLength(lines.length - 1, lines[lines.length - 1].length);\n}\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\nimport { Range } from 'vs/editor/common/core/range';\nimport { Length, lengthAdd, lengthDiffNonNegative, lengthLessThanEqual, lengthOfString, lengthToObj, positionToLength, toLength } from './length';\nimport { TextLength } from 'vs/editor/common/core/textLength';\nimport { IModelContentChange } from 'vs/editor/common/textModelEvents';\n\nexport class TextEditInfo {\n\tpublic static fromModelContentChanges(changes: IModelContentChange[]): TextEditInfo[] {\n\t\t// Must be sorted in ascending order\n\t\tconst edits = changes.map(c => {\n\t\t\tconst range = Range.lift(c.range);\n\t\t\treturn new TextEditInfo(\n\t\t\t\tpositionToLength(range.getStartPosition()),\n\t\t\t\tpositionToLength(range.getEndPosition()),\n\t\t\t\tlengthOfString(c.text)\n\t\t\t);\n\t\t}).reverse();\n\t\treturn edits;\n\t}\n\n\tconstructor(\n\t\tpublic readonly startOffset: Length,\n\t\tpublic readonly endOffset: Length,\n\t\tpublic readonly newLength: Length\n\t) {\n\t}\n\n\ttoString(): string {\n\t\treturn `[${lengthToObj(this.startOffset)}...${lengthToObj(this.endOffset)}) -> ${lengthToObj(this.newLength)}`;\n\t}\n}\n\nexport class BeforeEditPositionMapper {\n\tprivate nextEditIdx = 0;\n\tprivate deltaOldToNewLineCount = 0;\n\tprivate deltaOldToNewColumnCount = 0;\n\tprivate deltaLineIdxInOld = -1;\n\tprivate readonly edits: readonly TextEditInfoCache[];\n\n\t/**\n\t * @param edits Must be sorted by offset in ascending order.\n\t*/\n\tconstructor(\n\t\tedits: readonly TextEditInfo[],\n\t) {\n\t\tthis.edits = edits.map(edit => TextEditInfoCache.from(edit));\n\t}\n\n\t/**\n\t * @param offset Must be equal to or greater than the last offset this method has been called with.\n\t*/\n\tgetOffsetBeforeChange(offset: Length): Length {\n\t\tthis.adjustNextEdit(offset);\n\t\treturn this.translateCurToOld(offset);\n\t}\n\n\t/**\n\t * @param offset Must be equal to or greater than the last offset this method has been called with.\n\t * Returns null if there is no edit anymore.\n\t*/\n\tgetDistanceToNextChange(offset: Length): Length | null {\n\t\tthis.adjustNextEdit(offset);\n\n\t\tconst nextEdit = this.edits[this.nextEditIdx];\n\t\tconst nextChangeOffset = nextEdit ? this.translateOldToCur(nextEdit.offsetObj) : null;\n\t\tif (nextChangeOffset === null) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn lengthDiffNonNegative(offset, nextChangeOffset);\n\t}\n\n\tprivate translateOldToCur(oldOffsetObj: TextLength): Length {\n\t\tif (oldOffsetObj.lineCount === this.deltaLineIdxInOld) {\n\t\t\treturn toLength(oldOffsetObj.lineCount + this.deltaOldToNewLineCount, oldOffsetObj.columnCount + this.deltaOldToNewColumnCount);\n\t\t} else {\n\t\t\treturn toLength(oldOffsetObj.lineCount + this.deltaOldToNewLineCount, oldOffsetObj.columnCount);\n\t\t}\n\t}\n\n\tprivate translateCurToOld(newOffset: Length): Length {\n\t\tconst offsetObj = lengthToObj(newOffset);\n\t\tif (offsetObj.lineCount - this.deltaOldToNewLineCount === this.deltaLineIdxInOld) {\n\t\t\treturn toLength(offsetObj.lineCount - this.deltaOldToNewLineCount, offsetObj.columnCount - this.deltaOldToNewColumnCount);\n\t\t} else {\n\t\t\treturn toLength(offsetObj.lineCount - this.deltaOldToNewLineCount, offsetObj.columnCount);\n\t\t}\n\t}\n\n\tprivate adjustNextEdit(offset: Length) {\n\t\twhile (this.nextEditIdx < this.edits.length) {\n\t\t\tconst nextEdit = this.edits[this.nextEditIdx];\n\n\t\t\t// After applying the edit, what is its end offset (considering all previous edits)?\n\t\t\tconst nextEditEndOffsetInCur = this.translateOldToCur(nextEdit.endOffsetAfterObj);\n\n\t\t\tif (lengthLessThanEqual(nextEditEndOffsetInCur, offset)) {\n\t\t\t\t// We are after the edit, skip it\n\t\t\t\tthis.nextEditIdx++;\n\n\t\t\t\tconst nextEditEndOffsetInCurObj = lengthToObj(nextEditEndOffsetInCur);\n\n\t\t\t\t// Before applying the edit, what is its end offset (considering all previous edits)?\n\t\t\t\tconst nextEditEndOffsetBeforeInCurObj = lengthToObj(this.translateOldToCur(nextEdit.endOffsetBeforeObj));\n\n\t\t\t\tconst lineDelta = nextEditEndOffsetInCurObj.lineCount - nextEditEndOffsetBeforeInCurObj.lineCount;\n\t\t\t\tthis.deltaOldToNewLineCount += lineDelta;\n\n\t\t\t\tconst previousColumnDelta = this.deltaLineIdxInOld === nextEdit.endOffsetBeforeObj.lineCount ? this.deltaOldToNewColumnCount : 0;\n\t\t\t\tconst columnDelta = nextEditEndOffsetInCurObj.columnCount - nextEditEndOffsetBeforeInCurObj.columnCount;\n\t\t\t\tthis.deltaOldToNewColumnCount = previousColumnDelta + columnDelta;\n\t\t\t\tthis.deltaLineIdxInOld = nextEdit.endOffsetBeforeObj.lineCount;\n\t\t\t} else {\n\t\t\t\t// We are in or before the edit.\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n}\n\nclass TextEditInfoCache {\n\tstatic from(edit: TextEditInfo): TextEditInfoCache {\n\t\treturn new TextEditInfoCache(edit.startOffset, edit.endOffset, edit.newLength);\n\t}\n\n\tpublic readonly endOffsetBeforeObj: TextLength;\n\tpublic readonly endOffsetAfterObj: TextLength;\n\tpublic readonly offsetObj: TextLength;\n\n\tconstructor(\n\t\tstartOffset: Length,\n\t\tendOffset: Length,\n\t\ttextLength: Length,\n\t) {\n\t\tthis.endOffsetBeforeObj = lengthToObj(endOffset);\n\t\tthis.endOffsetAfterObj = lengthToObj(lengthAdd(startOffset, textLength));\n\t\tthis.offsetObj = lengthToObj(startOffset);\n\t}\n}\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\nimport { ArrayQueue } from 'vs/base/common/arrays';\nimport { TextEditInfo } from 'vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/beforeEditPositionMapper';\nimport { Length, lengthAdd, lengthDiffNonNegative, lengthEquals, lengthIsZero, lengthToObj, lengthZero, sumLengths } from 'vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/length';\n\nexport function combineTextEditInfos(textEditInfoFirst: TextEditInfo[], textEditInfoSecond: TextEditInfo[]): TextEditInfo[] {\n\tif (textEditInfoFirst.length === 0) {\n\t\treturn textEditInfoSecond;\n\t}\n\tif (textEditInfoSecond.length === 0) {\n\t\treturn textEditInfoFirst;\n\t}\n\n\t// s0: State before any edits\n\tconst s0ToS1Map = new ArrayQueue(toLengthMapping(textEditInfoFirst));\n\t// s1: State after first edit, but before second edit\n\tconst s1ToS2Map = toLengthMapping(textEditInfoSecond) as (LengthMapping | { lengthBefore: undefined; lengthAfter: undefined; modified: false })[];\n\ts1ToS2Map.push({ modified: false, lengthBefore: undefined, lengthAfter: undefined }); // Copy everything from old to new\n\t// s2: State after both edits\n\n\tlet curItem: LengthMapping | undefined = s0ToS1Map.dequeue();\n\n\t/**\n\t * @param s1Length Use undefined for length \"infinity\"\n\t */\n\tfunction nextS0ToS1MapWithS1LengthOf(s1Length: Length | undefined): LengthMapping[] {\n\t\tif (s1Length === undefined) {\n\t\t\tconst arr = s0ToS1Map.takeWhile(v => true) || [];\n\t\t\tif (curItem) {\n\t\t\t\tarr.unshift(curItem);\n\t\t\t}\n\t\t\treturn arr;\n\t\t}\n\n\t\tconst result: LengthMapping[] = [];\n\t\twhile (curItem && !lengthIsZero(s1Length)) {\n\t\t\tconst [item, remainingItem] = curItem.splitAt(s1Length);\n\t\t\tresult.push(item);\n\t\t\ts1Length = lengthDiffNonNegative(item.lengthAfter, s1Length);\n\t\t\tcurItem = remainingItem ?? s0ToS1Map.dequeue();\n\t\t}\n\t\tif (!lengthIsZero(s1Length)) {\n\t\t\tresult.push(new LengthMapping(false, s1Length, s1Length));\n\t\t}\n\t\treturn result;\n\t}\n\n\tconst result: TextEditInfo[] = [];\n\n\tfunction pushEdit(startOffset: Length, endOffset: Length, newLength: Length): void {\n\t\tif (result.length > 0 && lengthEquals(result[result.length - 1].endOffset, startOffset)) {\n\t\t\tconst lastResult = result[result.length - 1];\n\t\t\tresult[result.length - 1] = new TextEditInfo(lastResult.startOffset, endOffset, lengthAdd(lastResult.newLength, newLength));\n\t\t} else {\n\t\t\tresult.push({ startOffset, endOffset, newLength });\n\t\t}\n\t}\n\n\tlet s0offset = lengthZero;\n\tfor (const s1ToS2 of s1ToS2Map) {\n\t\tconst s0ToS1Map = nextS0ToS1MapWithS1LengthOf(s1ToS2.lengthBefore);\n\t\tif (s1ToS2.modified) {\n\t\t\tconst s0Length = sumLengths(s0ToS1Map, s => s.lengthBefore);\n\t\t\tconst s0EndOffset = lengthAdd(s0offset, s0Length);\n\t\t\tpushEdit(s0offset, s0EndOffset, s1ToS2.lengthAfter);\n\t\t\ts0offset = s0EndOffset;\n\t\t} else {\n\t\t\tfor (const s1 of s0ToS1Map) {\n\t\t\t\tconst s0startOffset = s0offset;\n\t\t\t\ts0offset = lengthAdd(s0offset, s1.lengthBefore);\n\t\t\t\tif (s1.modified) {\n\t\t\t\t\tpushEdit(s0startOffset, s0offset, s1.lengthAfter);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn result;\n}\n\nclass LengthMapping {\n\tconstructor(\n\t\t/**\n\t\t * If false, length before and length after equal.\n\t\t */\n\t\tpublic readonly modified: boolean,\n\t\tpublic readonly lengthBefore: Length,\n\t\tpublic readonly lengthAfter: Length,\n\t) {\n\t}\n\n\tsplitAt(lengthAfter: Length): [LengthMapping, LengthMapping | undefined] {\n\t\tconst remainingLengthAfter = lengthDiffNonNegative(lengthAfter, this.lengthAfter);\n\t\tif (lengthEquals(remainingLengthAfter, lengthZero)) {\n\t\t\treturn [this, undefined];\n\t\t} else if (this.modified) {\n\t\t\treturn [\n\t\t\t\tnew LengthMapping(this.modified, this.lengthBefore, lengthAfter),\n\t\t\t\tnew LengthMapping(this.modified, lengthZero, remainingLengthAfter)\n\t\t\t];\n\t\t} else {\n\t\t\treturn [\n\t\t\t\tnew LengthMapping(this.modified, lengthAfter, lengthAfter),\n\t\t\t\tnew LengthMapping(this.modified, remainingLengthAfter, remainingLengthAfter)\n\t\t\t];\n\t\t}\n\t}\n\n\ttoString(): string {\n\t\treturn `${this.modified ? 'M' : 'U'}:${lengthToObj(this.lengthBefore)} -> ${lengthToObj(this.lengthAfter)}`;\n\t}\n}\n\nfunction toLengthMapping(textEditInfos: TextEditInfo[]): LengthMapping[] {\n\tconst result: LengthMapping[] = [];\n\tlet lastOffset = lengthZero;\n\tfor (const textEditInfo of textEditInfos) {\n\t\tconst spaceLength = lengthDiffNonNegative(lastOffset, textEditInfo.startOffset);\n\t\tif (!lengthIsZero(spaceLength)) {\n\t\t\tresult.push(new LengthMapping(false, spaceLength, spaceLength));\n\t\t}\n\n\t\tconst lengthBefore = lengthDiffNonNegative(textEditInfo.startOffset, textEditInfo.endOffset);\n\t\tresult.push(new LengthMapping(true, lengthBefore, textEditInfo.newLength));\n\t\tlastOffset = textEditInfo.endOffset;\n\t}\n\treturn result;\n}\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\nimport { AstNode } from './ast';\nimport { lengthAdd, lengthZero, Length, lengthLessThan } from './length';\n\n/**\n * Allows to efficiently find a longest child at a given offset in a fixed node.\n * The requested offsets must increase monotonously.\n*/\nexport class NodeReader {\n\tprivate readonly nextNodes: AstNode[];\n\tprivate readonly offsets: Length[];\n\tprivate readonly idxs: number[];\n\tprivate lastOffset: Length = lengthZero;\n\n\tconstructor(node: AstNode) {\n\t\tthis.nextNodes = [node];\n\t\tthis.offsets = [lengthZero];\n\t\tthis.idxs = [];\n\t}\n\n\t/**\n\t * Returns the longest node at `offset` that satisfies the predicate.\n\t * @param offset must be greater than or equal to the last offset this method has been called with!\n\t*/\n\treadLongestNodeAt(offset: Length, predicate: (node: AstNode) => boolean): AstNode | undefined {\n\t\tif (lengthLessThan(offset, this.lastOffset)) {\n\t\t\tthrow new Error('Invalid offset');\n\t\t}\n\t\tthis.lastOffset = offset;\n\n\t\t// Find the longest node of all those that are closest to the current offset.\n\t\twhile (true) {\n\t\t\tconst curNode = lastOrUndefined(this.nextNodes);\n\n\t\t\tif (!curNode) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tconst curNodeOffset = lastOrUndefined(this.offsets)!;\n\n\t\t\tif (lengthLessThan(offset, curNodeOffset)) {\n\t\t\t\t// The next best node is not here yet.\n\t\t\t\t// The reader must advance before a cached node is hit.\n\t\t\t\treturn undefined;\n\t\t\t}\n\n\t\t\tif (lengthLessThan(curNodeOffset, offset)) {\n\t\t\t\t// The reader is ahead of the current node.\n\t\t\t\tif (lengthAdd(curNodeOffset, curNode.length) <= offset) {\n\t\t\t\t\t// The reader is after the end of the current node.\n\t\t\t\t\tthis.nextNodeAfterCurrent();\n\t\t\t\t} else {\n\t\t\t\t\t// The reader is somewhere in the current node.\n\t\t\t\t\tconst nextChildIdx = getNextChildIdx(curNode);\n\t\t\t\t\tif (nextChildIdx !== -1) {\n\t\t\t\t\t\t// Go to the first child and repeat.\n\t\t\t\t\t\tthis.nextNodes.push(curNode.getChild(nextChildIdx)!);\n\t\t\t\t\t\tthis.offsets.push(curNodeOffset);\n\t\t\t\t\t\tthis.idxs.push(nextChildIdx);\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// We don't have children\n\t\t\t\t\t\tthis.nextNodeAfterCurrent();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// readerOffsetBeforeChange === curNodeOffset\n\t\t\t\tif (predicate(curNode)) {\n\t\t\t\t\tthis.nextNodeAfterCurrent();\n\t\t\t\t\treturn curNode;\n\t\t\t\t} else {\n\t\t\t\t\tconst nextChildIdx = getNextChildIdx(curNode);\n\t\t\t\t\t// look for shorter node\n\t\t\t\t\tif (nextChildIdx === -1) {\n\t\t\t\t\t\t// There is no shorter node.\n\t\t\t\t\t\tthis.nextNodeAfterCurrent();\n\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Descend into first child & repeat.\n\t\t\t\t\t\tthis.nextNodes.push(curNode.getChild(nextChildIdx)!);\n\t\t\t\t\t\tthis.offsets.push(curNodeOffset);\n\t\t\t\t\t\tthis.idxs.push(nextChildIdx);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Navigates to the longest node that continues after the current node.\n\tprivate nextNodeAfterCurrent(): void {\n\t\twhile (true) {\n\t\t\tconst currentOffset = lastOrUndefined(this.offsets);\n\t\t\tconst currentNode = lastOrUndefined(this.nextNodes);\n\t\t\tthis.nextNodes.pop();\n\t\t\tthis.offsets.pop();\n\n\t\t\tif (this.idxs.length === 0) {\n\t\t\t\t// We just popped the root node, there is no next node.\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// Parent is not undefined, because idxs is not empty\n\t\t\tconst parent = lastOrUndefined(this.nextNodes)!;\n\t\t\tconst nextChildIdx = getNextChildIdx(parent, this.idxs[this.idxs.length - 1]);\n\n\t\t\tif (nextChildIdx !== -1) {\n\t\t\t\tthis.nextNodes.push(parent.getChild(nextChildIdx)!);\n\t\t\t\tthis.offsets.push(lengthAdd(currentOffset!, currentNode!.length));\n\t\t\t\tthis.idxs[this.idxs.length - 1] = nextChildIdx;\n\t\t\t\tbreak;\n\t\t\t} else {\n\t\t\t\tthis.idxs.pop();\n\t\t\t}\n\t\t\t// We fully consumed the parent.\n\t\t\t// Current node is now parent, so call nextNodeAfterCurrent again\n\t\t}\n\t}\n}\n\nfunction getNextChildIdx(node: AstNode, curIdx: number = -1): number | -1 {\n\twhile (true) {\n\t\tcurIdx++;\n\t\tif (curIdx >= node.childrenLength) {\n\t\t\treturn -1;\n\t\t}\n\t\tif (node.getChild(curIdx)) {\n\t\t\treturn curIdx;\n\t\t}\n\t}\n}\n\nfunction lastOrUndefined(arr: readonly T[]): T | undefined {\n\treturn arr.length > 0 ? arr[arr.length - 1] : undefined;\n}\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\nconst emptyArr: number[] = [];\n\n/**\n * Represents an immutable set that works best for a small number of elements (less than 32).\n * It uses bits to encode element membership efficiently.\n*/\nexport class SmallImmutableSet {\n\tprivate static cache = new Array>(129);\n\n\tprivate static create(items: number, additionalItems: readonly number[]): SmallImmutableSet {\n\t\tif (items <= 128 && additionalItems.length === 0) {\n\t\t\t// We create a cache of 128=2^7 elements to cover all sets with up to 7 (dense) elements.\n\t\t\tlet cached = SmallImmutableSet.cache[items];\n\t\t\tif (!cached) {\n\t\t\t\tcached = new SmallImmutableSet(items, additionalItems);\n\t\t\t\tSmallImmutableSet.cache[items] = cached;\n\t\t\t}\n\t\t\treturn cached;\n\t\t}\n\n\t\treturn new SmallImmutableSet(items, additionalItems);\n\t}\n\n\tprivate static empty = SmallImmutableSet.create(0, emptyArr);\n\tpublic static getEmpty(): SmallImmutableSet {\n\t\treturn this.empty;\n\t}\n\n\tprivate constructor(\n\t\tprivate readonly items: number,\n\t\tprivate readonly additionalItems: readonly number[]\n\t) {\n\t}\n\n\tpublic add(value: T, keyProvider: IDenseKeyProvider): SmallImmutableSet {\n\t\tconst key = keyProvider.getKey(value);\n\t\tlet idx = key >> 5; // divided by 32\n\t\tif (idx === 0) {\n\t\t\t// fast path\n\t\t\tconst newItem = (1 << key) | this.items;\n\t\t\tif (newItem === this.items) {\n\t\t\t\treturn this;\n\t\t\t}\n\t\t\treturn SmallImmutableSet.create(newItem, this.additionalItems);\n\t\t}\n\t\tidx--;\n\n\t\tconst newItems = this.additionalItems.slice(0);\n\t\twhile (newItems.length < idx) {\n\t\t\tnewItems.push(0);\n\t\t}\n\t\tnewItems[idx] |= 1 << (key & 31);\n\n\t\treturn SmallImmutableSet.create(this.items, newItems);\n\t}\n\n\tpublic merge(other: SmallImmutableSet): SmallImmutableSet {\n\t\tconst merged = this.items | other.items;\n\n\t\tif (this.additionalItems === emptyArr && other.additionalItems === emptyArr) {\n\t\t\t// fast path\n\t\t\tif (merged === this.items) {\n\t\t\t\treturn this;\n\t\t\t}\n\t\t\tif (merged === other.items) {\n\t\t\t\treturn other;\n\t\t\t}\n\t\t\treturn SmallImmutableSet.create(merged, emptyArr);\n\t\t}\n\n\t\t// This can be optimized, but it's not a common case\n\t\tconst newItems: number[] = [];\n\t\tfor (let i = 0; i < Math.max(this.additionalItems.length, other.additionalItems.length); i++) {\n\t\t\tconst item1 = this.additionalItems[i] || 0;\n\t\t\tconst item2 = other.additionalItems[i] || 0;\n\t\t\tnewItems.push(item1 | item2);\n\t\t}\n\n\t\treturn SmallImmutableSet.create(merged, newItems);\n\t}\n\n\tpublic intersects(other: SmallImmutableSet): boolean {\n\t\tif ((this.items & other.items) !== 0) {\n\t\t\treturn true;\n\t\t}\n\n\t\tfor (let i = 0; i < Math.min(this.additionalItems.length, other.additionalItems.length); i++) {\n\t\t\tif ((this.additionalItems[i] & other.additionalItems[i]) !== 0) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n}\n\nexport interface IDenseKeyProvider {\n\tgetKey(value: T): number;\n}\n\nexport const identityKeyProvider: IDenseKeyProvider = {\n\tgetKey(value: number) {\n\t\treturn value;\n\t}\n};\n\n/**\n * Assigns values a unique incrementing key.\n*/\nexport class DenseKeyProvider {\n\tprivate readonly items = new Map();\n\n\tgetKey(value: T): number {\n\t\tlet existing = this.items.get(value);\n\t\tif (existing === undefined) {\n\t\t\texisting = this.items.size;\n\t\t\tthis.items.set(value, existing);\n\t\t}\n\t\treturn existing;\n\t}\n}\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\nimport { BugIndicatingError } from 'vs/base/common/errors';\nimport { CursorColumns } from 'vs/editor/common/core/cursorColumns';\nimport { BracketKind } from 'vs/editor/common/languages/supports/languageBracketsConfiguration';\nimport { ITextModel } from 'vs/editor/common/model';\nimport { Length, lengthAdd, lengthGetLineCount, lengthToObj, lengthZero } from './length';\nimport { SmallImmutableSet } from './smallImmutableSet';\nimport { OpeningBracketId } from './tokenizer';\n\nexport const enum AstNodeKind {\n\tText = 0,\n\tBracket = 1,\n\tPair = 2,\n\tUnexpectedClosingBracket = 3,\n\tList = 4,\n}\n\nexport type AstNode = PairAstNode | ListAstNode | BracketAstNode | InvalidBracketAstNode | TextAstNode;\n\n/**\n * The base implementation for all AST nodes.\n*/\nabstract class BaseAstNode {\n\tpublic abstract readonly kind: AstNodeKind;\n\n\tpublic abstract readonly childrenLength: number;\n\n\t/**\n\t * Might return null even if {@link idx} is smaller than {@link BaseAstNode.childrenLength}.\n\t*/\n\tpublic abstract getChild(idx: number): AstNode | null;\n\n\t/**\n\t * Try to avoid using this property, as implementations might need to allocate the resulting array.\n\t*/\n\tpublic abstract readonly children: readonly AstNode[];\n\n\t/**\n\t * Represents the set of all (potentially) missing opening bracket ids in this node.\n\t * E.g. in `{ ] ) }` that set is {`[`, `(` }.\n\t*/\n\tpublic abstract readonly missingOpeningBracketIds: SmallImmutableSet;\n\n\t/**\n\t * In case of a list, determines the height of the (2,3) tree.\n\t*/\n\tpublic abstract readonly listHeight: number;\n\n\tprotected _length: Length;\n\n\t/**\n\t * The length of the entire node, which should equal the sum of lengths of all children.\n\t*/\n\tpublic get length(): Length {\n\t\treturn this._length;\n\t}\n\n\tpublic constructor(length: Length) {\n\t\tthis._length = length;\n\t}\n\n\t/**\n\t * @param openBracketIds The set of all opening brackets that have not yet been closed.\n\t */\n\tpublic abstract canBeReused(\n\t\topenBracketIds: SmallImmutableSet\n\t): boolean;\n\n\t/**\n\t * Creates a deep clone.\n\t */\n\tpublic abstract deepClone(): AstNode;\n\n\tpublic abstract computeMinIndentation(offset: Length, textModel: ITextModel): number;\n}\n\n/**\n * Represents a bracket pair including its child (e.g. `{ ... }`).\n * Might be unclosed.\n * Immutable, if all children are immutable.\n*/\nexport class PairAstNode extends BaseAstNode {\n\tpublic static create(\n\t\topeningBracket: BracketAstNode,\n\t\tchild: AstNode | null,\n\t\tclosingBracket: BracketAstNode | null\n\t) {\n\t\tlet length = openingBracket.length;\n\t\tif (child) {\n\t\t\tlength = lengthAdd(length, child.length);\n\t\t}\n\t\tif (closingBracket) {\n\t\t\tlength = lengthAdd(length, closingBracket.length);\n\t\t}\n\t\treturn new PairAstNode(length, openingBracket, child, closingBracket, child ? child.missingOpeningBracketIds : SmallImmutableSet.getEmpty());\n\t}\n\n\tpublic get kind(): AstNodeKind.Pair {\n\t\treturn AstNodeKind.Pair;\n\t}\n\tpublic get listHeight() {\n\t\treturn 0;\n\t}\n\tpublic get childrenLength(): number {\n\t\treturn 3;\n\t}\n\tpublic getChild(idx: number): AstNode | null {\n\t\tswitch (idx) {\n\t\t\tcase 0: return this.openingBracket;\n\t\t\tcase 1: return this.child;\n\t\t\tcase 2: return this.closingBracket;\n\t\t}\n\t\tthrow new Error('Invalid child index');\n\t}\n\n\t/**\n\t * Avoid using this property, it allocates an array!\n\t*/\n\tpublic get children() {\n\t\tconst result: AstNode[] = [];\n\t\tresult.push(this.openingBracket);\n\t\tif (this.child) {\n\t\t\tresult.push(this.child);\n\t\t}\n\t\tif (this.closingBracket) {\n\t\t\tresult.push(this.closingBracket);\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate constructor(\n\t\tlength: Length,\n\t\tpublic readonly openingBracket: BracketAstNode,\n\t\tpublic readonly child: AstNode | null,\n\t\tpublic readonly closingBracket: BracketAstNode | null,\n\t\tpublic readonly missingOpeningBracketIds: SmallImmutableSet\n\t) {\n\t\tsuper(length);\n\t}\n\n\tpublic canBeReused(openBracketIds: SmallImmutableSet) {\n\t\tif (this.closingBracket === null) {\n\t\t\t// Unclosed pair ast nodes only\n\t\t\t// end at the end of the document\n\t\t\t// or when a parent node is closed.\n\n\t\t\t// This could be improved:\n\t\t\t// Only return false if some next token is neither \"undefined\" nor a bracket that closes a parent.\n\n\t\t\treturn false;\n\t\t}\n\n\t\tif (openBracketIds.intersects(this.missingOpeningBracketIds)) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tpublic deepClone(): PairAstNode {\n\t\treturn new PairAstNode(\n\t\t\tthis.length,\n\t\t\tthis.openingBracket.deepClone(),\n\t\t\tthis.child && this.child.deepClone(),\n\t\t\tthis.closingBracket && this.closingBracket.deepClone(),\n\t\t\tthis.missingOpeningBracketIds\n\t\t);\n\t}\n\n\tpublic computeMinIndentation(offset: Length, textModel: ITextModel): number {\n\t\treturn this.child ? this.child.computeMinIndentation(lengthAdd(offset, this.openingBracket.length), textModel) : Number.MAX_SAFE_INTEGER;\n\t}\n}\n\nexport abstract class ListAstNode extends BaseAstNode {\n\t/**\n\t * This method uses more memory-efficient list nodes that can only store 2 or 3 children.\n\t*/\n\tpublic static create23(item1: AstNode, item2: AstNode, item3: AstNode | null, immutable: boolean = false): ListAstNode {\n\t\tlet length = item1.length;\n\t\tlet missingBracketIds = item1.missingOpeningBracketIds;\n\n\t\tif (item1.listHeight !== item2.listHeight) {\n\t\t\tthrow new Error('Invalid list heights');\n\t\t}\n\n\t\tlength = lengthAdd(length, item2.length);\n\t\tmissingBracketIds = missingBracketIds.merge(item2.missingOpeningBracketIds);\n\n\t\tif (item3) {\n\t\t\tif (item1.listHeight !== item3.listHeight) {\n\t\t\t\tthrow new Error('Invalid list heights');\n\t\t\t}\n\t\t\tlength = lengthAdd(length, item3.length);\n\t\t\tmissingBracketIds = missingBracketIds.merge(item3.missingOpeningBracketIds);\n\t\t}\n\t\treturn immutable\n\t\t\t? new Immutable23ListAstNode(length, item1.listHeight + 1, item1, item2, item3, missingBracketIds)\n\t\t\t: new TwoThreeListAstNode(length, item1.listHeight + 1, item1, item2, item3, missingBracketIds);\n\t}\n\n\tpublic static getEmpty() {\n\t\treturn new ImmutableArrayListAstNode(lengthZero, 0, [], SmallImmutableSet.getEmpty());\n\t}\n\n\tpublic get kind(): AstNodeKind.List {\n\t\treturn AstNodeKind.List;\n\t}\n\n\tpublic get missingOpeningBracketIds(): SmallImmutableSet {\n\t\treturn this._missingOpeningBracketIds;\n\t}\n\n\tprivate cachedMinIndentation: number = -1;\n\n\t/**\n\t * Use ListAstNode.create.\n\t*/\n\tconstructor(\n\t\tlength: Length,\n\t\tpublic readonly listHeight: number,\n\t\tprivate _missingOpeningBracketIds: SmallImmutableSet\n\t) {\n\t\tsuper(length);\n\t}\n\n\tprotected throwIfImmutable(): void {\n\t\t// NOOP\n\t}\n\n\tprotected abstract setChild(idx: number, child: AstNode): void;\n\n\tpublic makeLastElementMutable(): AstNode | undefined {\n\t\tthis.throwIfImmutable();\n\t\tconst childCount = this.childrenLength;\n\t\tif (childCount === 0) {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst lastChild = this.getChild(childCount - 1)!;\n\t\tconst mutable = lastChild.kind === AstNodeKind.List ? lastChild.toMutable() : lastChild;\n\t\tif (lastChild !== mutable) {\n\t\t\tthis.setChild(childCount - 1, mutable);\n\t\t}\n\t\treturn mutable;\n\t}\n\n\tpublic makeFirstElementMutable(): AstNode | undefined {\n\t\tthis.throwIfImmutable();\n\t\tconst childCount = this.childrenLength;\n\t\tif (childCount === 0) {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst firstChild = this.getChild(0)!;\n\t\tconst mutable = firstChild.kind === AstNodeKind.List ? firstChild.toMutable() : firstChild;\n\t\tif (firstChild !== mutable) {\n\t\t\tthis.setChild(0, mutable);\n\t\t}\n\t\treturn mutable;\n\t}\n\n\tpublic canBeReused(openBracketIds: SmallImmutableSet): boolean {\n\t\tif (openBracketIds.intersects(this.missingOpeningBracketIds)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (this.childrenLength === 0) {\n\t\t\t// Don't reuse empty lists.\n\t\t\treturn false;\n\t\t}\n\n\t\tlet lastChild: ListAstNode = this;\n\t\twhile (lastChild.kind === AstNodeKind.List) {\n\t\t\tconst lastLength = lastChild.childrenLength;\n\t\t\tif (lastLength === 0) {\n\t\t\t\t// Empty lists should never be contained in other lists.\n\t\t\t\tthrow new BugIndicatingError();\n\t\t\t}\n\t\t\tlastChild = lastChild.getChild(lastLength - 1) as ListAstNode;\n\t\t}\n\n\t\treturn lastChild.canBeReused(openBracketIds);\n\t}\n\n\tpublic handleChildrenChanged(): void {\n\t\tthis.throwIfImmutable();\n\n\t\tconst count = this.childrenLength;\n\n\t\tlet length = this.getChild(0)!.length;\n\t\tlet unopenedBrackets = this.getChild(0)!.missingOpeningBracketIds;\n\n\t\tfor (let i = 1; i < count; i++) {\n\t\t\tconst child = this.getChild(i)!;\n\t\t\tlength = lengthAdd(length, child.length);\n\t\t\tunopenedBrackets = unopenedBrackets.merge(child.missingOpeningBracketIds);\n\t\t}\n\n\t\tthis._length = length;\n\t\tthis._missingOpeningBracketIds = unopenedBrackets;\n\t\tthis.cachedMinIndentation = -1;\n\t}\n\n\tpublic computeMinIndentation(offset: Length, textModel: ITextModel): number {\n\t\tif (this.cachedMinIndentation !== -1) {\n\t\t\treturn this.cachedMinIndentation;\n\t\t}\n\n\t\tlet minIndentation = Number.MAX_SAFE_INTEGER;\n\t\tlet childOffset = offset;\n\t\tfor (let i = 0; i < this.childrenLength; i++) {\n\t\t\tconst child = this.getChild(i);\n\t\t\tif (child) {\n\t\t\t\tminIndentation = Math.min(minIndentation, child.computeMinIndentation(childOffset, textModel));\n\t\t\t\tchildOffset = lengthAdd(childOffset, child.length);\n\t\t\t}\n\t\t}\n\n\t\tthis.cachedMinIndentation = minIndentation;\n\t\treturn minIndentation;\n\t}\n\n\t/**\n\t * Creates a shallow clone that is mutable, or itself if it is already mutable.\n\t */\n\tpublic abstract toMutable(): ListAstNode;\n\n\tpublic abstract appendChildOfSameHeight(node: AstNode): void;\n\tpublic abstract unappendChild(): AstNode | undefined;\n\tpublic abstract prependChildOfSameHeight(node: AstNode): void;\n\tpublic abstract unprependChild(): AstNode | undefined;\n}\n\nclass TwoThreeListAstNode extends ListAstNode {\n\tpublic get childrenLength(): number {\n\t\treturn this._item3 !== null ? 3 : 2;\n\t}\n\tpublic getChild(idx: number): AstNode | null {\n\t\tswitch (idx) {\n\t\t\tcase 0: return this._item1;\n\t\t\tcase 1: return this._item2;\n\t\t\tcase 2: return this._item3;\n\t\t}\n\t\tthrow new Error('Invalid child index');\n\t}\n\tprotected setChild(idx: number, node: AstNode): void {\n\t\tswitch (idx) {\n\t\t\tcase 0: this._item1 = node; return;\n\t\t\tcase 1: this._item2 = node; return;\n\t\t\tcase 2: this._item3 = node; return;\n\t\t}\n\t\tthrow new Error('Invalid child index');\n\t}\n\n\tpublic get children(): readonly AstNode[] {\n\t\treturn this._item3 ? [this._item1, this._item2, this._item3] : [this._item1, this._item2];\n\t}\n\n\tpublic get item1(): AstNode {\n\t\treturn this._item1;\n\t}\n\tpublic get item2(): AstNode {\n\t\treturn this._item2;\n\t}\n\tpublic get item3(): AstNode | null {\n\t\treturn this._item3;\n\t}\n\n\tpublic constructor(\n\t\tlength: Length,\n\t\tlistHeight: number,\n\t\tprivate _item1: AstNode,\n\t\tprivate _item2: AstNode,\n\t\tprivate _item3: AstNode | null,\n\t\tmissingOpeningBracketIds: SmallImmutableSet\n\t) {\n\t\tsuper(length, listHeight, missingOpeningBracketIds);\n\t}\n\n\tpublic deepClone(): ListAstNode {\n\t\treturn new TwoThreeListAstNode(\n\t\t\tthis.length,\n\t\t\tthis.listHeight,\n\t\t\tthis._item1.deepClone(),\n\t\t\tthis._item2.deepClone(),\n\t\t\tthis._item3 ? this._item3.deepClone() : null,\n\t\t\tthis.missingOpeningBracketIds\n\t\t);\n\t}\n\n\tpublic appendChildOfSameHeight(node: AstNode): void {\n\t\tif (this._item3) {\n\t\t\tthrow new Error('Cannot append to a full (2,3) tree node');\n\t\t}\n\t\tthis.throwIfImmutable();\n\t\tthis._item3 = node;\n\t\tthis.handleChildrenChanged();\n\t}\n\n\tpublic unappendChild(): AstNode | undefined {\n\t\tif (!this._item3) {\n\t\t\tthrow new Error('Cannot remove from a non-full (2,3) tree node');\n\t\t}\n\t\tthis.throwIfImmutable();\n\t\tconst result = this._item3;\n\t\tthis._item3 = null;\n\t\tthis.handleChildrenChanged();\n\t\treturn result;\n\t}\n\n\tpublic prependChildOfSameHeight(node: AstNode): void {\n\t\tif (this._item3) {\n\t\t\tthrow new Error('Cannot prepend to a full (2,3) tree node');\n\t\t}\n\t\tthis.throwIfImmutable();\n\t\tthis._item3 = this._item2;\n\t\tthis._item2 = this._item1;\n\t\tthis._item1 = node;\n\t\tthis.handleChildrenChanged();\n\t}\n\n\tpublic unprependChild(): AstNode | undefined {\n\t\tif (!this._item3) {\n\t\t\tthrow new Error('Cannot remove from a non-full (2,3) tree node');\n\t\t}\n\t\tthis.throwIfImmutable();\n\t\tconst result = this._item1;\n\t\tthis._item1 = this._item2;\n\t\tthis._item2 = this._item3;\n\t\tthis._item3 = null;\n\n\t\tthis.handleChildrenChanged();\n\t\treturn result;\n\t}\n\n\toverride toMutable(): ListAstNode {\n\t\treturn this;\n\t}\n}\n\n/**\n * Immutable, if all children are immutable.\n*/\nclass Immutable23ListAstNode extends TwoThreeListAstNode {\n\toverride toMutable(): ListAstNode {\n\t\treturn new TwoThreeListAstNode(this.length, this.listHeight, this.item1, this.item2, this.item3, this.missingOpeningBracketIds);\n\t}\n\n\tprotected override throwIfImmutable(): void {\n\t\tthrow new Error('this instance is immutable');\n\t}\n}\n\n/**\n * For debugging.\n*/\nclass ArrayListAstNode extends ListAstNode {\n\tget childrenLength(): number {\n\t\treturn this._children.length;\n\t}\n\tgetChild(idx: number): AstNode | null {\n\t\treturn this._children[idx];\n\t}\n\tprotected setChild(idx: number, child: AstNode): void {\n\t\tthis._children[idx] = child;\n\t}\n\tget children(): readonly AstNode[] {\n\t\treturn this._children;\n\t}\n\n\tconstructor(\n\t\tlength: Length,\n\t\tlistHeight: number,\n\t\tprivate readonly _children: AstNode[],\n\t\tmissingOpeningBracketIds: SmallImmutableSet\n\t) {\n\t\tsuper(length, listHeight, missingOpeningBracketIds);\n\t}\n\n\tdeepClone(): ListAstNode {\n\t\tconst children = new Array(this._children.length);\n\t\tfor (let i = 0; i < this._children.length; i++) {\n\t\t\tchildren[i] = this._children[i].deepClone();\n\t\t}\n\t\treturn new ArrayListAstNode(this.length, this.listHeight, children, this.missingOpeningBracketIds);\n\t}\n\n\tpublic appendChildOfSameHeight(node: AstNode): void {\n\t\tthis.throwIfImmutable();\n\t\tthis._children.push(node);\n\t\tthis.handleChildrenChanged();\n\t}\n\n\tpublic unappendChild(): AstNode | undefined {\n\t\tthis.throwIfImmutable();\n\t\tconst item = this._children.pop();\n\t\tthis.handleChildrenChanged();\n\t\treturn item;\n\t}\n\n\tpublic prependChildOfSameHeight(node: AstNode): void {\n\t\tthis.throwIfImmutable();\n\t\tthis._children.unshift(node);\n\t\tthis.handleChildrenChanged();\n\t}\n\n\tpublic unprependChild(): AstNode | undefined {\n\t\tthis.throwIfImmutable();\n\t\tconst item = this._children.shift();\n\t\tthis.handleChildrenChanged();\n\t\treturn item;\n\t}\n\n\tpublic override toMutable(): ListAstNode {\n\t\treturn this;\n\t}\n}\n\n/**\n * Immutable, if all children are immutable.\n*/\nclass ImmutableArrayListAstNode extends ArrayListAstNode {\n\toverride toMutable(): ListAstNode {\n\t\treturn new ArrayListAstNode(this.length, this.listHeight, [...this.children], this.missingOpeningBracketIds);\n\t}\n\n\tprotected override throwIfImmutable(): void {\n\t\tthrow new Error('this instance is immutable');\n\t}\n}\n\nconst emptyArray: readonly AstNode[] = [];\n\nabstract class ImmutableLeafAstNode extends BaseAstNode {\n\tpublic get listHeight() {\n\t\treturn 0;\n\t}\n\tpublic get childrenLength(): number {\n\t\treturn 0;\n\t}\n\tpublic getChild(idx: number): AstNode | null {\n\t\treturn null;\n\t}\n\tpublic get children(): readonly AstNode[] {\n\t\treturn emptyArray;\n\t}\n\tpublic deepClone(): this & AstNode {\n\t\treturn this as this & AstNode;\n\t}\n}\n\nexport class TextAstNode extends ImmutableLeafAstNode {\n\tpublic get kind(): AstNodeKind.Text {\n\t\treturn AstNodeKind.Text;\n\t}\n\tpublic get missingOpeningBracketIds(): SmallImmutableSet {\n\t\treturn SmallImmutableSet.getEmpty();\n\t}\n\n\tpublic canBeReused(_openedBracketIds: SmallImmutableSet) {\n\t\treturn true;\n\t}\n\n\tpublic computeMinIndentation(offset: Length, textModel: ITextModel): number {\n\t\tconst start = lengthToObj(offset);\n\t\t// Text ast nodes don't have partial indentation (ensured by the tokenizer).\n\t\t// Thus, if this text node does not start at column 0, the first line cannot have any indentation at all.\n\t\tconst startLineNumber = (start.columnCount === 0 ? start.lineCount : start.lineCount + 1) + 1;\n\t\tconst endLineNumber = lengthGetLineCount(lengthAdd(offset, this.length)) + 1;\n\n\t\tlet result = Number.MAX_SAFE_INTEGER;\n\n\t\tfor (let lineNumber = startLineNumber; lineNumber <= endLineNumber; lineNumber++) {\n\t\t\tconst firstNonWsColumn = textModel.getLineFirstNonWhitespaceColumn(lineNumber);\n\t\t\tconst lineContent = textModel.getLineContent(lineNumber);\n\t\t\tif (firstNonWsColumn === 0) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst visibleColumn = CursorColumns.visibleColumnFromColumn(lineContent, firstNonWsColumn, textModel.getOptions().tabSize)!;\n\t\t\tresult = Math.min(result, visibleColumn);\n\t\t}\n\n\t\treturn result;\n\t}\n}\n\nexport class BracketAstNode extends ImmutableLeafAstNode {\n\tpublic static create(\n\t\tlength: Length,\n\t\tbracketInfo: BracketKind,\n\t\tbracketIds: SmallImmutableSet\n\t): BracketAstNode {\n\t\tconst node = new BracketAstNode(length, bracketInfo, bracketIds);\n\t\treturn node;\n\t}\n\n\tpublic get kind(): AstNodeKind.Bracket {\n\t\treturn AstNodeKind.Bracket;\n\t}\n\n\tpublic get missingOpeningBracketIds(): SmallImmutableSet {\n\t\treturn SmallImmutableSet.getEmpty();\n\t}\n\n\tprivate constructor(\n\t\tlength: Length,\n\t\tpublic readonly bracketInfo: BracketKind,\n\t\t/**\n\t\t * In case of a opening bracket, this is the id of the opening bracket.\n\t\t * In case of a closing bracket, this contains the ids of all opening brackets it can close.\n\t\t*/\n\t\tpublic readonly bracketIds: SmallImmutableSet\n\t) {\n\t\tsuper(length);\n\t}\n\n\tpublic get text() {\n\t\treturn this.bracketInfo.bracketText;\n\t}\n\n\tpublic get languageId() {\n\t\treturn this.bracketInfo.languageId;\n\t}\n\n\tpublic canBeReused(_openedBracketIds: SmallImmutableSet) {\n\t\t// These nodes could be reused,\n\t\t// but not in a general way.\n\t\t// Their parent may be reused.\n\t\treturn false;\n\t}\n\n\tpublic computeMinIndentation(offset: Length, textModel: ITextModel): number {\n\t\treturn Number.MAX_SAFE_INTEGER;\n\t}\n}\n\nexport class InvalidBracketAstNode extends ImmutableLeafAstNode {\n\tpublic get kind(): AstNodeKind.UnexpectedClosingBracket {\n\t\treturn AstNodeKind.UnexpectedClosingBracket;\n\t}\n\n\tpublic readonly missingOpeningBracketIds: SmallImmutableSet;\n\n\tpublic constructor(closingBrackets: SmallImmutableSet, length: Length) {\n\t\tsuper(length);\n\t\tthis.missingOpeningBracketIds = closingBrackets;\n\t}\n\n\tpublic canBeReused(openedBracketIds: SmallImmutableSet) {\n\t\treturn !openedBracketIds.intersects(this.missingOpeningBracketIds);\n\t}\n\n\tpublic computeMinIndentation(offset: Length, textModel: ITextModel): number {\n\t\treturn Number.MAX_SAFE_INTEGER;\n\t}\n}\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\nimport { AstNode, AstNodeKind, ListAstNode } from './ast';\n\n/**\n * Concatenates a list of (2,3) AstNode's into a single (2,3) AstNode.\n * This mutates the items of the input array!\n * If all items have the same height, this method has runtime O(items.length).\n * Otherwise, it has runtime O(items.length * max(log(items.length), items.max(i => i.height))).\n*/\nexport function concat23Trees(items: AstNode[]): AstNode | null {\n\tif (items.length === 0) {\n\t\treturn null;\n\t}\n\tif (items.length === 1) {\n\t\treturn items[0];\n\t}\n\n\tlet i = 0;\n\t/**\n\t * Reads nodes of same height and concatenates them to a single node.\n\t*/\n\tfunction readNode(): AstNode | null {\n\t\tif (i >= items.length) {\n\t\t\treturn null;\n\t\t}\n\t\tconst start = i;\n\t\tconst height = items[start].listHeight;\n\n\t\ti++;\n\t\twhile (i < items.length && items[i].listHeight === height) {\n\t\t\ti++;\n\t\t}\n\n\t\tif (i - start >= 2) {\n\t\t\treturn concat23TreesOfSameHeight(start === 0 && i === items.length ? items : items.slice(start, i), false);\n\t\t} else {\n\t\t\treturn items[start];\n\t\t}\n\t}\n\n\t// The items might not have the same height.\n\t// We merge all items by using a binary concat operator.\n\tlet first = readNode()!; // There must be a first item\n\tlet second = readNode();\n\tif (!second) {\n\t\treturn first;\n\t}\n\n\tfor (let item = readNode(); item; item = readNode()) {\n\t\t// Prefer concatenating smaller trees, as the runtime of concat depends on the tree height.\n\t\tif (heightDiff(first, second) <= heightDiff(second, item)) {\n\t\t\tfirst = concat(first, second);\n\t\t\tsecond = item;\n\t\t} else {\n\t\t\tsecond = concat(second, item);\n\t\t}\n\t}\n\n\tconst result = concat(first, second);\n\treturn result;\n}\n\nexport function concat23TreesOfSameHeight(items: AstNode[], createImmutableLists: boolean = false): AstNode | null {\n\tif (items.length === 0) {\n\t\treturn null;\n\t}\n\tif (items.length === 1) {\n\t\treturn items[0];\n\t}\n\n\tlet length = items.length;\n\t// All trees have same height, just create parent nodes.\n\twhile (length > 3) {\n\t\tconst newLength = length >> 1;\n\t\tfor (let i = 0; i < newLength; i++) {\n\t\t\tconst j = i << 1;\n\t\t\titems[i] = ListAstNode.create23(items[j], items[j + 1], j + 3 === length ? items[j + 2] : null, createImmutableLists);\n\t\t}\n\t\tlength = newLength;\n\t}\n\treturn ListAstNode.create23(items[0], items[1], length >= 3 ? items[2] : null, createImmutableLists);\n}\n\nfunction heightDiff(node1: AstNode, node2: AstNode): number {\n\treturn Math.abs(node1.listHeight - node2.listHeight);\n}\n\nfunction concat(node1: AstNode, node2: AstNode): AstNode {\n\tif (node1.listHeight === node2.listHeight) {\n\t\treturn ListAstNode.create23(node1, node2, null, false);\n\t}\n\telse if (node1.listHeight > node2.listHeight) {\n\t\t// node1 is the tree we want to insert into\n\t\treturn append(node1 as ListAstNode, node2);\n\t} else {\n\t\treturn prepend(node2 as ListAstNode, node1);\n\t}\n}\n\n/**\n * Appends the given node to the end of this (2,3) tree.\n * Returns the new root.\n*/\nfunction append(list: ListAstNode, nodeToAppend: AstNode): AstNode {\n\tlist = list.toMutable() as ListAstNode;\n\tlet curNode: AstNode = list;\n\tconst parents: ListAstNode[] = [];\n\tlet nodeToAppendOfCorrectHeight: AstNode | undefined;\n\twhile (true) {\n\t\t// assert nodeToInsert.listHeight <= curNode.listHeight\n\t\tif (nodeToAppend.listHeight === curNode.listHeight) {\n\t\t\tnodeToAppendOfCorrectHeight = nodeToAppend;\n\t\t\tbreak;\n\t\t}\n\t\t// assert 0 <= nodeToInsert.listHeight < curNode.listHeight\n\t\tif (curNode.kind !== AstNodeKind.List) {\n\t\t\tthrow new Error('unexpected');\n\t\t}\n\t\tparents.push(curNode);\n\t\t// assert 2 <= curNode.childrenLength <= 3\n\t\tcurNode = curNode.makeLastElementMutable()!;\n\t}\n\t// assert nodeToAppendOfCorrectHeight!.listHeight === curNode.listHeight\n\tfor (let i = parents.length - 1; i >= 0; i--) {\n\t\tconst parent = parents[i];\n\t\tif (nodeToAppendOfCorrectHeight) {\n\t\t\t// Can we take the element?\n\t\t\tif (parent.childrenLength >= 3) {\n\t\t\t\t// assert parent.childrenLength === 3 && parent.listHeight === nodeToAppendOfCorrectHeight.listHeight + 1\n\n\t\t\t\t// we need to split to maintain (2,3)-tree property.\n\t\t\t\t// Send the third element + the new element to the parent.\n\t\t\t\tnodeToAppendOfCorrectHeight = ListAstNode.create23(parent.unappendChild()!, nodeToAppendOfCorrectHeight, null, false);\n\t\t\t} else {\n\t\t\t\tparent.appendChildOfSameHeight(nodeToAppendOfCorrectHeight);\n\t\t\t\tnodeToAppendOfCorrectHeight = undefined;\n\t\t\t}\n\t\t} else {\n\t\t\tparent.handleChildrenChanged();\n\t\t}\n\t}\n\tif (nodeToAppendOfCorrectHeight) {\n\t\treturn ListAstNode.create23(list, nodeToAppendOfCorrectHeight, null, false);\n\t} else {\n\t\treturn list;\n\t}\n}\n\n/**\n * Prepends the given node to the end of this (2,3) tree.\n * Returns the new root.\n*/\nfunction prepend(list: ListAstNode, nodeToAppend: AstNode): AstNode {\n\tlist = list.toMutable() as ListAstNode;\n\tlet curNode: AstNode = list;\n\tconst parents: ListAstNode[] = [];\n\t// assert nodeToInsert.listHeight <= curNode.listHeight\n\twhile (nodeToAppend.listHeight !== curNode.listHeight) {\n\t\t// assert 0 <= nodeToInsert.listHeight < curNode.listHeight\n\t\tif (curNode.kind !== AstNodeKind.List) {\n\t\t\tthrow new Error('unexpected');\n\t\t}\n\t\tparents.push(curNode);\n\t\t// assert 2 <= curNode.childrenFast.length <= 3\n\t\tcurNode = curNode.makeFirstElementMutable()!;\n\t}\n\tlet nodeToPrependOfCorrectHeight: AstNode | undefined = nodeToAppend;\n\t// assert nodeToAppendOfCorrectHeight!.listHeight === curNode.listHeight\n\tfor (let i = parents.length - 1; i >= 0; i--) {\n\t\tconst parent = parents[i];\n\t\tif (nodeToPrependOfCorrectHeight) {\n\t\t\t// Can we take the element?\n\t\t\tif (parent.childrenLength >= 3) {\n\t\t\t\t// assert parent.childrenLength === 3 && parent.listHeight === nodeToAppendOfCorrectHeight.listHeight + 1\n\n\t\t\t\t// we need to split to maintain (2,3)-tree property.\n\t\t\t\t// Send the third element + the new element to the parent.\n\t\t\t\tnodeToPrependOfCorrectHeight = ListAstNode.create23(nodeToPrependOfCorrectHeight, parent.unprependChild()!, null, false);\n\t\t\t} else {\n\t\t\t\tparent.prependChildOfSameHeight(nodeToPrependOfCorrectHeight);\n\t\t\t\tnodeToPrependOfCorrectHeight = undefined;\n\t\t\t}\n\t\t} else {\n\t\t\tparent.handleChildrenChanged();\n\t\t}\n\t}\n\tif (nodeToPrependOfCorrectHeight) {\n\t\treturn ListAstNode.create23(nodeToPrependOfCorrectHeight, list, null, false);\n\t} else {\n\t\treturn list;\n\t}\n}\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\nimport { AstNode, AstNodeKind, BracketAstNode, InvalidBracketAstNode, ListAstNode, PairAstNode, TextAstNode } from './ast';\nimport { BeforeEditPositionMapper, TextEditInfo } from './beforeEditPositionMapper';\nimport { SmallImmutableSet } from './smallImmutableSet';\nimport { lengthIsZero, lengthLessThan } from './length';\nimport { concat23Trees, concat23TreesOfSameHeight } from './concat23Trees';\nimport { NodeReader } from './nodeReader';\nimport { OpeningBracketId, Tokenizer, TokenKind } from './tokenizer';\n\n/**\n * Non incrementally built ASTs are immutable.\n*/\nexport function parseDocument(tokenizer: Tokenizer, edits: TextEditInfo[], oldNode: AstNode | undefined, createImmutableLists: boolean): AstNode {\n\tconst parser = new Parser(tokenizer, edits, oldNode, createImmutableLists);\n\treturn parser.parseDocument();\n}\n\n/**\n * Non incrementally built ASTs are immutable.\n*/\nclass Parser {\n\tprivate readonly oldNodeReader?: NodeReader;\n\tprivate readonly positionMapper: BeforeEditPositionMapper;\n\tprivate _itemsConstructed: number = 0;\n\tprivate _itemsFromCache: number = 0;\n\n\tconstructor(\n\t\tprivate readonly tokenizer: Tokenizer,\n\t\tedits: TextEditInfo[],\n\t\toldNode: AstNode | undefined,\n\t\tprivate readonly createImmutableLists: boolean,\n\t) {\n\t\tif (oldNode && createImmutableLists) {\n\t\t\tthrow new Error('Not supported');\n\t\t}\n\n\t\tthis.oldNodeReader = oldNode ? new NodeReader(oldNode) : undefined;\n\t\tthis.positionMapper = new BeforeEditPositionMapper(edits);\n\t}\n\n\tparseDocument(): AstNode {\n\t\tthis._itemsConstructed = 0;\n\t\tthis._itemsFromCache = 0;\n\n\t\tlet result = this.parseList(SmallImmutableSet.getEmpty(), 0);\n\t\tif (!result) {\n\t\t\tresult = ListAstNode.getEmpty();\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tprivate parseList(\n\t\topenedBracketIds: SmallImmutableSet,\n\t\tlevel: number,\n\t): AstNode | null {\n\t\tconst items: AstNode[] = [];\n\n\t\twhile (true) {\n\t\t\tlet child = this.tryReadChildFromCache(openedBracketIds);\n\n\t\t\tif (!child) {\n\t\t\t\tconst token = this.tokenizer.peek();\n\t\t\t\tif (\n\t\t\t\t\t!token ||\n\t\t\t\t\t(token.kind === TokenKind.ClosingBracket &&\n\t\t\t\t\t\ttoken.bracketIds.intersects(openedBracketIds))\n\t\t\t\t) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tchild = this.parseChild(openedBracketIds, level + 1);\n\t\t\t}\n\n\t\t\tif (child.kind === AstNodeKind.List && child.childrenLength === 0) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\titems.push(child);\n\t\t}\n\n\t\t// When there is no oldNodeReader, all items are created from scratch and must have the same height.\n\t\tconst result = this.oldNodeReader ? concat23Trees(items) : concat23TreesOfSameHeight(items, this.createImmutableLists);\n\t\treturn result;\n\t}\n\n\tprivate tryReadChildFromCache(openedBracketIds: SmallImmutableSet): AstNode | undefined {\n\t\tif (this.oldNodeReader) {\n\t\t\tconst maxCacheableLength = this.positionMapper.getDistanceToNextChange(this.tokenizer.offset);\n\t\t\tif (maxCacheableLength === null || !lengthIsZero(maxCacheableLength)) {\n\t\t\t\tconst cachedNode = this.oldNodeReader.readLongestNodeAt(this.positionMapper.getOffsetBeforeChange(this.tokenizer.offset), curNode => {\n\t\t\t\t\t// The edit could extend the ending token, thus we cannot re-use nodes that touch the edit.\n\t\t\t\t\t// If there is no edit anymore, we can re-use the node in any case.\n\t\t\t\t\tif (maxCacheableLength !== null && !lengthLessThan(curNode.length, maxCacheableLength)) {\n\t\t\t\t\t\t// Either the node contains edited text or touches edited text.\n\t\t\t\t\t\t// In the latter case, brackets might have been extended (`end` -> `ending`), so even touching nodes cannot be reused.\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tconst canBeReused = curNode.canBeReused(openedBracketIds);\n\t\t\t\t\treturn canBeReused;\n\t\t\t\t});\n\n\t\t\t\tif (cachedNode) {\n\t\t\t\t\tthis._itemsFromCache++;\n\t\t\t\t\tthis.tokenizer.skip(cachedNode.length);\n\t\t\t\t\treturn cachedNode;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tprivate parseChild(\n\t\topenedBracketIds: SmallImmutableSet,\n\t\tlevel: number,\n\t): AstNode {\n\t\tthis._itemsConstructed++;\n\n\t\tconst token = this.tokenizer.read()!;\n\n\t\tswitch (token.kind) {\n\t\t\tcase TokenKind.ClosingBracket:\n\t\t\t\treturn new InvalidBracketAstNode(token.bracketIds, token.length);\n\n\t\t\tcase TokenKind.Text:\n\t\t\t\treturn token.astNode as TextAstNode;\n\n\t\t\tcase TokenKind.OpeningBracket: {\n\t\t\t\tif (level > 300) {\n\t\t\t\t\t// To prevent stack overflows\n\t\t\t\t\treturn new TextAstNode(token.length);\n\t\t\t\t}\n\n\t\t\t\tconst set = openedBracketIds.merge(token.bracketIds);\n\t\t\t\tconst child = this.parseList(set, level + 1);\n\n\t\t\t\tconst nextToken = this.tokenizer.peek();\n\t\t\t\tif (\n\t\t\t\t\tnextToken &&\n\t\t\t\t\tnextToken.kind === TokenKind.ClosingBracket &&\n\t\t\t\t\t(nextToken.bracketId === token.bracketId || nextToken.bracketIds.intersects(token.bracketIds))\n\t\t\t\t) {\n\t\t\t\t\tthis.tokenizer.read();\n\t\t\t\t\treturn PairAstNode.create(\n\t\t\t\t\t\ttoken.astNode as BracketAstNode,\n\t\t\t\t\t\tchild,\n\t\t\t\t\t\tnextToken.astNode as BracketAstNode\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\treturn PairAstNode.create(\n\t\t\t\t\t\ttoken.astNode as BracketAstNode,\n\t\t\t\t\t\tchild,\n\t\t\t\t\t\tnull\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\tdefault:\n\t\t\t\tthrow new Error('unexpected');\n\t\t}\n\t}\n}\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\nimport { NotSupportedError } from 'vs/base/common/errors';\nimport { StandardTokenType, TokenMetadata } from 'vs/editor/common/encodedTokenAttributes';\nimport { IViewLineTokens } from 'vs/editor/common/tokens/lineTokens';\nimport { BracketAstNode, TextAstNode } from './ast';\nimport { BracketTokens, LanguageAgnosticBracketTokens } from './brackets';\nimport { Length, lengthAdd, lengthDiff, lengthGetColumnCountIfZeroLineCount, lengthToObj, lengthZero, toLength } from './length';\nimport { SmallImmutableSet } from './smallImmutableSet';\n\nexport interface Tokenizer {\n\treadonly offset: Length;\n\n\tread(): Token | null;\n\tpeek(): Token | null;\n\tskip(length: Length): void;\n}\n\nexport const enum TokenKind {\n\tText = 0,\n\tOpeningBracket = 1,\n\tClosingBracket = 2,\n}\n\nexport type OpeningBracketId = number;\n\nexport class Token {\n\tconstructor(\n\t\treadonly length: Length,\n\t\treadonly kind: TokenKind,\n\t\t/**\n\t\t * If this token is an opening bracket, this is the id of the opening bracket.\n\t\t * If this token is a closing bracket, this is the id of the first opening bracket that is closed by this bracket.\n\t\t * Otherwise, it is -1.\n\t\t */\n\t\treadonly bracketId: OpeningBracketId,\n\t\t/**\n\t\t * If this token is an opening bracket, this just contains `bracketId`.\n\t\t * If this token is a closing bracket, this lists all opening bracket ids, that it closes.\n\t\t * Otherwise, it is empty.\n\t\t */\n\t\treadonly bracketIds: SmallImmutableSet,\n\t\treadonly astNode: BracketAstNode | TextAstNode | undefined,\n\t) { }\n}\n\nexport interface ITokenizerSource {\n\tgetLineCount(): number;\n\tgetLineLength(lineNumber: number): number;\n\n\ttokenization: {\n\t\tgetLineTokens(lineNumber: number): IViewLineTokens;\n\t};\n}\n\nexport class TextBufferTokenizer implements Tokenizer {\n\tprivate readonly textBufferLineCount: number;\n\tprivate readonly textBufferLastLineLength: number;\n\n\tprivate readonly reader = new NonPeekableTextBufferTokenizer(this.textModel, this.bracketTokens);\n\n\tconstructor(\n\t\tprivate readonly textModel: ITokenizerSource,\n\t\tprivate readonly bracketTokens: LanguageAgnosticBracketTokens\n\t) {\n\t\tthis.textBufferLineCount = textModel.getLineCount();\n\t\tthis.textBufferLastLineLength = textModel.getLineLength(this.textBufferLineCount);\n\t}\n\n\tprivate _offset: Length = lengthZero;\n\n\tget offset() {\n\t\treturn this._offset;\n\t}\n\n\tget length() {\n\t\treturn toLength(this.textBufferLineCount - 1, this.textBufferLastLineLength);\n\t}\n\n\tskip(length: Length): void {\n\t\tthis.didPeek = false;\n\t\tthis._offset = lengthAdd(this._offset, length);\n\t\tconst obj = lengthToObj(this._offset);\n\t\tthis.reader.setPosition(obj.lineCount, obj.columnCount);\n\t}\n\n\tprivate didPeek = false;\n\tprivate peeked: Token | null = null;\n\n\tread(): Token | null {\n\t\tlet token: Token | null;\n\t\tif (this.peeked) {\n\t\t\tthis.didPeek = false;\n\t\t\ttoken = this.peeked;\n\t\t} else {\n\t\t\ttoken = this.reader.read();\n\t\t}\n\t\tif (token) {\n\t\t\tthis._offset = lengthAdd(this._offset, token.length);\n\t\t}\n\t\treturn token;\n\t}\n\n\tpeek(): Token | null {\n\t\tif (!this.didPeek) {\n\t\t\tthis.peeked = this.reader.read();\n\t\t\tthis.didPeek = true;\n\t\t}\n\t\treturn this.peeked;\n\t}\n}\n\n/**\n * Does not support peek.\n*/\nclass NonPeekableTextBufferTokenizer {\n\tprivate readonly textBufferLineCount: number;\n\tprivate readonly textBufferLastLineLength: number;\n\n\tconstructor(private readonly textModel: ITokenizerSource, private readonly bracketTokens: LanguageAgnosticBracketTokens) {\n\t\tthis.textBufferLineCount = textModel.getLineCount();\n\t\tthis.textBufferLastLineLength = textModel.getLineLength(this.textBufferLineCount);\n\t}\n\n\tprivate lineIdx = 0;\n\tprivate line: string | null = null;\n\tprivate lineCharOffset = 0;\n\tprivate lineTokens: IViewLineTokens | null = null;\n\tprivate lineTokenOffset = 0;\n\n\tpublic setPosition(lineIdx: number, column: number): void {\n\t\t// We must not jump into a token!\n\t\tif (lineIdx === this.lineIdx) {\n\t\t\tthis.lineCharOffset = column;\n\t\t\tif (this.line !== null) {\n\t\t\t\tthis.lineTokenOffset = this.lineCharOffset === 0 ? 0 : this.lineTokens!.findTokenIndexAtOffset(this.lineCharOffset);\n\t\t\t}\n\t\t} else {\n\t\t\tthis.lineIdx = lineIdx;\n\t\t\tthis.lineCharOffset = column;\n\t\t\tthis.line = null;\n\t\t}\n\t\tthis.peekedToken = null;\n\t}\n\n\t/** Must be a zero line token. The end of the document cannot be peeked. */\n\tprivate peekedToken: Token | null = null;\n\n\tpublic read(): Token | null {\n\t\tif (this.peekedToken) {\n\t\t\tconst token = this.peekedToken;\n\t\t\tthis.peekedToken = null;\n\t\t\tthis.lineCharOffset += lengthGetColumnCountIfZeroLineCount(token.length);\n\t\t\treturn token;\n\t\t}\n\n\t\tif (this.lineIdx > this.textBufferLineCount - 1 || (this.lineIdx === this.textBufferLineCount - 1 && this.lineCharOffset >= this.textBufferLastLineLength)) {\n\t\t\t// We are after the end\n\t\t\treturn null;\n\t\t}\n\n\t\tif (this.line === null) {\n\t\t\tthis.lineTokens = this.textModel.tokenization.getLineTokens(this.lineIdx + 1);\n\t\t\tthis.line = this.lineTokens.getLineContent();\n\t\t\tthis.lineTokenOffset = this.lineCharOffset === 0 ? 0 : this.lineTokens.findTokenIndexAtOffset(this.lineCharOffset);\n\t\t}\n\n\t\tconst startLineIdx = this.lineIdx;\n\t\tconst startLineCharOffset = this.lineCharOffset;\n\n\t\t// limits the length of text tokens.\n\t\t// If text tokens get too long, incremental updates will be slow\n\t\tlet lengthHeuristic = 0;\n\t\twhile (true) {\n\t\t\tconst lineTokens = this.lineTokens!;\n\t\t\tconst tokenCount = lineTokens.getCount();\n\n\t\t\tlet peekedBracketToken: Token | null = null;\n\n\t\t\tif (this.lineTokenOffset < tokenCount) {\n\t\t\t\tconst tokenMetadata = lineTokens.getMetadata(this.lineTokenOffset);\n\t\t\t\twhile (this.lineTokenOffset + 1 < tokenCount && tokenMetadata === lineTokens.getMetadata(this.lineTokenOffset + 1)) {\n\t\t\t\t\t// Skip tokens that are identical.\n\t\t\t\t\t// Sometimes, (bracket) identifiers are split up into multiple tokens.\n\t\t\t\t\tthis.lineTokenOffset++;\n\t\t\t\t}\n\n\t\t\t\tconst isOther = TokenMetadata.getTokenType(tokenMetadata) === StandardTokenType.Other;\n\t\t\t\tconst containsBracketType = TokenMetadata.containsBalancedBrackets(tokenMetadata);\n\n\t\t\t\tconst endOffset = lineTokens.getEndOffset(this.lineTokenOffset);\n\t\t\t\t// Is there a bracket token next? Only consume text.\n\t\t\t\tif (containsBracketType && isOther && this.lineCharOffset < endOffset) {\n\t\t\t\t\tconst languageId = lineTokens.getLanguageId(this.lineTokenOffset);\n\t\t\t\t\tconst text = this.line.substring(this.lineCharOffset, endOffset);\n\n\t\t\t\t\tconst brackets = this.bracketTokens.getSingleLanguageBracketTokens(languageId);\n\t\t\t\t\tconst regexp = brackets.regExpGlobal;\n\t\t\t\t\tif (regexp) {\n\t\t\t\t\t\tregexp.lastIndex = 0;\n\t\t\t\t\t\tconst match = regexp.exec(text);\n\t\t\t\t\t\tif (match) {\n\t\t\t\t\t\t\tpeekedBracketToken = brackets.getToken(match[0])!;\n\t\t\t\t\t\t\tif (peekedBracketToken) {\n\t\t\t\t\t\t\t\t// Consume leading text of the token\n\t\t\t\t\t\t\t\tthis.lineCharOffset += match.index;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tlengthHeuristic += endOffset - this.lineCharOffset;\n\n\t\t\t\tif (peekedBracketToken) {\n\t\t\t\t\t// Don't skip the entire token, as a single token could contain multiple brackets.\n\n\t\t\t\t\tif (startLineIdx !== this.lineIdx || startLineCharOffset !== this.lineCharOffset) {\n\t\t\t\t\t\t// There is text before the bracket\n\t\t\t\t\t\tthis.peekedToken = peekedBracketToken;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Consume the peeked token\n\t\t\t\t\t\tthis.lineCharOffset += lengthGetColumnCountIfZeroLineCount(peekedBracketToken.length);\n\t\t\t\t\t\treturn peekedBracketToken;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Skip the entire token, as the token contains no brackets at all.\n\t\t\t\t\tthis.lineTokenOffset++;\n\t\t\t\t\tthis.lineCharOffset = endOffset;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (this.lineIdx === this.textBufferLineCount - 1) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tthis.lineIdx++;\n\t\t\t\tthis.lineTokens = this.textModel.tokenization.getLineTokens(this.lineIdx + 1);\n\t\t\t\tthis.lineTokenOffset = 0;\n\t\t\t\tthis.line = this.lineTokens.getLineContent();\n\t\t\t\tthis.lineCharOffset = 0;\n\n\t\t\t\tlengthHeuristic += 33; // max 1000/33 = 30 lines\n\t\t\t\t// This limits the amount of work to recompute min-indentation\n\n\t\t\t\tif (lengthHeuristic > 1000) {\n\t\t\t\t\t// only break (automatically) at the end of line.\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (lengthHeuristic > 1500) {\n\t\t\t\t// Eventually break regardless of the line length so that\n\t\t\t\t// very long lines do not cause bad performance.\n\t\t\t\t// This effective limits max indentation to 500, as\n\t\t\t\t// indentation is not computed across multiple text nodes.\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// If a token contains some proper indentation, it also contains \\n{INDENTATION+}(?!{INDENTATION}),\n\t\t// unless the line is too long.\n\t\t// Thus, the min indentation of the document is the minimum min indentation of every text node.\n\t\tconst length = lengthDiff(startLineIdx, startLineCharOffset, this.lineIdx, this.lineCharOffset);\n\t\treturn new Token(length, TokenKind.Text, -1, SmallImmutableSet.getEmpty(), new TextAstNode(length));\n\t}\n}\n\nexport class FastTokenizer implements Tokenizer {\n\tprivate _offset: Length = lengthZero;\n\tprivate readonly tokens: readonly Token[];\n\tprivate idx = 0;\n\n\tconstructor(private readonly text: string, brackets: BracketTokens) {\n\t\tconst regExpStr = brackets.getRegExpStr();\n\t\tconst regexp = regExpStr ? new RegExp(regExpStr + '|\\n', 'gi') : null;\n\n\t\tconst tokens: Token[] = [];\n\n\t\tlet match: RegExpExecArray | null;\n\t\tlet curLineCount = 0;\n\t\tlet lastLineBreakOffset = 0;\n\n\t\tlet lastTokenEndOffset = 0;\n\t\tlet lastTokenEndLine = 0;\n\n\t\tconst smallTextTokens0Line: Token[] = [];\n\t\tfor (let i = 0; i < 60; i++) {\n\t\t\tsmallTextTokens0Line.push(\n\t\t\t\tnew Token(\n\t\t\t\t\ttoLength(0, i), TokenKind.Text, -1, SmallImmutableSet.getEmpty(),\n\t\t\t\t\tnew TextAstNode(toLength(0, i))\n\t\t\t\t)\n\t\t\t);\n\t\t}\n\n\t\tconst smallTextTokens1Line: Token[] = [];\n\t\tfor (let i = 0; i < 60; i++) {\n\t\t\tsmallTextTokens1Line.push(\n\t\t\t\tnew Token(\n\t\t\t\t\ttoLength(1, i), TokenKind.Text, -1, SmallImmutableSet.getEmpty(),\n\t\t\t\t\tnew TextAstNode(toLength(1, i))\n\t\t\t\t)\n\t\t\t);\n\t\t}\n\n\t\tif (regexp) {\n\t\t\tregexp.lastIndex = 0;\n\t\t\t// If a token contains indentation, it also contains \\n{INDENTATION+}(?!{INDENTATION})\n\t\t\twhile ((match = regexp.exec(text)) !== null) {\n\t\t\t\tconst curOffset = match.index;\n\t\t\t\tconst value = match[0];\n\t\t\t\tif (value === '\\n') {\n\t\t\t\t\tcurLineCount++;\n\t\t\t\t\tlastLineBreakOffset = curOffset + 1;\n\t\t\t\t} else {\n\t\t\t\t\tif (lastTokenEndOffset !== curOffset) {\n\t\t\t\t\t\tlet token: Token;\n\t\t\t\t\t\tif (lastTokenEndLine === curLineCount) {\n\t\t\t\t\t\t\tconst colCount = curOffset - lastTokenEndOffset;\n\t\t\t\t\t\t\tif (colCount < smallTextTokens0Line.length) {\n\t\t\t\t\t\t\t\ttoken = smallTextTokens0Line[colCount];\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tconst length = toLength(0, colCount);\n\t\t\t\t\t\t\t\ttoken = new Token(length, TokenKind.Text, -1, SmallImmutableSet.getEmpty(), new TextAstNode(length));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tconst lineCount = curLineCount - lastTokenEndLine;\n\t\t\t\t\t\t\tconst colCount = curOffset - lastLineBreakOffset;\n\t\t\t\t\t\t\tif (lineCount === 1 && colCount < smallTextTokens1Line.length) {\n\t\t\t\t\t\t\t\ttoken = smallTextTokens1Line[colCount];\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tconst length = toLength(lineCount, colCount);\n\t\t\t\t\t\t\t\ttoken = new Token(length, TokenKind.Text, -1, SmallImmutableSet.getEmpty(), new TextAstNode(length));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\ttokens.push(token);\n\t\t\t\t\t}\n\n\t\t\t\t\t// value is matched by regexp, so the token must exist\n\t\t\t\t\ttokens.push(brackets.getToken(value)!);\n\n\t\t\t\t\tlastTokenEndOffset = curOffset + value.length;\n\t\t\t\t\tlastTokenEndLine = curLineCount;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst offset = text.length;\n\n\t\tif (lastTokenEndOffset !== offset) {\n\t\t\tconst length = (lastTokenEndLine === curLineCount)\n\t\t\t\t? toLength(0, offset - lastTokenEndOffset)\n\t\t\t\t: toLength(curLineCount - lastTokenEndLine, offset - lastLineBreakOffset);\n\t\t\ttokens.push(new Token(length, TokenKind.Text, -1, SmallImmutableSet.getEmpty(), new TextAstNode(length)));\n\t\t}\n\n\t\tthis.length = toLength(curLineCount, offset - lastLineBreakOffset);\n\t\tthis.tokens = tokens;\n\t}\n\n\tget offset(): Length {\n\t\treturn this._offset;\n\t}\n\n\treadonly length: Length;\n\n\tread(): Token | null {\n\t\treturn this.tokens[this.idx++] || null;\n\t}\n\n\tpeek(): Token | null {\n\t\treturn this.tokens[this.idx] || null;\n\t}\n\n\tskip(length: Length): void {\n\t\tthrow new NotSupportedError();\n\t}\n}\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 *--------------------------------------------------------------------------------------------*/\nimport { escapeRegExpCharacters } from 'vs/base/common/strings';\nimport { ResolvedLanguageConfiguration } from 'vs/editor/common/languages/languageConfigurationRegistry';\nimport { BracketKind } from 'vs/editor/common/languages/supports/languageBracketsConfiguration';\nimport { BracketAstNode } from './ast';\nimport { toLength } from './length';\nimport { DenseKeyProvider, identityKeyProvider, SmallImmutableSet } from './smallImmutableSet';\nimport { OpeningBracketId, Token, TokenKind } from './tokenizer';\n\nexport class BracketTokens {\n\tstatic createFromLanguage(configuration: ResolvedLanguageConfiguration, denseKeyProvider: DenseKeyProvider): BracketTokens {\n\t\tfunction getId(bracketInfo: BracketKind): OpeningBracketId {\n\t\t\treturn denseKeyProvider.getKey(`${bracketInfo.languageId}:::${bracketInfo.bracketText}`);\n\t\t}\n\n\t\tconst map = new Map();\n\t\tfor (const openingBracket of configuration.bracketsNew.openingBrackets) {\n\t\t\tconst length = toLength(0, openingBracket.bracketText.length);\n\t\t\tconst openingTextId = getId(openingBracket);\n\t\t\tconst bracketIds = SmallImmutableSet.getEmpty().add(openingTextId, identityKeyProvider);\n\t\t\tmap.set(openingBracket.bracketText, new Token(\n\t\t\t\tlength,\n\t\t\t\tTokenKind.OpeningBracket,\n\t\t\t\topeningTextId,\n\t\t\t\tbracketIds,\n\t\t\t\tBracketAstNode.create(length, openingBracket, bracketIds)\n\t\t\t));\n\t\t}\n\n\t\tfor (const closingBracket of configuration.bracketsNew.closingBrackets) {\n\t\t\tconst length = toLength(0, closingBracket.bracketText.length);\n\t\t\tlet bracketIds = SmallImmutableSet.getEmpty();\n\t\t\tconst closingBrackets = closingBracket.getOpeningBrackets();\n\t\t\tfor (const bracket of closingBrackets) {\n\t\t\t\tbracketIds = bracketIds.add(getId(bracket), identityKeyProvider);\n\t\t\t}\n\t\t\tmap.set(closingBracket.bracketText, new Token(\n\t\t\t\tlength,\n\t\t\t\tTokenKind.ClosingBracket,\n\t\t\t\tgetId(closingBrackets[0]),\n\t\t\t\tbracketIds,\n\t\t\t\tBracketAstNode.create(length, closingBracket, bracketIds)\n\t\t\t));\n\t\t}\n\n\t\treturn new BracketTokens(map);\n\t}\n\n\tprivate hasRegExp = false;\n\tprivate _regExpGlobal: RegExp | null = null;\n\n\tconstructor(\n\t\tprivate readonly map: Map\n\t) { }\n\n\tgetRegExpStr(): string | null {\n\t\tif (this.isEmpty) {\n\t\t\treturn null;\n\t\t} else {\n\t\t\tconst keys = [...this.map.keys()];\n\t\t\tkeys.sort();\n\t\t\tkeys.reverse();\n\t\t\treturn keys.map(k => prepareBracketForRegExp(k)).join('|');\n\t\t}\n\t}\n\n\t/**\n\t * Returns null if there is no such regexp (because there are no brackets).\n\t*/\n\tget regExpGlobal(): RegExp | null {\n\t\tif (!this.hasRegExp) {\n\t\t\tconst regExpStr = this.getRegExpStr();\n\t\t\tthis._regExpGlobal = regExpStr ? new RegExp(regExpStr, 'gi') : null;\n\t\t\tthis.hasRegExp = true;\n\t\t}\n\t\treturn this._regExpGlobal;\n\t}\n\n\tgetToken(value: string): Token | undefined {\n\t\treturn this.map.get(value.toLowerCase());\n\t}\n\n\tfindClosingTokenText(openingBracketIds: SmallImmutableSet): string | undefined {\n\t\tfor (const [closingText, info] of this.map) {\n\t\t\tif (info.kind === TokenKind.ClosingBracket && info.bracketIds.intersects(openingBracketIds)) {\n\t\t\t\treturn closingText;\n\t\t\t}\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tget isEmpty(): boolean {\n\t\treturn this.map.size === 0;\n\t}\n}\n\nfunction prepareBracketForRegExp(str: string): string {\n\tlet escaped = escapeRegExpCharacters(str);\n\t// These bracket pair delimiters start or end with letters\n\t// see https://github.com/microsoft/vscode/issues/132162 https://github.com/microsoft/vscode/issues/150440\n\tif (/^[\\w ]+/.test(str)) {\n\t\tescaped = `\\\\b${escaped}`;\n\t}\n\tif (/[\\w ]+$/.test(str)) {\n\t\tescaped = `${escaped}\\\\b`;\n\t}\n\treturn escaped;\n}\n\nexport class LanguageAgnosticBracketTokens {\n\tprivate readonly languageIdToBracketTokens = new Map();\n\n\tconstructor(\n\t\tprivate readonly denseKeyProvider: DenseKeyProvider,\n\t\tprivate readonly getLanguageConfiguration: (languageId: string) => ResolvedLanguageConfiguration,\n\t) {\n\t}\n\n\tpublic didLanguageChange(languageId: string): boolean {\n\t\t// Report a change whenever the language configuration updates.\n\t\treturn this.languageIdToBracketTokens.has(languageId);\n\t}\n\n\tgetSingleLanguageBracketTokens(languageId: string): BracketTokens {\n\t\tlet singleLanguageBracketTokens = this.languageIdToBracketTokens.get(languageId);\n\t\tif (!singleLanguageBracketTokens) {\n\t\t\tsingleLanguageBracketTokens = BracketTokens.createFromLanguage(this.getLanguageConfiguration(languageId), this.denseKeyProvider);\n\t\t\tthis.languageIdToBracketTokens.set(languageId, singleLanguageBracketTokens);\n\t\t}\n\t\treturn singleLanguageBracketTokens;\n\t}\n}\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\nimport { ILanguageConfigurationService } from 'vs/editor/common/languages/languageConfigurationRegistry';\nimport { AstNode, AstNodeKind } from 'vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/ast';\nimport { LanguageAgnosticBracketTokens } from 'vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/brackets';\nimport { Length, lengthAdd, lengthGetColumnCountIfZeroLineCount, lengthZero } from 'vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/length';\nimport { parseDocument } from 'vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/parser';\nimport { DenseKeyProvider } from 'vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/smallImmutableSet';\nimport { ITokenizerSource, TextBufferTokenizer } from 'vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/tokenizer';\nimport { IViewLineTokens } from 'vs/editor/common/tokens/lineTokens';\n\nexport function fixBracketsInLine(tokens: IViewLineTokens, languageConfigurationService: ILanguageConfigurationService): string {\n\tconst denseKeyProvider = new DenseKeyProvider();\n\tconst bracketTokens = new LanguageAgnosticBracketTokens(denseKeyProvider, (languageId) =>\n\t\tlanguageConfigurationService.getLanguageConfiguration(languageId)\n\t);\n\tconst tokenizer = new TextBufferTokenizer(\n\t\tnew StaticTokenizerSource([tokens]),\n\t\tbracketTokens\n\t);\n\tconst node = parseDocument(tokenizer, [], undefined, true);\n\n\tlet str = '';\n\tconst line = tokens.getLineContent();\n\n\tfunction processNode(node: AstNode, offset: Length) {\n\t\tif (node.kind === AstNodeKind.Pair) {\n\t\t\tprocessNode(node.openingBracket, offset);\n\t\t\toffset = lengthAdd(offset, node.openingBracket.length);\n\n\t\t\tif (node.child) {\n\t\t\t\tprocessNode(node.child, offset);\n\t\t\t\toffset = lengthAdd(offset, node.child.length);\n\t\t\t}\n\t\t\tif (node.closingBracket) {\n\t\t\t\tprocessNode(node.closingBracket, offset);\n\t\t\t\toffset = lengthAdd(offset, node.closingBracket.length);\n\t\t\t} else {\n\t\t\t\tconst singleLangBracketTokens = bracketTokens.getSingleLanguageBracketTokens(node.openingBracket.languageId);\n\n\t\t\t\tconst closingTokenText = singleLangBracketTokens.findClosingTokenText(node.openingBracket.bracketIds);\n\t\t\t\tstr += closingTokenText;\n\t\t\t}\n\t\t} else if (node.kind === AstNodeKind.UnexpectedClosingBracket) {\n\t\t\t// remove the bracket\n\t\t} else if (node.kind === AstNodeKind.Text || node.kind === AstNodeKind.Bracket) {\n\t\t\tstr += line.substring(\n\t\t\t\tlengthGetColumnCountIfZeroLineCount(offset),\n\t\t\t\tlengthGetColumnCountIfZeroLineCount(lengthAdd(offset, node.length))\n\t\t\t);\n\t\t} else if (node.kind === AstNodeKind.List) {\n\t\t\tfor (const child of node.children) {\n\t\t\t\tprocessNode(child, offset);\n\t\t\t\toffset = lengthAdd(offset, child.length);\n\t\t\t}\n\t\t}\n\t}\n\n\tprocessNode(node, lengthZero);\n\n\treturn str;\n}\n\nclass StaticTokenizerSource implements ITokenizerSource {\n\tconstructor(private readonly lines: IViewLineTokens[]) { }\n\tgetLineCount(): number {\n\t\treturn this.lines.length;\n\t}\n\tgetLineLength(lineNumber: number): number {\n\t\treturn this.lines[lineNumber - 1].getLineContent().length;\n\t}\n\n\ttokenization = {\n\t\tgetLineTokens: (lineNumber: number): IViewLineTokens => {\n\t\t\treturn this.lines[lineNumber - 1];\n\t\t}\n\t};\n}\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\nimport { arrayInsert } from 'vs/base/common/arrays';\n\n/**\n * An array that avoids being sparse by always\n * filling up unused indices with a default value.\n */\nexport class FixedArray {\n\tprivate _store: T[] = [];\n\n\tconstructor(\n\t\tprivate readonly _default: T\n\t) { }\n\n\tpublic get(index: number): T {\n\t\tif (index < this._store.length) {\n\t\t\treturn this._store[index];\n\t\t}\n\t\treturn this._default;\n\t}\n\n\tpublic set(index: number, value: T): void {\n\t\twhile (index >= this._store.length) {\n\t\t\tthis._store[this._store.length] = this._default;\n\t\t}\n\t\tthis._store[index] = value;\n\t}\n\n\tpublic replace(index: number, oldLength: number, newLength: number): void {\n\t\tif (index >= this._store.length) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (oldLength === 0) {\n\t\t\tthis.insert(index, newLength);\n\t\t\treturn;\n\t\t} else if (newLength === 0) {\n\t\t\tthis.delete(index, oldLength);\n\t\t\treturn;\n\t\t}\n\n\t\tconst before = this._store.slice(0, index);\n\t\tconst after = this._store.slice(index + oldLength);\n\t\tconst insertArr = arrayFill(newLength, this._default);\n\t\tthis._store = before.concat(insertArr, after);\n\t}\n\n\tpublic delete(deleteIndex: number, deleteCount: number): void {\n\t\tif (deleteCount === 0 || deleteIndex >= this._store.length) {\n\t\t\treturn;\n\t\t}\n\t\tthis._store.splice(deleteIndex, deleteCount);\n\t}\n\n\tpublic insert(insertIndex: number, insertCount: number): void {\n\t\tif (insertCount === 0 || insertIndex >= this._store.length) {\n\t\t\treturn;\n\t\t}\n\t\tconst arr: T[] = [];\n\t\tfor (let i = 0; i < insertCount; i++) {\n\t\t\tarr[i] = this._default;\n\t\t}\n\t\tthis._store = arrayInsert(this._store, insertIndex, arr);\n\t}\n}\n\nfunction arrayFill(length: number, value: T): T[] {\n\tconst arr: T[] = [];\n\tfor (let i = 0; i < length; i++) {\n\t\tarr[i] = value;\n\t}\n\treturn arr;\n}\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\nimport { CharCode } from 'vs/base/common/charCode';\nimport { ITextBuffer } from 'vs/editor/common/model';\n\nclass SpacesDiffResult {\n\tpublic spacesDiff: number = 0;\n\tpublic looksLikeAlignment: boolean = false;\n}\n\n/**\n * Compute the diff in spaces between two line's indentation.\n */\nfunction spacesDiff(a: string, aLength: number, b: string, bLength: number, result: SpacesDiffResult): void {\n\n\tresult.spacesDiff = 0;\n\tresult.looksLikeAlignment = false;\n\n\t// This can go both ways (e.g.):\n\t// - a: \"\\t\"\n\t// - b: \"\\t \"\n\t// => This should count 1 tab and 4 spaces\n\n\tlet i: number;\n\n\tfor (i = 0; i < aLength && i < bLength; i++) {\n\t\tconst aCharCode = a.charCodeAt(i);\n\t\tconst bCharCode = b.charCodeAt(i);\n\n\t\tif (aCharCode !== bCharCode) {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tlet aSpacesCnt = 0, aTabsCount = 0;\n\tfor (let j = i; j < aLength; j++) {\n\t\tconst aCharCode = a.charCodeAt(j);\n\t\tif (aCharCode === CharCode.Space) {\n\t\t\taSpacesCnt++;\n\t\t} else {\n\t\t\taTabsCount++;\n\t\t}\n\t}\n\n\tlet bSpacesCnt = 0, bTabsCount = 0;\n\tfor (let j = i; j < bLength; j++) {\n\t\tconst bCharCode = b.charCodeAt(j);\n\t\tif (bCharCode === CharCode.Space) {\n\t\t\tbSpacesCnt++;\n\t\t} else {\n\t\t\tbTabsCount++;\n\t\t}\n\t}\n\n\tif (aSpacesCnt > 0 && aTabsCount > 0) {\n\t\treturn;\n\t}\n\tif (bSpacesCnt > 0 && bTabsCount > 0) {\n\t\treturn;\n\t}\n\n\tconst tabsDiff = Math.abs(aTabsCount - bTabsCount);\n\tconst spacesDiff = Math.abs(aSpacesCnt - bSpacesCnt);\n\n\tif (tabsDiff === 0) {\n\t\t// check if the indentation difference might be caused by alignment reasons\n\t\t// sometime folks like to align their code, but this should not be used as a hint\n\t\tresult.spacesDiff = spacesDiff;\n\n\t\tif (spacesDiff > 0 && 0 <= bSpacesCnt - 1 && bSpacesCnt - 1 < a.length && bSpacesCnt < b.length) {\n\t\t\tif (b.charCodeAt(bSpacesCnt) !== CharCode.Space && a.charCodeAt(bSpacesCnt - 1) === CharCode.Space) {\n\t\t\t\tif (a.charCodeAt(a.length - 1) === CharCode.Comma) {\n\t\t\t\t\t// This looks like an alignment desire: e.g.\n\t\t\t\t\t// const a = b + c,\n\t\t\t\t\t// d = b - c;\n\t\t\t\t\tresult.looksLikeAlignment = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn;\n\t}\n\tif (spacesDiff % tabsDiff === 0) {\n\t\tresult.spacesDiff = spacesDiff / tabsDiff;\n\t\treturn;\n\t}\n}\n\n/**\n * Result for a guessIndentation\n */\nexport interface IGuessedIndentation {\n\t/**\n\t * If indentation is based on spaces (`insertSpaces` = true), then what is the number of spaces that make an indent?\n\t */\n\ttabSize: number;\n\t/**\n\t * Is indentation based on spaces?\n\t */\n\tinsertSpaces: boolean;\n}\n\nexport function guessIndentation(source: ITextBuffer, defaultTabSize: number, defaultInsertSpaces: boolean): IGuessedIndentation {\n\t// Look at most at the first 10k lines\n\tconst linesCount = Math.min(source.getLineCount(), 10000);\n\n\tlet linesIndentedWithTabsCount = 0;\t\t\t\t// number of lines that contain at least one tab in indentation\n\tlet linesIndentedWithSpacesCount = 0;\t\t\t// number of lines that contain only spaces in indentation\n\n\tlet previousLineText = '';\t\t\t\t\t\t// content of latest line that contained non-whitespace chars\n\tlet previousLineIndentation = 0;\t\t\t\t// index at which latest line contained the first non-whitespace char\n\n\tconst ALLOWED_TAB_SIZE_GUESSES = [2, 4, 6, 8, 3, 5, 7];\t// prefer even guesses for `tabSize`, limit to [2, 8].\n\tconst MAX_ALLOWED_TAB_SIZE_GUESS = 8;\t\t\t// max(ALLOWED_TAB_SIZE_GUESSES) = 8\n\n\tconst spacesDiffCount = [0, 0, 0, 0, 0, 0, 0, 0, 0];\t\t// `tabSize` scores\n\tconst tmp = new SpacesDiffResult();\n\n\tfor (let lineNumber = 1; lineNumber <= linesCount; lineNumber++) {\n\t\tconst currentLineLength = source.getLineLength(lineNumber);\n\t\tconst currentLineText = source.getLineContent(lineNumber);\n\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.\n\t\t// checking charCode on chunks directly is cheaper.\n\t\tconst useCurrentLineText = (currentLineLength <= 65536);\n\n\t\tlet currentLineHasContent = false;\t\t\t// does `currentLineText` contain non-whitespace chars\n\t\tlet currentLineIndentation = 0;\t\t\t\t// index at which `currentLineText` contains the first non-whitespace char\n\t\tlet currentLineSpacesCount = 0;\t\t\t\t// count of spaces found in `currentLineText` indentation\n\t\tlet currentLineTabsCount = 0;\t\t\t\t// count of tabs found in `currentLineText` indentation\n\t\tfor (let j = 0, lenJ = currentLineLength; j < lenJ; j++) {\n\t\t\tconst charCode = (useCurrentLineText ? currentLineText.charCodeAt(j) : source.getLineCharCode(lineNumber, j));\n\n\t\t\tif (charCode === CharCode.Tab) {\n\t\t\t\tcurrentLineTabsCount++;\n\t\t\t} else if (charCode === CharCode.Space) {\n\t\t\t\tcurrentLineSpacesCount++;\n\t\t\t} else {\n\t\t\t\t// Hit non whitespace character on this line\n\t\t\t\tcurrentLineHasContent = true;\n\t\t\t\tcurrentLineIndentation = j;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// Ignore empty or only whitespace lines\n\t\tif (!currentLineHasContent) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (currentLineTabsCount > 0) {\n\t\t\tlinesIndentedWithTabsCount++;\n\t\t} else if (currentLineSpacesCount > 1) {\n\t\t\tlinesIndentedWithSpacesCount++;\n\t\t}\n\n\t\tspacesDiff(previousLineText, previousLineIndentation, currentLineText, currentLineIndentation, tmp);\n\n\t\tif (tmp.looksLikeAlignment) {\n\t\t\t// if defaultInsertSpaces === true && the spaces count == tabSize, we may want to count it as valid indentation\n\t\t\t//\n\t\t\t// - item1\n\t\t\t// - item2\n\t\t\t//\n\t\t\t// otherwise skip this line entirely\n\t\t\t//\n\t\t\t// const a = 1,\n\t\t\t// b = 2;\n\n\t\t\tif (!(defaultInsertSpaces && defaultTabSize === tmp.spacesDiff)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\tconst currentSpacesDiff = tmp.spacesDiff;\n\t\tif (currentSpacesDiff <= MAX_ALLOWED_TAB_SIZE_GUESS) {\n\t\t\tspacesDiffCount[currentSpacesDiff]++;\n\t\t}\n\n\t\tpreviousLineText = currentLineText;\n\t\tpreviousLineIndentation = currentLineIndentation;\n\t}\n\n\tlet insertSpaces = defaultInsertSpaces;\n\tif (linesIndentedWithTabsCount !== linesIndentedWithSpacesCount) {\n\t\tinsertSpaces = (linesIndentedWithTabsCount < linesIndentedWithSpacesCount);\n\t}\n\n\tlet tabSize = defaultTabSize;\n\n\t// Guess tabSize only if inserting spaces...\n\tif (insertSpaces) {\n\t\tlet tabSizeScore = (insertSpaces ? 0 : 0.1 * linesCount);\n\n\t\t// console.log(\"score threshold: \" + tabSizeScore);\n\n\t\tALLOWED_TAB_SIZE_GUESSES.forEach((possibleTabSize) => {\n\t\t\tconst possibleTabSizeScore = spacesDiffCount[possibleTabSize];\n\t\t\tif (possibleTabSizeScore > tabSizeScore) {\n\t\t\t\ttabSizeScore = possibleTabSizeScore;\n\t\t\t\ttabSize = possibleTabSize;\n\t\t\t}\n\t\t});\n\n\t\t// Let a tabSize of 2 win even if it is not the maximum\n\t\t// (only in case 4 was guessed)\n\t\tif (tabSize === 4 && spacesDiffCount[4] > 0 && spacesDiffCount[2] > 0 && spacesDiffCount[2] >= spacesDiffCount[4] / 2) {\n\t\t\ttabSize = 2;\n\t\t}\n\t}\n\n\n\t// console.log('--------------------------');\n\t// console.log('linesIndentedWithTabsCount: ' + linesIndentedWithTabsCount + ', linesIndentedWithSpacesCount: ' + linesIndentedWithSpacesCount);\n\t// console.log('spacesDiffCount: ' + spacesDiffCount);\n\t// console.log('tabSize: ' + tabSize + ', tabSizeScore: ' + tabSizeScore);\n\n\treturn {\n\t\tinsertSpaces: insertSpaces,\n\t\ttabSize: tabSize\n\t};\n}\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\nimport { Range } from 'vs/editor/common/core/range';\nimport { TrackedRangeStickiness } from 'vs/editor/common/model';\nimport { ModelDecorationOptions } from 'vs/editor/common/model/textModel';\n\n//\n// The red-black tree is based on the \"Introduction to Algorithms\" by Cormen, Leiserson and Rivest.\n//\n\nexport const enum ClassName {\n\tEditorHintDecoration = 'squiggly-hint',\n\tEditorInfoDecoration = 'squiggly-info',\n\tEditorWarningDecoration = 'squiggly-warning',\n\tEditorErrorDecoration = 'squiggly-error',\n\tEditorUnnecessaryDecoration = 'squiggly-unnecessary',\n\tEditorUnnecessaryInlineDecoration = 'squiggly-inline-unnecessary',\n\tEditorDeprecatedInlineDecoration = 'squiggly-inline-deprecated'\n}\n\nexport const enum NodeColor {\n\tBlack = 0,\n\tRed = 1,\n}\n\nconst enum Constants {\n\tColorMask = 0b00000001,\n\tColorMaskInverse = 0b11111110,\n\tColorOffset = 0,\n\n\tIsVisitedMask = 0b00000010,\n\tIsVisitedMaskInverse = 0b11111101,\n\tIsVisitedOffset = 1,\n\n\tIsForValidationMask = 0b00000100,\n\tIsForValidationMaskInverse = 0b11111011,\n\tIsForValidationOffset = 2,\n\n\tStickinessMask = 0b00011000,\n\tStickinessMaskInverse = 0b11100111,\n\tStickinessOffset = 3,\n\n\tCollapseOnReplaceEditMask = 0b00100000,\n\tCollapseOnReplaceEditMaskInverse = 0b11011111,\n\tCollapseOnReplaceEditOffset = 5,\n\n\tIsMarginMask = 0b01000000,\n\tIsMarginMaskInverse = 0b10111111,\n\tIsMarginOffset = 6,\n\n\t/**\n\t * Due to how deletion works (in order to avoid always walking the right subtree of the deleted node),\n\t * the deltas for nodes can grow and shrink dramatically. It has been observed, in practice, that unless\n\t * the deltas are corrected, integer overflow will occur.\n\t *\n\t * The integer overflow occurs when 53 bits are used in the numbers, but we will try to avoid it as\n\t * a node's delta gets below a negative 30 bits number.\n\t *\n\t * MIN SMI (SMall Integer) as defined in v8.\n\t * one bit is lost for boxing/unboxing flag.\n\t * one bit is lost for sign flag.\n\t * See https://thibaultlaurens.github.io/javascript/2013/04/29/how-the-v8-engine-works/#tagged-values\n\t */\n\tMIN_SAFE_DELTA = -(1 << 30),\n\t/**\n\t * MAX SMI (SMall Integer) as defined in v8.\n\t * one bit is lost for boxing/unboxing flag.\n\t * one bit is lost for sign flag.\n\t * See https://thibaultlaurens.github.io/javascript/2013/04/29/how-the-v8-engine-works/#tagged-values\n\t */\n\tMAX_SAFE_DELTA = 1 << 30,\n}\n\nexport function getNodeColor(node: IntervalNode): NodeColor {\n\treturn ((node.metadata & Constants.ColorMask) >>> Constants.ColorOffset);\n}\nfunction setNodeColor(node: IntervalNode, color: NodeColor): void {\n\tnode.metadata = (\n\t\t(node.metadata & Constants.ColorMaskInverse) | (color << Constants.ColorOffset)\n\t);\n}\nfunction getNodeIsVisited(node: IntervalNode): boolean {\n\treturn ((node.metadata & Constants.IsVisitedMask) >>> Constants.IsVisitedOffset) === 1;\n}\nfunction setNodeIsVisited(node: IntervalNode, value: boolean): void {\n\tnode.metadata = (\n\t\t(node.metadata & Constants.IsVisitedMaskInverse) | ((value ? 1 : 0) << Constants.IsVisitedOffset)\n\t);\n}\nfunction getNodeIsForValidation(node: IntervalNode): boolean {\n\treturn ((node.metadata & Constants.IsForValidationMask) >>> Constants.IsForValidationOffset) === 1;\n}\nfunction setNodeIsForValidation(node: IntervalNode, value: boolean): void {\n\tnode.metadata = (\n\t\t(node.metadata & Constants.IsForValidationMaskInverse) | ((value ? 1 : 0) << Constants.IsForValidationOffset)\n\t);\n}\nfunction getNodeIsInGlyphMargin(node: IntervalNode): boolean {\n\treturn ((node.metadata & Constants.IsMarginMask) >>> Constants.IsMarginOffset) === 1;\n}\nfunction setNodeIsInGlyphMargin(node: IntervalNode, value: boolean): void {\n\tnode.metadata = (\n\t\t(node.metadata & Constants.IsMarginMaskInverse) | ((value ? 1 : 0) << Constants.IsMarginOffset)\n\t);\n}\nfunction getNodeStickiness(node: IntervalNode): TrackedRangeStickiness {\n\treturn ((node.metadata & Constants.StickinessMask) >>> Constants.StickinessOffset);\n}\nfunction _setNodeStickiness(node: IntervalNode, stickiness: TrackedRangeStickiness): void {\n\tnode.metadata = (\n\t\t(node.metadata & Constants.StickinessMaskInverse) | (stickiness << Constants.StickinessOffset)\n\t);\n}\nfunction getCollapseOnReplaceEdit(node: IntervalNode): boolean {\n\treturn ((node.metadata & Constants.CollapseOnReplaceEditMask) >>> Constants.CollapseOnReplaceEditOffset) === 1;\n}\nfunction setCollapseOnReplaceEdit(node: IntervalNode, value: boolean): void {\n\tnode.metadata = (\n\t\t(node.metadata & Constants.CollapseOnReplaceEditMaskInverse) | ((value ? 1 : 0) << Constants.CollapseOnReplaceEditOffset)\n\t);\n}\n\nexport class IntervalNode {\n\n\t/**\n\t * contains binary encoded information for color, visited, isForValidation and stickiness.\n\t */\n\tpublic metadata: number;\n\n\tpublic parent: IntervalNode;\n\tpublic left: IntervalNode;\n\tpublic right: IntervalNode;\n\n\tpublic start: number;\n\tpublic end: number;\n\tpublic delta: number;\n\tpublic maxEnd: number;\n\n\tpublic id: string;\n\tpublic ownerId: number;\n\tpublic options: ModelDecorationOptions;\n\n\tpublic cachedVersionId: number;\n\tpublic cachedAbsoluteStart: number;\n\tpublic cachedAbsoluteEnd: number;\n\tpublic range: Range | null;\n\n\tconstructor(id: string, start: number, end: number) {\n\t\tthis.metadata = 0;\n\n\t\tthis.parent = this;\n\t\tthis.left = this;\n\t\tthis.right = this;\n\t\tsetNodeColor(this, NodeColor.Red);\n\n\t\tthis.start = start;\n\t\tthis.end = end;\n\t\t// FORCE_OVERFLOWING_TEST: this.delta = start;\n\t\tthis.delta = 0;\n\t\tthis.maxEnd = end;\n\n\t\tthis.id = id;\n\t\tthis.ownerId = 0;\n\t\tthis.options = null!;\n\t\tsetNodeIsForValidation(this, false);\n\t\tsetNodeIsInGlyphMargin(this, false);\n\t\t_setNodeStickiness(this, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges);\n\t\tsetCollapseOnReplaceEdit(this, false);\n\n\t\tthis.cachedVersionId = 0;\n\t\tthis.cachedAbsoluteStart = start;\n\t\tthis.cachedAbsoluteEnd = end;\n\t\tthis.range = null;\n\n\t\tsetNodeIsVisited(this, false);\n\t}\n\n\tpublic reset(versionId: number, start: number, end: number, range: Range): void {\n\t\tthis.start = start;\n\t\tthis.end = end;\n\t\tthis.maxEnd = end;\n\t\tthis.cachedVersionId = versionId;\n\t\tthis.cachedAbsoluteStart = start;\n\t\tthis.cachedAbsoluteEnd = end;\n\t\tthis.range = range;\n\t}\n\n\tpublic setOptions(options: ModelDecorationOptions) {\n\t\tthis.options = options;\n\t\tconst className = this.options.className;\n\t\tsetNodeIsForValidation(this, (\n\t\t\tclassName === ClassName.EditorErrorDecoration\n\t\t\t|| className === ClassName.EditorWarningDecoration\n\t\t\t|| className === ClassName.EditorInfoDecoration\n\t\t));\n\t\tsetNodeIsInGlyphMargin(this, this.options.glyphMarginClassName !== null);\n\t\t_setNodeStickiness(this, this.options.stickiness);\n\t\tsetCollapseOnReplaceEdit(this, this.options.collapseOnReplaceEdit);\n\t}\n\n\tpublic setCachedOffsets(absoluteStart: number, absoluteEnd: number, cachedVersionId: number): void {\n\t\tif (this.cachedVersionId !== cachedVersionId) {\n\t\t\tthis.range = null;\n\t\t}\n\t\tthis.cachedVersionId = cachedVersionId;\n\t\tthis.cachedAbsoluteStart = absoluteStart;\n\t\tthis.cachedAbsoluteEnd = absoluteEnd;\n\t}\n\n\tpublic detach(): void {\n\t\tthis.parent = null!;\n\t\tthis.left = null!;\n\t\tthis.right = null!;\n\t}\n}\n\nexport const SENTINEL: IntervalNode = new IntervalNode(null!, 0, 0);\nSENTINEL.parent = SENTINEL;\nSENTINEL.left = SENTINEL;\nSENTINEL.right = SENTINEL;\nsetNodeColor(SENTINEL, NodeColor.Black);\n\nexport class IntervalTree {\n\n\tpublic root: IntervalNode;\n\tpublic requestNormalizeDelta: boolean;\n\n\tconstructor() {\n\t\tthis.root = SENTINEL;\n\t\tthis.requestNormalizeDelta = false;\n\t}\n\n\tpublic intervalSearch(start: number, end: number, filterOwnerId: number, filterOutValidation: boolean, cachedVersionId: number, onlyMarginDecorations: boolean): IntervalNode[] {\n\t\tif (this.root === SENTINEL) {\n\t\t\treturn [];\n\t\t}\n\t\treturn intervalSearch(this, start, end, filterOwnerId, filterOutValidation, cachedVersionId, onlyMarginDecorations);\n\t}\n\n\tpublic search(filterOwnerId: number, filterOutValidation: boolean, cachedVersionId: number, onlyMarginDecorations: boolean): IntervalNode[] {\n\t\tif (this.root === SENTINEL) {\n\t\t\treturn [];\n\t\t}\n\t\treturn search(this, filterOwnerId, filterOutValidation, cachedVersionId, onlyMarginDecorations);\n\t}\n\n\t/**\n\t * Will not set `cachedAbsoluteStart` nor `cachedAbsoluteEnd` on the returned nodes!\n\t */\n\tpublic collectNodesFromOwner(ownerId: number): IntervalNode[] {\n\t\treturn collectNodesFromOwner(this, ownerId);\n\t}\n\n\t/**\n\t * Will not set `cachedAbsoluteStart` nor `cachedAbsoluteEnd` on the returned nodes!\n\t */\n\tpublic collectNodesPostOrder(): IntervalNode[] {\n\t\treturn collectNodesPostOrder(this);\n\t}\n\n\tpublic insert(node: IntervalNode): void {\n\t\trbTreeInsert(this, node);\n\t\tthis._normalizeDeltaIfNecessary();\n\t}\n\n\tpublic delete(node: IntervalNode): void {\n\t\trbTreeDelete(this, node);\n\t\tthis._normalizeDeltaIfNecessary();\n\t}\n\n\tpublic resolveNode(node: IntervalNode, cachedVersionId: number): void {\n\t\tconst initialNode = node;\n\t\tlet delta = 0;\n\t\twhile (node !== this.root) {\n\t\t\tif (node === node.parent.right) {\n\t\t\t\tdelta += node.parent.delta;\n\t\t\t}\n\t\t\tnode = node.parent;\n\t\t}\n\n\t\tconst nodeStart = initialNode.start + delta;\n\t\tconst nodeEnd = initialNode.end + delta;\n\t\tinitialNode.setCachedOffsets(nodeStart, nodeEnd, cachedVersionId);\n\t}\n\n\tpublic acceptReplace(offset: number, length: number, textLength: number, forceMoveMarkers: boolean): void {\n\t\t// Our strategy is to remove all directly impacted nodes, and then add them back to the tree.\n\n\t\t// (1) collect all nodes that are intersecting this edit as nodes of interest\n\t\tconst nodesOfInterest = searchForEditing(this, offset, offset + length);\n\n\t\t// (2) remove all nodes that are intersecting this edit\n\t\tfor (let i = 0, len = nodesOfInterest.length; i < len; i++) {\n\t\t\tconst node = nodesOfInterest[i];\n\t\t\trbTreeDelete(this, node);\n\t\t}\n\t\tthis._normalizeDeltaIfNecessary();\n\n\t\t// (3) edit all tree nodes except the nodes of interest\n\t\tnoOverlapReplace(this, offset, offset + length, textLength);\n\t\tthis._normalizeDeltaIfNecessary();\n\n\t\t// (4) edit the nodes of interest and insert them back in the tree\n\t\tfor (let i = 0, len = nodesOfInterest.length; i < len; i++) {\n\t\t\tconst node = nodesOfInterest[i];\n\t\t\tnode.start = node.cachedAbsoluteStart;\n\t\t\tnode.end = node.cachedAbsoluteEnd;\n\t\t\tnodeAcceptEdit(node, offset, (offset + length), textLength, forceMoveMarkers);\n\t\t\tnode.maxEnd = node.end;\n\t\t\trbTreeInsert(this, node);\n\t\t}\n\t\tthis._normalizeDeltaIfNecessary();\n\t}\n\n\tprivate _normalizeDeltaIfNecessary(): void {\n\t\tif (!this.requestNormalizeDelta) {\n\t\t\treturn;\n\t\t}\n\t\tthis.requestNormalizeDelta = false;\n\t\tnormalizeDelta(this);\n\t}\n}\n\n//#region Delta Normalization\nfunction normalizeDelta(T: IntervalTree): void {\n\tlet node = T.root;\n\tlet delta = 0;\n\twhile (node !== SENTINEL) {\n\n\t\tif (node.left !== SENTINEL && !getNodeIsVisited(node.left)) {\n\t\t\t// go left\n\t\t\tnode = node.left;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (node.right !== SENTINEL && !getNodeIsVisited(node.right)) {\n\t\t\t// go right\n\t\t\tdelta += node.delta;\n\t\t\tnode = node.right;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// handle current node\n\t\tnode.start = delta + node.start;\n\t\tnode.end = delta + node.end;\n\t\tnode.delta = 0;\n\t\trecomputeMaxEnd(node);\n\n\t\tsetNodeIsVisited(node, true);\n\n\t\t// going up from this node\n\t\tsetNodeIsVisited(node.left, false);\n\t\tsetNodeIsVisited(node.right, false);\n\t\tif (node === node.parent.right) {\n\t\t\tdelta -= node.parent.delta;\n\t\t}\n\t\tnode = node.parent;\n\t}\n\n\tsetNodeIsVisited(T.root, false);\n}\n//#endregion\n\n//#region Editing\n\nconst enum MarkerMoveSemantics {\n\tMarkerDefined = 0,\n\tForceMove = 1,\n\tForceStay = 2\n}\n\nfunction adjustMarkerBeforeColumn(markerOffset: number, markerStickToPreviousCharacter: boolean, checkOffset: number, moveSemantics: MarkerMoveSemantics): boolean {\n\tif (markerOffset < checkOffset) {\n\t\treturn true;\n\t}\n\tif (markerOffset > checkOffset) {\n\t\treturn false;\n\t}\n\tif (moveSemantics === MarkerMoveSemantics.ForceMove) {\n\t\treturn false;\n\t}\n\tif (moveSemantics === MarkerMoveSemantics.ForceStay) {\n\t\treturn true;\n\t}\n\treturn markerStickToPreviousCharacter;\n}\n\n/**\n * This is a lot more complicated than strictly necessary to maintain the same behaviour\n * as when decorations were implemented using two markers.\n */\nexport function nodeAcceptEdit(node: IntervalNode, start: number, end: number, textLength: number, forceMoveMarkers: boolean): void {\n\tconst nodeStickiness = getNodeStickiness(node);\n\tconst startStickToPreviousCharacter = (\n\t\tnodeStickiness === TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges\n\t\t|| nodeStickiness === TrackedRangeStickiness.GrowsOnlyWhenTypingBefore\n\t);\n\tconst endStickToPreviousCharacter = (\n\t\tnodeStickiness === TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges\n\t\t|| nodeStickiness === TrackedRangeStickiness.GrowsOnlyWhenTypingBefore\n\t);\n\n\tconst deletingCnt = (end - start);\n\tconst insertingCnt = textLength;\n\tconst commonLength = Math.min(deletingCnt, insertingCnt);\n\n\tconst nodeStart = node.start;\n\tlet startDone = false;\n\n\tconst nodeEnd = node.end;\n\tlet endDone = false;\n\n\tif (start <= nodeStart && nodeEnd <= end && getCollapseOnReplaceEdit(node)) {\n\t\t// This edit encompasses the entire decoration range\n\t\t// and the decoration has asked to become collapsed\n\t\tnode.start = start;\n\t\tstartDone = true;\n\t\tnode.end = start;\n\t\tendDone = true;\n\t}\n\n\t{\n\t\tconst moveSemantics = forceMoveMarkers ? MarkerMoveSemantics.ForceMove : (deletingCnt > 0 ? MarkerMoveSemantics.ForceStay : MarkerMoveSemantics.MarkerDefined);\n\t\tif (!startDone && adjustMarkerBeforeColumn(nodeStart, startStickToPreviousCharacter, start, moveSemantics)) {\n\t\t\tstartDone = true;\n\t\t}\n\t\tif (!endDone && adjustMarkerBeforeColumn(nodeEnd, endStickToPreviousCharacter, start, moveSemantics)) {\n\t\t\tendDone = true;\n\t\t}\n\t}\n\n\tif (commonLength > 0 && !forceMoveMarkers) {\n\t\tconst moveSemantics = (deletingCnt > insertingCnt ? MarkerMoveSemantics.ForceStay : MarkerMoveSemantics.MarkerDefined);\n\t\tif (!startDone && adjustMarkerBeforeColumn(nodeStart, startStickToPreviousCharacter, start + commonLength, moveSemantics)) {\n\t\t\tstartDone = true;\n\t\t}\n\t\tif (!endDone && adjustMarkerBeforeColumn(nodeEnd, endStickToPreviousCharacter, start + commonLength, moveSemantics)) {\n\t\t\tendDone = true;\n\t\t}\n\t}\n\n\t{\n\t\tconst moveSemantics = forceMoveMarkers ? MarkerMoveSemantics.ForceMove : MarkerMoveSemantics.MarkerDefined;\n\t\tif (!startDone && adjustMarkerBeforeColumn(nodeStart, startStickToPreviousCharacter, end, moveSemantics)) {\n\t\t\tnode.start = start + insertingCnt;\n\t\t\tstartDone = true;\n\t\t}\n\t\tif (!endDone && adjustMarkerBeforeColumn(nodeEnd, endStickToPreviousCharacter, end, moveSemantics)) {\n\t\t\tnode.end = start + insertingCnt;\n\t\t\tendDone = true;\n\t\t}\n\t}\n\n\t// Finish\n\tconst deltaColumn = (insertingCnt - deletingCnt);\n\tif (!startDone) {\n\t\tnode.start = Math.max(0, nodeStart + deltaColumn);\n\t}\n\tif (!endDone) {\n\t\tnode.end = Math.max(0, nodeEnd + deltaColumn);\n\t}\n\n\tif (node.start > node.end) {\n\t\tnode.end = node.start;\n\t}\n}\n\nfunction searchForEditing(T: IntervalTree, start: number, end: number): IntervalNode[] {\n\t// https://en.wikipedia.org/wiki/Interval_tree#Augmented_tree\n\t// Now, it is known that two intervals A and B overlap only when both\n\t// A.low <= B.high and A.high >= B.low. When searching the trees for\n\t// nodes overlapping with a given interval, you can immediately skip:\n\t// a) all nodes to the right of nodes whose low value is past the end of the given interval.\n\t// b) all nodes that have their maximum 'high' value below the start of the given interval.\n\tlet node = T.root;\n\tlet delta = 0;\n\tlet nodeMaxEnd = 0;\n\tlet nodeStart = 0;\n\tlet nodeEnd = 0;\n\tconst result: IntervalNode[] = [];\n\tlet resultLen = 0;\n\twhile (node !== SENTINEL) {\n\t\tif (getNodeIsVisited(node)) {\n\t\t\t// going up from this node\n\t\t\tsetNodeIsVisited(node.left, false);\n\t\t\tsetNodeIsVisited(node.right, false);\n\t\t\tif (node === node.parent.right) {\n\t\t\t\tdelta -= node.parent.delta;\n\t\t\t}\n\t\t\tnode = node.parent;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (!getNodeIsVisited(node.left)) {\n\t\t\t// first time seeing this node\n\t\t\tnodeMaxEnd = delta + node.maxEnd;\n\t\t\tif (nodeMaxEnd < start) {\n\t\t\t\t// cover case b) from above\n\t\t\t\t// there is no need to search this node or its children\n\t\t\t\tsetNodeIsVisited(node, true);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (node.left !== SENTINEL) {\n\t\t\t\t// go left\n\t\t\t\tnode = node.left;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\t// handle current node\n\t\tnodeStart = delta + node.start;\n\t\tif (nodeStart > end) {\n\t\t\t// cover case a) from above\n\t\t\t// there is no need to search this node or its right subtree\n\t\t\tsetNodeIsVisited(node, true);\n\t\t\tcontinue;\n\t\t}\n\n\t\tnodeEnd = delta + node.end;\n\t\tif (nodeEnd >= start) {\n\t\t\tnode.setCachedOffsets(nodeStart, nodeEnd, 0);\n\t\t\tresult[resultLen++] = node;\n\t\t}\n\t\tsetNodeIsVisited(node, true);\n\n\t\tif (node.right !== SENTINEL && !getNodeIsVisited(node.right)) {\n\t\t\t// go right\n\t\t\tdelta += node.delta;\n\t\t\tnode = node.right;\n\t\t\tcontinue;\n\t\t}\n\t}\n\n\tsetNodeIsVisited(T.root, false);\n\n\treturn result;\n}\n\nfunction noOverlapReplace(T: IntervalTree, start: number, end: number, textLength: number): void {\n\t// https://en.wikipedia.org/wiki/Interval_tree#Augmented_tree\n\t// Now, it is known that two intervals A and B overlap only when both\n\t// A.low <= B.high and A.high >= B.low. When searching the trees for\n\t// nodes overlapping with a given interval, you can immediately skip:\n\t// a) all nodes to the right of nodes whose low value is past the end of the given interval.\n\t// b) all nodes that have their maximum 'high' value below the start of the given interval.\n\tlet node = T.root;\n\tlet delta = 0;\n\tlet nodeMaxEnd = 0;\n\tlet nodeStart = 0;\n\tconst editDelta = (textLength - (end - start));\n\twhile (node !== SENTINEL) {\n\t\tif (getNodeIsVisited(node)) {\n\t\t\t// going up from this node\n\t\t\tsetNodeIsVisited(node.left, false);\n\t\t\tsetNodeIsVisited(node.right, false);\n\t\t\tif (node === node.parent.right) {\n\t\t\t\tdelta -= node.parent.delta;\n\t\t\t}\n\t\t\trecomputeMaxEnd(node);\n\t\t\tnode = node.parent;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (!getNodeIsVisited(node.left)) {\n\t\t\t// first time seeing this node\n\t\t\tnodeMaxEnd = delta + node.maxEnd;\n\t\t\tif (nodeMaxEnd < start) {\n\t\t\t\t// cover case b) from above\n\t\t\t\t// there is no need to search this node or its children\n\t\t\t\tsetNodeIsVisited(node, true);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (node.left !== SENTINEL) {\n\t\t\t\t// go left\n\t\t\t\tnode = node.left;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\t// handle current node\n\t\tnodeStart = delta + node.start;\n\t\tif (nodeStart > end) {\n\t\t\tnode.start += editDelta;\n\t\t\tnode.end += editDelta;\n\t\t\tnode.delta += editDelta;\n\t\t\tif (node.delta < Constants.MIN_SAFE_DELTA || node.delta > Constants.MAX_SAFE_DELTA) {\n\t\t\t\tT.requestNormalizeDelta = true;\n\t\t\t}\n\t\t\t// cover case a) from above\n\t\t\t// there is no need to search this node or its right subtree\n\t\t\tsetNodeIsVisited(node, true);\n\t\t\tcontinue;\n\t\t}\n\n\t\tsetNodeIsVisited(node, true);\n\n\t\tif (node.right !== SENTINEL && !getNodeIsVisited(node.right)) {\n\t\t\t// go right\n\t\t\tdelta += node.delta;\n\t\t\tnode = node.right;\n\t\t\tcontinue;\n\t\t}\n\t}\n\n\tsetNodeIsVisited(T.root, false);\n}\n\n//#endregion\n\n//#region Searching\n\nfunction collectNodesFromOwner(T: IntervalTree, ownerId: number): IntervalNode[] {\n\tlet node = T.root;\n\tconst result: IntervalNode[] = [];\n\tlet resultLen = 0;\n\twhile (node !== SENTINEL) {\n\t\tif (getNodeIsVisited(node)) {\n\t\t\t// going up from this node\n\t\t\tsetNodeIsVisited(node.left, false);\n\t\t\tsetNodeIsVisited(node.right, false);\n\t\t\tnode = node.parent;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (node.left !== SENTINEL && !getNodeIsVisited(node.left)) {\n\t\t\t// go left\n\t\t\tnode = node.left;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// handle current node\n\t\tif (node.ownerId === ownerId) {\n\t\t\tresult[resultLen++] = node;\n\t\t}\n\n\t\tsetNodeIsVisited(node, true);\n\n\t\tif (node.right !== SENTINEL && !getNodeIsVisited(node.right)) {\n\t\t\t// go right\n\t\t\tnode = node.right;\n\t\t\tcontinue;\n\t\t}\n\t}\n\n\tsetNodeIsVisited(T.root, false);\n\n\treturn result;\n}\n\nfunction collectNodesPostOrder(T: IntervalTree): IntervalNode[] {\n\tlet node = T.root;\n\tconst result: IntervalNode[] = [];\n\tlet resultLen = 0;\n\twhile (node !== SENTINEL) {\n\t\tif (getNodeIsVisited(node)) {\n\t\t\t// going up from this node\n\t\t\tsetNodeIsVisited(node.left, false);\n\t\t\tsetNodeIsVisited(node.right, false);\n\t\t\tnode = node.parent;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (node.left !== SENTINEL && !getNodeIsVisited(node.left)) {\n\t\t\t// go left\n\t\t\tnode = node.left;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (node.right !== SENTINEL && !getNodeIsVisited(node.right)) {\n\t\t\t// go right\n\t\t\tnode = node.right;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// handle current node\n\t\tresult[resultLen++] = node;\n\t\tsetNodeIsVisited(node, true);\n\t}\n\n\tsetNodeIsVisited(T.root, false);\n\n\treturn result;\n}\n\nfunction search(T: IntervalTree, filterOwnerId: number, filterOutValidation: boolean, cachedVersionId: number, onlyMarginDecorations: boolean): IntervalNode[] {\n\tlet node = T.root;\n\tlet delta = 0;\n\tlet nodeStart = 0;\n\tlet nodeEnd = 0;\n\tconst result: IntervalNode[] = [];\n\tlet resultLen = 0;\n\twhile (node !== SENTINEL) {\n\t\tif (getNodeIsVisited(node)) {\n\t\t\t// going up from this node\n\t\t\tsetNodeIsVisited(node.left, false);\n\t\t\tsetNodeIsVisited(node.right, false);\n\t\t\tif (node === node.parent.right) {\n\t\t\t\tdelta -= node.parent.delta;\n\t\t\t}\n\t\t\tnode = node.parent;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (node.left !== SENTINEL && !getNodeIsVisited(node.left)) {\n\t\t\t// go left\n\t\t\tnode = node.left;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// handle current node\n\t\tnodeStart = delta + node.start;\n\t\tnodeEnd = delta + node.end;\n\n\t\tnode.setCachedOffsets(nodeStart, nodeEnd, cachedVersionId);\n\n\t\tlet include = true;\n\t\tif (filterOwnerId && node.ownerId && node.ownerId !== filterOwnerId) {\n\t\t\tinclude = false;\n\t\t}\n\t\tif (filterOutValidation && getNodeIsForValidation(node)) {\n\t\t\tinclude = false;\n\t\t}\n\t\tif (onlyMarginDecorations && !getNodeIsInGlyphMargin(node)) {\n\t\t\tinclude = false;\n\t\t}\n\n\t\tif (include) {\n\t\t\tresult[resultLen++] = node;\n\t\t}\n\n\t\tsetNodeIsVisited(node, true);\n\n\t\tif (node.right !== SENTINEL && !getNodeIsVisited(node.right)) {\n\t\t\t// go right\n\t\t\tdelta += node.delta;\n\t\t\tnode = node.right;\n\t\t\tcontinue;\n\t\t}\n\t}\n\n\tsetNodeIsVisited(T.root, false);\n\n\treturn result;\n}\n\nfunction intervalSearch(T: IntervalTree, intervalStart: number, intervalEnd: number, filterOwnerId: number, filterOutValidation: boolean, cachedVersionId: number, onlyMarginDecorations: boolean): IntervalNode[] {\n\t// https://en.wikipedia.org/wiki/Interval_tree#Augmented_tree\n\t// Now, it is known that two intervals A and B overlap only when both\n\t// A.low <= B.high and A.high >= B.low. When searching the trees for\n\t// nodes overlapping with a given interval, you can immediately skip:\n\t// a) all nodes to the right of nodes whose low value is past the end of the given interval.\n\t// b) all nodes that have their maximum 'high' value below the start of the given interval.\n\n\tlet node = T.root;\n\tlet delta = 0;\n\tlet nodeMaxEnd = 0;\n\tlet nodeStart = 0;\n\tlet nodeEnd = 0;\n\tconst result: IntervalNode[] = [];\n\tlet resultLen = 0;\n\twhile (node !== SENTINEL) {\n\t\tif (getNodeIsVisited(node)) {\n\t\t\t// going up from this node\n\t\t\tsetNodeIsVisited(node.left, false);\n\t\t\tsetNodeIsVisited(node.right, false);\n\t\t\tif (node === node.parent.right) {\n\t\t\t\tdelta -= node.parent.delta;\n\t\t\t}\n\t\t\tnode = node.parent;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (!getNodeIsVisited(node.left)) {\n\t\t\t// first time seeing this node\n\t\t\tnodeMaxEnd = delta + node.maxEnd;\n\t\t\tif (nodeMaxEnd < intervalStart) {\n\t\t\t\t// cover case b) from above\n\t\t\t\t// there is no need to search this node or its children\n\t\t\t\tsetNodeIsVisited(node, true);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (node.left !== SENTINEL) {\n\t\t\t\t// go left\n\t\t\t\tnode = node.left;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\t// handle current node\n\t\tnodeStart = delta + node.start;\n\t\tif (nodeStart > intervalEnd) {\n\t\t\t// cover case a) from above\n\t\t\t// there is no need to search this node or its right subtree\n\t\t\tsetNodeIsVisited(node, true);\n\t\t\tcontinue;\n\t\t}\n\n\t\tnodeEnd = delta + node.end;\n\n\t\tif (nodeEnd >= intervalStart) {\n\t\t\t// There is overlap\n\t\t\tnode.setCachedOffsets(nodeStart, nodeEnd, cachedVersionId);\n\n\t\t\tlet include = true;\n\t\t\tif (filterOwnerId && node.ownerId && node.ownerId !== filterOwnerId) {\n\t\t\t\tinclude = false;\n\t\t\t}\n\t\t\tif (filterOutValidation && getNodeIsForValidation(node)) {\n\t\t\t\tinclude = false;\n\t\t\t}\n\t\t\tif (onlyMarginDecorations && !getNodeIsInGlyphMargin(node)) {\n\t\t\t\tinclude = false;\n\t\t\t}\n\n\t\t\tif (include) {\n\t\t\t\tresult[resultLen++] = node;\n\t\t\t}\n\t\t}\n\n\t\tsetNodeIsVisited(node, true);\n\n\t\tif (node.right !== SENTINEL && !getNodeIsVisited(node.right)) {\n\t\t\t// go right\n\t\t\tdelta += node.delta;\n\t\t\tnode = node.right;\n\t\t\tcontinue;\n\t\t}\n\t}\n\n\tsetNodeIsVisited(T.root, false);\n\n\treturn result;\n}\n\n//#endregion\n\n//#region Insertion\nfunction rbTreeInsert(T: IntervalTree, newNode: IntervalNode): IntervalNode {\n\tif (T.root === SENTINEL) {\n\t\tnewNode.parent = SENTINEL;\n\t\tnewNode.left = SENTINEL;\n\t\tnewNode.right = SENTINEL;\n\t\tsetNodeColor(newNode, NodeColor.Black);\n\t\tT.root = newNode;\n\t\treturn T.root;\n\t}\n\n\ttreeInsert(T, newNode);\n\n\trecomputeMaxEndWalkToRoot(newNode.parent);\n\n\t// repair tree\n\tlet x = newNode;\n\twhile (x !== T.root && getNodeColor(x.parent) === NodeColor.Red) {\n\t\tif (x.parent === x.parent.parent.left) {\n\t\t\tconst y = x.parent.parent.right;\n\n\t\t\tif (getNodeColor(y) === NodeColor.Red) {\n\t\t\t\tsetNodeColor(x.parent, NodeColor.Black);\n\t\t\t\tsetNodeColor(y, NodeColor.Black);\n\t\t\t\tsetNodeColor(x.parent.parent, NodeColor.Red);\n\t\t\t\tx = x.parent.parent;\n\t\t\t} else {\n\t\t\t\tif (x === x.parent.right) {\n\t\t\t\t\tx = x.parent;\n\t\t\t\t\tleftRotate(T, x);\n\t\t\t\t}\n\t\t\t\tsetNodeColor(x.parent, NodeColor.Black);\n\t\t\t\tsetNodeColor(x.parent.parent, NodeColor.Red);\n\t\t\t\trightRotate(T, x.parent.parent);\n\t\t\t}\n\t\t} else {\n\t\t\tconst y = x.parent.parent.left;\n\n\t\t\tif (getNodeColor(y) === NodeColor.Red) {\n\t\t\t\tsetNodeColor(x.parent, NodeColor.Black);\n\t\t\t\tsetNodeColor(y, NodeColor.Black);\n\t\t\t\tsetNodeColor(x.parent.parent, NodeColor.Red);\n\t\t\t\tx = x.parent.parent;\n\t\t\t} else {\n\t\t\t\tif (x === x.parent.left) {\n\t\t\t\t\tx = x.parent;\n\t\t\t\t\trightRotate(T, x);\n\t\t\t\t}\n\t\t\t\tsetNodeColor(x.parent, NodeColor.Black);\n\t\t\t\tsetNodeColor(x.parent.parent, NodeColor.Red);\n\t\t\t\tleftRotate(T, x.parent.parent);\n\t\t\t}\n\t\t}\n\t}\n\n\tsetNodeColor(T.root, NodeColor.Black);\n\n\treturn newNode;\n}\n\nfunction treeInsert(T: IntervalTree, z: IntervalNode): void {\n\tlet delta: number = 0;\n\tlet x = T.root;\n\tconst zAbsoluteStart = z.start;\n\tconst zAbsoluteEnd = z.end;\n\twhile (true) {\n\t\tconst cmp = intervalCompare(zAbsoluteStart, zAbsoluteEnd, x.start + delta, x.end + delta);\n\t\tif (cmp < 0) {\n\t\t\t// this node should be inserted to the left\n\t\t\t// => it is not affected by the node's delta\n\t\t\tif (x.left === SENTINEL) {\n\t\t\t\tz.start -= delta;\n\t\t\t\tz.end -= delta;\n\t\t\t\tz.maxEnd -= delta;\n\t\t\t\tx.left = z;\n\t\t\t\tbreak;\n\t\t\t} else {\n\t\t\t\tx = x.left;\n\t\t\t}\n\t\t} else {\n\t\t\t// this node should be inserted to the right\n\t\t\t// => it is not affected by the node's delta\n\t\t\tif (x.right === SENTINEL) {\n\t\t\t\tz.start -= (delta + x.delta);\n\t\t\t\tz.end -= (delta + x.delta);\n\t\t\t\tz.maxEnd -= (delta + x.delta);\n\t\t\t\tx.right = z;\n\t\t\t\tbreak;\n\t\t\t} else {\n\t\t\t\tdelta += x.delta;\n\t\t\t\tx = x.right;\n\t\t\t}\n\t\t}\n\t}\n\n\tz.parent = x;\n\tz.left = SENTINEL;\n\tz.right = SENTINEL;\n\tsetNodeColor(z, NodeColor.Red);\n}\n//#endregion\n\n//#region Deletion\nfunction rbTreeDelete(T: IntervalTree, z: IntervalNode): void {\n\n\tlet x: IntervalNode;\n\tlet y: IntervalNode;\n\n\t// RB-DELETE except we don't swap z and y in case c)\n\t// i.e. we always delete what's pointed at by z.\n\n\tif (z.left === SENTINEL) {\n\t\tx = z.right;\n\t\ty = z;\n\n\t\t// x's delta is no longer influenced by z's delta\n\t\tx.delta += z.delta;\n\t\tif (x.delta < Constants.MIN_SAFE_DELTA || x.delta > Constants.MAX_SAFE_DELTA) {\n\t\t\tT.requestNormalizeDelta = true;\n\t\t}\n\t\tx.start += z.delta;\n\t\tx.end += z.delta;\n\n\t} else if (z.right === SENTINEL) {\n\t\tx = z.left;\n\t\ty = z;\n\n\t} else {\n\t\ty = leftest(z.right);\n\t\tx = y.right;\n\n\t\t// y's delta is no longer influenced by z's delta,\n\t\t// but we don't want to walk the entire right-hand-side subtree of x.\n\t\t// we therefore maintain z's delta in y, and adjust only x\n\t\tx.start += y.delta;\n\t\tx.end += y.delta;\n\t\tx.delta += y.delta;\n\t\tif (x.delta < Constants.MIN_SAFE_DELTA || x.delta > Constants.MAX_SAFE_DELTA) {\n\t\t\tT.requestNormalizeDelta = true;\n\t\t}\n\n\t\ty.start += z.delta;\n\t\ty.end += z.delta;\n\t\ty.delta = z.delta;\n\t\tif (y.delta < Constants.MIN_SAFE_DELTA || y.delta > Constants.MAX_SAFE_DELTA) {\n\t\t\tT.requestNormalizeDelta = true;\n\t\t}\n\t}\n\n\tif (y === T.root) {\n\t\tT.root = x;\n\t\tsetNodeColor(x, NodeColor.Black);\n\n\t\tz.detach();\n\t\tresetSentinel();\n\t\trecomputeMaxEnd(x);\n\t\tT.root.parent = SENTINEL;\n\t\treturn;\n\t}\n\n\tconst yWasRed = (getNodeColor(y) === NodeColor.Red);\n\n\tif (y === y.parent.left) {\n\t\ty.parent.left = x;\n\t} else {\n\t\ty.parent.right = x;\n\t}\n\n\tif (y === z) {\n\t\tx.parent = y.parent;\n\t} else {\n\n\t\tif (y.parent === z) {\n\t\t\tx.parent = y;\n\t\t} else {\n\t\t\tx.parent = y.parent;\n\t\t}\n\n\t\ty.left = z.left;\n\t\ty.right = z.right;\n\t\ty.parent = z.parent;\n\t\tsetNodeColor(y, getNodeColor(z));\n\n\t\tif (z === T.root) {\n\t\t\tT.root = y;\n\t\t} else {\n\t\t\tif (z === z.parent.left) {\n\t\t\t\tz.parent.left = y;\n\t\t\t} else {\n\t\t\t\tz.parent.right = y;\n\t\t\t}\n\t\t}\n\n\t\tif (y.left !== SENTINEL) {\n\t\t\ty.left.parent = y;\n\t\t}\n\t\tif (y.right !== SENTINEL) {\n\t\t\ty.right.parent = y;\n\t\t}\n\t}\n\n\tz.detach();\n\n\tif (yWasRed) {\n\t\trecomputeMaxEndWalkToRoot(x.parent);\n\t\tif (y !== z) {\n\t\t\trecomputeMaxEndWalkToRoot(y);\n\t\t\trecomputeMaxEndWalkToRoot(y.parent);\n\t\t}\n\t\tresetSentinel();\n\t\treturn;\n\t}\n\n\trecomputeMaxEndWalkToRoot(x);\n\trecomputeMaxEndWalkToRoot(x.parent);\n\tif (y !== z) {\n\t\trecomputeMaxEndWalkToRoot(y);\n\t\trecomputeMaxEndWalkToRoot(y.parent);\n\t}\n\n\t// RB-DELETE-FIXUP\n\tlet w: IntervalNode;\n\twhile (x !== T.root && getNodeColor(x) === NodeColor.Black) {\n\n\t\tif (x === x.parent.left) {\n\t\t\tw = x.parent.right;\n\n\t\t\tif (getNodeColor(w) === NodeColor.Red) {\n\t\t\t\tsetNodeColor(w, NodeColor.Black);\n\t\t\t\tsetNodeColor(x.parent, NodeColor.Red);\n\t\t\t\tleftRotate(T, x.parent);\n\t\t\t\tw = x.parent.right;\n\t\t\t}\n\n\t\t\tif (getNodeColor(w.left) === NodeColor.Black && getNodeColor(w.right) === NodeColor.Black) {\n\t\t\t\tsetNodeColor(w, NodeColor.Red);\n\t\t\t\tx = x.parent;\n\t\t\t} else {\n\t\t\t\tif (getNodeColor(w.right) === NodeColor.Black) {\n\t\t\t\t\tsetNodeColor(w.left, NodeColor.Black);\n\t\t\t\t\tsetNodeColor(w, NodeColor.Red);\n\t\t\t\t\trightRotate(T, w);\n\t\t\t\t\tw = x.parent.right;\n\t\t\t\t}\n\n\t\t\t\tsetNodeColor(w, getNodeColor(x.parent));\n\t\t\t\tsetNodeColor(x.parent, NodeColor.Black);\n\t\t\t\tsetNodeColor(w.right, NodeColor.Black);\n\t\t\t\tleftRotate(T, x.parent);\n\t\t\t\tx = T.root;\n\t\t\t}\n\n\t\t} else {\n\t\t\tw = x.parent.left;\n\n\t\t\tif (getNodeColor(w) === NodeColor.Red) {\n\t\t\t\tsetNodeColor(w, NodeColor.Black);\n\t\t\t\tsetNodeColor(x.parent, NodeColor.Red);\n\t\t\t\trightRotate(T, x.parent);\n\t\t\t\tw = x.parent.left;\n\t\t\t}\n\n\t\t\tif (getNodeColor(w.left) === NodeColor.Black && getNodeColor(w.right) === NodeColor.Black) {\n\t\t\t\tsetNodeColor(w, NodeColor.Red);\n\t\t\t\tx = x.parent;\n\n\t\t\t} else {\n\t\t\t\tif (getNodeColor(w.left) === NodeColor.Black) {\n\t\t\t\t\tsetNodeColor(w.right, NodeColor.Black);\n\t\t\t\t\tsetNodeColor(w, NodeColor.Red);\n\t\t\t\t\tleftRotate(T, w);\n\t\t\t\t\tw = x.parent.left;\n\t\t\t\t}\n\n\t\t\t\tsetNodeColor(w, getNodeColor(x.parent));\n\t\t\t\tsetNodeColor(x.parent, NodeColor.Black);\n\t\t\t\tsetNodeColor(w.left, NodeColor.Black);\n\t\t\t\trightRotate(T, x.parent);\n\t\t\t\tx = T.root;\n\t\t\t}\n\t\t}\n\t}\n\n\tsetNodeColor(x, NodeColor.Black);\n\tresetSentinel();\n}\n\nfunction leftest(node: IntervalNode): IntervalNode {\n\twhile (node.left !== SENTINEL) {\n\t\tnode = node.left;\n\t}\n\treturn node;\n}\n\nfunction resetSentinel(): void {\n\tSENTINEL.parent = SENTINEL;\n\tSENTINEL.delta = 0; // optional\n\tSENTINEL.start = 0; // optional\n\tSENTINEL.end = 0; // optional\n}\n//#endregion\n\n//#region Rotations\nfunction leftRotate(T: IntervalTree, x: IntervalNode): void {\n\tconst y = x.right;\t\t\t\t// set y.\n\n\ty.delta += x.delta;\t\t\t\t// y's delta is no longer influenced by x's delta\n\tif (y.delta < Constants.MIN_SAFE_DELTA || y.delta > Constants.MAX_SAFE_DELTA) {\n\t\tT.requestNormalizeDelta = true;\n\t}\n\ty.start += x.delta;\n\ty.end += x.delta;\n\n\tx.right = y.left;\t\t\t\t// turn y's left subtree into x's right subtree.\n\tif (y.left !== SENTINEL) {\n\t\ty.left.parent = x;\n\t}\n\ty.parent = x.parent;\t\t\t// link x's parent to y.\n\tif (x.parent === SENTINEL) {\n\t\tT.root = y;\n\t} else if (x === x.parent.left) {\n\t\tx.parent.left = y;\n\t} else {\n\t\tx.parent.right = y;\n\t}\n\n\ty.left = x;\t\t\t\t\t\t// put x on y's left.\n\tx.parent = y;\n\n\trecomputeMaxEnd(x);\n\trecomputeMaxEnd(y);\n}\n\nfunction rightRotate(T: IntervalTree, y: IntervalNode): void {\n\tconst x = y.left;\n\n\ty.delta -= x.delta;\n\tif (y.delta < Constants.MIN_SAFE_DELTA || y.delta > Constants.MAX_SAFE_DELTA) {\n\t\tT.requestNormalizeDelta = true;\n\t}\n\ty.start -= x.delta;\n\ty.end -= x.delta;\n\n\ty.left = x.right;\n\tif (x.right !== SENTINEL) {\n\t\tx.right.parent = y;\n\t}\n\tx.parent = y.parent;\n\tif (y.parent === SENTINEL) {\n\t\tT.root = x;\n\t} else if (y === y.parent.right) {\n\t\ty.parent.right = x;\n\t} else {\n\t\ty.parent.left = x;\n\t}\n\n\tx.right = y;\n\ty.parent = x;\n\n\trecomputeMaxEnd(y);\n\trecomputeMaxEnd(x);\n}\n//#endregion\n\n//#region max end computation\n\nfunction computeMaxEnd(node: IntervalNode): number {\n\tlet maxEnd = node.end;\n\tif (node.left !== SENTINEL) {\n\t\tconst leftMaxEnd = node.left.maxEnd;\n\t\tif (leftMaxEnd > maxEnd) {\n\t\t\tmaxEnd = leftMaxEnd;\n\t\t}\n\t}\n\tif (node.right !== SENTINEL) {\n\t\tconst rightMaxEnd = node.right.maxEnd + node.delta;\n\t\tif (rightMaxEnd > maxEnd) {\n\t\t\tmaxEnd = rightMaxEnd;\n\t\t}\n\t}\n\treturn maxEnd;\n}\n\nexport function recomputeMaxEnd(node: IntervalNode): void {\n\tnode.maxEnd = computeMaxEnd(node);\n}\n\nfunction recomputeMaxEndWalkToRoot(node: IntervalNode): void {\n\twhile (node !== SENTINEL) {\n\n\t\tconst maxEnd = computeMaxEnd(node);\n\n\t\tif (node.maxEnd === maxEnd) {\n\t\t\t// no need to go further\n\t\t\treturn;\n\t\t}\n\n\t\tnode.maxEnd = maxEnd;\n\t\tnode = node.parent;\n\t}\n}\n\n//#endregion\n\n//#region utils\nexport function intervalCompare(aStart: number, aEnd: number, bStart: number, bEnd: number): number {\n\tif (aStart === bStart) {\n\t\treturn aEnd - bEnd;\n\t}\n\treturn aStart - bStart;\n}\n//#endregion\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\nimport { Piece, PieceTreeBase } from 'vs/editor/common/model/pieceTreeTextBuffer/pieceTreeBase';\n\nexport class TreeNode {\n\tparent: TreeNode;\n\tleft: TreeNode;\n\tright: TreeNode;\n\tcolor: NodeColor;\n\n\t// Piece\n\tpiece: Piece;\n\tsize_left: number; // size of the left subtree (not inorder)\n\tlf_left: number; // line feeds cnt in the left subtree (not in order)\n\n\tconstructor(piece: Piece, color: NodeColor) {\n\t\tthis.piece = piece;\n\t\tthis.color = color;\n\t\tthis.size_left = 0;\n\t\tthis.lf_left = 0;\n\t\tthis.parent = this;\n\t\tthis.left = this;\n\t\tthis.right = this;\n\t}\n\n\tpublic next(): TreeNode {\n\t\tif (this.right !== SENTINEL) {\n\t\t\treturn leftest(this.right);\n\t\t}\n\n\t\tlet node: TreeNode = this;\n\n\t\twhile (node.parent !== SENTINEL) {\n\t\t\tif (node.parent.left === node) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tnode = node.parent;\n\t\t}\n\n\t\tif (node.parent === SENTINEL) {\n\t\t\treturn SENTINEL;\n\t\t} else {\n\t\t\treturn node.parent;\n\t\t}\n\t}\n\n\tpublic prev(): TreeNode {\n\t\tif (this.left !== SENTINEL) {\n\t\t\treturn righttest(this.left);\n\t\t}\n\n\t\tlet node: TreeNode = this;\n\n\t\twhile (node.parent !== SENTINEL) {\n\t\t\tif (node.parent.right === node) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tnode = node.parent;\n\t\t}\n\n\t\tif (node.parent === SENTINEL) {\n\t\t\treturn SENTINEL;\n\t\t} else {\n\t\t\treturn node.parent;\n\t\t}\n\t}\n\n\tpublic detach(): void {\n\t\tthis.parent = null!;\n\t\tthis.left = null!;\n\t\tthis.right = null!;\n\t}\n}\n\nexport const enum NodeColor {\n\tBlack = 0,\n\tRed = 1,\n}\n\nexport const SENTINEL: TreeNode = new TreeNode(null!, NodeColor.Black);\nSENTINEL.parent = SENTINEL;\nSENTINEL.left = SENTINEL;\nSENTINEL.right = SENTINEL;\nSENTINEL.color = NodeColor.Black;\n\nexport function leftest(node: TreeNode): TreeNode {\n\twhile (node.left !== SENTINEL) {\n\t\tnode = node.left;\n\t}\n\treturn node;\n}\n\nexport function righttest(node: TreeNode): TreeNode {\n\twhile (node.right !== SENTINEL) {\n\t\tnode = node.right;\n\t}\n\treturn node;\n}\n\nfunction calculateSize(node: TreeNode): number {\n\tif (node === SENTINEL) {\n\t\treturn 0;\n\t}\n\n\treturn node.size_left + node.piece.length + calculateSize(node.right);\n}\n\nfunction calculateLF(node: TreeNode): number {\n\tif (node === SENTINEL) {\n\t\treturn 0;\n\t}\n\n\treturn node.lf_left + node.piece.lineFeedCnt + calculateLF(node.right);\n}\n\nfunction resetSentinel(): void {\n\tSENTINEL.parent = SENTINEL;\n}\n\nexport function leftRotate(tree: PieceTreeBase, x: TreeNode) {\n\tconst y = x.right;\n\n\t// fix size_left\n\ty.size_left += x.size_left + (x.piece ? x.piece.length : 0);\n\ty.lf_left += x.lf_left + (x.piece ? x.piece.lineFeedCnt : 0);\n\tx.right = y.left;\n\n\tif (y.left !== SENTINEL) {\n\t\ty.left.parent = x;\n\t}\n\ty.parent = x.parent;\n\tif (x.parent === SENTINEL) {\n\t\ttree.root = y;\n\t} else if (x.parent.left === x) {\n\t\tx.parent.left = y;\n\t} else {\n\t\tx.parent.right = y;\n\t}\n\ty.left = x;\n\tx.parent = y;\n}\n\nexport function rightRotate(tree: PieceTreeBase, y: TreeNode) {\n\tconst x = y.left;\n\ty.left = x.right;\n\tif (x.right !== SENTINEL) {\n\t\tx.right.parent = y;\n\t}\n\tx.parent = y.parent;\n\n\t// fix size_left\n\ty.size_left -= x.size_left + (x.piece ? x.piece.length : 0);\n\ty.lf_left -= x.lf_left + (x.piece ? x.piece.lineFeedCnt : 0);\n\n\tif (y.parent === SENTINEL) {\n\t\ttree.root = x;\n\t} else if (y === y.parent.right) {\n\t\ty.parent.right = x;\n\t} else {\n\t\ty.parent.left = x;\n\t}\n\n\tx.right = y;\n\ty.parent = x;\n}\n\nexport function rbDelete(tree: PieceTreeBase, z: TreeNode) {\n\tlet x: TreeNode;\n\tlet y: TreeNode;\n\n\tif (z.left === SENTINEL) {\n\t\ty = z;\n\t\tx = y.right;\n\t} else if (z.right === SENTINEL) {\n\t\ty = z;\n\t\tx = y.left;\n\t} else {\n\t\ty = leftest(z.right);\n\t\tx = y.right;\n\t}\n\n\tif (y === tree.root) {\n\t\ttree.root = x;\n\n\t\t// if x is null, we are removing the only node\n\t\tx.color = NodeColor.Black;\n\t\tz.detach();\n\t\tresetSentinel();\n\t\ttree.root.parent = SENTINEL;\n\n\t\treturn;\n\t}\n\n\tconst yWasRed = (y.color === NodeColor.Red);\n\n\tif (y === y.parent.left) {\n\t\ty.parent.left = x;\n\t} else {\n\t\ty.parent.right = x;\n\t}\n\n\tif (y === z) {\n\t\tx.parent = y.parent;\n\t\trecomputeTreeMetadata(tree, x);\n\t} else {\n\t\tif (y.parent === z) {\n\t\t\tx.parent = y;\n\t\t} else {\n\t\t\tx.parent = y.parent;\n\t\t}\n\n\t\t// as we make changes to x's hierarchy, update size_left of subtree first\n\t\trecomputeTreeMetadata(tree, x);\n\n\t\ty.left = z.left;\n\t\ty.right = z.right;\n\t\ty.parent = z.parent;\n\t\ty.color = z.color;\n\n\t\tif (z === tree.root) {\n\t\t\ttree.root = y;\n\t\t} else {\n\t\t\tif (z === z.parent.left) {\n\t\t\t\tz.parent.left = y;\n\t\t\t} else {\n\t\t\t\tz.parent.right = y;\n\t\t\t}\n\t\t}\n\n\t\tif (y.left !== SENTINEL) {\n\t\t\ty.left.parent = y;\n\t\t}\n\t\tif (y.right !== SENTINEL) {\n\t\t\ty.right.parent = y;\n\t\t}\n\t\t// update metadata\n\t\t// we replace z with y, so in this sub tree, the length change is z.item.length\n\t\ty.size_left = z.size_left;\n\t\ty.lf_left = z.lf_left;\n\t\trecomputeTreeMetadata(tree, y);\n\t}\n\n\tz.detach();\n\n\tif (x.parent.left === x) {\n\t\tconst newSizeLeft = calculateSize(x);\n\t\tconst newLFLeft = calculateLF(x);\n\t\tif (newSizeLeft !== x.parent.size_left || newLFLeft !== x.parent.lf_left) {\n\t\t\tconst delta = newSizeLeft - x.parent.size_left;\n\t\t\tconst lf_delta = newLFLeft - x.parent.lf_left;\n\t\t\tx.parent.size_left = newSizeLeft;\n\t\t\tx.parent.lf_left = newLFLeft;\n\t\t\tupdateTreeMetadata(tree, x.parent, delta, lf_delta);\n\t\t}\n\t}\n\n\trecomputeTreeMetadata(tree, x.parent);\n\n\tif (yWasRed) {\n\t\tresetSentinel();\n\t\treturn;\n\t}\n\n\t// RB-DELETE-FIXUP\n\tlet w: TreeNode;\n\twhile (x !== tree.root && x.color === NodeColor.Black) {\n\t\tif (x === x.parent.left) {\n\t\t\tw = x.parent.right;\n\n\t\t\tif (w.color === NodeColor.Red) {\n\t\t\t\tw.color = NodeColor.Black;\n\t\t\t\tx.parent.color = NodeColor.Red;\n\t\t\t\tleftRotate(tree, x.parent);\n\t\t\t\tw = x.parent.right;\n\t\t\t}\n\n\t\t\tif (w.left.color === NodeColor.Black && w.right.color === NodeColor.Black) {\n\t\t\t\tw.color = NodeColor.Red;\n\t\t\t\tx = x.parent;\n\t\t\t} else {\n\t\t\t\tif (w.right.color === NodeColor.Black) {\n\t\t\t\t\tw.left.color = NodeColor.Black;\n\t\t\t\t\tw.color = NodeColor.Red;\n\t\t\t\t\trightRotate(tree, w);\n\t\t\t\t\tw = x.parent.right;\n\t\t\t\t}\n\n\t\t\t\tw.color = x.parent.color;\n\t\t\t\tx.parent.color = NodeColor.Black;\n\t\t\t\tw.right.color = NodeColor.Black;\n\t\t\t\tleftRotate(tree, x.parent);\n\t\t\t\tx = tree.root;\n\t\t\t}\n\t\t} else {\n\t\t\tw = x.parent.left;\n\n\t\t\tif (w.color === NodeColor.Red) {\n\t\t\t\tw.color = NodeColor.Black;\n\t\t\t\tx.parent.color = NodeColor.Red;\n\t\t\t\trightRotate(tree, x.parent);\n\t\t\t\tw = x.parent.left;\n\t\t\t}\n\n\t\t\tif (w.left.color === NodeColor.Black && w.right.color === NodeColor.Black) {\n\t\t\t\tw.color = NodeColor.Red;\n\t\t\t\tx = x.parent;\n\n\t\t\t} else {\n\t\t\t\tif (w.left.color === NodeColor.Black) {\n\t\t\t\t\tw.right.color = NodeColor.Black;\n\t\t\t\t\tw.color = NodeColor.Red;\n\t\t\t\t\tleftRotate(tree, w);\n\t\t\t\t\tw = x.parent.left;\n\t\t\t\t}\n\n\t\t\t\tw.color = x.parent.color;\n\t\t\t\tx.parent.color = NodeColor.Black;\n\t\t\t\tw.left.color = NodeColor.Black;\n\t\t\t\trightRotate(tree, x.parent);\n\t\t\t\tx = tree.root;\n\t\t\t}\n\t\t}\n\t}\n\tx.color = NodeColor.Black;\n\tresetSentinel();\n}\n\nexport function fixInsert(tree: PieceTreeBase, x: TreeNode) {\n\trecomputeTreeMetadata(tree, x);\n\n\twhile (x !== tree.root && x.parent.color === NodeColor.Red) {\n\t\tif (x.parent === x.parent.parent.left) {\n\t\t\tconst y = x.parent.parent.right;\n\n\t\t\tif (y.color === NodeColor.Red) {\n\t\t\t\tx.parent.color = NodeColor.Black;\n\t\t\t\ty.color = NodeColor.Black;\n\t\t\t\tx.parent.parent.color = NodeColor.Red;\n\t\t\t\tx = x.parent.parent;\n\t\t\t} else {\n\t\t\t\tif (x === x.parent.right) {\n\t\t\t\t\tx = x.parent;\n\t\t\t\t\tleftRotate(tree, x);\n\t\t\t\t}\n\n\t\t\t\tx.parent.color = NodeColor.Black;\n\t\t\t\tx.parent.parent.color = NodeColor.Red;\n\t\t\t\trightRotate(tree, x.parent.parent);\n\t\t\t}\n\t\t} else {\n\t\t\tconst y = x.parent.parent.left;\n\n\t\t\tif (y.color === NodeColor.Red) {\n\t\t\t\tx.parent.color = NodeColor.Black;\n\t\t\t\ty.color = NodeColor.Black;\n\t\t\t\tx.parent.parent.color = NodeColor.Red;\n\t\t\t\tx = x.parent.parent;\n\t\t\t} else {\n\t\t\t\tif (x === x.parent.left) {\n\t\t\t\t\tx = x.parent;\n\t\t\t\t\trightRotate(tree, x);\n\t\t\t\t}\n\t\t\t\tx.parent.color = NodeColor.Black;\n\t\t\t\tx.parent.parent.color = NodeColor.Red;\n\t\t\t\tleftRotate(tree, x.parent.parent);\n\t\t\t}\n\t\t}\n\t}\n\n\ttree.root.color = NodeColor.Black;\n}\n\nexport function updateTreeMetadata(tree: PieceTreeBase, x: TreeNode, delta: number, lineFeedCntDelta: number): void {\n\t// node length change or line feed count change\n\twhile (x !== tree.root && x !== SENTINEL) {\n\t\tif (x.parent.left === x) {\n\t\t\tx.parent.size_left += delta;\n\t\t\tx.parent.lf_left += lineFeedCntDelta;\n\t\t}\n\n\t\tx = x.parent;\n\t}\n}\n\nexport function recomputeTreeMetadata(tree: PieceTreeBase, x: TreeNode) {\n\tlet delta = 0;\n\tlet lf_delta = 0;\n\tif (x === tree.root) {\n\t\treturn;\n\t}\n\n\t// go upwards till the node whose left subtree is changed.\n\twhile (x !== tree.root && x === x.parent.right) {\n\t\tx = x.parent;\n\t}\n\n\tif (x === tree.root) {\n\t\t// well, it means we add a node to the end (inorder)\n\t\treturn;\n\t}\n\n\t// x is the node whose right subtree is changed.\n\tx = x.parent;\n\n\tdelta = calculateSize(x.left) - x.size_left;\n\tlf_delta = calculateLF(x.left) - x.lf_left;\n\tx.size_left += delta;\n\tx.lf_left += lf_delta;\n\n\n\t// go upwards till root. O(logN)\n\twhile (x !== tree.root && (delta !== 0 || lf_delta !== 0)) {\n\t\tif (x.parent.left === x) {\n\t\t\tx.parent.size_left += delta;\n\t\t\tx.parent.lf_left += lf_delta;\n\t\t}\n\n\t\tx = x.parent;\n\t}\n}\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\nimport { arrayInsert } from 'vs/base/common/arrays';\nimport { toUint32 } from 'vs/base/common/uint';\n\nexport class PrefixSumComputer {\n\n\t/**\n\t * values[i] is the value at index i\n\t */\n\tprivate values: Uint32Array;\n\n\t/**\n\t * prefixSum[i] = SUM(heights[j]), 0 <= j <= i\n\t */\n\tprivate prefixSum: Uint32Array;\n\n\t/**\n\t * prefixSum[i], 0 <= i <= prefixSumValidIndex can be trusted\n\t */\n\tprivate readonly prefixSumValidIndex: Int32Array;\n\n\tconstructor(values: Uint32Array) {\n\t\tthis.values = values;\n\t\tthis.prefixSum = new Uint32Array(values.length);\n\t\tthis.prefixSumValidIndex = new Int32Array(1);\n\t\tthis.prefixSumValidIndex[0] = -1;\n\t}\n\n\tpublic insertValues(insertIndex: number, insertValues: Uint32Array): boolean {\n\t\tinsertIndex = toUint32(insertIndex);\n\t\tconst oldValues = this.values;\n\t\tconst oldPrefixSum = this.prefixSum;\n\t\tconst insertValuesLen = insertValues.length;\n\n\t\tif (insertValuesLen === 0) {\n\t\t\treturn false;\n\t\t}\n\n\t\tthis.values = new Uint32Array(oldValues.length + insertValuesLen);\n\t\tthis.values.set(oldValues.subarray(0, insertIndex), 0);\n\t\tthis.values.set(oldValues.subarray(insertIndex), insertIndex + insertValuesLen);\n\t\tthis.values.set(insertValues, insertIndex);\n\n\t\tif (insertIndex - 1 < this.prefixSumValidIndex[0]) {\n\t\t\tthis.prefixSumValidIndex[0] = insertIndex - 1;\n\t\t}\n\n\t\tthis.prefixSum = new Uint32Array(this.values.length);\n\t\tif (this.prefixSumValidIndex[0] >= 0) {\n\t\t\tthis.prefixSum.set(oldPrefixSum.subarray(0, this.prefixSumValidIndex[0] + 1));\n\t\t}\n\t\treturn true;\n\t}\n\n\tpublic setValue(index: number, value: number): boolean {\n\t\tindex = toUint32(index);\n\t\tvalue = toUint32(value);\n\n\t\tif (this.values[index] === value) {\n\t\t\treturn false;\n\t\t}\n\t\tthis.values[index] = value;\n\t\tif (index - 1 < this.prefixSumValidIndex[0]) {\n\t\t\tthis.prefixSumValidIndex[0] = index - 1;\n\t\t}\n\t\treturn true;\n\t}\n\n\tpublic removeValues(startIndex: number, count: number): boolean {\n\t\tstartIndex = toUint32(startIndex);\n\t\tcount = toUint32(count);\n\n\t\tconst oldValues = this.values;\n\t\tconst oldPrefixSum = this.prefixSum;\n\n\t\tif (startIndex >= oldValues.length) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst maxCount = oldValues.length - startIndex;\n\t\tif (count >= maxCount) {\n\t\t\tcount = maxCount;\n\t\t}\n\n\t\tif (count === 0) {\n\t\t\treturn false;\n\t\t}\n\n\t\tthis.values = new Uint32Array(oldValues.length - count);\n\t\tthis.values.set(oldValues.subarray(0, startIndex), 0);\n\t\tthis.values.set(oldValues.subarray(startIndex + count), startIndex);\n\n\t\tthis.prefixSum = new Uint32Array(this.values.length);\n\t\tif (startIndex - 1 < this.prefixSumValidIndex[0]) {\n\t\t\tthis.prefixSumValidIndex[0] = startIndex - 1;\n\t\t}\n\t\tif (this.prefixSumValidIndex[0] >= 0) {\n\t\t\tthis.prefixSum.set(oldPrefixSum.subarray(0, this.prefixSumValidIndex[0] + 1));\n\t\t}\n\t\treturn true;\n\t}\n\n\tpublic getTotalSum(): number {\n\t\tif (this.values.length === 0) {\n\t\t\treturn 0;\n\t\t}\n\t\treturn this._getPrefixSum(this.values.length - 1);\n\t}\n\n\t/**\n\t * Returns the sum of the first `index + 1` many items.\n\t * @returns `SUM(0 <= j <= index, values[j])`.\n\t */\n\tpublic getPrefixSum(index: number): number {\n\t\tif (index < 0) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tindex = toUint32(index);\n\t\treturn this._getPrefixSum(index);\n\t}\n\n\tprivate _getPrefixSum(index: number): number {\n\t\tif (index <= this.prefixSumValidIndex[0]) {\n\t\t\treturn this.prefixSum[index];\n\t\t}\n\n\t\tlet startIndex = this.prefixSumValidIndex[0] + 1;\n\t\tif (startIndex === 0) {\n\t\t\tthis.prefixSum[0] = this.values[0];\n\t\t\tstartIndex++;\n\t\t}\n\n\t\tif (index >= this.values.length) {\n\t\t\tindex = this.values.length - 1;\n\t\t}\n\n\t\tfor (let i = startIndex; i <= index; i++) {\n\t\t\tthis.prefixSum[i] = this.prefixSum[i - 1] + this.values[i];\n\t\t}\n\t\tthis.prefixSumValidIndex[0] = Math.max(this.prefixSumValidIndex[0], index);\n\t\treturn this.prefixSum[index];\n\t}\n\n\tpublic getIndexOf(sum: number): PrefixSumIndexOfResult {\n\t\tsum = Math.floor(sum);\n\n\t\t// Compute all sums (to get a fully valid prefixSum)\n\t\tthis.getTotalSum();\n\n\t\tlet low = 0;\n\t\tlet high = this.values.length - 1;\n\t\tlet mid = 0;\n\t\tlet midStop = 0;\n\t\tlet midStart = 0;\n\n\t\twhile (low <= high) {\n\t\t\tmid = low + ((high - low) / 2) | 0;\n\n\t\t\tmidStop = this.prefixSum[mid];\n\t\t\tmidStart = midStop - this.values[mid];\n\n\t\t\tif (sum < midStart) {\n\t\t\t\thigh = mid - 1;\n\t\t\t} else if (sum >= midStop) {\n\t\t\t\tlow = mid + 1;\n\t\t\t} else {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn new PrefixSumIndexOfResult(mid, sum - midStart);\n\t}\n}\n\n/**\n * {@link getIndexOf} has an amortized runtime complexity of O(1).\n *\n * ({@link PrefixSumComputer.getIndexOf} is just O(log n))\n*/\nexport class ConstantTimePrefixSumComputer {\n\tprivate _values: number[];\n\tprivate _isValid: boolean;\n\tprivate _validEndIndex: number;\n\n\t/**\n\t * _prefixSum[i] = SUM(values[j]), 0 <= j <= i\n\t */\n\tprivate _prefixSum: number[];\n\n\t/**\n\t * _indexBySum[sum] = idx => _prefixSum[idx - 1] <= sum < _prefixSum[idx]\n\t*/\n\tprivate _indexBySum: number[];\n\n\tconstructor(values: number[]) {\n\t\tthis._values = values;\n\t\tthis._isValid = false;\n\t\tthis._validEndIndex = -1;\n\t\tthis._prefixSum = [];\n\t\tthis._indexBySum = [];\n\t}\n\n\t/**\n\t * @returns SUM(0 <= j < values.length, values[j])\n\t */\n\tpublic getTotalSum(): number {\n\t\tthis._ensureValid();\n\t\treturn this._indexBySum.length;\n\t}\n\n\t/**\n\t * Returns the sum of the first `count` many items.\n\t * @returns `SUM(0 <= j < count, values[j])`.\n\t */\n\tpublic getPrefixSum(count: number): number {\n\t\tthis._ensureValid();\n\t\tif (count === 0) {\n\t\t\treturn 0;\n\t\t}\n\t\treturn this._prefixSum[count - 1];\n\t}\n\n\t/**\n\t * @returns `result`, such that `getPrefixSum(result.index) + result.remainder = sum`\n\t */\n\tpublic getIndexOf(sum: number): PrefixSumIndexOfResult {\n\t\tthis._ensureValid();\n\t\tconst idx = this._indexBySum[sum];\n\t\tconst viewLinesAbove = idx > 0 ? this._prefixSum[idx - 1] : 0;\n\t\treturn new PrefixSumIndexOfResult(idx, sum - viewLinesAbove);\n\t}\n\n\tpublic removeValues(start: number, deleteCount: number): void {\n\t\tthis._values.splice(start, deleteCount);\n\t\tthis._invalidate(start);\n\t}\n\n\tpublic insertValues(insertIndex: number, insertArr: number[]): void {\n\t\tthis._values = arrayInsert(this._values, insertIndex, insertArr);\n\t\tthis._invalidate(insertIndex);\n\t}\n\n\tprivate _invalidate(index: number): void {\n\t\tthis._isValid = false;\n\t\tthis._validEndIndex = Math.min(this._validEndIndex, index - 1);\n\t}\n\n\tprivate _ensureValid(): void {\n\t\tif (this._isValid) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor (let i = this._validEndIndex + 1, len = this._values.length; i < len; i++) {\n\t\t\tconst value = this._values[i];\n\t\t\tconst sumAbove = i > 0 ? this._prefixSum[i - 1] : 0;\n\n\t\t\tthis._prefixSum[i] = sumAbove + value;\n\t\t\tfor (let j = 0; j < value; j++) {\n\t\t\t\tthis._indexBySum[sumAbove + j] = i;\n\t\t\t}\n\t\t}\n\n\t\t// trim things\n\t\tthis._prefixSum.length = this._values.length;\n\t\tthis._indexBySum.length = this._prefixSum[this._prefixSum.length - 1];\n\n\t\t// mark as valid\n\t\tthis._isValid = true;\n\t\tthis._validEndIndex = this._values.length - 1;\n\t}\n\n\tpublic setValue(index: number, value: number): void {\n\t\tif (this._values[index] === value) {\n\t\t\t// no change\n\t\t\treturn;\n\t\t}\n\t\tthis._values[index] = value;\n\t\tthis._invalidate(index);\n\t}\n}\n\n\nexport class PrefixSumIndexOfResult {\n\t_prefixSumIndexOfResultBrand: void = undefined;\n\n\tconstructor(\n\t\tpublic readonly index: number,\n\t\tpublic readonly remainder: number\n\t) {\n\t\tthis.index = index;\n\t\tthis.remainder = remainder;\n\t}\n}\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\nimport { splitLines } from 'vs/base/common/strings';\nimport { URI } from 'vs/base/common/uri';\nimport { Position } from 'vs/editor/common/core/position';\nimport { IRange } from 'vs/editor/common/core/range';\nimport { IModelContentChange } from 'vs/editor/common/textModelEvents';\nimport { PrefixSumComputer } from 'vs/editor/common/model/prefixSumComputer';\n\nexport interface IModelChangedEvent {\n\t/**\n\t * The actual changes.\n\t */\n\treadonly changes: IModelContentChange[];\n\t/**\n\t * The (new) end-of-line character.\n\t */\n\treadonly eol: string;\n\t/**\n\t * The new version id the model has transitioned to.\n\t */\n\treadonly versionId: number;\n}\n\nexport interface IMirrorTextModel {\n\treadonly version: number;\n}\n\nexport class MirrorTextModel implements IMirrorTextModel {\n\n\tprotected _uri: URI;\n\tprotected _lines: string[];\n\tprotected _eol: string;\n\tprotected _versionId: number;\n\tprotected _lineStarts: PrefixSumComputer | null;\n\tprivate _cachedTextValue: string | null;\n\n\tconstructor(uri: URI, lines: string[], eol: string, versionId: number) {\n\t\tthis._uri = uri;\n\t\tthis._lines = lines;\n\t\tthis._eol = eol;\n\t\tthis._versionId = versionId;\n\t\tthis._lineStarts = null;\n\t\tthis._cachedTextValue = null;\n\t}\n\n\tdispose(): void {\n\t\tthis._lines.length = 0;\n\t}\n\n\tget version(): number {\n\t\treturn this._versionId;\n\t}\n\n\tgetText(): string {\n\t\tif (this._cachedTextValue === null) {\n\t\t\tthis._cachedTextValue = this._lines.join(this._eol);\n\t\t}\n\t\treturn this._cachedTextValue;\n\t}\n\n\tonEvents(e: IModelChangedEvent): void {\n\t\tif (e.eol && e.eol !== this._eol) {\n\t\t\tthis._eol = e.eol;\n\t\t\tthis._lineStarts = null;\n\t\t}\n\n\t\t// Update my lines\n\t\tconst changes = e.changes;\n\t\tfor (const change of changes) {\n\t\t\tthis._acceptDeleteRange(change.range);\n\t\t\tthis._acceptInsertText(new Position(change.range.startLineNumber, change.range.startColumn), change.text);\n\t\t}\n\n\t\tthis._versionId = e.versionId;\n\t\tthis._cachedTextValue = null;\n\t}\n\n\tprotected _ensureLineStarts(): void {\n\t\tif (!this._lineStarts) {\n\t\t\tconst eolLength = this._eol.length;\n\t\t\tconst linesLength = this._lines.length;\n\t\t\tconst lineStartValues = new Uint32Array(linesLength);\n\t\t\tfor (let i = 0; i < linesLength; i++) {\n\t\t\t\tlineStartValues[i] = this._lines[i].length + eolLength;\n\t\t\t}\n\t\t\tthis._lineStarts = new PrefixSumComputer(lineStartValues);\n\t\t}\n\t}\n\n\t/**\n\t * All changes to a line's text go through this method\n\t */\n\tprivate _setLineText(lineIndex: number, newValue: string): void {\n\t\tthis._lines[lineIndex] = newValue;\n\t\tif (this._lineStarts) {\n\t\t\t// update prefix sum\n\t\t\tthis._lineStarts.setValue(lineIndex, this._lines[lineIndex].length + this._eol.length);\n\t\t}\n\t}\n\n\tprivate _acceptDeleteRange(range: IRange): void {\n\n\t\tif (range.startLineNumber === range.endLineNumber) {\n\t\t\tif (range.startColumn === range.endColumn) {\n\t\t\t\t// Nothing to delete\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// Delete text on the affected line\n\t\t\tthis._setLineText(range.startLineNumber - 1,\n\t\t\t\tthis._lines[range.startLineNumber - 1].substring(0, range.startColumn - 1)\n\t\t\t\t+ this._lines[range.startLineNumber - 1].substring(range.endColumn - 1)\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\t// Take remaining text on last line and append it to remaining text on first line\n\t\tthis._setLineText(range.startLineNumber - 1,\n\t\t\tthis._lines[range.startLineNumber - 1].substring(0, range.startColumn - 1)\n\t\t\t+ this._lines[range.endLineNumber - 1].substring(range.endColumn - 1)\n\t\t);\n\n\t\t// Delete middle lines\n\t\tthis._lines.splice(range.startLineNumber, range.endLineNumber - range.startLineNumber);\n\t\tif (this._lineStarts) {\n\t\t\t// update prefix sum\n\t\t\tthis._lineStarts.removeValues(range.startLineNumber, range.endLineNumber - range.startLineNumber);\n\t\t}\n\t}\n\n\tprivate _acceptInsertText(position: Position, insertText: string): void {\n\t\tif (insertText.length === 0) {\n\t\t\t// Nothing to insert\n\t\t\treturn;\n\t\t}\n\t\tconst insertLines = splitLines(insertText);\n\t\tif (insertLines.length === 1) {\n\t\t\t// Inserting text on one line\n\t\t\tthis._setLineText(position.lineNumber - 1,\n\t\t\t\tthis._lines[position.lineNumber - 1].substring(0, position.column - 1)\n\t\t\t\t+ insertLines[0]\n\t\t\t\t+ this._lines[position.lineNumber - 1].substring(position.column - 1)\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\t// Append overflowing text from first line to the end of text to insert\n\t\tinsertLines[insertLines.length - 1] += this._lines[position.lineNumber - 1].substring(position.column - 1);\n\n\t\t// Delete overflowing text from first line and insert text on first line\n\t\tthis._setLineText(position.lineNumber - 1,\n\t\t\tthis._lines[position.lineNumber - 1].substring(0, position.column - 1)\n\t\t\t+ insertLines[0]\n\t\t);\n\n\t\t// Insert new lines & store lengths\n\t\tconst newLengths = new Uint32Array(insertLines.length - 1);\n\t\tfor (let i = 1; i < insertLines.length; i++) {\n\t\t\tthis._lines.splice(position.lineNumber + i - 1, 0, insertLines[i]);\n\t\t\tnewLengths[i - 1] = insertLines[i].length + this._eol.length;\n\t\t}\n\n\t\tif (this._lineStarts) {\n\t\t\t// update prefix sum\n\t\t\tthis._lineStarts.insertValues(position.lineNumber, newLengths);\n\t\t}\n\t}\n}\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\nimport { Disposable } from 'vs/base/common/lifecycle';\n\nexport class TextModelPart extends Disposable {\n\tprivate _isDisposed = false;\n\n\tpublic override dispose(): void {\n\t\tsuper.dispose();\n\t\tthis._isDisposed = true;\n\t}\n\tprotected assertNotDisposed(): void {\n\t\tif (this._isDisposed) {\n\t\t\tthrow new Error('TextModelPart is disposed!');\n\t\t}\n\t}\n}\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\nimport { CharCode } from 'vs/base/common/charCode';\nimport * as strings from 'vs/base/common/strings';\nimport { WordCharacterClass, WordCharacterClassifier, getMapForWordSeparators } from 'vs/editor/common/core/wordCharacterClassifier';\nimport { Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\nimport { EndOfLinePreference, FindMatch, SearchData } from 'vs/editor/common/model';\nimport { TextModel } from 'vs/editor/common/model/textModel';\n\nconst LIMIT_FIND_COUNT = 999;\n\nexport class SearchParams {\n\tpublic readonly searchString: string;\n\tpublic readonly isRegex: boolean;\n\tpublic readonly matchCase: boolean;\n\tpublic readonly wordSeparators: string | null;\n\n\tconstructor(searchString: string, isRegex: boolean, matchCase: boolean, wordSeparators: string | null) {\n\t\tthis.searchString = searchString;\n\t\tthis.isRegex = isRegex;\n\t\tthis.matchCase = matchCase;\n\t\tthis.wordSeparators = wordSeparators;\n\t}\n\n\tpublic parseSearchRequest(): SearchData | null {\n\t\tif (this.searchString === '') {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Try to create a RegExp out of the params\n\t\tlet multiline: boolean;\n\t\tif (this.isRegex) {\n\t\t\tmultiline = isMultilineRegexSource(this.searchString);\n\t\t} else {\n\t\t\tmultiline = (this.searchString.indexOf('\\n') >= 0);\n\t\t}\n\n\t\tlet regex: RegExp | null = null;\n\t\ttry {\n\t\t\tregex = strings.createRegExp(this.searchString, this.isRegex, {\n\t\t\t\tmatchCase: this.matchCase,\n\t\t\t\twholeWord: false,\n\t\t\t\tmultiline: multiline,\n\t\t\t\tglobal: true,\n\t\t\t\tunicode: true\n\t\t\t});\n\t\t} catch (err) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif (!regex) {\n\t\t\treturn null;\n\t\t}\n\n\t\tlet canUseSimpleSearch = (!this.isRegex && !multiline);\n\t\tif (canUseSimpleSearch && this.searchString.toLowerCase() !== this.searchString.toUpperCase()) {\n\t\t\t// casing might make a difference\n\t\t\tcanUseSimpleSearch = this.matchCase;\n\t\t}\n\n\t\treturn new SearchData(regex, this.wordSeparators ? getMapForWordSeparators(this.wordSeparators, []) : null, canUseSimpleSearch ? this.searchString : null);\n\t}\n}\n\nexport function isMultilineRegexSource(searchString: string): boolean {\n\tif (!searchString || searchString.length === 0) {\n\t\treturn false;\n\t}\n\n\tfor (let i = 0, len = searchString.length; i < len; i++) {\n\t\tconst chCode = searchString.charCodeAt(i);\n\n\t\tif (chCode === CharCode.LineFeed) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif (chCode === CharCode.Backslash) {\n\n\t\t\t// move to next char\n\t\t\ti++;\n\n\t\t\tif (i >= len) {\n\t\t\t\t// string ends with a \\\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tconst nextChCode = searchString.charCodeAt(i);\n\t\t\tif (nextChCode === CharCode.n || nextChCode === CharCode.r || nextChCode === CharCode.W) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn false;\n}\n\nexport function createFindMatch(range: Range, rawMatches: RegExpExecArray, captureMatches: boolean): FindMatch {\n\tif (!captureMatches) {\n\t\treturn new FindMatch(range, null);\n\t}\n\tconst matches: string[] = [];\n\tfor (let i = 0, len = rawMatches.length; i < len; i++) {\n\t\tmatches[i] = rawMatches[i];\n\t}\n\treturn new FindMatch(range, matches);\n}\n\nclass LineFeedCounter {\n\n\tprivate readonly _lineFeedsOffsets: number[];\n\n\tconstructor(text: string) {\n\t\tconst lineFeedsOffsets: number[] = [];\n\t\tlet lineFeedsOffsetsLen = 0;\n\t\tfor (let i = 0, textLen = text.length; i < textLen; i++) {\n\t\t\tif (text.charCodeAt(i) === CharCode.LineFeed) {\n\t\t\t\tlineFeedsOffsets[lineFeedsOffsetsLen++] = i;\n\t\t\t}\n\t\t}\n\t\tthis._lineFeedsOffsets = lineFeedsOffsets;\n\t}\n\n\tpublic findLineFeedCountBeforeOffset(offset: number): number {\n\t\tconst lineFeedsOffsets = this._lineFeedsOffsets;\n\t\tlet min = 0;\n\t\tlet max = lineFeedsOffsets.length - 1;\n\n\t\tif (max === -1) {\n\t\t\t// no line feeds\n\t\t\treturn 0;\n\t\t}\n\n\t\tif (offset <= lineFeedsOffsets[0]) {\n\t\t\t// before first line feed\n\t\t\treturn 0;\n\t\t}\n\n\t\twhile (min < max) {\n\t\t\tconst mid = min + ((max - min) / 2 >> 0);\n\n\t\t\tif (lineFeedsOffsets[mid] >= offset) {\n\t\t\t\tmax = mid - 1;\n\t\t\t} else {\n\t\t\t\tif (lineFeedsOffsets[mid + 1] >= offset) {\n\t\t\t\t\t// bingo!\n\t\t\t\t\tmin = mid;\n\t\t\t\t\tmax = mid;\n\t\t\t\t} else {\n\t\t\t\t\tmin = mid + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn min + 1;\n\t}\n}\n\nexport class TextModelSearch {\n\n\tpublic static findMatches(model: TextModel, searchParams: SearchParams, searchRange: Range, captureMatches: boolean, limitResultCount: number): FindMatch[] {\n\t\tconst searchData = searchParams.parseSearchRequest();\n\t\tif (!searchData) {\n\t\t\treturn [];\n\t\t}\n\n\t\tif (searchData.regex.multiline) {\n\t\t\treturn this._doFindMatchesMultiline(model, searchRange, new Searcher(searchData.wordSeparators, searchData.regex), captureMatches, limitResultCount);\n\t\t}\n\t\treturn this._doFindMatchesLineByLine(model, searchRange, searchData, captureMatches, limitResultCount);\n\t}\n\n\t/**\n\t * Multiline search always executes on the lines concatenated with \\n.\n\t * We must therefore compensate for the count of \\n in case the model is CRLF\n\t */\n\tprivate static _getMultilineMatchRange(model: TextModel, deltaOffset: number, text: string, lfCounter: LineFeedCounter | null, matchIndex: number, match0: string): Range {\n\t\tlet startOffset: number;\n\t\tlet lineFeedCountBeforeMatch = 0;\n\t\tif (lfCounter) {\n\t\t\tlineFeedCountBeforeMatch = lfCounter.findLineFeedCountBeforeOffset(matchIndex);\n\t\t\tstartOffset = deltaOffset + matchIndex + lineFeedCountBeforeMatch /* add as many \\r as there were \\n */;\n\t\t} else {\n\t\t\tstartOffset = deltaOffset + matchIndex;\n\t\t}\n\n\t\tlet endOffset: number;\n\t\tif (lfCounter) {\n\t\t\tconst lineFeedCountBeforeEndOfMatch = lfCounter.findLineFeedCountBeforeOffset(matchIndex + match0.length);\n\t\t\tconst lineFeedCountInMatch = lineFeedCountBeforeEndOfMatch - lineFeedCountBeforeMatch;\n\t\t\tendOffset = startOffset + match0.length + lineFeedCountInMatch /* add as many \\r as there were \\n */;\n\t\t} else {\n\t\t\tendOffset = startOffset + match0.length;\n\t\t}\n\n\t\tconst startPosition = model.getPositionAt(startOffset);\n\t\tconst endPosition = model.getPositionAt(endOffset);\n\t\treturn new Range(startPosition.lineNumber, startPosition.column, endPosition.lineNumber, endPosition.column);\n\t}\n\n\tprivate static _doFindMatchesMultiline(model: TextModel, searchRange: Range, searcher: Searcher, captureMatches: boolean, limitResultCount: number): FindMatch[] {\n\t\tconst deltaOffset = model.getOffsetAt(searchRange.getStartPosition());\n\t\t// We always execute multiline search over the lines joined with \\n\n\t\t// This makes it that \\n will match the EOL for both CRLF and LF models\n\t\t// We compensate for offset errors in `_getMultilineMatchRange`\n\t\tconst text = model.getValueInRange(searchRange, EndOfLinePreference.LF);\n\t\tconst lfCounter = (model.getEOL() === '\\r\\n' ? new LineFeedCounter(text) : null);\n\n\t\tconst result: FindMatch[] = [];\n\t\tlet counter = 0;\n\n\t\tlet m: RegExpExecArray | null;\n\t\tsearcher.reset(0);\n\t\twhile ((m = searcher.next(text))) {\n\t\t\tresult[counter++] = createFindMatch(this._getMultilineMatchRange(model, deltaOffset, text, lfCounter, m.index, m[0]), m, captureMatches);\n\t\t\tif (counter >= limitResultCount) {\n\t\t\t\treturn result;\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tprivate static _doFindMatchesLineByLine(model: TextModel, searchRange: Range, searchData: SearchData, captureMatches: boolean, limitResultCount: number): FindMatch[] {\n\t\tconst result: FindMatch[] = [];\n\t\tlet resultLen = 0;\n\n\t\t// Early case for a search range that starts & stops on the same line number\n\t\tif (searchRange.startLineNumber === searchRange.endLineNumber) {\n\t\t\tconst text = model.getLineContent(searchRange.startLineNumber).substring(searchRange.startColumn - 1, searchRange.endColumn - 1);\n\t\t\tresultLen = this._findMatchesInLine(searchData, text, searchRange.startLineNumber, searchRange.startColumn - 1, resultLen, result, captureMatches, limitResultCount);\n\t\t\treturn result;\n\t\t}\n\n\t\t// Collect results from first line\n\t\tconst text = model.getLineContent(searchRange.startLineNumber).substring(searchRange.startColumn - 1);\n\t\tresultLen = this._findMatchesInLine(searchData, text, searchRange.startLineNumber, searchRange.startColumn - 1, resultLen, result, captureMatches, limitResultCount);\n\n\t\t// Collect results from middle lines\n\t\tfor (let lineNumber = searchRange.startLineNumber + 1; lineNumber < searchRange.endLineNumber && resultLen < limitResultCount; lineNumber++) {\n\t\t\tresultLen = this._findMatchesInLine(searchData, model.getLineContent(lineNumber), lineNumber, 0, resultLen, result, captureMatches, limitResultCount);\n\t\t}\n\n\t\t// Collect results from last line\n\t\tif (resultLen < limitResultCount) {\n\t\t\tconst text = model.getLineContent(searchRange.endLineNumber).substring(0, searchRange.endColumn - 1);\n\t\t\tresultLen = this._findMatchesInLine(searchData, text, searchRange.endLineNumber, 0, resultLen, result, captureMatches, limitResultCount);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tprivate static _findMatchesInLine(searchData: SearchData, text: string, lineNumber: number, deltaOffset: number, resultLen: number, result: FindMatch[], captureMatches: boolean, limitResultCount: number): number {\n\t\tconst wordSeparators = searchData.wordSeparators;\n\t\tif (!captureMatches && searchData.simpleSearch) {\n\t\t\tconst searchString = searchData.simpleSearch;\n\t\t\tconst searchStringLen = searchString.length;\n\t\t\tconst textLength = text.length;\n\n\t\t\tlet lastMatchIndex = -searchStringLen;\n\t\t\twhile ((lastMatchIndex = text.indexOf(searchString, lastMatchIndex + searchStringLen)) !== -1) {\n\t\t\t\tif (!wordSeparators || isValidMatch(wordSeparators, text, textLength, lastMatchIndex, searchStringLen)) {\n\t\t\t\t\tresult[resultLen++] = new FindMatch(new Range(lineNumber, lastMatchIndex + 1 + deltaOffset, lineNumber, lastMatchIndex + 1 + searchStringLen + deltaOffset), null);\n\t\t\t\t\tif (resultLen >= limitResultCount) {\n\t\t\t\t\t\treturn resultLen;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn resultLen;\n\t\t}\n\n\t\tconst searcher = new Searcher(searchData.wordSeparators, searchData.regex);\n\t\tlet m: RegExpExecArray | null;\n\t\t// Reset regex to search from the beginning\n\t\tsearcher.reset(0);\n\t\tdo {\n\t\t\tm = searcher.next(text);\n\t\t\tif (m) {\n\t\t\t\tresult[resultLen++] = createFindMatch(new Range(lineNumber, m.index + 1 + deltaOffset, lineNumber, m.index + 1 + m[0].length + deltaOffset), m, captureMatches);\n\t\t\t\tif (resultLen >= limitResultCount) {\n\t\t\t\t\treturn resultLen;\n\t\t\t\t}\n\t\t\t}\n\t\t} while (m);\n\t\treturn resultLen;\n\t}\n\n\tpublic static findNextMatch(model: TextModel, searchParams: SearchParams, searchStart: Position, captureMatches: boolean): FindMatch | null {\n\t\tconst searchData = searchParams.parseSearchRequest();\n\t\tif (!searchData) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst searcher = new Searcher(searchData.wordSeparators, searchData.regex);\n\n\t\tif (searchData.regex.multiline) {\n\t\t\treturn this._doFindNextMatchMultiline(model, searchStart, searcher, captureMatches);\n\t\t}\n\t\treturn this._doFindNextMatchLineByLine(model, searchStart, searcher, captureMatches);\n\t}\n\n\tprivate static _doFindNextMatchMultiline(model: TextModel, searchStart: Position, searcher: Searcher, captureMatches: boolean): FindMatch | null {\n\t\tconst searchTextStart = new Position(searchStart.lineNumber, 1);\n\t\tconst deltaOffset = model.getOffsetAt(searchTextStart);\n\t\tconst lineCount = model.getLineCount();\n\t\t// We always execute multiline search over the lines joined with \\n\n\t\t// This makes it that \\n will match the EOL for both CRLF and LF models\n\t\t// We compensate for offset errors in `_getMultilineMatchRange`\n\t\tconst text = model.getValueInRange(new Range(searchTextStart.lineNumber, searchTextStart.column, lineCount, model.getLineMaxColumn(lineCount)), EndOfLinePreference.LF);\n\t\tconst lfCounter = (model.getEOL() === '\\r\\n' ? new LineFeedCounter(text) : null);\n\t\tsearcher.reset(searchStart.column - 1);\n\t\tconst m = searcher.next(text);\n\t\tif (m) {\n\t\t\treturn createFindMatch(\n\t\t\t\tthis._getMultilineMatchRange(model, deltaOffset, text, lfCounter, m.index, m[0]),\n\t\t\t\tm,\n\t\t\t\tcaptureMatches\n\t\t\t);\n\t\t}\n\n\t\tif (searchStart.lineNumber !== 1 || searchStart.column !== 1) {\n\t\t\t// Try again from the top\n\t\t\treturn this._doFindNextMatchMultiline(model, new Position(1, 1), searcher, captureMatches);\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tprivate static _doFindNextMatchLineByLine(model: TextModel, searchStart: Position, searcher: Searcher, captureMatches: boolean): FindMatch | null {\n\t\tconst lineCount = model.getLineCount();\n\t\tconst startLineNumber = searchStart.lineNumber;\n\n\t\t// Look in first line\n\t\tconst text = model.getLineContent(startLineNumber);\n\t\tconst r = this._findFirstMatchInLine(searcher, text, startLineNumber, searchStart.column, captureMatches);\n\t\tif (r) {\n\t\t\treturn r;\n\t\t}\n\n\t\tfor (let i = 1; i <= lineCount; i++) {\n\t\t\tconst lineIndex = (startLineNumber + i - 1) % lineCount;\n\t\t\tconst text = model.getLineContent(lineIndex + 1);\n\t\t\tconst r = this._findFirstMatchInLine(searcher, text, lineIndex + 1, 1, captureMatches);\n\t\t\tif (r) {\n\t\t\t\treturn r;\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tprivate static _findFirstMatchInLine(searcher: Searcher, text: string, lineNumber: number, fromColumn: number, captureMatches: boolean): FindMatch | null {\n\t\t// Set regex to search from column\n\t\tsearcher.reset(fromColumn - 1);\n\t\tconst m: RegExpExecArray | null = searcher.next(text);\n\t\tif (m) {\n\t\t\treturn createFindMatch(\n\t\t\t\tnew Range(lineNumber, m.index + 1, lineNumber, m.index + 1 + m[0].length),\n\t\t\t\tm,\n\t\t\t\tcaptureMatches\n\t\t\t);\n\t\t}\n\t\treturn null;\n\t}\n\n\tpublic static findPreviousMatch(model: TextModel, searchParams: SearchParams, searchStart: Position, captureMatches: boolean): FindMatch | null {\n\t\tconst searchData = searchParams.parseSearchRequest();\n\t\tif (!searchData) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst searcher = new Searcher(searchData.wordSeparators, searchData.regex);\n\n\t\tif (searchData.regex.multiline) {\n\t\t\treturn this._doFindPreviousMatchMultiline(model, searchStart, searcher, captureMatches);\n\t\t}\n\t\treturn this._doFindPreviousMatchLineByLine(model, searchStart, searcher, captureMatches);\n\t}\n\n\tprivate static _doFindPreviousMatchMultiline(model: TextModel, searchStart: Position, searcher: Searcher, captureMatches: boolean): FindMatch | null {\n\t\tconst matches = this._doFindMatchesMultiline(model, new Range(1, 1, searchStart.lineNumber, searchStart.column), searcher, captureMatches, 10 * LIMIT_FIND_COUNT);\n\t\tif (matches.length > 0) {\n\t\t\treturn matches[matches.length - 1];\n\t\t}\n\n\t\tconst lineCount = model.getLineCount();\n\t\tif (searchStart.lineNumber !== lineCount || searchStart.column !== model.getLineMaxColumn(lineCount)) {\n\t\t\t// Try again with all content\n\t\t\treturn this._doFindPreviousMatchMultiline(model, new Position(lineCount, model.getLineMaxColumn(lineCount)), searcher, captureMatches);\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tprivate static _doFindPreviousMatchLineByLine(model: TextModel, searchStart: Position, searcher: Searcher, captureMatches: boolean): FindMatch | null {\n\t\tconst lineCount = model.getLineCount();\n\t\tconst startLineNumber = searchStart.lineNumber;\n\n\t\t// Look in first line\n\t\tconst text = model.getLineContent(startLineNumber).substring(0, searchStart.column - 1);\n\t\tconst r = this._findLastMatchInLine(searcher, text, startLineNumber, captureMatches);\n\t\tif (r) {\n\t\t\treturn r;\n\t\t}\n\n\t\tfor (let i = 1; i <= lineCount; i++) {\n\t\t\tconst lineIndex = (lineCount + startLineNumber - i - 1) % lineCount;\n\t\t\tconst text = model.getLineContent(lineIndex + 1);\n\t\t\tconst r = this._findLastMatchInLine(searcher, text, lineIndex + 1, captureMatches);\n\t\t\tif (r) {\n\t\t\t\treturn r;\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tprivate static _findLastMatchInLine(searcher: Searcher, text: string, lineNumber: number, captureMatches: boolean): FindMatch | null {\n\t\tlet bestResult: FindMatch | null = null;\n\t\tlet m: RegExpExecArray | null;\n\t\tsearcher.reset(0);\n\t\twhile ((m = searcher.next(text))) {\n\t\t\tbestResult = createFindMatch(new Range(lineNumber, m.index + 1, lineNumber, m.index + 1 + m[0].length), m, captureMatches);\n\t\t}\n\t\treturn bestResult;\n\t}\n}\n\nfunction leftIsWordBounday(wordSeparators: WordCharacterClassifier, text: string, textLength: number, matchStartIndex: number, matchLength: number): boolean {\n\tif (matchStartIndex === 0) {\n\t\t// Match starts at start of string\n\t\treturn true;\n\t}\n\n\tconst charBefore = text.charCodeAt(matchStartIndex - 1);\n\tif (wordSeparators.get(charBefore) !== WordCharacterClass.Regular) {\n\t\t// The character before the match is a word separator\n\t\treturn true;\n\t}\n\n\tif (charBefore === CharCode.CarriageReturn || charBefore === CharCode.LineFeed) {\n\t\t// The character before the match is line break or carriage return.\n\t\treturn true;\n\t}\n\n\tif (matchLength > 0) {\n\t\tconst firstCharInMatch = text.charCodeAt(matchStartIndex);\n\t\tif (wordSeparators.get(firstCharInMatch) !== WordCharacterClass.Regular) {\n\t\t\t// The first character inside the match is a word separator\n\t\t\treturn true;\n\t\t}\n\t}\n\n\treturn false;\n}\n\nfunction rightIsWordBounday(wordSeparators: WordCharacterClassifier, text: string, textLength: number, matchStartIndex: number, matchLength: number): boolean {\n\tif (matchStartIndex + matchLength === textLength) {\n\t\t// Match ends at end of string\n\t\treturn true;\n\t}\n\n\tconst charAfter = text.charCodeAt(matchStartIndex + matchLength);\n\tif (wordSeparators.get(charAfter) !== WordCharacterClass.Regular) {\n\t\t// The character after the match is a word separator\n\t\treturn true;\n\t}\n\n\tif (charAfter === CharCode.CarriageReturn || charAfter === CharCode.LineFeed) {\n\t\t// The character after the match is line break or carriage return.\n\t\treturn true;\n\t}\n\n\tif (matchLength > 0) {\n\t\tconst lastCharInMatch = text.charCodeAt(matchStartIndex + matchLength - 1);\n\t\tif (wordSeparators.get(lastCharInMatch) !== WordCharacterClass.Regular) {\n\t\t\t// The last character in the match is a word separator\n\t\t\treturn true;\n\t\t}\n\t}\n\n\treturn false;\n}\n\nexport function isValidMatch(wordSeparators: WordCharacterClassifier, text: string, textLength: number, matchStartIndex: number, matchLength: number): boolean {\n\treturn (\n\t\tleftIsWordBounday(wordSeparators, text, textLength, matchStartIndex, matchLength)\n\t\t&& rightIsWordBounday(wordSeparators, text, textLength, matchStartIndex, matchLength)\n\t);\n}\n\nexport class Searcher {\n\tpublic readonly _wordSeparators: WordCharacterClassifier | null;\n\tprivate readonly _searchRegex: RegExp;\n\tprivate _prevMatchStartIndex: number;\n\tprivate _prevMatchLength: number;\n\n\tconstructor(wordSeparators: WordCharacterClassifier | null, searchRegex: RegExp,) {\n\t\tthis._wordSeparators = wordSeparators;\n\t\tthis._searchRegex = searchRegex;\n\t\tthis._prevMatchStartIndex = -1;\n\t\tthis._prevMatchLength = 0;\n\t}\n\n\tpublic reset(lastIndex: number): void {\n\t\tthis._searchRegex.lastIndex = lastIndex;\n\t\tthis._prevMatchStartIndex = -1;\n\t\tthis._prevMatchLength = 0;\n\t}\n\n\tpublic next(text: string): RegExpExecArray | null {\n\t\tconst textLength = text.length;\n\n\t\tlet m: RegExpExecArray | null;\n\t\tdo {\n\t\t\tif (this._prevMatchStartIndex + this._prevMatchLength === textLength) {\n\t\t\t\t// Reached the end of the line\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tm = this._searchRegex.exec(text);\n\t\t\tif (!m) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst matchStartIndex = m.index;\n\t\t\tconst matchLength = m[0].length;\n\t\t\tif (matchStartIndex === this._prevMatchStartIndex && matchLength === this._prevMatchLength) {\n\t\t\t\tif (matchLength === 0) {\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\n\t\t\t\t\t// we attempt to recover from that by advancing by two if surrogate pair found and by one otherwise\n\t\t\t\t\tif (strings.getNextCodePoint(text, textLength, this._searchRegex.lastIndex) > 0xFFFF) {\n\t\t\t\t\t\tthis._searchRegex.lastIndex += 2;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis._searchRegex.lastIndex += 1;\n\t\t\t\t\t}\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t// Exit early if the regex matches the same range twice\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tthis._prevMatchStartIndex = matchStartIndex;\n\t\t\tthis._prevMatchLength = matchLength;\n\n\t\t\tif (!this._wordSeparators || isValidMatch(this._wordSeparators, text, textLength, matchStartIndex, matchLength)) {\n\t\t\t\treturn m;\n\t\t\t}\n\n\t\t} while (m);\n\n\t\treturn null;\n\t}\n}\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\nimport { CharCode } from 'vs/base/common/charCode';\nimport { Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\nimport { FindMatch, ITextSnapshot, SearchData } from 'vs/editor/common/model';\nimport { NodeColor, SENTINEL, TreeNode, fixInsert, leftest, rbDelete, righttest, updateTreeMetadata } from 'vs/editor/common/model/pieceTreeTextBuffer/rbTreeBase';\nimport { Searcher, createFindMatch, isValidMatch } from 'vs/editor/common/model/textModelSearch';\n\n// const lfRegex = new RegExp(/\\r\\n|\\r|\\n/g);\nconst AverageBufferSize = 65535;\n\nfunction createUintArray(arr: number[]): Uint32Array | Uint16Array {\n\tlet r;\n\tif (arr[arr.length - 1] < 65536) {\n\t\tr = new Uint16Array(arr.length);\n\t} else {\n\t\tr = new Uint32Array(arr.length);\n\t}\n\tr.set(arr, 0);\n\treturn r;\n}\n\nclass LineStarts {\n\tconstructor(\n\t\tpublic readonly lineStarts: Uint32Array | Uint16Array | number[],\n\t\tpublic readonly cr: number,\n\t\tpublic readonly lf: number,\n\t\tpublic readonly crlf: number,\n\t\tpublic readonly isBasicASCII: boolean\n\t) { }\n}\n\nexport function createLineStartsFast(str: string, readonly: boolean = true): Uint32Array | Uint16Array | number[] {\n\tconst r: number[] = [0];\n\tlet rLength = 1;\n\n\tfor (let i = 0, len = str.length; i < len; i++) {\n\t\tconst chr = str.charCodeAt(i);\n\n\t\tif (chr === CharCode.CarriageReturn) {\n\t\t\tif (i + 1 < len && str.charCodeAt(i + 1) === CharCode.LineFeed) {\n\t\t\t\t// \\r\\n... case\n\t\t\t\tr[rLength++] = i + 2;\n\t\t\t\ti++; // skip \\n\n\t\t\t} else {\n\t\t\t\t// \\r... case\n\t\t\t\tr[rLength++] = i + 1;\n\t\t\t}\n\t\t} else if (chr === CharCode.LineFeed) {\n\t\t\tr[rLength++] = i + 1;\n\t\t}\n\t}\n\tif (readonly) {\n\t\treturn createUintArray(r);\n\t} else {\n\t\treturn r;\n\t}\n}\n\nexport function createLineStarts(r: number[], str: string): LineStarts {\n\tr.length = 0;\n\tr[0] = 0;\n\tlet rLength = 1;\n\tlet cr = 0, lf = 0, crlf = 0;\n\tlet isBasicASCII = true;\n\tfor (let i = 0, len = str.length; i < len; i++) {\n\t\tconst chr = str.charCodeAt(i);\n\n\t\tif (chr === CharCode.CarriageReturn) {\n\t\t\tif (i + 1 < len && str.charCodeAt(i + 1) === CharCode.LineFeed) {\n\t\t\t\t// \\r\\n... case\n\t\t\t\tcrlf++;\n\t\t\t\tr[rLength++] = i + 2;\n\t\t\t\ti++; // skip \\n\n\t\t\t} else {\n\t\t\t\tcr++;\n\t\t\t\t// \\r... case\n\t\t\t\tr[rLength++] = i + 1;\n\t\t\t}\n\t\t} else if (chr === CharCode.LineFeed) {\n\t\t\tlf++;\n\t\t\tr[rLength++] = i + 1;\n\t\t} else {\n\t\t\tif (isBasicASCII) {\n\t\t\t\tif (chr !== CharCode.Tab && (chr < 32 || chr > 126)) {\n\t\t\t\t\tisBasicASCII = false;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tconst result = new LineStarts(createUintArray(r), cr, lf, crlf, isBasicASCII);\n\tr.length = 0;\n\n\treturn result;\n}\n\ninterface NodePosition {\n\t/**\n\t * Piece Index\n\t */\n\tnode: TreeNode;\n\t/**\n\t * remainder in current piece.\n\t*/\n\tremainder: number;\n\t/**\n\t * node start offset in document.\n\t */\n\tnodeStartOffset: number;\n}\n\ninterface BufferCursor {\n\t/**\n\t * Line number in current buffer\n\t */\n\tline: number;\n\t/**\n\t * Column number in current buffer\n\t */\n\tcolumn: number;\n}\n\nexport class Piece {\n\treadonly bufferIndex: number;\n\treadonly start: BufferCursor;\n\treadonly end: BufferCursor;\n\treadonly length: number;\n\treadonly lineFeedCnt: number;\n\n\tconstructor(bufferIndex: number, start: BufferCursor, end: BufferCursor, lineFeedCnt: number, length: number) {\n\t\tthis.bufferIndex = bufferIndex;\n\t\tthis.start = start;\n\t\tthis.end = end;\n\t\tthis.lineFeedCnt = lineFeedCnt;\n\t\tthis.length = length;\n\t}\n}\n\nexport class StringBuffer {\n\tbuffer: string;\n\tlineStarts: Uint32Array | Uint16Array | number[];\n\n\tconstructor(buffer: string, lineStarts: Uint32Array | Uint16Array | number[]) {\n\t\tthis.buffer = buffer;\n\t\tthis.lineStarts = lineStarts;\n\t}\n}\n\n/**\n * Readonly snapshot for piece tree.\n * In a real multiple thread environment, to make snapshot reading always work correctly, we need to\n * 1. Make TreeNode.piece immutable, then reading and writing can run in parallel.\n * 2. TreeNode/Buffers normalization should not happen during snapshot reading.\n */\nclass PieceTreeSnapshot implements ITextSnapshot {\n\tprivate readonly _pieces: Piece[];\n\tprivate _index: number;\n\tprivate readonly _tree: PieceTreeBase;\n\tprivate readonly _BOM: string;\n\n\tconstructor(tree: PieceTreeBase, BOM: string) {\n\t\tthis._pieces = [];\n\t\tthis._tree = tree;\n\t\tthis._BOM = BOM;\n\t\tthis._index = 0;\n\t\tif (tree.root !== SENTINEL) {\n\t\t\ttree.iterate(tree.root, node => {\n\t\t\t\tif (node !== SENTINEL) {\n\t\t\t\t\tthis._pieces.push(node.piece);\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t});\n\t\t}\n\t}\n\n\tread(): string | null {\n\t\tif (this._pieces.length === 0) {\n\t\t\tif (this._index === 0) {\n\t\t\t\tthis._index++;\n\t\t\t\treturn this._BOM;\n\t\t\t} else {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\n\t\tif (this._index > this._pieces.length - 1) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif (this._index === 0) {\n\t\t\treturn this._BOM + this._tree.getPieceContent(this._pieces[this._index++]);\n\t\t}\n\t\treturn this._tree.getPieceContent(this._pieces[this._index++]);\n\t}\n}\n\ninterface CacheEntry {\n\tnode: TreeNode;\n\tnodeStartOffset: number;\n\tnodeStartLineNumber?: number;\n}\n\nclass PieceTreeSearchCache {\n\tprivate readonly _limit: number;\n\tprivate _cache: CacheEntry[];\n\n\tconstructor(limit: number) {\n\t\tthis._limit = limit;\n\t\tthis._cache = [];\n\t}\n\n\tpublic get(offset: number): CacheEntry | null {\n\t\tfor (let i = this._cache.length - 1; i >= 0; i--) {\n\t\t\tconst nodePos = this._cache[i];\n\t\t\tif (nodePos.nodeStartOffset <= offset && nodePos.nodeStartOffset + nodePos.node.piece.length >= offset) {\n\t\t\t\treturn nodePos;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tpublic get2(lineNumber: number): { node: TreeNode; nodeStartOffset: number; nodeStartLineNumber: number } | null {\n\t\tfor (let i = this._cache.length - 1; i >= 0; i--) {\n\t\t\tconst nodePos = this._cache[i];\n\t\t\tif (nodePos.nodeStartLineNumber && nodePos.nodeStartLineNumber < lineNumber && nodePos.nodeStartLineNumber + nodePos.node.piece.lineFeedCnt >= lineNumber) {\n\t\t\t\treturn <{ node: TreeNode; nodeStartOffset: number; nodeStartLineNumber: number }>nodePos;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tpublic set(nodePosition: CacheEntry) {\n\t\tif (this._cache.length >= this._limit) {\n\t\t\tthis._cache.shift();\n\t\t}\n\t\tthis._cache.push(nodePosition);\n\t}\n\n\tpublic validate(offset: number) {\n\t\tlet hasInvalidVal = false;\n\t\tconst tmp: Array = this._cache;\n\t\tfor (let i = 0; i < tmp.length; i++) {\n\t\t\tconst nodePos = tmp[i]!;\n\t\t\tif (nodePos.node.parent === null || nodePos.nodeStartOffset >= offset) {\n\t\t\t\ttmp[i] = null;\n\t\t\t\thasInvalidVal = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\tif (hasInvalidVal) {\n\t\t\tconst newArr: CacheEntry[] = [];\n\t\t\tfor (const entry of tmp) {\n\t\t\t\tif (entry !== null) {\n\t\t\t\t\tnewArr.push(entry);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis._cache = newArr;\n\t\t}\n\t}\n}\n\nexport class PieceTreeBase {\n\troot!: TreeNode;\n\tprotected _buffers!: StringBuffer[]; // 0 is change buffer, others are readonly original buffer.\n\tprotected _lineCnt!: number;\n\tprotected _length!: number;\n\tprotected _EOL!: '\\r\\n' | '\\n';\n\tprotected _EOLLength!: number;\n\tprotected _EOLNormalized!: boolean;\n\tprivate _lastChangeBufferPos!: BufferCursor;\n\tprivate _searchCache!: PieceTreeSearchCache;\n\tprivate _lastVisitedLine!: { lineNumber: number; value: string };\n\n\tconstructor(chunks: StringBuffer[], eol: '\\r\\n' | '\\n', eolNormalized: boolean) {\n\t\tthis.create(chunks, eol, eolNormalized);\n\t}\n\n\tcreate(chunks: StringBuffer[], eol: '\\r\\n' | '\\n', eolNormalized: boolean) {\n\t\tthis._buffers = [\n\t\t\tnew StringBuffer('', [0])\n\t\t];\n\t\tthis._lastChangeBufferPos = { line: 0, column: 0 };\n\t\tthis.root = SENTINEL;\n\t\tthis._lineCnt = 1;\n\t\tthis._length = 0;\n\t\tthis._EOL = eol;\n\t\tthis._EOLLength = eol.length;\n\t\tthis._EOLNormalized = eolNormalized;\n\n\t\tlet lastNode: TreeNode | null = null;\n\t\tfor (let i = 0, len = chunks.length; i < len; i++) {\n\t\t\tif (chunks[i].buffer.length > 0) {\n\t\t\t\tif (!chunks[i].lineStarts) {\n\t\t\t\t\tchunks[i].lineStarts = createLineStartsFast(chunks[i].buffer);\n\t\t\t\t}\n\n\t\t\t\tconst piece = new Piece(\n\t\t\t\t\ti + 1,\n\t\t\t\t\t{ line: 0, column: 0 },\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] },\n\t\t\t\t\tchunks[i].lineStarts.length - 1,\n\t\t\t\t\tchunks[i].buffer.length\n\t\t\t\t);\n\t\t\t\tthis._buffers.push(chunks[i]);\n\t\t\t\tlastNode = this.rbInsertRight(lastNode, piece);\n\t\t\t}\n\t\t}\n\n\t\tthis._searchCache = new PieceTreeSearchCache(1);\n\t\tthis._lastVisitedLine = { lineNumber: 0, value: '' };\n\t\tthis.computeBufferMetadata();\n\t}\n\n\tnormalizeEOL(eol: '\\r\\n' | '\\n') {\n\t\tconst averageBufferSize = AverageBufferSize;\n\t\tconst min = averageBufferSize - Math.floor(averageBufferSize / 3);\n\t\tconst max = min * 2;\n\n\t\tlet tempChunk = '';\n\t\tlet tempChunkLen = 0;\n\t\tconst chunks: StringBuffer[] = [];\n\n\t\tthis.iterate(this.root, node => {\n\t\t\tconst str = this.getNodeContent(node);\n\t\t\tconst len = str.length;\n\t\t\tif (tempChunkLen <= min || tempChunkLen + len < max) {\n\t\t\t\ttempChunk += str;\n\t\t\t\ttempChunkLen += len;\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\t// flush anyways\n\t\t\tconst text = tempChunk.replace(/\\r\\n|\\r|\\n/g, eol);\n\t\t\tchunks.push(new StringBuffer(text, createLineStartsFast(text)));\n\t\t\ttempChunk = str;\n\t\t\ttempChunkLen = len;\n\t\t\treturn true;\n\t\t});\n\n\t\tif (tempChunkLen > 0) {\n\t\t\tconst text = tempChunk.replace(/\\r\\n|\\r|\\n/g, eol);\n\t\t\tchunks.push(new StringBuffer(text, createLineStartsFast(text)));\n\t\t}\n\n\t\tthis.create(chunks, eol, true);\n\t}\n\n\t// #region Buffer API\n\tpublic getEOL(): '\\r\\n' | '\\n' {\n\t\treturn this._EOL;\n\t}\n\n\tpublic setEOL(newEOL: '\\r\\n' | '\\n'): void {\n\t\tthis._EOL = newEOL;\n\t\tthis._EOLLength = this._EOL.length;\n\t\tthis.normalizeEOL(newEOL);\n\t}\n\n\tpublic createSnapshot(BOM: string): ITextSnapshot {\n\t\treturn new PieceTreeSnapshot(this, BOM);\n\t}\n\n\tpublic getOffsetAt(lineNumber: number, column: number): number {\n\t\tlet leftLen = 0; // inorder\n\n\t\tlet x = this.root;\n\n\t\twhile (x !== SENTINEL) {\n\t\t\tif (x.left !== SENTINEL && x.lf_left + 1 >= lineNumber) {\n\t\t\t\tx = x.left;\n\t\t\t} else if (x.lf_left + x.piece.lineFeedCnt + 1 >= lineNumber) {\n\t\t\t\tleftLen += x.size_left;\n\t\t\t\t// lineNumber >= 2\n\t\t\t\tconst accumualtedValInCurrentIndex = this.getAccumulatedValue(x, lineNumber - x.lf_left - 2);\n\t\t\t\treturn leftLen += accumualtedValInCurrentIndex + column - 1;\n\t\t\t} else {\n\t\t\t\tlineNumber -= x.lf_left + x.piece.lineFeedCnt;\n\t\t\t\tleftLen += x.size_left + x.piece.length;\n\t\t\t\tx = x.right;\n\t\t\t}\n\t\t}\n\n\t\treturn leftLen;\n\t}\n\n\tpublic getPositionAt(offset: number): Position {\n\t\toffset = Math.floor(offset);\n\t\toffset = Math.max(0, offset);\n\n\t\tlet x = this.root;\n\t\tlet lfCnt = 0;\n\t\tconst originalOffset = offset;\n\n\t\twhile (x !== SENTINEL) {\n\t\t\tif (x.size_left !== 0 && x.size_left >= offset) {\n\t\t\t\tx = x.left;\n\t\t\t} else if (x.size_left + x.piece.length >= offset) {\n\t\t\t\tconst out = this.getIndexOf(x, offset - x.size_left);\n\n\t\t\t\tlfCnt += x.lf_left + out.index;\n\n\t\t\t\tif (out.index === 0) {\n\t\t\t\t\tconst lineStartOffset = this.getOffsetAt(lfCnt + 1, 1);\n\t\t\t\t\tconst column = originalOffset - lineStartOffset;\n\t\t\t\t\treturn new Position(lfCnt + 1, column + 1);\n\t\t\t\t}\n\n\t\t\t\treturn new Position(lfCnt + 1, out.remainder + 1);\n\t\t\t} else {\n\t\t\t\toffset -= x.size_left + x.piece.length;\n\t\t\t\tlfCnt += x.lf_left + x.piece.lineFeedCnt;\n\n\t\t\t\tif (x.right === SENTINEL) {\n\t\t\t\t\t// last node\n\t\t\t\t\tconst lineStartOffset = this.getOffsetAt(lfCnt + 1, 1);\n\t\t\t\t\tconst column = originalOffset - offset - lineStartOffset;\n\t\t\t\t\treturn new Position(lfCnt + 1, column + 1);\n\t\t\t\t} else {\n\t\t\t\t\tx = x.right;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn new Position(1, 1);\n\t}\n\n\tpublic getValueInRange(range: Range, eol?: string): string {\n\t\tif (range.startLineNumber === range.endLineNumber && range.startColumn === range.endColumn) {\n\t\t\treturn '';\n\t\t}\n\n\t\tconst startPosition = this.nodeAt2(range.startLineNumber, range.startColumn);\n\t\tconst endPosition = this.nodeAt2(range.endLineNumber, range.endColumn);\n\n\t\tconst value = this.getValueInRange2(startPosition, endPosition);\n\t\tif (eol) {\n\t\t\tif (eol !== this._EOL || !this._EOLNormalized) {\n\t\t\t\treturn value.replace(/\\r\\n|\\r|\\n/g, eol);\n\t\t\t}\n\n\t\t\tif (eol === this.getEOL() && this._EOLNormalized) {\n\t\t\t\tif (eol === '\\r\\n') {\n\n\t\t\t\t}\n\t\t\t\treturn value;\n\t\t\t}\n\t\t\treturn value.replace(/\\r\\n|\\r|\\n/g, eol);\n\t\t}\n\t\treturn value;\n\t}\n\n\tpublic getValueInRange2(startPosition: NodePosition, endPosition: NodePosition): string {\n\t\tif (startPosition.node === endPosition.node) {\n\t\t\tconst node = startPosition.node;\n\t\t\tconst buffer = this._buffers[node.piece.bufferIndex].buffer;\n\t\t\tconst startOffset = this.offsetInBuffer(node.piece.bufferIndex, node.piece.start);\n\t\t\treturn buffer.substring(startOffset + startPosition.remainder, startOffset + endPosition.remainder);\n\t\t}\n\n\t\tlet x = startPosition.node;\n\t\tconst buffer = this._buffers[x.piece.bufferIndex].buffer;\n\t\tconst startOffset = this.offsetInBuffer(x.piece.bufferIndex, x.piece.start);\n\t\tlet ret = buffer.substring(startOffset + startPosition.remainder, startOffset + x.piece.length);\n\n\t\tx = x.next();\n\t\twhile (x !== SENTINEL) {\n\t\t\tconst buffer = this._buffers[x.piece.bufferIndex].buffer;\n\t\t\tconst startOffset = this.offsetInBuffer(x.piece.bufferIndex, x.piece.start);\n\n\t\t\tif (x === endPosition.node) {\n\t\t\t\tret += buffer.substring(startOffset, startOffset + endPosition.remainder);\n\t\t\t\tbreak;\n\t\t\t} else {\n\t\t\t\tret += buffer.substr(startOffset, x.piece.length);\n\t\t\t}\n\n\t\t\tx = x.next();\n\t\t}\n\n\t\treturn ret;\n\t}\n\n\tpublic getLinesContent(): string[] {\n\t\tconst lines: string[] = [];\n\t\tlet linesLength = 0;\n\t\tlet currentLine = '';\n\t\tlet danglingCR = false;\n\n\t\tthis.iterate(this.root, node => {\n\t\t\tif (node === SENTINEL) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tconst piece = node.piece;\n\t\t\tlet pieceLength = piece.length;\n\t\t\tif (pieceLength === 0) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tconst buffer = this._buffers[piece.bufferIndex].buffer;\n\t\t\tconst lineStarts = this._buffers[piece.bufferIndex].lineStarts;\n\n\t\t\tconst pieceStartLine = piece.start.line;\n\t\t\tconst pieceEndLine = piece.end.line;\n\t\t\tlet pieceStartOffset = lineStarts[pieceStartLine] + piece.start.column;\n\n\t\t\tif (danglingCR) {\n\t\t\t\tif (buffer.charCodeAt(pieceStartOffset) === CharCode.LineFeed) {\n\t\t\t\t\t// pretend the \\n was in the previous piece..\n\t\t\t\t\tpieceStartOffset++;\n\t\t\t\t\tpieceLength--;\n\t\t\t\t}\n\t\t\t\tlines[linesLength++] = currentLine;\n\t\t\t\tcurrentLine = '';\n\t\t\t\tdanglingCR = false;\n\t\t\t\tif (pieceLength === 0) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (pieceStartLine === pieceEndLine) {\n\t\t\t\t// this piece has no new lines\n\t\t\t\tif (!this._EOLNormalized && buffer.charCodeAt(pieceStartOffset + pieceLength - 1) === CharCode.CarriageReturn) {\n\t\t\t\t\tdanglingCR = true;\n\t\t\t\t\tcurrentLine += buffer.substr(pieceStartOffset, pieceLength - 1);\n\t\t\t\t} else {\n\t\t\t\t\tcurrentLine += buffer.substr(pieceStartOffset, pieceLength);\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\t// add the text before the first line start in this piece\n\t\t\tcurrentLine += (\n\t\t\t\tthis._EOLNormalized\n\t\t\t\t\t? buffer.substring(pieceStartOffset, Math.max(pieceStartOffset, lineStarts[pieceStartLine + 1] - this._EOLLength))\n\t\t\t\t\t: buffer.substring(pieceStartOffset, lineStarts[pieceStartLine + 1]).replace(/(\\r\\n|\\r|\\n)$/, '')\n\t\t\t);\n\t\t\tlines[linesLength++] = currentLine;\n\n\t\t\tfor (let line = pieceStartLine + 1; line < pieceEndLine; line++) {\n\t\t\t\tcurrentLine = (\n\t\t\t\t\tthis._EOLNormalized\n\t\t\t\t\t\t? buffer.substring(lineStarts[line], lineStarts[line + 1] - this._EOLLength)\n\t\t\t\t\t\t: buffer.substring(lineStarts[line], lineStarts[line + 1]).replace(/(\\r\\n|\\r|\\n)$/, '')\n\t\t\t\t);\n\t\t\t\tlines[linesLength++] = currentLine;\n\t\t\t}\n\n\t\t\tif (!this._EOLNormalized && buffer.charCodeAt(lineStarts[pieceEndLine] + piece.end.column - 1) === CharCode.CarriageReturn) {\n\t\t\t\tdanglingCR = true;\n\t\t\t\tif (piece.end.column === 0) {\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\n\t\t\t\t\tlinesLength--;\n\t\t\t\t} else {\n\t\t\t\t\tcurrentLine = buffer.substr(lineStarts[pieceEndLine], piece.end.column - 1);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tcurrentLine = buffer.substr(lineStarts[pieceEndLine], piece.end.column);\n\t\t\t}\n\n\t\t\treturn true;\n\t\t});\n\n\t\tif (danglingCR) {\n\t\t\tlines[linesLength++] = currentLine;\n\t\t\tcurrentLine = '';\n\t\t}\n\n\t\tlines[linesLength++] = currentLine;\n\t\treturn lines;\n\t}\n\n\tpublic getLength(): number {\n\t\treturn this._length;\n\t}\n\n\tpublic getLineCount(): number {\n\t\treturn this._lineCnt;\n\t}\n\n\tpublic getLineContent(lineNumber: number): string {\n\t\tif (this._lastVisitedLine.lineNumber === lineNumber) {\n\t\t\treturn this._lastVisitedLine.value;\n\t\t}\n\n\t\tthis._lastVisitedLine.lineNumber = lineNumber;\n\n\t\tif (lineNumber === this._lineCnt) {\n\t\t\tthis._lastVisitedLine.value = this.getLineRawContent(lineNumber);\n\t\t} else if (this._EOLNormalized) {\n\t\t\tthis._lastVisitedLine.value = this.getLineRawContent(lineNumber, this._EOLLength);\n\t\t} else {\n\t\t\tthis._lastVisitedLine.value = this.getLineRawContent(lineNumber).replace(/(\\r\\n|\\r|\\n)$/, '');\n\t\t}\n\n\t\treturn this._lastVisitedLine.value;\n\t}\n\n\tprivate _getCharCode(nodePos: NodePosition): number {\n\t\tif (nodePos.remainder === nodePos.node.piece.length) {\n\t\t\t// the char we want to fetch is at the head of next node.\n\t\t\tconst matchingNode = nodePos.node.next();\n\t\t\tif (!matchingNode) {\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\tconst buffer = this._buffers[matchingNode.piece.bufferIndex];\n\t\t\tconst startOffset = this.offsetInBuffer(matchingNode.piece.bufferIndex, matchingNode.piece.start);\n\t\t\treturn buffer.buffer.charCodeAt(startOffset);\n\t\t} else {\n\t\t\tconst buffer = this._buffers[nodePos.node.piece.bufferIndex];\n\t\t\tconst startOffset = this.offsetInBuffer(nodePos.node.piece.bufferIndex, nodePos.node.piece.start);\n\t\t\tconst targetOffset = startOffset + nodePos.remainder;\n\n\t\t\treturn buffer.buffer.charCodeAt(targetOffset);\n\t\t}\n\t}\n\n\tpublic getLineCharCode(lineNumber: number, index: number): number {\n\t\tconst nodePos = this.nodeAt2(lineNumber, index + 1);\n\t\treturn this._getCharCode(nodePos);\n\t}\n\n\tpublic getLineLength(lineNumber: number): number {\n\t\tif (lineNumber === this.getLineCount()) {\n\t\t\tconst startOffset = this.getOffsetAt(lineNumber, 1);\n\t\t\treturn this.getLength() - startOffset;\n\t\t}\n\t\treturn this.getOffsetAt(lineNumber + 1, 1) - this.getOffsetAt(lineNumber, 1) - this._EOLLength;\n\t}\n\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[]) {\n\t\tconst buffer = this._buffers[node.piece.bufferIndex];\n\t\tconst startOffsetInBuffer = this.offsetInBuffer(node.piece.bufferIndex, node.piece.start);\n\t\tconst start = this.offsetInBuffer(node.piece.bufferIndex, startCursor);\n\t\tconst end = this.offsetInBuffer(node.piece.bufferIndex, endCursor);\n\n\t\tlet m: RegExpExecArray | null;\n\t\t// Reset regex to search from the beginning\n\t\tconst ret: BufferCursor = { line: 0, column: 0 };\n\t\tlet searchText: string;\n\t\tlet offsetInBuffer: (offset: number) => number;\n\n\t\tif (searcher._wordSeparators) {\n\t\t\tsearchText = buffer.buffer.substring(start, end);\n\t\t\toffsetInBuffer = (offset: number) => offset + start;\n\t\t\tsearcher.reset(0);\n\t\t} else {\n\t\t\tsearchText = buffer.buffer;\n\t\t\toffsetInBuffer = (offset: number) => offset;\n\t\t\tsearcher.reset(start);\n\t\t}\n\n\t\tdo {\n\t\t\tm = searcher.next(searchText);\n\n\t\t\tif (m) {\n\t\t\t\tif (offsetInBuffer(m.index) >= end) {\n\t\t\t\t\treturn resultLen;\n\t\t\t\t}\n\t\t\t\tthis.positionInBuffer(node, offsetInBuffer(m.index) - startOffsetInBuffer, ret);\n\t\t\t\tconst lineFeedCnt = this.getLineFeedCnt(node.piece.bufferIndex, startCursor, ret);\n\t\t\t\tconst retStartColumn = ret.line === startCursor.line ? ret.column - startCursor.column + startColumn : ret.column + 1;\n\t\t\t\tconst retEndColumn = retStartColumn + m[0].length;\n\t\t\t\tresult[resultLen++] = createFindMatch(new Range(startLineNumber + lineFeedCnt, retStartColumn, startLineNumber + lineFeedCnt, retEndColumn), m, captureMatches);\n\n\t\t\t\tif (offsetInBuffer(m.index) + m[0].length >= end) {\n\t\t\t\t\treturn resultLen;\n\t\t\t\t}\n\t\t\t\tif (resultLen >= limitResultCount) {\n\t\t\t\t\treturn resultLen;\n\t\t\t\t}\n\t\t\t}\n\n\t\t} while (m);\n\n\t\treturn resultLen;\n\t}\n\n\tpublic findMatchesLineByLine(searchRange: Range, searchData: SearchData, captureMatches: boolean, limitResultCount: number): FindMatch[] {\n\t\tconst result: FindMatch[] = [];\n\t\tlet resultLen = 0;\n\t\tconst searcher = new Searcher(searchData.wordSeparators, searchData.regex);\n\n\t\tlet startPosition = this.nodeAt2(searchRange.startLineNumber, searchRange.startColumn);\n\t\tif (startPosition === null) {\n\t\t\treturn [];\n\t\t}\n\t\tconst endPosition = this.nodeAt2(searchRange.endLineNumber, searchRange.endColumn);\n\t\tif (endPosition === null) {\n\t\t\treturn [];\n\t\t}\n\t\tlet start = this.positionInBuffer(startPosition.node, startPosition.remainder);\n\t\tconst end = this.positionInBuffer(endPosition.node, endPosition.remainder);\n\n\t\tif (startPosition.node === endPosition.node) {\n\t\t\tthis.findMatchesInNode(startPosition.node, searcher, searchRange.startLineNumber, searchRange.startColumn, start, end, searchData, captureMatches, limitResultCount, resultLen, result);\n\t\t\treturn result;\n\t\t}\n\n\t\tlet startLineNumber = searchRange.startLineNumber;\n\n\t\tlet currentNode = startPosition.node;\n\t\twhile (currentNode !== endPosition.node) {\n\t\t\tconst lineBreakCnt = this.getLineFeedCnt(currentNode.piece.bufferIndex, start, currentNode.piece.end);\n\n\t\t\tif (lineBreakCnt >= 1) {\n\t\t\t\t// last line break position\n\t\t\t\tconst lineStarts = this._buffers[currentNode.piece.bufferIndex].lineStarts;\n\t\t\t\tconst startOffsetInBuffer = this.offsetInBuffer(currentNode.piece.bufferIndex, currentNode.piece.start);\n\t\t\t\tconst nextLineStartOffset = lineStarts[start.line + lineBreakCnt];\n\t\t\t\tconst startColumn = startLineNumber === searchRange.startLineNumber ? searchRange.startColumn : 1;\n\t\t\t\tresultLen = this.findMatchesInNode(currentNode, searcher, startLineNumber, startColumn, start, this.positionInBuffer(currentNode, nextLineStartOffset - startOffsetInBuffer), searchData, captureMatches, limitResultCount, resultLen, result);\n\n\t\t\t\tif (resultLen >= limitResultCount) {\n\t\t\t\t\treturn result;\n\t\t\t\t}\n\n\t\t\t\tstartLineNumber += lineBreakCnt;\n\t\t\t}\n\n\t\t\tconst startColumn = startLineNumber === searchRange.startLineNumber ? searchRange.startColumn - 1 : 0;\n\t\t\t// search for the remaining content\n\t\t\tif (startLineNumber === searchRange.endLineNumber) {\n\t\t\t\tconst text = this.getLineContent(startLineNumber).substring(startColumn, searchRange.endColumn - 1);\n\t\t\t\tresultLen = this._findMatchesInLine(searchData, searcher, text, searchRange.endLineNumber, startColumn, resultLen, result, captureMatches, limitResultCount);\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\tresultLen = this._findMatchesInLine(searchData, searcher, this.getLineContent(startLineNumber).substr(startColumn), startLineNumber, startColumn, resultLen, result, captureMatches, limitResultCount);\n\n\t\t\tif (resultLen >= limitResultCount) {\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\tstartLineNumber++;\n\t\t\tstartPosition = this.nodeAt2(startLineNumber, 1);\n\t\t\tcurrentNode = startPosition.node;\n\t\t\tstart = this.positionInBuffer(startPosition.node, startPosition.remainder);\n\t\t}\n\n\t\tif (startLineNumber === searchRange.endLineNumber) {\n\t\t\tconst startColumn = startLineNumber === searchRange.startLineNumber ? searchRange.startColumn - 1 : 0;\n\t\t\tconst text = this.getLineContent(startLineNumber).substring(startColumn, searchRange.endColumn - 1);\n\t\t\tresultLen = this._findMatchesInLine(searchData, searcher, text, searchRange.endLineNumber, startColumn, resultLen, result, captureMatches, limitResultCount);\n\t\t\treturn result;\n\t\t}\n\n\t\tconst startColumn = startLineNumber === searchRange.startLineNumber ? searchRange.startColumn : 1;\n\t\tresultLen = this.findMatchesInNode(endPosition.node, searcher, startLineNumber, startColumn, start, end, searchData, captureMatches, limitResultCount, resultLen, result);\n\t\treturn result;\n\t}\n\n\tprivate _findMatchesInLine(searchData: SearchData, searcher: Searcher, text: string, lineNumber: number, deltaOffset: number, resultLen: number, result: FindMatch[], captureMatches: boolean, limitResultCount: number): number {\n\t\tconst wordSeparators = searchData.wordSeparators;\n\t\tif (!captureMatches && searchData.simpleSearch) {\n\t\t\tconst searchString = searchData.simpleSearch;\n\t\t\tconst searchStringLen = searchString.length;\n\t\t\tconst textLength = text.length;\n\n\t\t\tlet lastMatchIndex = -searchStringLen;\n\t\t\twhile ((lastMatchIndex = text.indexOf(searchString, lastMatchIndex + searchStringLen)) !== -1) {\n\t\t\t\tif (!wordSeparators || isValidMatch(wordSeparators, text, textLength, lastMatchIndex, searchStringLen)) {\n\t\t\t\t\tresult[resultLen++] = new FindMatch(new Range(lineNumber, lastMatchIndex + 1 + deltaOffset, lineNumber, lastMatchIndex + 1 + searchStringLen + deltaOffset), null);\n\t\t\t\t\tif (resultLen >= limitResultCount) {\n\t\t\t\t\t\treturn resultLen;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn resultLen;\n\t\t}\n\n\t\tlet m: RegExpExecArray | null;\n\t\t// Reset regex to search from the beginning\n\t\tsearcher.reset(0);\n\t\tdo {\n\t\t\tm = searcher.next(text);\n\t\t\tif (m) {\n\t\t\t\tresult[resultLen++] = createFindMatch(new Range(lineNumber, m.index + 1 + deltaOffset, lineNumber, m.index + 1 + m[0].length + deltaOffset), m, captureMatches);\n\t\t\t\tif (resultLen >= limitResultCount) {\n\t\t\t\t\treturn resultLen;\n\t\t\t\t}\n\t\t\t}\n\t\t} while (m);\n\t\treturn resultLen;\n\t}\n\n\t// #endregion\n\n\t// #region Piece Table\n\tpublic insert(offset: number, value: string, eolNormalized: boolean = false): void {\n\t\tthis._EOLNormalized = this._EOLNormalized && eolNormalized;\n\t\tthis._lastVisitedLine.lineNumber = 0;\n\t\tthis._lastVisitedLine.value = '';\n\n\t\tif (this.root !== SENTINEL) {\n\t\t\tconst { node, remainder, nodeStartOffset } = this.nodeAt(offset);\n\t\t\tconst piece = node.piece;\n\t\t\tconst bufferIndex = piece.bufferIndex;\n\t\t\tconst insertPosInBuffer = this.positionInBuffer(node, remainder);\n\t\t\tif (node.piece.bufferIndex === 0 &&\n\t\t\t\tpiece.end.line === this._lastChangeBufferPos.line &&\n\t\t\t\tpiece.end.column === this._lastChangeBufferPos.column &&\n\t\t\t\t(nodeStartOffset + piece.length === offset) &&\n\t\t\t\tvalue.length < AverageBufferSize\n\t\t\t) {\n\t\t\t\t// changed buffer\n\t\t\t\tthis.appendToNode(node, value);\n\t\t\t\tthis.computeBufferMetadata();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (nodeStartOffset === offset) {\n\t\t\t\tthis.insertContentToNodeLeft(value, node);\n\t\t\t\tthis._searchCache.validate(offset);\n\t\t\t} else if (nodeStartOffset + node.piece.length > offset) {\n\t\t\t\t// we are inserting into the middle of a node.\n\t\t\t\tconst nodesToDel: TreeNode[] = [];\n\t\t\t\tlet newRightPiece = new Piece(\n\t\t\t\t\tpiece.bufferIndex,\n\t\t\t\t\tinsertPosInBuffer,\n\t\t\t\t\tpiece.end,\n\t\t\t\t\tthis.getLineFeedCnt(piece.bufferIndex, insertPosInBuffer, piece.end),\n\t\t\t\t\tthis.offsetInBuffer(bufferIndex, piece.end) - this.offsetInBuffer(bufferIndex, insertPosInBuffer)\n\t\t\t\t);\n\n\t\t\t\tif (this.shouldCheckCRLF() && this.endWithCR(value)) {\n\t\t\t\t\tconst headOfRight = this.nodeCharCodeAt(node, remainder);\n\n\t\t\t\t\tif (headOfRight === 10 /** \\n */) {\n\t\t\t\t\t\tconst newStart: BufferCursor = { line: newRightPiece.start.line + 1, column: 0 };\n\t\t\t\t\t\tnewRightPiece = new Piece(\n\t\t\t\t\t\t\tnewRightPiece.bufferIndex,\n\t\t\t\t\t\t\tnewStart,\n\t\t\t\t\t\t\tnewRightPiece.end,\n\t\t\t\t\t\t\tthis.getLineFeedCnt(newRightPiece.bufferIndex, newStart, newRightPiece.end),\n\t\t\t\t\t\t\tnewRightPiece.length - 1\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tvalue += '\\n';\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// reuse node for content before insertion point.\n\t\t\t\tif (this.shouldCheckCRLF() && this.startWithLF(value)) {\n\t\t\t\t\tconst tailOfLeft = this.nodeCharCodeAt(node, remainder - 1);\n\t\t\t\t\tif (tailOfLeft === 13 /** \\r */) {\n\t\t\t\t\t\tconst previousPos = this.positionInBuffer(node, remainder - 1);\n\t\t\t\t\t\tthis.deleteNodeTail(node, previousPos);\n\t\t\t\t\t\tvalue = '\\r' + value;\n\n\t\t\t\t\t\tif (node.piece.length === 0) {\n\t\t\t\t\t\t\tnodesToDel.push(node);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.deleteNodeTail(node, insertPosInBuffer);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tthis.deleteNodeTail(node, insertPosInBuffer);\n\t\t\t\t}\n\n\t\t\t\tconst newPieces = this.createNewPieces(value);\n\t\t\t\tif (newRightPiece.length > 0) {\n\t\t\t\t\tthis.rbInsertRight(node, newRightPiece);\n\t\t\t\t}\n\n\t\t\t\tlet tmpNode = node;\n\t\t\t\tfor (let k = 0; k < newPieces.length; k++) {\n\t\t\t\t\ttmpNode = this.rbInsertRight(tmpNode, newPieces[k]);\n\t\t\t\t}\n\t\t\t\tthis.deleteNodes(nodesToDel);\n\t\t\t} else {\n\t\t\t\tthis.insertContentToNodeRight(value, node);\n\t\t\t}\n\t\t} else {\n\t\t\t// insert new node\n\t\t\tconst pieces = this.createNewPieces(value);\n\t\t\tlet node = this.rbInsertLeft(null, pieces[0]);\n\n\t\t\tfor (let k = 1; k < pieces.length; k++) {\n\t\t\t\tnode = this.rbInsertRight(node, pieces[k]);\n\t\t\t}\n\t\t}\n\n\t\t// todo, this is too brutal. Total line feed count should be updated the same way as lf_left.\n\t\tthis.computeBufferMetadata();\n\t}\n\n\tpublic delete(offset: number, cnt: number): void {\n\t\tthis._lastVisitedLine.lineNumber = 0;\n\t\tthis._lastVisitedLine.value = '';\n\n\t\tif (cnt <= 0 || this.root === SENTINEL) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst startPosition = this.nodeAt(offset);\n\t\tconst endPosition = this.nodeAt(offset + cnt);\n\t\tconst startNode = startPosition.node;\n\t\tconst endNode = endPosition.node;\n\n\t\tif (startNode === endNode) {\n\t\t\tconst startSplitPosInBuffer = this.positionInBuffer(startNode, startPosition.remainder);\n\t\t\tconst endSplitPosInBuffer = this.positionInBuffer(startNode, endPosition.remainder);\n\n\t\t\tif (startPosition.nodeStartOffset === offset) {\n\t\t\t\tif (cnt === startNode.piece.length) { // delete node\n\t\t\t\t\tconst next = startNode.next();\n\t\t\t\t\trbDelete(this, startNode);\n\t\t\t\t\tthis.validateCRLFWithPrevNode(next);\n\t\t\t\t\tthis.computeBufferMetadata();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tthis.deleteNodeHead(startNode, endSplitPosInBuffer);\n\t\t\t\tthis._searchCache.validate(offset);\n\t\t\t\tthis.validateCRLFWithPrevNode(startNode);\n\t\t\t\tthis.computeBufferMetadata();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (startPosition.nodeStartOffset + startNode.piece.length === offset + cnt) {\n\t\t\t\tthis.deleteNodeTail(startNode, startSplitPosInBuffer);\n\t\t\t\tthis.validateCRLFWithNextNode(startNode);\n\t\t\t\tthis.computeBufferMetadata();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// delete content in the middle, this node will be splitted to nodes\n\t\t\tthis.shrinkNode(startNode, startSplitPosInBuffer, endSplitPosInBuffer);\n\t\t\tthis.computeBufferMetadata();\n\t\t\treturn;\n\t\t}\n\n\t\tconst nodesToDel: TreeNode[] = [];\n\n\t\tconst startSplitPosInBuffer = this.positionInBuffer(startNode, startPosition.remainder);\n\t\tthis.deleteNodeTail(startNode, startSplitPosInBuffer);\n\t\tthis._searchCache.validate(offset);\n\t\tif (startNode.piece.length === 0) {\n\t\t\tnodesToDel.push(startNode);\n\t\t}\n\n\t\t// update last touched node\n\t\tconst endSplitPosInBuffer = this.positionInBuffer(endNode, endPosition.remainder);\n\t\tthis.deleteNodeHead(endNode, endSplitPosInBuffer);\n\t\tif (endNode.piece.length === 0) {\n\t\t\tnodesToDel.push(endNode);\n\t\t}\n\n\t\t// delete nodes in between\n\t\tconst secondNode = startNode.next();\n\t\tfor (let node = secondNode; node !== SENTINEL && node !== endNode; node = node.next()) {\n\t\t\tnodesToDel.push(node);\n\t\t}\n\n\t\tconst prev = startNode.piece.length === 0 ? startNode.prev() : startNode;\n\t\tthis.deleteNodes(nodesToDel);\n\t\tthis.validateCRLFWithNextNode(prev);\n\t\tthis.computeBufferMetadata();\n\t}\n\n\tprivate insertContentToNodeLeft(value: string, node: TreeNode) {\n\t\t// we are inserting content to the beginning of node\n\t\tconst nodesToDel: TreeNode[] = [];\n\t\tif (this.shouldCheckCRLF() && this.endWithCR(value) && this.startWithLF(node)) {\n\t\t\t// move `\\n` to new node.\n\n\t\t\tconst piece = node.piece;\n\t\t\tconst newStart: BufferCursor = { line: piece.start.line + 1, column: 0 };\n\t\t\tconst nPiece = new Piece(\n\t\t\t\tpiece.bufferIndex,\n\t\t\t\tnewStart,\n\t\t\t\tpiece.end,\n\t\t\t\tthis.getLineFeedCnt(piece.bufferIndex, newStart, piece.end),\n\t\t\t\tpiece.length - 1\n\t\t\t);\n\n\t\t\tnode.piece = nPiece;\n\n\t\t\tvalue += '\\n';\n\t\t\tupdateTreeMetadata(this, node, -1, -1);\n\n\t\t\tif (node.piece.length === 0) {\n\t\t\t\tnodesToDel.push(node);\n\t\t\t}\n\t\t}\n\n\t\tconst newPieces = this.createNewPieces(value);\n\t\tlet newNode = this.rbInsertLeft(node, newPieces[newPieces.length - 1]);\n\t\tfor (let k = newPieces.length - 2; k >= 0; k--) {\n\t\t\tnewNode = this.rbInsertLeft(newNode, newPieces[k]);\n\t\t}\n\t\tthis.validateCRLFWithPrevNode(newNode);\n\t\tthis.deleteNodes(nodesToDel);\n\t}\n\n\tprivate insertContentToNodeRight(value: string, node: TreeNode) {\n\t\t// we are inserting to the right of this node.\n\t\tif (this.adjustCarriageReturnFromNext(value, node)) {\n\t\t\t// move \\n to the new node.\n\t\t\tvalue += '\\n';\n\t\t}\n\n\t\tconst newPieces = this.createNewPieces(value);\n\t\tconst newNode = this.rbInsertRight(node, newPieces[0]);\n\t\tlet tmpNode = newNode;\n\n\t\tfor (let k = 1; k < newPieces.length; k++) {\n\t\t\ttmpNode = this.rbInsertRight(tmpNode, newPieces[k]);\n\t\t}\n\n\t\tthis.validateCRLFWithPrevNode(newNode);\n\t}\n\n\tprivate positionInBuffer(node: TreeNode, remainder: number): BufferCursor;\n\tprivate positionInBuffer(node: TreeNode, remainder: number, ret: BufferCursor): null;\n\tprivate positionInBuffer(node: TreeNode, remainder: number, ret?: BufferCursor): BufferCursor | null {\n\t\tconst piece = node.piece;\n\t\tconst bufferIndex = node.piece.bufferIndex;\n\t\tconst lineStarts = this._buffers[bufferIndex].lineStarts;\n\n\t\tconst startOffset = lineStarts[piece.start.line] + piece.start.column;\n\n\t\tconst offset = startOffset + remainder;\n\n\t\t// binary search offset between startOffset and endOffset\n\t\tlet low = piece.start.line;\n\t\tlet high = piece.end.line;\n\n\t\tlet mid: number = 0;\n\t\tlet midStop: number = 0;\n\t\tlet midStart: number = 0;\n\n\t\twhile (low <= high) {\n\t\t\tmid = low + ((high - low) / 2) | 0;\n\t\t\tmidStart = lineStarts[mid];\n\n\t\t\tif (mid === high) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tmidStop = lineStarts[mid + 1];\n\n\t\t\tif (offset < midStart) {\n\t\t\t\thigh = mid - 1;\n\t\t\t} else if (offset >= midStop) {\n\t\t\t\tlow = mid + 1;\n\t\t\t} else {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (ret) {\n\t\t\tret.line = mid;\n\t\t\tret.column = offset - midStart;\n\t\t\treturn null;\n\t\t}\n\n\t\treturn {\n\t\t\tline: mid,\n\t\t\tcolumn: offset - midStart\n\t\t};\n\t}\n\n\tprivate getLineFeedCnt(bufferIndex: number, start: BufferCursor, end: BufferCursor): number {\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.\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\n\t\tif (end.column === 0) {\n\t\t\treturn end.line - start.line;\n\t\t}\n\n\t\tconst lineStarts = this._buffers[bufferIndex].lineStarts;\n\t\tif (end.line === lineStarts.length - 1) { // it means, there is no \\n after end, otherwise, there will be one more lineStart.\n\t\t\treturn end.line - start.line;\n\t\t}\n\n\t\tconst nextLineStartOffset = lineStarts[end.line + 1];\n\t\tconst endOffset = lineStarts[end.line] + end.column;\n\t\tif (nextLineStartOffset > endOffset + 1) { // there are more than 1 character after end, which means it can't be \\n\n\t\t\treturn end.line - start.line;\n\t\t}\n\t\t// endOffset + 1 === nextLineStartOffset\n\t\t// character at endOffset is \\n, so we check the character before first\n\t\t// if character at endOffset is \\r, end.column is 0 and we can't get here.\n\t\tconst previousCharOffset = endOffset - 1; // end.column > 0 so it's okay.\n\t\tconst buffer = this._buffers[bufferIndex].buffer;\n\n\t\tif (buffer.charCodeAt(previousCharOffset) === 13) {\n\t\t\treturn end.line - start.line + 1;\n\t\t} else {\n\t\t\treturn end.line - start.line;\n\t\t}\n\t}\n\n\tprivate offsetInBuffer(bufferIndex: number, cursor: BufferCursor): number {\n\t\tconst lineStarts = this._buffers[bufferIndex].lineStarts;\n\t\treturn lineStarts[cursor.line] + cursor.column;\n\t}\n\n\tprivate deleteNodes(nodes: TreeNode[]): void {\n\t\tfor (let i = 0; i < nodes.length; i++) {\n\t\t\trbDelete(this, nodes[i]);\n\t\t}\n\t}\n\n\tprivate createNewPieces(text: string): Piece[] {\n\t\tif (text.length > AverageBufferSize) {\n\t\t\t// the content is large, operations like substring, charCode becomes slow\n\t\t\t// so here we split it into smaller chunks, just like what we did for CR/LF normalization\n\t\t\tconst newPieces: Piece[] = [];\n\t\t\twhile (text.length > AverageBufferSize) {\n\t\t\t\tconst lastChar = text.charCodeAt(AverageBufferSize - 1);\n\t\t\t\tlet splitText;\n\t\t\t\tif (lastChar === CharCode.CarriageReturn || (lastChar >= 0xD800 && lastChar <= 0xDBFF)) {\n\t\t\t\t\t// last character is \\r or a high surrogate => keep it back\n\t\t\t\t\tsplitText = text.substring(0, AverageBufferSize - 1);\n\t\t\t\t\ttext = text.substring(AverageBufferSize - 1);\n\t\t\t\t} else {\n\t\t\t\t\tsplitText = text.substring(0, AverageBufferSize);\n\t\t\t\t\ttext = text.substring(AverageBufferSize);\n\t\t\t\t}\n\n\t\t\t\tconst lineStarts = createLineStartsFast(splitText);\n\t\t\t\tnewPieces.push(new Piece(\n\t\t\t\t\tthis._buffers.length, /* buffer index */\n\t\t\t\t\t{ line: 0, column: 0 },\n\t\t\t\t\t{ line: lineStarts.length - 1, column: splitText.length - lineStarts[lineStarts.length - 1] },\n\t\t\t\t\tlineStarts.length - 1,\n\t\t\t\t\tsplitText.length\n\t\t\t\t));\n\t\t\t\tthis._buffers.push(new StringBuffer(splitText, lineStarts));\n\t\t\t}\n\n\t\t\tconst lineStarts = createLineStartsFast(text);\n\t\t\tnewPieces.push(new Piece(\n\t\t\t\tthis._buffers.length, /* buffer index */\n\t\t\t\t{ line: 0, column: 0 },\n\t\t\t\t{ line: lineStarts.length - 1, column: text.length - lineStarts[lineStarts.length - 1] },\n\t\t\t\tlineStarts.length - 1,\n\t\t\t\ttext.length\n\t\t\t));\n\t\t\tthis._buffers.push(new StringBuffer(text, lineStarts));\n\n\t\t\treturn newPieces;\n\t\t}\n\n\t\tlet startOffset = this._buffers[0].buffer.length;\n\t\tconst lineStarts = createLineStartsFast(text, false);\n\n\t\tlet start = this._lastChangeBufferPos;\n\t\tif (this._buffers[0].lineStarts[this._buffers[0].lineStarts.length - 1] === startOffset\n\t\t\t&& startOffset !== 0\n\t\t\t&& this.startWithLF(text)\n\t\t\t&& this.endWithCR(this._buffers[0].buffer) // todo, we can check this._lastChangeBufferPos's column as it's the last one\n\t\t) {\n\t\t\tthis._lastChangeBufferPos = { line: this._lastChangeBufferPos.line, column: this._lastChangeBufferPos.column + 1 };\n\t\t\tstart = this._lastChangeBufferPos;\n\n\t\t\tfor (let i = 0; i < lineStarts.length; i++) {\n\t\t\t\tlineStarts[i] += startOffset + 1;\n\t\t\t}\n\n\t\t\tthis._buffers[0].lineStarts = (this._buffers[0].lineStarts).concat(lineStarts.slice(1));\n\t\t\tthis._buffers[0].buffer += '_' + text;\n\t\t\tstartOffset += 1;\n\t\t} else {\n\t\t\tif (startOffset !== 0) {\n\t\t\t\tfor (let i = 0; i < lineStarts.length; i++) {\n\t\t\t\t\tlineStarts[i] += startOffset;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis._buffers[0].lineStarts = (this._buffers[0].lineStarts).concat(lineStarts.slice(1));\n\t\t\tthis._buffers[0].buffer += text;\n\t\t}\n\n\t\tconst endOffset = this._buffers[0].buffer.length;\n\t\tconst endIndex = this._buffers[0].lineStarts.length - 1;\n\t\tconst endColumn = endOffset - this._buffers[0].lineStarts[endIndex];\n\t\tconst endPos = { line: endIndex, column: endColumn };\n\t\tconst newPiece = new Piece(\n\t\t\t0, /** todo@peng */\n\t\t\tstart,\n\t\t\tendPos,\n\t\t\tthis.getLineFeedCnt(0, start, endPos),\n\t\t\tendOffset - startOffset\n\t\t);\n\t\tthis._lastChangeBufferPos = endPos;\n\t\treturn [newPiece];\n\t}\n\n\tpublic getLineRawContent(lineNumber: number, endOffset: number = 0): string {\n\t\tlet x = this.root;\n\n\t\tlet ret = '';\n\t\tconst cache = this._searchCache.get2(lineNumber);\n\t\tif (cache) {\n\t\t\tx = cache.node;\n\t\t\tconst prevAccumulatedValue = this.getAccumulatedValue(x, lineNumber - cache.nodeStartLineNumber - 1);\n\t\t\tconst buffer = this._buffers[x.piece.bufferIndex].buffer;\n\t\t\tconst startOffset = this.offsetInBuffer(x.piece.bufferIndex, x.piece.start);\n\t\t\tif (cache.nodeStartLineNumber + x.piece.lineFeedCnt === lineNumber) {\n\t\t\t\tret = buffer.substring(startOffset + prevAccumulatedValue, startOffset + x.piece.length);\n\t\t\t} else {\n\t\t\t\tconst accumulatedValue = this.getAccumulatedValue(x, lineNumber - cache.nodeStartLineNumber);\n\t\t\t\treturn buffer.substring(startOffset + prevAccumulatedValue, startOffset + accumulatedValue - endOffset);\n\t\t\t}\n\t\t} else {\n\t\t\tlet nodeStartOffset = 0;\n\t\t\tconst originalLineNumber = lineNumber;\n\t\t\twhile (x !== SENTINEL) {\n\t\t\t\tif (x.left !== SENTINEL && x.lf_left >= lineNumber - 1) {\n\t\t\t\t\tx = x.left;\n\t\t\t\t} else if (x.lf_left + x.piece.lineFeedCnt > lineNumber - 1) {\n\t\t\t\t\tconst prevAccumulatedValue = this.getAccumulatedValue(x, lineNumber - x.lf_left - 2);\n\t\t\t\t\tconst accumulatedValue = this.getAccumulatedValue(x, lineNumber - x.lf_left - 1);\n\t\t\t\t\tconst buffer = this._buffers[x.piece.bufferIndex].buffer;\n\t\t\t\t\tconst startOffset = this.offsetInBuffer(x.piece.bufferIndex, x.piece.start);\n\t\t\t\t\tnodeStartOffset += x.size_left;\n\t\t\t\t\tthis._searchCache.set({\n\t\t\t\t\t\tnode: x,\n\t\t\t\t\t\tnodeStartOffset,\n\t\t\t\t\t\tnodeStartLineNumber: originalLineNumber - (lineNumber - 1 - x.lf_left)\n\t\t\t\t\t});\n\n\t\t\t\t\treturn buffer.substring(startOffset + prevAccumulatedValue, startOffset + accumulatedValue - endOffset);\n\t\t\t\t} else if (x.lf_left + x.piece.lineFeedCnt === lineNumber - 1) {\n\t\t\t\t\tconst prevAccumulatedValue = this.getAccumulatedValue(x, lineNumber - x.lf_left - 2);\n\t\t\t\t\tconst buffer = this._buffers[x.piece.bufferIndex].buffer;\n\t\t\t\t\tconst startOffset = this.offsetInBuffer(x.piece.bufferIndex, x.piece.start);\n\n\t\t\t\t\tret = buffer.substring(startOffset + prevAccumulatedValue, startOffset + x.piece.length);\n\t\t\t\t\tbreak;\n\t\t\t\t} else {\n\t\t\t\t\tlineNumber -= x.lf_left + x.piece.lineFeedCnt;\n\t\t\t\t\tnodeStartOffset += x.size_left + x.piece.length;\n\t\t\t\t\tx = x.right;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// search in order, to find the node contains end column\n\t\tx = x.next();\n\t\twhile (x !== SENTINEL) {\n\t\t\tconst buffer = this._buffers[x.piece.bufferIndex].buffer;\n\n\t\t\tif (x.piece.lineFeedCnt > 0) {\n\t\t\t\tconst accumulatedValue = this.getAccumulatedValue(x, 0);\n\t\t\t\tconst startOffset = this.offsetInBuffer(x.piece.bufferIndex, x.piece.start);\n\n\t\t\t\tret += buffer.substring(startOffset, startOffset + accumulatedValue - endOffset);\n\t\t\t\treturn ret;\n\t\t\t} else {\n\t\t\t\tconst startOffset = this.offsetInBuffer(x.piece.bufferIndex, x.piece.start);\n\t\t\t\tret += buffer.substr(startOffset, x.piece.length);\n\t\t\t}\n\n\t\t\tx = x.next();\n\t\t}\n\n\t\treturn ret;\n\t}\n\n\tprivate computeBufferMetadata() {\n\t\tlet x = this.root;\n\n\t\tlet lfCnt = 1;\n\t\tlet len = 0;\n\n\t\twhile (x !== SENTINEL) {\n\t\t\tlfCnt += x.lf_left + x.piece.lineFeedCnt;\n\t\t\tlen += x.size_left + x.piece.length;\n\t\t\tx = x.right;\n\t\t}\n\n\t\tthis._lineCnt = lfCnt;\n\t\tthis._length = len;\n\t\tthis._searchCache.validate(this._length);\n\t}\n\n\t// #region node operations\n\tprivate getIndexOf(node: TreeNode, accumulatedValue: number): { index: number; remainder: number } {\n\t\tconst piece = node.piece;\n\t\tconst pos = this.positionInBuffer(node, accumulatedValue);\n\t\tconst lineCnt = pos.line - piece.start.line;\n\n\t\tif (this.offsetInBuffer(piece.bufferIndex, piece.end) - this.offsetInBuffer(piece.bufferIndex, piece.start) === accumulatedValue) {\n\t\t\t// we are checking the end of this node, so a CRLF check is necessary.\n\t\t\tconst realLineCnt = this.getLineFeedCnt(node.piece.bufferIndex, piece.start, pos);\n\t\t\tif (realLineCnt !== lineCnt) {\n\t\t\t\t// aha yes, CRLF\n\t\t\t\treturn { index: realLineCnt, remainder: 0 };\n\t\t\t}\n\t\t}\n\n\t\treturn { index: lineCnt, remainder: pos.column };\n\t}\n\n\tprivate getAccumulatedValue(node: TreeNode, index: number) {\n\t\tif (index < 0) {\n\t\t\treturn 0;\n\t\t}\n\t\tconst piece = node.piece;\n\t\tconst lineStarts = this._buffers[piece.bufferIndex].lineStarts;\n\t\tconst expectedLineStartIndex = piece.start.line + index + 1;\n\t\tif (expectedLineStartIndex > piece.end.line) {\n\t\t\treturn lineStarts[piece.end.line] + piece.end.column - lineStarts[piece.start.line] - piece.start.column;\n\t\t} else {\n\t\t\treturn lineStarts[expectedLineStartIndex] - lineStarts[piece.start.line] - piece.start.column;\n\t\t}\n\t}\n\n\tprivate deleteNodeTail(node: TreeNode, pos: BufferCursor) {\n\t\tconst piece = node.piece;\n\t\tconst originalLFCnt = piece.lineFeedCnt;\n\t\tconst originalEndOffset = this.offsetInBuffer(piece.bufferIndex, piece.end);\n\n\t\tconst newEnd = pos;\n\t\tconst newEndOffset = this.offsetInBuffer(piece.bufferIndex, newEnd);\n\t\tconst newLineFeedCnt = this.getLineFeedCnt(piece.bufferIndex, piece.start, newEnd);\n\n\t\tconst lf_delta = newLineFeedCnt - originalLFCnt;\n\t\tconst size_delta = newEndOffset - originalEndOffset;\n\t\tconst newLength = piece.length + size_delta;\n\n\t\tnode.piece = new Piece(\n\t\t\tpiece.bufferIndex,\n\t\t\tpiece.start,\n\t\t\tnewEnd,\n\t\t\tnewLineFeedCnt,\n\t\t\tnewLength\n\t\t);\n\n\t\tupdateTreeMetadata(this, node, size_delta, lf_delta);\n\t}\n\n\tprivate deleteNodeHead(node: TreeNode, pos: BufferCursor) {\n\t\tconst piece = node.piece;\n\t\tconst originalLFCnt = piece.lineFeedCnt;\n\t\tconst originalStartOffset = this.offsetInBuffer(piece.bufferIndex, piece.start);\n\n\t\tconst newStart = pos;\n\t\tconst newLineFeedCnt = this.getLineFeedCnt(piece.bufferIndex, newStart, piece.end);\n\t\tconst newStartOffset = this.offsetInBuffer(piece.bufferIndex, newStart);\n\t\tconst lf_delta = newLineFeedCnt - originalLFCnt;\n\t\tconst size_delta = originalStartOffset - newStartOffset;\n\t\tconst newLength = piece.length + size_delta;\n\t\tnode.piece = new Piece(\n\t\t\tpiece.bufferIndex,\n\t\t\tnewStart,\n\t\t\tpiece.end,\n\t\t\tnewLineFeedCnt,\n\t\t\tnewLength\n\t\t);\n\n\t\tupdateTreeMetadata(this, node, size_delta, lf_delta);\n\t}\n\n\tprivate shrinkNode(node: TreeNode, start: BufferCursor, end: BufferCursor) {\n\t\tconst piece = node.piece;\n\t\tconst originalStartPos = piece.start;\n\t\tconst originalEndPos = piece.end;\n\n\t\t// old piece, originalStartPos, start\n\t\tconst oldLength = piece.length;\n\t\tconst oldLFCnt = piece.lineFeedCnt;\n\t\tconst newEnd = start;\n\t\tconst newLineFeedCnt = this.getLineFeedCnt(piece.bufferIndex, piece.start, newEnd);\n\t\tconst newLength = this.offsetInBuffer(piece.bufferIndex, start) - this.offsetInBuffer(piece.bufferIndex, originalStartPos);\n\n\t\tnode.piece = new Piece(\n\t\t\tpiece.bufferIndex,\n\t\t\tpiece.start,\n\t\t\tnewEnd,\n\t\t\tnewLineFeedCnt,\n\t\t\tnewLength\n\t\t);\n\n\t\tupdateTreeMetadata(this, node, newLength - oldLength, newLineFeedCnt - oldLFCnt);\n\n\t\t// new right piece, end, originalEndPos\n\t\tconst newPiece = new Piece(\n\t\t\tpiece.bufferIndex,\n\t\t\tend,\n\t\t\toriginalEndPos,\n\t\t\tthis.getLineFeedCnt(piece.bufferIndex, end, originalEndPos),\n\t\t\tthis.offsetInBuffer(piece.bufferIndex, originalEndPos) - this.offsetInBuffer(piece.bufferIndex, end)\n\t\t);\n\n\t\tconst newNode = this.rbInsertRight(node, newPiece);\n\t\tthis.validateCRLFWithPrevNode(newNode);\n\t}\n\n\tprivate appendToNode(node: TreeNode, value: string): void {\n\t\tif (this.adjustCarriageReturnFromNext(value, node)) {\n\t\t\tvalue += '\\n';\n\t\t}\n\n\t\tconst hitCRLF = this.shouldCheckCRLF() && this.startWithLF(value) && this.endWithCR(node);\n\t\tconst startOffset = this._buffers[0].buffer.length;\n\t\tthis._buffers[0].buffer += value;\n\t\tconst lineStarts = createLineStartsFast(value, false);\n\t\tfor (let i = 0; i < lineStarts.length; i++) {\n\t\t\tlineStarts[i] += startOffset;\n\t\t}\n\t\tif (hitCRLF) {\n\t\t\tconst prevStartOffset = this._buffers[0].lineStarts[this._buffers[0].lineStarts.length - 2];\n\t\t\t(this._buffers[0].lineStarts).pop();\n\t\t\t// _lastChangeBufferPos is already wrong\n\t\t\tthis._lastChangeBufferPos = { line: this._lastChangeBufferPos.line - 1, column: startOffset - prevStartOffset };\n\t\t}\n\n\t\tthis._buffers[0].lineStarts = (this._buffers[0].lineStarts).concat(lineStarts.slice(1));\n\t\tconst endIndex = this._buffers[0].lineStarts.length - 1;\n\t\tconst endColumn = this._buffers[0].buffer.length - this._buffers[0].lineStarts[endIndex];\n\t\tconst newEnd = { line: endIndex, column: endColumn };\n\t\tconst newLength = node.piece.length + value.length;\n\t\tconst oldLineFeedCnt = node.piece.lineFeedCnt;\n\t\tconst newLineFeedCnt = this.getLineFeedCnt(0, node.piece.start, newEnd);\n\t\tconst lf_delta = newLineFeedCnt - oldLineFeedCnt;\n\n\t\tnode.piece = new Piece(\n\t\t\tnode.piece.bufferIndex,\n\t\t\tnode.piece.start,\n\t\t\tnewEnd,\n\t\t\tnewLineFeedCnt,\n\t\t\tnewLength\n\t\t);\n\n\t\tthis._lastChangeBufferPos = newEnd;\n\t\tupdateTreeMetadata(this, node, value.length, lf_delta);\n\t}\n\n\tprivate nodeAt(offset: number): NodePosition {\n\t\tlet x = this.root;\n\t\tconst cache = this._searchCache.get(offset);\n\t\tif (cache) {\n\t\t\treturn {\n\t\t\t\tnode: cache.node,\n\t\t\t\tnodeStartOffset: cache.nodeStartOffset,\n\t\t\t\tremainder: offset - cache.nodeStartOffset\n\t\t\t};\n\t\t}\n\n\t\tlet nodeStartOffset = 0;\n\n\t\twhile (x !== SENTINEL) {\n\t\t\tif (x.size_left > offset) {\n\t\t\t\tx = x.left;\n\t\t\t} else if (x.size_left + x.piece.length >= offset) {\n\t\t\t\tnodeStartOffset += x.size_left;\n\t\t\t\tconst ret = {\n\t\t\t\t\tnode: x,\n\t\t\t\t\tremainder: offset - x.size_left,\n\t\t\t\t\tnodeStartOffset\n\t\t\t\t};\n\t\t\t\tthis._searchCache.set(ret);\n\t\t\t\treturn ret;\n\t\t\t} else {\n\t\t\t\toffset -= x.size_left + x.piece.length;\n\t\t\t\tnodeStartOffset += x.size_left + x.piece.length;\n\t\t\t\tx = x.right;\n\t\t\t}\n\t\t}\n\n\t\treturn null!;\n\t}\n\n\tprivate nodeAt2(lineNumber: number, column: number): NodePosition {\n\t\tlet x = this.root;\n\t\tlet nodeStartOffset = 0;\n\n\t\twhile (x !== SENTINEL) {\n\t\t\tif (x.left !== SENTINEL && x.lf_left >= lineNumber - 1) {\n\t\t\t\tx = x.left;\n\t\t\t} else if (x.lf_left + x.piece.lineFeedCnt > lineNumber - 1) {\n\t\t\t\tconst prevAccumualtedValue = this.getAccumulatedValue(x, lineNumber - x.lf_left - 2);\n\t\t\t\tconst accumulatedValue = this.getAccumulatedValue(x, lineNumber - x.lf_left - 1);\n\t\t\t\tnodeStartOffset += x.size_left;\n\n\t\t\t\treturn {\n\t\t\t\t\tnode: x,\n\t\t\t\t\tremainder: Math.min(prevAccumualtedValue + column - 1, accumulatedValue),\n\t\t\t\t\tnodeStartOffset\n\t\t\t\t};\n\t\t\t} else if (x.lf_left + x.piece.lineFeedCnt === lineNumber - 1) {\n\t\t\t\tconst prevAccumualtedValue = this.getAccumulatedValue(x, lineNumber - x.lf_left - 2);\n\t\t\t\tif (prevAccumualtedValue + column - 1 <= x.piece.length) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tnode: x,\n\t\t\t\t\t\tremainder: prevAccumualtedValue + column - 1,\n\t\t\t\t\t\tnodeStartOffset\n\t\t\t\t\t};\n\t\t\t\t} else {\n\t\t\t\t\tcolumn -= x.piece.length - prevAccumualtedValue;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tlineNumber -= x.lf_left + x.piece.lineFeedCnt;\n\t\t\t\tnodeStartOffset += x.size_left + x.piece.length;\n\t\t\t\tx = x.right;\n\t\t\t}\n\t\t}\n\n\t\t// search in order, to find the node contains position.column\n\t\tx = x.next();\n\t\twhile (x !== SENTINEL) {\n\n\t\t\tif (x.piece.lineFeedCnt > 0) {\n\t\t\t\tconst accumulatedValue = this.getAccumulatedValue(x, 0);\n\t\t\t\tconst nodeStartOffset = this.offsetOfNode(x);\n\t\t\t\treturn {\n\t\t\t\t\tnode: x,\n\t\t\t\t\tremainder: Math.min(column - 1, accumulatedValue),\n\t\t\t\t\tnodeStartOffset\n\t\t\t\t};\n\t\t\t} else {\n\t\t\t\tif (x.piece.length >= column - 1) {\n\t\t\t\t\tconst nodeStartOffset = this.offsetOfNode(x);\n\t\t\t\t\treturn {\n\t\t\t\t\t\tnode: x,\n\t\t\t\t\t\tremainder: column - 1,\n\t\t\t\t\t\tnodeStartOffset\n\t\t\t\t\t};\n\t\t\t\t} else {\n\t\t\t\t\tcolumn -= x.piece.length;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tx = x.next();\n\t\t}\n\n\t\treturn null!;\n\t}\n\n\tprivate nodeCharCodeAt(node: TreeNode, offset: number): number {\n\t\tif (node.piece.lineFeedCnt < 1) {\n\t\t\treturn -1;\n\t\t}\n\t\tconst buffer = this._buffers[node.piece.bufferIndex];\n\t\tconst newOffset = this.offsetInBuffer(node.piece.bufferIndex, node.piece.start) + offset;\n\t\treturn buffer.buffer.charCodeAt(newOffset);\n\t}\n\n\tprivate offsetOfNode(node: TreeNode): number {\n\t\tif (!node) {\n\t\t\treturn 0;\n\t\t}\n\t\tlet pos = node.size_left;\n\t\twhile (node !== this.root) {\n\t\t\tif (node.parent.right === node) {\n\t\t\t\tpos += node.parent.size_left + node.parent.piece.length;\n\t\t\t}\n\n\t\t\tnode = node.parent;\n\t\t}\n\n\t\treturn pos;\n\t}\n\n\t// #endregion\n\n\t// #region CRLF\n\tprivate shouldCheckCRLF() {\n\t\treturn !(this._EOLNormalized && this._EOL === '\\n');\n\t}\n\n\tprivate startWithLF(val: string | TreeNode): boolean {\n\t\tif (typeof val === 'string') {\n\t\t\treturn val.charCodeAt(0) === 10;\n\t\t}\n\n\t\tif (val === SENTINEL || val.piece.lineFeedCnt === 0) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst piece = val.piece;\n\t\tconst lineStarts = this._buffers[piece.bufferIndex].lineStarts;\n\t\tconst line = piece.start.line;\n\t\tconst startOffset = lineStarts[line] + piece.start.column;\n\t\tif (line === lineStarts.length - 1) {\n\t\t\t// last line, so there is no line feed at the end of this line\n\t\t\treturn false;\n\t\t}\n\t\tconst nextLineOffset = lineStarts[line + 1];\n\t\tif (nextLineOffset > startOffset + 1) {\n\t\t\treturn false;\n\t\t}\n\t\treturn this._buffers[piece.bufferIndex].buffer.charCodeAt(startOffset) === 10;\n\t}\n\n\tprivate endWithCR(val: string | TreeNode): boolean {\n\t\tif (typeof val === 'string') {\n\t\t\treturn val.charCodeAt(val.length - 1) === 13;\n\t\t}\n\n\t\tif (val === SENTINEL || val.piece.lineFeedCnt === 0) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn this.nodeCharCodeAt(val, val.piece.length - 1) === 13;\n\t}\n\n\tprivate validateCRLFWithPrevNode(nextNode: TreeNode) {\n\t\tif (this.shouldCheckCRLF() && this.startWithLF(nextNode)) {\n\t\t\tconst node = nextNode.prev();\n\t\t\tif (this.endWithCR(node)) {\n\t\t\t\tthis.fixCRLF(node, nextNode);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate validateCRLFWithNextNode(node: TreeNode) {\n\t\tif (this.shouldCheckCRLF() && this.endWithCR(node)) {\n\t\t\tconst nextNode = node.next();\n\t\t\tif (this.startWithLF(nextNode)) {\n\t\t\t\tthis.fixCRLF(node, nextNode);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate fixCRLF(prev: TreeNode, next: TreeNode) {\n\t\tconst nodesToDel: TreeNode[] = [];\n\t\t// update node\n\t\tconst lineStarts = this._buffers[prev.piece.bufferIndex].lineStarts;\n\t\tlet newEnd: BufferCursor;\n\t\tif (prev.piece.end.column === 0) {\n\t\t\t// it means, last line ends with \\r, not \\r\\n\n\t\t\tnewEnd = { line: prev.piece.end.line - 1, column: lineStarts[prev.piece.end.line] - lineStarts[prev.piece.end.line - 1] - 1 };\n\t\t} else {\n\t\t\t// \\r\\n\n\t\t\tnewEnd = { line: prev.piece.end.line, column: prev.piece.end.column - 1 };\n\t\t}\n\n\t\tconst prevNewLength = prev.piece.length - 1;\n\t\tconst prevNewLFCnt = prev.piece.lineFeedCnt - 1;\n\t\tprev.piece = new Piece(\n\t\t\tprev.piece.bufferIndex,\n\t\t\tprev.piece.start,\n\t\t\tnewEnd,\n\t\t\tprevNewLFCnt,\n\t\t\tprevNewLength\n\t\t);\n\n\t\tupdateTreeMetadata(this, prev, - 1, -1);\n\t\tif (prev.piece.length === 0) {\n\t\t\tnodesToDel.push(prev);\n\t\t}\n\n\t\t// update nextNode\n\t\tconst newStart: BufferCursor = { line: next.piece.start.line + 1, column: 0 };\n\t\tconst newLength = next.piece.length - 1;\n\t\tconst newLineFeedCnt = this.getLineFeedCnt(next.piece.bufferIndex, newStart, next.piece.end);\n\t\tnext.piece = new Piece(\n\t\t\tnext.piece.bufferIndex,\n\t\t\tnewStart,\n\t\t\tnext.piece.end,\n\t\t\tnewLineFeedCnt,\n\t\t\tnewLength\n\t\t);\n\n\t\tupdateTreeMetadata(this, next, - 1, -1);\n\t\tif (next.piece.length === 0) {\n\t\t\tnodesToDel.push(next);\n\t\t}\n\n\t\t// create new piece which contains \\r\\n\n\t\tconst pieces = this.createNewPieces('\\r\\n');\n\t\tthis.rbInsertRight(prev, pieces[0]);\n\t\t// delete empty nodes\n\n\t\tfor (let i = 0; i < nodesToDel.length; i++) {\n\t\t\trbDelete(this, nodesToDel[i]);\n\t\t}\n\t}\n\n\tprivate adjustCarriageReturnFromNext(value: string, node: TreeNode): boolean {\n\t\tif (this.shouldCheckCRLF() && this.endWithCR(value)) {\n\t\t\tconst nextNode = node.next();\n\t\t\tif (this.startWithLF(nextNode)) {\n\t\t\t\t// move `\\n` forward\n\t\t\t\tvalue += '\\n';\n\n\t\t\t\tif (nextNode.piece.length === 1) {\n\t\t\t\t\trbDelete(this, nextNode);\n\t\t\t\t} else {\n\n\t\t\t\t\tconst piece = nextNode.piece;\n\t\t\t\t\tconst newStart: BufferCursor = { line: piece.start.line + 1, column: 0 };\n\t\t\t\t\tconst newLength = piece.length - 1;\n\t\t\t\t\tconst newLineFeedCnt = this.getLineFeedCnt(piece.bufferIndex, newStart, piece.end);\n\t\t\t\t\tnextNode.piece = new Piece(\n\t\t\t\t\t\tpiece.bufferIndex,\n\t\t\t\t\t\tnewStart,\n\t\t\t\t\t\tpiece.end,\n\t\t\t\t\t\tnewLineFeedCnt,\n\t\t\t\t\t\tnewLength\n\t\t\t\t\t);\n\n\t\t\t\t\tupdateTreeMetadata(this, nextNode, -1, -1);\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t// #endregion\n\n\t// #endregion\n\n\t// #region Tree operations\n\titerate(node: TreeNode, callback: (node: TreeNode) => boolean): boolean {\n\t\tif (node === SENTINEL) {\n\t\t\treturn callback(SENTINEL);\n\t\t}\n\n\t\tconst leftRet = this.iterate(node.left, callback);\n\t\tif (!leftRet) {\n\t\t\treturn leftRet;\n\t\t}\n\n\t\treturn callback(node) && this.iterate(node.right, callback);\n\t}\n\n\tprivate getNodeContent(node: TreeNode) {\n\t\tif (node === SENTINEL) {\n\t\t\treturn '';\n\t\t}\n\t\tconst buffer = this._buffers[node.piece.bufferIndex];\n\t\tconst piece = node.piece;\n\t\tconst startOffset = this.offsetInBuffer(piece.bufferIndex, piece.start);\n\t\tconst endOffset = this.offsetInBuffer(piece.bufferIndex, piece.end);\n\t\tconst currentContent = buffer.buffer.substring(startOffset, endOffset);\n\t\treturn currentContent;\n\t}\n\n\tgetPieceContent(piece: Piece) {\n\t\tconst buffer = this._buffers[piece.bufferIndex];\n\t\tconst startOffset = this.offsetInBuffer(piece.bufferIndex, piece.start);\n\t\tconst endOffset = this.offsetInBuffer(piece.bufferIndex, piece.end);\n\t\tconst currentContent = buffer.buffer.substring(startOffset, endOffset);\n\t\treturn currentContent;\n\t}\n\n\t/**\n\t * node node\n\t * / \\ / \\\n\t * a b <---- a b\n\t * /\n\t * z\n\t */\n\tprivate rbInsertRight(node: TreeNode | null, p: Piece): TreeNode {\n\t\tconst z = new TreeNode(p, NodeColor.Red);\n\t\tz.left = SENTINEL;\n\t\tz.right = SENTINEL;\n\t\tz.parent = SENTINEL;\n\t\tz.size_left = 0;\n\t\tz.lf_left = 0;\n\n\t\tconst x = this.root;\n\t\tif (x === SENTINEL) {\n\t\t\tthis.root = z;\n\t\t\tz.color = NodeColor.Black;\n\t\t} else if (node!.right === SENTINEL) {\n\t\t\tnode!.right = z;\n\t\t\tz.parent = node!;\n\t\t} else {\n\t\t\tconst nextNode = leftest(node!.right);\n\t\t\tnextNode.left = z;\n\t\t\tz.parent = nextNode;\n\t\t}\n\n\t\tfixInsert(this, z);\n\t\treturn z;\n\t}\n\n\t/**\n\t * node node\n\t * / \\ / \\\n\t * a b ----> a b\n\t * \\\n\t * z\n\t */\n\tprivate rbInsertLeft(node: TreeNode | null, p: Piece): TreeNode {\n\t\tconst z = new TreeNode(p, NodeColor.Red);\n\t\tz.left = SENTINEL;\n\t\tz.right = SENTINEL;\n\t\tz.parent = SENTINEL;\n\t\tz.size_left = 0;\n\t\tz.lf_left = 0;\n\n\t\tif (this.root === SENTINEL) {\n\t\t\tthis.root = z;\n\t\t\tz.color = NodeColor.Black;\n\t\t} else if (node!.left === SENTINEL) {\n\t\t\tnode!.left = z;\n\t\t\tz.parent = node!;\n\t\t} else {\n\t\t\tconst prevNode = righttest(node!.left); // a\n\t\t\tprevNode.right = z;\n\t\t\tz.parent = prevNode;\n\t\t}\n\n\t\tfixInsert(this, z);\n\t\treturn z;\n\t}\n\t// #endregion\n}\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\nimport { Range } from 'vs/editor/common/core/range';\nimport { AbstractText } from 'vs/editor/common/core/textEdit';\nimport { TextLength } from 'vs/editor/common/core/textLength';\nimport { ITextModel } from 'vs/editor/common/model';\n\nexport class TextModelText extends AbstractText {\n\tconstructor(private readonly _textModel: ITextModel) {\n\t\tsuper();\n\t}\n\n\tgetValueOfRange(range: Range): string {\n\t\treturn this._textModel.getValueInRange(range);\n\t}\n\n\tget length(): TextLength {\n\t\tconst lastLineNumber = this._textModel.getLineCount();\n\t\tconst lastLineLen = this._textModel.getLineLength(lastLineNumber);\n\t\treturn new TextLength(lastLineNumber - 1, lastLineLen);\n\t}\n}\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\nimport { CharCode } from 'vs/base/common/charCode';\n\n/**\n * Returns:\n * - -1 => the line consists of whitespace\n * - otherwise => the indent level is returned value\n */\nexport function computeIndentLevel(line: string, tabSize: number): number {\n\tlet indent = 0;\n\tlet i = 0;\n\tconst len = line.length;\n\n\twhile (i < len) {\n\t\tconst chCode = line.charCodeAt(i);\n\t\tif (chCode === CharCode.Space) {\n\t\t\tindent++;\n\t\t} else if (chCode === CharCode.Tab) {\n\t\t\tindent = indent - indent % tabSize + tabSize;\n\t\t} else {\n\t\t\tbreak;\n\t\t}\n\t\ti++;\n\t}\n\n\tif (i === len) {\n\t\treturn -1; // line only consists of whitespace\n\t}\n\n\treturn indent;\n}\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\nimport { assertNever } from 'vs/base/common/assert';\nimport { WrappingIndent } from 'vs/editor/common/config/editorOptions';\nimport { FontInfo } from 'vs/editor/common/config/fontInfo';\nimport { Position } from 'vs/editor/common/core/position';\nimport { InjectedTextCursorStops, InjectedTextOptions, PositionAffinity } from 'vs/editor/common/model';\nimport { LineInjectedText } from 'vs/editor/common/textModelEvents';\n\n/**\n * *input*:\n * ```\n * xxxxxxxxxxxxxxxxxxxxxxxxxxx\n * ```\n *\n * -> Applying injections `[i...i]`, *inputWithInjections*:\n * ```\n * xxxxxx[iiiiiiiiii]xxxxxxxxxxxxxxxxx[ii]xxxx\n * ```\n *\n * -> breaking at offsets `|` in `xxxxxx[iiiiiii|iii]xxxxxxxxxxx|xxxxxx[ii]xxxx|`:\n * ```\n * xxxxxx[iiiiiii\n * iii]xxxxxxxxxxx\n * xxxxxx[ii]xxxx\n * ```\n *\n * -> applying wrappedTextIndentLength, *output*:\n * ```\n * xxxxxx[iiiiiii\n * iii]xxxxxxxxxxx\n * xxxxxx[ii]xxxx\n * ```\n */\nexport class ModelLineProjectionData {\n\tconstructor(\n\t\tpublic injectionOffsets: number[] | null,\n\t\t/**\n\t\t * `injectionOptions.length` must equal `injectionOffsets.length`\n\t\t */\n\t\tpublic injectionOptions: InjectedTextOptions[] | null,\n\t\t/**\n\t\t * Refers to offsets after applying injections to the source.\n\t\t * The last break offset indicates the length of the source after applying injections.\n\t\t */\n\t\tpublic breakOffsets: number[],\n\t\t/**\n\t\t * Refers to offsets after applying injections\n\t\t */\n\t\tpublic breakOffsetsVisibleColumn: number[],\n\t\tpublic wrappedTextIndentLength: number\n\t) {\n\t}\n\n\tpublic getOutputLineCount(): number {\n\t\treturn this.breakOffsets.length;\n\t}\n\n\tpublic getMinOutputOffset(outputLineIndex: number): number {\n\t\tif (outputLineIndex > 0) {\n\t\t\treturn this.wrappedTextIndentLength;\n\t\t}\n\t\treturn 0;\n\t}\n\n\tpublic getLineLength(outputLineIndex: number): number {\n\t\t// These offsets refer to model text with injected text.\n\t\tconst startOffset = outputLineIndex > 0 ? this.breakOffsets[outputLineIndex - 1] : 0;\n\t\tconst endOffset = this.breakOffsets[outputLineIndex];\n\n\t\tlet lineLength = endOffset - startOffset;\n\t\tif (outputLineIndex > 0) {\n\t\t\tlineLength += this.wrappedTextIndentLength;\n\t\t}\n\t\treturn lineLength;\n\t}\n\n\tpublic getMaxOutputOffset(outputLineIndex: number): number {\n\t\treturn this.getLineLength(outputLineIndex);\n\t}\n\n\tpublic translateToInputOffset(outputLineIndex: number, outputOffset: number): number {\n\t\tif (outputLineIndex > 0) {\n\t\t\toutputOffset = Math.max(0, outputOffset - this.wrappedTextIndentLength);\n\t\t}\n\n\t\tconst offsetInInputWithInjection = outputLineIndex === 0 ? outputOffset : this.breakOffsets[outputLineIndex - 1] + outputOffset;\n\t\tlet offsetInInput = offsetInInputWithInjection;\n\n\t\tif (this.injectionOffsets !== null) {\n\t\t\tfor (let i = 0; i < this.injectionOffsets.length; i++) {\n\t\t\t\tif (offsetInInput > this.injectionOffsets[i]) {\n\t\t\t\t\tif (offsetInInput < this.injectionOffsets[i] + this.injectionOptions![i].content.length) {\n\t\t\t\t\t\t// `inputOffset` is within injected text\n\t\t\t\t\t\toffsetInInput = this.injectionOffsets[i];\n\t\t\t\t\t} else {\n\t\t\t\t\t\toffsetInInput -= this.injectionOptions![i].content.length;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn offsetInInput;\n\t}\n\n\tpublic translateToOutputPosition(inputOffset: number, affinity: PositionAffinity = PositionAffinity.None): OutputPosition {\n\t\tlet inputOffsetInInputWithInjection = inputOffset;\n\t\tif (this.injectionOffsets !== null) {\n\t\t\tfor (let i = 0; i < this.injectionOffsets.length; i++) {\n\t\t\t\tif (inputOffset < this.injectionOffsets[i]) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tif (affinity !== PositionAffinity.Right && inputOffset === this.injectionOffsets[i]) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tinputOffsetInInputWithInjection += this.injectionOptions![i].content.length;\n\t\t\t}\n\t\t}\n\n\t\treturn this.offsetInInputWithInjectionsToOutputPosition(inputOffsetInInputWithInjection, affinity);\n\t}\n\n\tprivate offsetInInputWithInjectionsToOutputPosition(offsetInInputWithInjections: number, affinity: PositionAffinity = PositionAffinity.None): OutputPosition {\n\t\tlet low = 0;\n\t\tlet high = this.breakOffsets.length - 1;\n\t\tlet mid = 0;\n\t\tlet midStart = 0;\n\n\t\twhile (low <= high) {\n\t\t\tmid = low + ((high - low) / 2) | 0;\n\n\t\t\tconst midStop = this.breakOffsets[mid];\n\t\t\tmidStart = mid > 0 ? this.breakOffsets[mid - 1] : 0;\n\n\t\t\tif (affinity === PositionAffinity.Left) {\n\t\t\t\tif (offsetInInputWithInjections <= midStart) {\n\t\t\t\t\thigh = mid - 1;\n\t\t\t\t} else if (offsetInInputWithInjections > midStop) {\n\t\t\t\t\tlow = mid + 1;\n\t\t\t\t} else {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (offsetInInputWithInjections < midStart) {\n\t\t\t\t\thigh = mid - 1;\n\t\t\t\t} else if (offsetInInputWithInjections >= midStop) {\n\t\t\t\t\tlow = mid + 1;\n\t\t\t\t} else {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tlet outputOffset = offsetInInputWithInjections - midStart;\n\t\tif (mid > 0) {\n\t\t\toutputOffset += this.wrappedTextIndentLength;\n\t\t}\n\n\t\treturn new OutputPosition(mid, outputOffset);\n\t}\n\n\tpublic normalizeOutputPosition(outputLineIndex: number, outputOffset: number, affinity: PositionAffinity): OutputPosition {\n\t\tif (this.injectionOffsets !== null) {\n\t\t\tconst offsetInInputWithInjections = this.outputPositionToOffsetInInputWithInjections(outputLineIndex, outputOffset);\n\t\t\tconst normalizedOffsetInUnwrappedLine = this.normalizeOffsetInInputWithInjectionsAroundInjections(offsetInInputWithInjections, affinity);\n\t\t\tif (normalizedOffsetInUnwrappedLine !== offsetInInputWithInjections) {\n\t\t\t\t// injected text caused a change\n\t\t\t\treturn this.offsetInInputWithInjectionsToOutputPosition(normalizedOffsetInUnwrappedLine, affinity);\n\t\t\t}\n\t\t}\n\n\t\tif (affinity === PositionAffinity.Left) {\n\t\t\tif (outputLineIndex > 0 && outputOffset === this.getMinOutputOffset(outputLineIndex)) {\n\t\t\t\treturn new OutputPosition(outputLineIndex - 1, this.getMaxOutputOffset(outputLineIndex - 1));\n\t\t\t}\n\t\t}\n\t\telse if (affinity === PositionAffinity.Right) {\n\t\t\tconst maxOutputLineIndex = this.getOutputLineCount() - 1;\n\t\t\tif (outputLineIndex < maxOutputLineIndex && outputOffset === this.getMaxOutputOffset(outputLineIndex)) {\n\t\t\t\treturn new OutputPosition(outputLineIndex + 1, this.getMinOutputOffset(outputLineIndex + 1));\n\t\t\t}\n\t\t}\n\n\t\treturn new OutputPosition(outputLineIndex, outputOffset);\n\t}\n\n\tprivate outputPositionToOffsetInInputWithInjections(outputLineIndex: number, outputOffset: number): number {\n\t\tif (outputLineIndex > 0) {\n\t\t\toutputOffset = Math.max(0, outputOffset - this.wrappedTextIndentLength);\n\t\t}\n\t\tconst result = (outputLineIndex > 0 ? this.breakOffsets[outputLineIndex - 1] : 0) + outputOffset;\n\t\treturn result;\n\t}\n\n\tprivate normalizeOffsetInInputWithInjectionsAroundInjections(offsetInInputWithInjections: number, affinity: PositionAffinity): number {\n\t\tconst injectedText = this.getInjectedTextAtOffset(offsetInInputWithInjections);\n\t\tif (!injectedText) {\n\t\t\treturn offsetInInputWithInjections;\n\t\t}\n\n\t\tif (affinity === PositionAffinity.None) {\n\t\t\tif (offsetInInputWithInjections === injectedText.offsetInInputWithInjections + injectedText.length\n\t\t\t\t&& hasRightCursorStop(this.injectionOptions![injectedText.injectedTextIndex].cursorStops)) {\n\t\t\t\treturn injectedText.offsetInInputWithInjections + injectedText.length;\n\t\t\t} else {\n\t\t\t\tlet result = injectedText.offsetInInputWithInjections;\n\t\t\t\tif (hasLeftCursorStop(this.injectionOptions![injectedText.injectedTextIndex].cursorStops)) {\n\t\t\t\t\treturn result;\n\t\t\t\t}\n\n\t\t\t\tlet index = injectedText.injectedTextIndex - 1;\n\t\t\t\twhile (index >= 0 && this.injectionOffsets![index] === this.injectionOffsets![injectedText.injectedTextIndex]) {\n\t\t\t\t\tif (hasRightCursorStop(this.injectionOptions![index].cursorStops)) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tresult -= this.injectionOptions![index].content.length;\n\t\t\t\t\tif (hasLeftCursorStop(this.injectionOptions![index].cursorStops)) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tindex--;\n\t\t\t\t}\n\n\t\t\t\treturn result;\n\t\t\t}\n\t\t} else if (affinity === PositionAffinity.Right || affinity === PositionAffinity.RightOfInjectedText) {\n\t\t\tlet result = injectedText.offsetInInputWithInjections + injectedText.length;\n\t\t\tlet index = injectedText.injectedTextIndex;\n\t\t\t// traverse all injected text that touch each other\n\t\t\twhile (index + 1 < this.injectionOffsets!.length && this.injectionOffsets![index + 1] === this.injectionOffsets![index]) {\n\t\t\t\tresult += this.injectionOptions![index + 1].content.length;\n\t\t\t\tindex++;\n\t\t\t}\n\t\t\treturn result;\n\t\t} else if (affinity === PositionAffinity.Left || affinity === PositionAffinity.LeftOfInjectedText) {\n\t\t\t// affinity is left\n\t\t\tlet result = injectedText.offsetInInputWithInjections;\n\t\t\tlet index = injectedText.injectedTextIndex;\n\t\t\t// traverse all injected text that touch each other\n\t\t\twhile (index - 1 >= 0 && this.injectionOffsets![index - 1] === this.injectionOffsets![index]) {\n\t\t\t\tresult -= this.injectionOptions![index - 1].content.length;\n\t\t\t\tindex--;\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\n\t\tassertNever(affinity);\n\t}\n\n\tpublic getInjectedText(outputLineIndex: number, outputOffset: number): InjectedText | null {\n\t\tconst offset = this.outputPositionToOffsetInInputWithInjections(outputLineIndex, outputOffset);\n\t\tconst injectedText = this.getInjectedTextAtOffset(offset);\n\t\tif (!injectedText) {\n\t\t\treturn null;\n\t\t}\n\t\treturn {\n\t\t\toptions: this.injectionOptions![injectedText.injectedTextIndex]\n\t\t};\n\t}\n\n\tprivate getInjectedTextAtOffset(offsetInInputWithInjections: number): { injectedTextIndex: number; offsetInInputWithInjections: number; length: number } | undefined {\n\t\tconst injectionOffsets = this.injectionOffsets;\n\t\tconst injectionOptions = this.injectionOptions;\n\n\t\tif (injectionOffsets !== null) {\n\t\t\tlet totalInjectedTextLengthBefore = 0;\n\t\t\tfor (let i = 0; i < injectionOffsets.length; i++) {\n\t\t\t\tconst length = injectionOptions![i].content.length;\n\t\t\t\tconst injectedTextStartOffsetInInputWithInjections = injectionOffsets[i] + totalInjectedTextLengthBefore;\n\t\t\t\tconst injectedTextEndOffsetInInputWithInjections = injectionOffsets[i] + totalInjectedTextLengthBefore + length;\n\n\t\t\t\tif (injectedTextStartOffsetInInputWithInjections > offsetInInputWithInjections) {\n\t\t\t\t\t// Injected text starts later.\n\t\t\t\t\tbreak; // All later injected texts have an even larger offset.\n\t\t\t\t}\n\n\t\t\t\tif (offsetInInputWithInjections <= injectedTextEndOffsetInInputWithInjections) {\n\t\t\t\t\t// Injected text ends after or with the given position (but also starts with or before it).\n\t\t\t\t\treturn {\n\t\t\t\t\t\tinjectedTextIndex: i,\n\t\t\t\t\t\toffsetInInputWithInjections: injectedTextStartOffsetInInputWithInjections,\n\t\t\t\t\t\tlength\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\ttotalInjectedTextLengthBefore += length;\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n}\n\nfunction hasRightCursorStop(cursorStop: InjectedTextCursorStops | null | undefined): boolean {\n\tif (cursorStop === null || cursorStop === undefined) { return true; }\n\treturn cursorStop === InjectedTextCursorStops.Right || cursorStop === InjectedTextCursorStops.Both;\n}\nfunction hasLeftCursorStop(cursorStop: InjectedTextCursorStops | null | undefined): boolean {\n\tif (cursorStop === null || cursorStop === undefined) { return true; }\n\treturn cursorStop === InjectedTextCursorStops.Left || cursorStop === InjectedTextCursorStops.Both;\n}\n\nexport class InjectedText {\n\tconstructor(public readonly options: InjectedTextOptions) { }\n}\n\nexport class OutputPosition {\n\toutputLineIndex: number;\n\toutputOffset: number;\n\n\tconstructor(outputLineIndex: number, outputOffset: number) {\n\t\tthis.outputLineIndex = outputLineIndex;\n\t\tthis.outputOffset = outputOffset;\n\t}\n\n\ttoString(): string {\n\t\treturn `${this.outputLineIndex}:${this.outputOffset}`;\n\t}\n\n\ttoPosition(baseLineNumber: number): Position {\n\t\treturn new Position(baseLineNumber + this.outputLineIndex, this.outputOffset + 1);\n\t}\n}\n\nexport interface ILineBreaksComputerFactory {\n\tcreateLineBreaksComputer(fontInfo: FontInfo, tabSize: number, wrappingColumn: number, wrappingIndent: WrappingIndent, wordBreak: 'normal' | 'keepAll'): ILineBreaksComputer;\n}\n\nexport interface ILineBreaksComputer {\n\t/**\n\t * Pass in `previousLineBreakData` if the only difference is in breaking columns!!!\n\t */\n\taddRequest(lineText: string, injectedText: LineInjectedText[] | null, previousLineBreakData: ModelLineProjectionData | null): void;\n\tfinalize(): (ModelLineProjectionData | null)[];\n}\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\nimport { IRange } from 'vs/editor/common/core/range';\nimport { FoldingRules } from 'vs/editor/common/languages/languageConfiguration';\n\nexport interface ISectionHeaderFinderTarget {\n\tgetLineCount(): number;\n\tgetLineContent(lineNumber: number): string;\n}\n\nexport interface FindSectionHeaderOptions {\n\tfoldingRules?: FoldingRules;\n\tfindRegionSectionHeaders: boolean;\n\tfindMarkSectionHeaders: boolean;\n}\n\nexport interface SectionHeader {\n\t/**\n\t * The location of the header text in the text model.\n\t */\n\trange: IRange;\n\t/**\n\t * The section header text.\n\t */\n\ttext: string;\n\t/**\n\t * Whether the section header includes a separator line.\n\t */\n\thasSeparatorLine: boolean;\n\t/**\n\t * This section should be omitted before rendering if it's not in a comment.\n\t */\n\tshouldBeInComments: boolean;\n}\n\nconst markRegex = new RegExp('\\\\bMARK:\\\\s*(.*)$', 'd');\nconst trimDashesRegex = /^-+|-+$/g;\n\n/**\n * Find section headers in the model.\n *\n * @param model the text model to search in\n * @param options options to search with\n * @returns an array of section headers\n */\nexport function findSectionHeaders(model: ISectionHeaderFinderTarget, options: FindSectionHeaderOptions): SectionHeader[] {\n\tlet headers: SectionHeader[] = [];\n\tif (options.findRegionSectionHeaders && options.foldingRules?.markers) {\n\t\tconst regionHeaders = collectRegionHeaders(model, options);\n\t\theaders = headers.concat(regionHeaders);\n\t}\n\tif (options.findMarkSectionHeaders) {\n\t\tconst markHeaders = collectMarkHeaders(model);\n\t\theaders = headers.concat(markHeaders);\n\t}\n\treturn headers;\n}\n\nfunction collectRegionHeaders(model: ISectionHeaderFinderTarget, options: FindSectionHeaderOptions): SectionHeader[] {\n\tconst regionHeaders: SectionHeader[] = [];\n\tconst endLineNumber = model.getLineCount();\n\tfor (let lineNumber = 1; lineNumber <= endLineNumber; lineNumber++) {\n\t\tconst lineContent = model.getLineContent(lineNumber);\n\t\tconst match = lineContent.match(options.foldingRules!.markers!.start);\n\t\tif (match) {\n\t\t\tconst range = { startLineNumber: lineNumber, startColumn: match[0].length + 1, endLineNumber: lineNumber, endColumn: lineContent.length + 1 };\n\t\t\tif (range.endColumn > range.startColumn) {\n\t\t\t\tconst sectionHeader = {\n\t\t\t\t\trange,\n\t\t\t\t\t...getHeaderText(lineContent.substring(match[0].length)),\n\t\t\t\t\tshouldBeInComments: false\n\t\t\t\t};\n\t\t\t\tif (sectionHeader.text || sectionHeader.hasSeparatorLine) {\n\t\t\t\t\tregionHeaders.push(sectionHeader);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn regionHeaders;\n}\n\nfunction collectMarkHeaders(model: ISectionHeaderFinderTarget): SectionHeader[] {\n\tconst markHeaders: SectionHeader[] = [];\n\tconst endLineNumber = model.getLineCount();\n\tfor (let lineNumber = 1; lineNumber <= endLineNumber; lineNumber++) {\n\t\tconst lineContent = model.getLineContent(lineNumber);\n\t\taddMarkHeaderIfFound(lineContent, lineNumber, markHeaders);\n\t}\n\treturn markHeaders;\n}\n\nfunction addMarkHeaderIfFound(lineContent: string, lineNumber: number, sectionHeaders: SectionHeader[]) {\n\tmarkRegex.lastIndex = 0;\n\tconst match = markRegex.exec(lineContent);\n\tif (match) {\n\t\tconst column = match.indices![1][0] + 1;\n\t\tconst endColumn = match.indices![1][1] + 1;\n\t\tconst range = { startLineNumber: lineNumber, startColumn: column, endLineNumber: lineNumber, endColumn: endColumn };\n\t\tif (range.endColumn > range.startColumn) {\n\t\t\tconst sectionHeader = {\n\t\t\t\trange,\n\t\t\t\t...getHeaderText(match[1]),\n\t\t\t\tshouldBeInComments: true\n\t\t\t};\n\t\t\tif (sectionHeader.text || sectionHeader.hasSeparatorLine) {\n\t\t\t\tsectionHeaders.push(sectionHeader);\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction getHeaderText(text: string): { text: string; hasSeparatorLine: boolean } {\n\ttext = text.trim();\n\tconst hasSeparatorLine = text.startsWith('-');\n\ttext = text.replace(trimDashesRegex, '');\n\treturn { text, hasSeparatorLine };\n}\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\nexport interface ITreeViewsDnDService {\n\treadonly _serviceBrand: undefined;\n\n\tremoveDragOperationTransfer(uuid: string | undefined): Promise | undefined;\n}\n\nexport class TreeViewsDnDService implements ITreeViewsDnDService {\n\t_serviceBrand: undefined;\n\tprivate _dragOperations: Map> = new Map();\n\n\tremoveDragOperationTransfer(uuid: string | undefined): Promise | undefined {\n\t\tif ((uuid && this._dragOperations.has(uuid))) {\n\t\t\tconst operation = this._dragOperations.get(uuid);\n\t\t\tthis._dragOperations.delete(uuid);\n\t\t\treturn operation;\n\t\t}\n\t\treturn undefined;\n\t}\n}\n\n\nexport class DraggedTreeItemsIdentifier {\n\n\tconstructor(readonly identifier: string) { }\n}\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\nimport { IRange, Range } from 'vs/editor/common/core/range';\nimport { Searcher } from 'vs/editor/common/model/textModelSearch';\nimport * as strings from 'vs/base/common/strings';\nimport { IUnicodeHighlightsResult } from 'vs/editor/common/services/editorWorker';\nimport { assertNever } from 'vs/base/common/assert';\nimport { DEFAULT_WORD_REGEXP, getWordAtText } from 'vs/editor/common/core/wordHelper';\n\nexport class UnicodeTextModelHighlighter {\n\tpublic static computeUnicodeHighlights(model: IUnicodeCharacterSearcherTarget, options: UnicodeHighlighterOptions, range?: IRange): IUnicodeHighlightsResult {\n\t\tconst startLine = range ? range.startLineNumber : 1;\n\t\tconst endLine = range ? range.endLineNumber : model.getLineCount();\n\n\t\tconst codePointHighlighter = new CodePointHighlighter(options);\n\n\t\tconst candidates = codePointHighlighter.getCandidateCodePoints();\n\t\tlet regex: RegExp;\n\t\tif (candidates === 'allNonBasicAscii') {\n\t\t\tregex = new RegExp('[^\\\\t\\\\n\\\\r\\\\x20-\\\\x7E]', 'g');\n\t\t} else {\n\t\t\tregex = new RegExp(`${buildRegExpCharClassExpr(Array.from(candidates))}`, 'g');\n\t\t}\n\n\t\tconst searcher = new Searcher(null, regex);\n\t\tconst ranges: Range[] = [];\n\t\tlet hasMore = false;\n\t\tlet m: RegExpExecArray | null;\n\n\t\tlet ambiguousCharacterCount = 0;\n\t\tlet invisibleCharacterCount = 0;\n\t\tlet nonBasicAsciiCharacterCount = 0;\n\n\t\tforLoop:\n\t\tfor (let lineNumber = startLine, lineCount = endLine; lineNumber <= lineCount; lineNumber++) {\n\t\t\tconst lineContent = model.getLineContent(lineNumber);\n\t\t\tconst lineLength = lineContent.length;\n\n\t\t\t// Reset regex to search from the beginning\n\t\t\tsearcher.reset(0);\n\t\t\tdo {\n\t\t\t\tm = searcher.next(lineContent);\n\t\t\t\tif (m) {\n\t\t\t\t\tlet startIndex = m.index;\n\t\t\t\t\tlet endIndex = m.index + m[0].length;\n\n\t\t\t\t\t// Extend range to entire code point\n\t\t\t\t\tif (startIndex > 0) {\n\t\t\t\t\t\tconst charCodeBefore = lineContent.charCodeAt(startIndex - 1);\n\t\t\t\t\t\tif (strings.isHighSurrogate(charCodeBefore)) {\n\t\t\t\t\t\t\tstartIndex--;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (endIndex + 1 < lineLength) {\n\t\t\t\t\t\tconst charCodeBefore = lineContent.charCodeAt(endIndex - 1);\n\t\t\t\t\t\tif (strings.isHighSurrogate(charCodeBefore)) {\n\t\t\t\t\t\t\tendIndex++;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tconst str = lineContent.substring(startIndex, endIndex);\n\t\t\t\t\tlet word = getWordAtText(startIndex + 1, DEFAULT_WORD_REGEXP, lineContent, 0);\n\t\t\t\t\tif (word && word.endColumn <= startIndex + 1) {\n\t\t\t\t\t\t// The word does not include the problematic character, ignore the word\n\t\t\t\t\t\tword = null;\n\t\t\t\t\t}\n\t\t\t\t\tconst highlightReason = codePointHighlighter.shouldHighlightNonBasicASCII(str, word ? word.word : null);\n\n\t\t\t\t\tif (highlightReason !== SimpleHighlightReason.None) {\n\t\t\t\t\t\tif (highlightReason === SimpleHighlightReason.Ambiguous) {\n\t\t\t\t\t\t\tambiguousCharacterCount++;\n\t\t\t\t\t\t} else if (highlightReason === SimpleHighlightReason.Invisible) {\n\t\t\t\t\t\t\tinvisibleCharacterCount++;\n\t\t\t\t\t\t} else if (highlightReason === SimpleHighlightReason.NonBasicASCII) {\n\t\t\t\t\t\t\tnonBasicAsciiCharacterCount++;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tassertNever(highlightReason);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst MAX_RESULT_LENGTH = 1000;\n\t\t\t\t\t\tif (ranges.length >= MAX_RESULT_LENGTH) {\n\t\t\t\t\t\t\thasMore = true;\n\t\t\t\t\t\t\tbreak forLoop;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tranges.push(new Range(lineNumber, startIndex + 1, lineNumber, endIndex + 1));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} while (m);\n\t\t}\n\t\treturn {\n\t\t\tranges,\n\t\t\thasMore,\n\t\t\tambiguousCharacterCount,\n\t\t\tinvisibleCharacterCount,\n\t\t\tnonBasicAsciiCharacterCount\n\t\t};\n\t}\n\n\tpublic static computeUnicodeHighlightReason(char: string, options: UnicodeHighlighterOptions): UnicodeHighlighterReason | null {\n\t\tconst codePointHighlighter = new CodePointHighlighter(options);\n\n\t\tconst reason = codePointHighlighter.shouldHighlightNonBasicASCII(char, null);\n\t\tswitch (reason) {\n\t\t\tcase SimpleHighlightReason.None:\n\t\t\t\treturn null;\n\t\t\tcase SimpleHighlightReason.Invisible:\n\t\t\t\treturn { kind: UnicodeHighlighterReasonKind.Invisible };\n\n\t\t\tcase SimpleHighlightReason.Ambiguous: {\n\t\t\t\tconst codePoint = char.codePointAt(0)!;\n\t\t\t\tconst primaryConfusable = codePointHighlighter.ambiguousCharacters.getPrimaryConfusable(codePoint)!;\n\t\t\t\tconst notAmbiguousInLocales =\n\t\t\t\t\tstrings.AmbiguousCharacters.getLocales().filter(\n\t\t\t\t\t\t(l) =>\n\t\t\t\t\t\t\t!strings.AmbiguousCharacters.getInstance(\n\t\t\t\t\t\t\t\tnew Set([...options.allowedLocales, l])\n\t\t\t\t\t\t\t).isAmbiguous(codePoint)\n\t\t\t\t\t);\n\t\t\t\treturn { kind: UnicodeHighlighterReasonKind.Ambiguous, confusableWith: String.fromCodePoint(primaryConfusable), notAmbiguousInLocales };\n\t\t\t}\n\t\t\tcase SimpleHighlightReason.NonBasicASCII:\n\t\t\t\treturn { kind: UnicodeHighlighterReasonKind.NonBasicAscii };\n\t\t}\n\t}\n}\n\nfunction buildRegExpCharClassExpr(codePoints: number[], flags?: string): string {\n\tconst src = `[${strings.escapeRegExpCharacters(\n\t\tcodePoints.map((i) => String.fromCodePoint(i)).join('')\n\t)}]`;\n\treturn src;\n}\n\nexport const enum UnicodeHighlighterReasonKind {\n\tAmbiguous, Invisible, NonBasicAscii\n}\n\nexport type UnicodeHighlighterReason = {\n\tkind: UnicodeHighlighterReasonKind.Ambiguous;\n\tconfusableWith: string;\n\tnotAmbiguousInLocales: string[];\n} | {\n\tkind: UnicodeHighlighterReasonKind.Invisible;\n} | {\n\tkind: UnicodeHighlighterReasonKind.NonBasicAscii;\n};\n\nclass CodePointHighlighter {\n\tprivate readonly allowedCodePoints: Set;\n\tpublic readonly ambiguousCharacters: strings.AmbiguousCharacters;\n\tconstructor(private readonly options: UnicodeHighlighterOptions) {\n\t\tthis.allowedCodePoints = new Set(options.allowedCodePoints);\n\t\tthis.ambiguousCharacters = strings.AmbiguousCharacters.getInstance(new Set(options.allowedLocales));\n\t}\n\n\tpublic getCandidateCodePoints(): Set | 'allNonBasicAscii' {\n\t\tif (this.options.nonBasicASCII) {\n\t\t\treturn 'allNonBasicAscii';\n\t\t}\n\n\t\tconst set = new Set();\n\n\t\tif (this.options.invisibleCharacters) {\n\t\t\tfor (const cp of strings.InvisibleCharacters.codePoints) {\n\t\t\t\tif (!isAllowedInvisibleCharacter(String.fromCodePoint(cp))) {\n\t\t\t\t\tset.add(cp);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (this.options.ambiguousCharacters) {\n\t\t\tfor (const cp of this.ambiguousCharacters.getConfusableCodePoints()) {\n\t\t\t\tset.add(cp);\n\t\t\t}\n\t\t}\n\n\t\tfor (const cp of this.allowedCodePoints) {\n\t\t\tset.delete(cp);\n\t\t}\n\n\t\treturn set;\n\t}\n\n\tpublic shouldHighlightNonBasicASCII(character: string, wordContext: string | null): SimpleHighlightReason {\n\t\tconst codePoint = character.codePointAt(0)!;\n\n\t\tif (this.allowedCodePoints.has(codePoint)) {\n\t\t\treturn SimpleHighlightReason.None;\n\t\t}\n\n\t\tif (this.options.nonBasicASCII) {\n\t\t\treturn SimpleHighlightReason.NonBasicASCII;\n\t\t}\n\n\t\tlet hasBasicASCIICharacters = false;\n\t\tlet hasNonConfusableNonBasicAsciiCharacter = false;\n\t\tif (wordContext) {\n\t\t\tfor (const char of wordContext) {\n\t\t\t\tconst codePoint = char.codePointAt(0)!;\n\t\t\t\tconst isBasicASCII = strings.isBasicASCII(char);\n\t\t\t\thasBasicASCIICharacters = hasBasicASCIICharacters || isBasicASCII;\n\n\t\t\t\tif (\n\t\t\t\t\t!isBasicASCII &&\n\t\t\t\t\t!this.ambiguousCharacters.isAmbiguous(codePoint) &&\n\t\t\t\t\t!strings.InvisibleCharacters.isInvisibleCharacter(codePoint)\n\t\t\t\t) {\n\t\t\t\t\thasNonConfusableNonBasicAsciiCharacter = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (\n\t\t\t/* Don't allow mixing weird looking characters with ASCII */ !hasBasicASCIICharacters &&\n\t\t\t/* Is there an obviously weird looking character? */ hasNonConfusableNonBasicAsciiCharacter\n\t\t) {\n\t\t\treturn SimpleHighlightReason.None;\n\t\t}\n\n\t\tif (this.options.invisibleCharacters) {\n\t\t\t// TODO check for emojis\n\t\t\tif (!isAllowedInvisibleCharacter(character) && strings.InvisibleCharacters.isInvisibleCharacter(codePoint)) {\n\t\t\t\treturn SimpleHighlightReason.Invisible;\n\t\t\t}\n\t\t}\n\n\t\tif (this.options.ambiguousCharacters) {\n\t\t\tif (this.ambiguousCharacters.isAmbiguous(codePoint)) {\n\t\t\t\treturn SimpleHighlightReason.Ambiguous;\n\t\t\t}\n\t\t}\n\n\t\treturn SimpleHighlightReason.None;\n\t}\n}\n\nfunction isAllowedInvisibleCharacter(character: string): boolean {\n\treturn character === ' ' || character === '\\n' || character === '\\t';\n}\n\nconst enum SimpleHighlightReason {\n\tNone,\n\tNonBasicASCII,\n\tInvisible,\n\tAmbiguous\n}\n\nexport interface IUnicodeCharacterSearcherTarget {\n\tgetLineCount(): number;\n\tgetLineContent(lineNumber: number): string;\n}\n\nexport interface UnicodeHighlighterOptions {\n\tnonBasicASCII: boolean;\n\tambiguousCharacters: boolean;\n\tinvisibleCharacters: boolean;\n\tincludeComments: boolean;\n\tincludeStrings: boolean;\n\tallowedCodePoints: number[];\n\tallowedLocales: string[];\n}\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 CodeActionTriggerType {\n\tInvoke = 1,\n\tAuto = 2\n}\n\nexport enum CompletionItemInsertTextRule {\n\tNone = 0,\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\tariaRequired = 5,\n\tautoClosingBrackets = 6,\n\tautoClosingComments = 7,\n\tscreenReaderAnnounceInlineSuggestion = 8,\n\tautoClosingDelete = 9,\n\tautoClosingOvertype = 10,\n\tautoClosingQuotes = 11,\n\tautoIndent = 12,\n\tautomaticLayout = 13,\n\tautoSurround = 14,\n\tbracketPairColorization = 15,\n\tguides = 16,\n\tcodeLens = 17,\n\tcodeLensFontFamily = 18,\n\tcodeLensFontSize = 19,\n\tcolorDecorators = 20,\n\tcolorDecoratorsLimit = 21,\n\tcolumnSelection = 22,\n\tcomments = 23,\n\tcontextmenu = 24,\n\tcopyWithSyntaxHighlighting = 25,\n\tcursorBlinking = 26,\n\tcursorSmoothCaretAnimation = 27,\n\tcursorStyle = 28,\n\tcursorSurroundingLines = 29,\n\tcursorSurroundingLinesStyle = 30,\n\tcursorWidth = 31,\n\tdisableLayerHinting = 32,\n\tdisableMonospaceOptimizations = 33,\n\tdomReadOnly = 34,\n\tdragAndDrop = 35,\n\tdropIntoEditor = 36,\n\temptySelectionClipboard = 37,\n\texperimentalWhitespaceRendering = 38,\n\textraEditorClassName = 39,\n\tfastScrollSensitivity = 40,\n\tfind = 41,\n\tfixedOverflowWidgets = 42,\n\tfolding = 43,\n\tfoldingStrategy = 44,\n\tfoldingHighlight = 45,\n\tfoldingImportsByDefault = 46,\n\tfoldingMaximumRegions = 47,\n\tunfoldOnClickAfterEndOfLine = 48,\n\tfontFamily = 49,\n\tfontInfo = 50,\n\tfontLigatures = 51,\n\tfontSize = 52,\n\tfontWeight = 53,\n\tfontVariations = 54,\n\tformatOnPaste = 55,\n\tformatOnType = 56,\n\tglyphMargin = 57,\n\tgotoLocation = 58,\n\thideCursorInOverviewRuler = 59,\n\thover = 60,\n\tinDiffEditor = 61,\n\tinlineSuggest = 62,\n\tinlineEdit = 63,\n\tletterSpacing = 64,\n\tlightbulb = 65,\n\tlineDecorationsWidth = 66,\n\tlineHeight = 67,\n\tlineNumbers = 68,\n\tlineNumbersMinChars = 69,\n\tlinkedEditing = 70,\n\tlinks = 71,\n\tmatchBrackets = 72,\n\tminimap = 73,\n\tmouseStyle = 74,\n\tmouseWheelScrollSensitivity = 75,\n\tmouseWheelZoom = 76,\n\tmultiCursorMergeOverlapping = 77,\n\tmultiCursorModifier = 78,\n\tmultiCursorPaste = 79,\n\tmultiCursorLimit = 80,\n\toccurrencesHighlight = 81,\n\toverviewRulerBorder = 82,\n\toverviewRulerLanes = 83,\n\tpadding = 84,\n\tpasteAs = 85,\n\tparameterHints = 86,\n\tpeekWidgetDefaultFocus = 87,\n\tdefinitionLinkOpensInPeek = 88,\n\tquickSuggestions = 89,\n\tquickSuggestionsDelay = 90,\n\treadOnly = 91,\n\treadOnlyMessage = 92,\n\trenameOnType = 93,\n\trenderControlCharacters = 94,\n\trenderFinalNewline = 95,\n\trenderLineHighlight = 96,\n\trenderLineHighlightOnlyWhenFocus = 97,\n\trenderValidationDecorations = 98,\n\trenderWhitespace = 99,\n\trevealHorizontalRightPadding = 100,\n\troundedSelection = 101,\n\trulers = 102,\n\tscrollbar = 103,\n\tscrollBeyondLastColumn = 104,\n\tscrollBeyondLastLine = 105,\n\tscrollPredominantAxis = 106,\n\tselectionClipboard = 107,\n\tselectionHighlight = 108,\n\tselectOnLineNumbers = 109,\n\tshowFoldingControls = 110,\n\tshowUnused = 111,\n\tsnippetSuggestions = 112,\n\tsmartSelect = 113,\n\tsmoothScrolling = 114,\n\tstickyScroll = 115,\n\tstickyTabStops = 116,\n\tstopRenderingLineAfter = 117,\n\tsuggest = 118,\n\tsuggestFontSize = 119,\n\tsuggestLineHeight = 120,\n\tsuggestOnTriggerCharacters = 121,\n\tsuggestSelection = 122,\n\ttabCompletion = 123,\n\ttabIndex = 124,\n\tunicodeHighlighting = 125,\n\tunusualLineTerminators = 126,\n\tuseShadowDOM = 127,\n\tuseTabStops = 128,\n\twordBreak = 129,\n\twordSegmenterLocales = 130,\n\twordSeparators = 131,\n\twordWrap = 132,\n\twordWrapBreakAfterCharacters = 133,\n\twordWrapBreakBeforeCharacters = 134,\n\twordWrapColumn = 135,\n\twordWrapOverride1 = 136,\n\twordWrapOverride2 = 137,\n\twrappingIndent = 138,\n\twrappingStrategy = 139,\n\tshowDeprecated = 140,\n\tinlayHints = 141,\n\teditorClassName = 142,\n\tpixelRatio = 143,\n\ttabFocusMode = 144,\n\tlayoutInfo = 145,\n\twrappingInfo = 146,\n\tdefaultColorDecorators = 147,\n\tcolorDecoratorsActivatedOn = 148,\n\tinlineCompletionsAccessibilityVerbose = 149\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 * Vertical Lane in the glyph margin of the editor.\n */\nexport enum GlyphMarginLane {\n\tLeft = 1,\n\tCenter = 2,\n\tRight = 3\n}\n\nexport enum HoverVerbosityAction {\n\t/**\n\t * Increase the verbosity of the hover\n\t */\n\tIncrease = 0,\n\t/**\n\t * Decrease the verbosity of the hover\n\t */\n\tDecrease = 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\nexport enum InjectedTextCursorStops {\n\tBoth = 0,\n\tRight = 1,\n\tLeft = 2,\n\tNone = 3\n}\n\nexport enum InlayHintKind {\n\tType = 1,\n\tParameter = 2\n}\n\n/**\n * How an {@link InlineCompletionsProvider inline completion provider} was triggered.\n */\nexport enum InlineCompletionTriggerKind {\n\t/**\n\t * Completion was triggered automatically while editing.\n\t * It is sufficient to return a single completion item in this case.\n\t */\n\tAutomatic = 0,\n\t/**\n\t * Completion was triggered explicitly by a user gesture.\n\t * Return multiple completion items to enable cycling through them.\n\t */\n\tExplicit = 1\n}\n\nexport enum InlineEditTriggerKind {\n\tInvoke = 0,\n\tAutomatic = 1\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\tDependsOnKbLayout = -1,\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\tDigit0 = 21,\n\tDigit1 = 22,\n\tDigit2 = 23,\n\tDigit3 = 24,\n\tDigit4 = 25,\n\tDigit5 = 26,\n\tDigit6 = 27,\n\tDigit7 = 28,\n\tDigit8 = 29,\n\tDigit9 = 30,\n\tKeyA = 31,\n\tKeyB = 32,\n\tKeyC = 33,\n\tKeyD = 34,\n\tKeyE = 35,\n\tKeyF = 36,\n\tKeyG = 37,\n\tKeyH = 38,\n\tKeyI = 39,\n\tKeyJ = 40,\n\tKeyK = 41,\n\tKeyL = 42,\n\tKeyM = 43,\n\tKeyN = 44,\n\tKeyO = 45,\n\tKeyP = 46,\n\tKeyQ = 47,\n\tKeyR = 48,\n\tKeyS = 49,\n\tKeyT = 50,\n\tKeyU = 51,\n\tKeyV = 52,\n\tKeyW = 53,\n\tKeyX = 54,\n\tKeyY = 55,\n\tKeyZ = 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\tF20 = 78,\n\tF21 = 79,\n\tF22 = 80,\n\tF23 = 81,\n\tF24 = 82,\n\tNumLock = 83,\n\tScrollLock = 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\tSemicolon = 85,\n\t/**\n\t * For any country/region, the '+' key\n\t * For the US standard keyboard, the '=+' key\n\t */\n\tEqual = 86,\n\t/**\n\t * For any country/region, the ',' key\n\t * For the US standard keyboard, the ',<' key\n\t */\n\tComma = 87,\n\t/**\n\t * For any country/region, the '-' key\n\t * For the US standard keyboard, the '-_' key\n\t */\n\tMinus = 88,\n\t/**\n\t * For any country/region, the '.' key\n\t * For the US standard keyboard, the '.>' key\n\t */\n\tPeriod = 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\tSlash = 90,\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\tBackquote = 91,\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\tBracketLeft = 92,\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\tBackslash = 93,\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\tBracketRight = 94,\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\tQuote = 95,\n\t/**\n\t * Used for miscellaneous characters; it can vary by keyboard.\n\t */\n\tOEM_8 = 96,\n\t/**\n\t * Either the angle bracket key or the backslash key on the RT 102-key keyboard.\n\t */\n\tIntlBackslash = 97,\n\tNumpad0 = 98,// VK_NUMPAD0, 0x60, Numeric keypad 0 key\n\tNumpad1 = 99,// VK_NUMPAD1, 0x61, Numeric keypad 1 key\n\tNumpad2 = 100,// VK_NUMPAD2, 0x62, Numeric keypad 2 key\n\tNumpad3 = 101,// VK_NUMPAD3, 0x63, Numeric keypad 3 key\n\tNumpad4 = 102,// VK_NUMPAD4, 0x64, Numeric keypad 4 key\n\tNumpad5 = 103,// VK_NUMPAD5, 0x65, Numeric keypad 5 key\n\tNumpad6 = 104,// VK_NUMPAD6, 0x66, Numeric keypad 6 key\n\tNumpad7 = 105,// VK_NUMPAD7, 0x67, Numeric keypad 7 key\n\tNumpad8 = 106,// VK_NUMPAD8, 0x68, Numeric keypad 8 key\n\tNumpad9 = 107,// VK_NUMPAD9, 0x69, Numeric keypad 9 key\n\tNumpadMultiply = 108,// VK_MULTIPLY, 0x6A, Multiply key\n\tNumpadAdd = 109,// VK_ADD, 0x6B, Add key\n\tNUMPAD_SEPARATOR = 110,// VK_SEPARATOR, 0x6C, Separator key\n\tNumpadSubtract = 111,// VK_SUBTRACT, 0x6D, Subtract key\n\tNumpadDecimal = 112,// VK_DECIMAL, 0x6E, Decimal key\n\tNumpadDivide = 113,// VK_DIVIDE, 0x6F,\n\t/**\n\t * Cover all key codes when IME is processing input.\n\t */\n\tKEY_IN_COMPOSITION = 114,\n\tABNT_C1 = 115,// Brazilian (ABNT) Keyboard\n\tABNT_C2 = 116,// Brazilian (ABNT) Keyboard\n\tAudioVolumeMute = 117,\n\tAudioVolumeUp = 118,\n\tAudioVolumeDown = 119,\n\tBrowserSearch = 120,\n\tBrowserHome = 121,\n\tBrowserBack = 122,\n\tBrowserForward = 123,\n\tMediaTrackNext = 124,\n\tMediaTrackPrevious = 125,\n\tMediaStop = 126,\n\tMediaPlayPause = 127,\n\tLaunchMediaPlayer = 128,\n\tLaunchMail = 129,\n\tLaunchApp2 = 130,\n\t/**\n\t * VK_CLEAR, 0x0C, CLEAR key\n\t */\n\tClear = 131,\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 = 132\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 * Section header style.\n */\nexport enum MinimapSectionHeaderStyle {\n\tNormal = 1,\n\tUnderlined = 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\nexport enum NewSymbolNameTag {\n\tAIGenerated = 1\n}\n\nexport enum NewSymbolNameTriggerKind {\n\tInvoke = 0,\n\tAutomatic = 1\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\n/**\n * How a partial acceptance was triggered.\n */\nexport enum PartialAcceptTriggerKind {\n\tWord = 0,\n\tLine = 1,\n\tSuggest = 2\n}\n\nexport enum PositionAffinity {\n\t/**\n\t * Prefers the left most position.\n\t*/\n\tLeft = 0,\n\t/**\n\t * Prefers the right most position.\n\t*/\n\tRight = 1,\n\t/**\n\t * No preference.\n\t*/\n\tNone = 2,\n\t/**\n\t * If the given position is on injected text, prefers the position left of it.\n\t*/\n\tLeftOfInjectedText = 3,\n\t/**\n\t * If the given position is on injected text, prefers the position right of it.\n\t*/\n\tRightOfInjectedText = 4\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 ShowLightbulbIconMode {\n\tOff = 'off',\n\tOnCode = 'onCode',\n\tOn = 'on'\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}","/*---------------------------------------------------------------------------------------------\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\nimport { CallbackIterable } from 'vs/base/common/arrays';\nimport { Event } from 'vs/base/common/event';\nimport { IPosition } from 'vs/editor/common/core/position';\nimport { IRange, Range } from 'vs/editor/common/core/range';\nimport { ClosingBracketKind, OpeningBracketKind } from 'vs/editor/common/languages/supports/languageBracketsConfiguration';\nimport { PairAstNode } from 'vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/ast';\n\nexport interface IBracketPairsTextModelPart {\n\t/**\n\t * Is fired when bracket pairs change, either due to a text or a settings change.\n\t*/\n\tonDidChange: Event;\n\n\t/**\n\t * Gets all bracket pairs that intersect the given position.\n\t * The result is sorted by the start position.\n\t */\n\tgetBracketPairsInRange(range: IRange): CallbackIterable;\n\n\t/**\n\t * Gets all bracket pairs that intersect the given position.\n\t * The result is sorted by the start position.\n\t */\n\tgetBracketPairsInRangeWithMinIndentation(range: IRange): CallbackIterable;\n\n\tgetBracketsInRange(range: IRange, onlyColorizedBrackets?: boolean): CallbackIterable;\n\n\t/**\n\t * Find the matching bracket of `request` up, counting brackets.\n\t * @param request The bracket we're searching for\n\t * @param position The position at which to start the search.\n\t * @return The range of the matching bracket, or null if the bracket match was not found.\n\t */\n\tfindMatchingBracketUp(bracket: string, position: IPosition, maxDuration?: number): Range | null;\n\n\t/**\n\t * Find the first bracket in the model before `position`.\n\t * @param position The position at which to start the search.\n\t * @return The info for the first bracket before `position`, or null if there are no more brackets before `positions`.\n\t */\n\tfindPrevBracket(position: IPosition): IFoundBracket | null;\n\n\t/**\n\t * Find the first bracket in the model after `position`.\n\t * @param position The position at which to start the search.\n\t * @return The info for the first bracket after `position`, or null if there are no more brackets after `positions`.\n\t */\n\tfindNextBracket(position: IPosition): IFoundBracket | null;\n\n\t/**\n\t * Find the enclosing brackets that contain `position`.\n\t * @param position The position at which to start the search.\n\t */\n\tfindEnclosingBrackets(position: IPosition, maxDuration?: number): [Range, Range] | null;\n\n\t/**\n\t * Given a `position`, if the position is on top or near a bracket,\n\t * find the matching bracket of that bracket and return the ranges of both brackets.\n\t * @param position The position at which to look for a bracket.\n\t */\n\tmatchBracket(position: IPosition, maxDuration?: number): [Range, Range] | null;\n}\n\nexport interface IFoundBracket {\n\trange: Range;\n\tbracketInfo: OpeningBracketKind | ClosingBracketKind;\n}\n\nexport class BracketInfo {\n\tconstructor(\n\t\tpublic readonly range: Range,\n\t\t/** 0-based level */\n\t\tpublic readonly nestingLevel: number,\n\t\tpublic readonly nestingLevelOfEqualBracketType: number,\n\t\tpublic readonly isInvalid: boolean,\n\t) { }\n}\n\nexport class BracketPairInfo {\n\tconstructor(\n\t\tpublic readonly range: Range,\n\t\tpublic readonly openingBracketRange: Range,\n\t\tpublic readonly closingBracketRange: Range | undefined,\n\t\t/** 0-based */\n\t\tpublic readonly nestingLevel: number,\n\t\tpublic readonly nestingLevelOfEqualBracketType: number,\n\t\tprivate readonly bracketPairNode: PairAstNode,\n\n\t) {\n\t}\n\n\tpublic get openingBracketInfo(): OpeningBracketKind {\n\t\treturn this.bracketPairNode.openingBracket.bracketInfo as OpeningBracketKind;\n\t}\n}\n\nexport class BracketPairWithMinIndentationInfo extends BracketPairInfo {\n\tconstructor(\n\t\trange: Range,\n\t\topeningBracketRange: Range,\n\t\tclosingBracketRange: Range | undefined,\n\t\t/**\n\t\t * 0-based\n\t\t*/\n\t\tnestingLevel: number,\n\t\tnestingLevelOfEqualBracketType: number,\n\t\tbracketPairNode: PairAstNode,\n\t\t/**\n\t\t * -1 if not requested, otherwise the size of the minimum indentation in the bracket pair in terms of visible columns.\n\t\t*/\n\t\tpublic readonly minVisibleColumnIndentation: number,\n\t) {\n\t\tsuper(range, openingBracketRange, closingBracketRange, nestingLevel, nestingLevelOfEqualBracketType, bracketPairNode);\n\t}\n}\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\nimport { Emitter } from 'vs/base/common/event';\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport { Range } from 'vs/editor/common/core/range';\nimport { ITextModel } from 'vs/editor/common/model';\nimport { BracketInfo, BracketPairWithMinIndentationInfo, IFoundBracket } from 'vs/editor/common/textModelBracketPairs';\nimport { TextModel } from 'vs/editor/common/model/textModel';\nimport { IModelContentChangedEvent, IModelTokensChangedEvent } from 'vs/editor/common/textModelEvents';\nimport { ResolvedLanguageConfiguration } from 'vs/editor/common/languages/languageConfigurationRegistry';\nimport { AstNode, AstNodeKind } from './ast';\nimport { TextEditInfo } from './beforeEditPositionMapper';\nimport { LanguageAgnosticBracketTokens } from './brackets';\nimport { Length, lengthAdd, lengthGreaterThanEqual, lengthLessThan, lengthLessThanEqual, lengthsToRange, lengthZero, positionToLength, toLength } from './length';\nimport { parseDocument } from './parser';\nimport { DenseKeyProvider } from './smallImmutableSet';\nimport { FastTokenizer, TextBufferTokenizer } from './tokenizer';\nimport { BackgroundTokenizationState } from 'vs/editor/common/tokenizationTextModelPart';\nimport { Position } from 'vs/editor/common/core/position';\nimport { CallbackIterable } from 'vs/base/common/arrays';\nimport { combineTextEditInfos } from 'vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/combineTextEditInfos';\nimport { ClosingBracketKind, OpeningBracketKind } from 'vs/editor/common/languages/supports/languageBracketsConfiguration';\n\nexport class BracketPairsTree extends Disposable {\n\tprivate readonly didChangeEmitter = new Emitter();\n\n\t/*\n\t\tThere are two trees:\n\t\t* The initial tree that has no token information and is used for performant initial bracket colorization.\n\t\t* The tree that used token information to detect bracket pairs.\n\n\t\tTo prevent flickering, we only switch from the initial tree to tree with token information\n\t\twhen tokenization completes.\n\t\tSince the text can be edited while background tokenization is in progress, we need to update both trees.\n\t*/\n\tprivate initialAstWithoutTokens: AstNode | undefined;\n\tprivate astWithTokens: AstNode | undefined;\n\n\tprivate readonly denseKeyProvider = new DenseKeyProvider();\n\tprivate readonly brackets = new LanguageAgnosticBracketTokens(this.denseKeyProvider, this.getLanguageConfiguration);\n\n\tpublic didLanguageChange(languageId: string): boolean {\n\t\treturn this.brackets.didLanguageChange(languageId);\n\t}\n\n\tpublic readonly onDidChange = this.didChangeEmitter.event;\n\tprivate queuedTextEditsForInitialAstWithoutTokens: TextEditInfo[] = [];\n\tprivate queuedTextEdits: TextEditInfo[] = [];\n\n\tpublic constructor(\n\t\tprivate readonly textModel: TextModel,\n\t\tprivate readonly getLanguageConfiguration: (languageId: string) => ResolvedLanguageConfiguration\n\t) {\n\t\tsuper();\n\n\t\tif (!textModel.tokenization.hasTokens) {\n\t\t\tconst brackets = this.brackets.getSingleLanguageBracketTokens(this.textModel.getLanguageId());\n\t\t\tconst tokenizer = new FastTokenizer(this.textModel.getValue(), brackets);\n\t\t\tthis.initialAstWithoutTokens = parseDocument(tokenizer, [], undefined, true);\n\t\t\tthis.astWithTokens = this.initialAstWithoutTokens;\n\t\t} else if (textModel.tokenization.backgroundTokenizationState === BackgroundTokenizationState.Completed) {\n\t\t\t// Skip the initial ast, as there is no flickering.\n\t\t\t// Directly create the tree with token information.\n\t\t\tthis.initialAstWithoutTokens = undefined;\n\t\t\tthis.astWithTokens = this.parseDocumentFromTextBuffer([], undefined, false);\n\t\t} else {\n\t\t\t// We missed some token changes already, so we cannot use the fast tokenizer + delta increments\n\t\t\tthis.initialAstWithoutTokens = this.parseDocumentFromTextBuffer([], undefined, true);\n\t\t\tthis.astWithTokens = this.initialAstWithoutTokens;\n\t\t}\n\t}\n\n\t//#region TextModel events\n\n\tpublic handleDidChangeBackgroundTokenizationState(): void {\n\t\tif (this.textModel.tokenization.backgroundTokenizationState === BackgroundTokenizationState.Completed) {\n\t\t\tconst wasUndefined = this.initialAstWithoutTokens === undefined;\n\t\t\t// Clear the initial tree as we can use the tree with token information now.\n\t\t\tthis.initialAstWithoutTokens = undefined;\n\t\t\tif (!wasUndefined) {\n\t\t\t\tthis.didChangeEmitter.fire();\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic handleDidChangeTokens({ ranges }: IModelTokensChangedEvent): void {\n\t\tconst edits = ranges.map(r =>\n\t\t\tnew TextEditInfo(\n\t\t\t\ttoLength(r.fromLineNumber - 1, 0),\n\t\t\t\ttoLength(r.toLineNumber, 0),\n\t\t\t\ttoLength(r.toLineNumber - r.fromLineNumber + 1, 0)\n\t\t\t)\n\t\t);\n\n\t\tthis.handleEdits(edits, true);\n\n\t\tif (!this.initialAstWithoutTokens) {\n\t\t\tthis.didChangeEmitter.fire();\n\t\t}\n\t}\n\n\tpublic handleContentChanged(change: IModelContentChangedEvent) {\n\t\tconst edits = TextEditInfo.fromModelContentChanges(change.changes);\n\t\tthis.handleEdits(edits, false);\n\t}\n\n\tprivate handleEdits(edits: TextEditInfo[], tokenChange: boolean): void {\n\t\t// Lazily queue the edits and only apply them when the tree is accessed.\n\t\tconst result = combineTextEditInfos(this.queuedTextEdits, edits);\n\n\t\tthis.queuedTextEdits = result;\n\t\tif (this.initialAstWithoutTokens && !tokenChange) {\n\t\t\tthis.queuedTextEditsForInitialAstWithoutTokens = combineTextEditInfos(this.queuedTextEditsForInitialAstWithoutTokens, edits);\n\t\t}\n\t}\n\n\t//#endregion\n\n\tprivate flushQueue() {\n\t\tif (this.queuedTextEdits.length > 0) {\n\t\t\tthis.astWithTokens = this.parseDocumentFromTextBuffer(this.queuedTextEdits, this.astWithTokens, false);\n\t\t\tthis.queuedTextEdits = [];\n\t\t}\n\t\tif (this.queuedTextEditsForInitialAstWithoutTokens.length > 0) {\n\t\t\tif (this.initialAstWithoutTokens) {\n\t\t\t\tthis.initialAstWithoutTokens = this.parseDocumentFromTextBuffer(this.queuedTextEditsForInitialAstWithoutTokens, this.initialAstWithoutTokens, false);\n\t\t\t}\n\t\t\tthis.queuedTextEditsForInitialAstWithoutTokens = [];\n\t\t}\n\t}\n\n\t/**\n\t * @pure (only if isPure = true)\n\t*/\n\tprivate parseDocumentFromTextBuffer(edits: TextEditInfo[], previousAst: AstNode | undefined, immutable: boolean): AstNode {\n\t\t// Is much faster if `isPure = false`.\n\t\tconst isPure = false;\n\t\tconst previousAstClone = isPure ? previousAst?.deepClone() : previousAst;\n\t\tconst tokenizer = new TextBufferTokenizer(this.textModel, this.brackets);\n\t\tconst result = parseDocument(tokenizer, edits, previousAstClone, immutable);\n\t\treturn result;\n\t}\n\n\tpublic getBracketsInRange(range: Range, onlyColorizedBrackets: boolean): CallbackIterable {\n\t\tthis.flushQueue();\n\n\t\tconst startOffset = toLength(range.startLineNumber - 1, range.startColumn - 1);\n\t\tconst endOffset = toLength(range.endLineNumber - 1, range.endColumn - 1);\n\t\treturn new CallbackIterable(cb => {\n\t\t\tconst node = this.initialAstWithoutTokens || this.astWithTokens!;\n\t\t\tcollectBrackets(node, lengthZero, node.length, startOffset, endOffset, cb, 0, 0, new Map(), onlyColorizedBrackets);\n\t\t});\n\t}\n\n\tpublic getBracketPairsInRange(range: Range, includeMinIndentation: boolean): CallbackIterable {\n\t\tthis.flushQueue();\n\n\t\tconst startLength = positionToLength(range.getStartPosition());\n\t\tconst endLength = positionToLength(range.getEndPosition());\n\n\t\treturn new CallbackIterable(cb => {\n\t\t\tconst node = this.initialAstWithoutTokens || this.astWithTokens!;\n\t\t\tconst context = new CollectBracketPairsContext(cb, includeMinIndentation, this.textModel);\n\t\t\tcollectBracketPairs(node, lengthZero, node.length, startLength, endLength, context, 0, new Map());\n\t\t});\n\t}\n\n\tpublic getFirstBracketAfter(position: Position): IFoundBracket | null {\n\t\tthis.flushQueue();\n\n\t\tconst node = this.initialAstWithoutTokens || this.astWithTokens!;\n\t\treturn getFirstBracketAfter(node, lengthZero, node.length, positionToLength(position));\n\t}\n\n\tpublic getFirstBracketBefore(position: Position): IFoundBracket | null {\n\t\tthis.flushQueue();\n\n\t\tconst node = this.initialAstWithoutTokens || this.astWithTokens!;\n\t\treturn getFirstBracketBefore(node, lengthZero, node.length, positionToLength(position));\n\t}\n}\n\nfunction getFirstBracketBefore(node: AstNode, nodeOffsetStart: Length, nodeOffsetEnd: Length, position: Length): IFoundBracket | null {\n\tif (node.kind === AstNodeKind.List || node.kind === AstNodeKind.Pair) {\n\t\tconst lengths: { nodeOffsetStart: Length; nodeOffsetEnd: Length }[] = [];\n\t\tfor (const child of node.children) {\n\t\t\tnodeOffsetEnd = lengthAdd(nodeOffsetStart, child.length);\n\t\t\tlengths.push({ nodeOffsetStart, nodeOffsetEnd });\n\t\t\tnodeOffsetStart = nodeOffsetEnd;\n\t\t}\n\t\tfor (let i = lengths.length - 1; i >= 0; i--) {\n\t\t\tconst { nodeOffsetStart, nodeOffsetEnd } = lengths[i];\n\t\t\tif (lengthLessThan(nodeOffsetStart, position)) {\n\t\t\t\tconst result = getFirstBracketBefore(node.children[i], nodeOffsetStart, nodeOffsetEnd, position);\n\t\t\t\tif (result) {\n\t\t\t\t\treturn result;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t} else if (node.kind === AstNodeKind.UnexpectedClosingBracket) {\n\t\treturn null;\n\t} else if (node.kind === AstNodeKind.Bracket) {\n\t\tconst range = lengthsToRange(nodeOffsetStart, nodeOffsetEnd);\n\t\treturn {\n\t\t\tbracketInfo: node.bracketInfo,\n\t\t\trange\n\t\t};\n\t}\n\treturn null;\n}\n\nfunction getFirstBracketAfter(node: AstNode, nodeOffsetStart: Length, nodeOffsetEnd: Length, position: Length): IFoundBracket | null {\n\tif (node.kind === AstNodeKind.List || node.kind === AstNodeKind.Pair) {\n\t\tfor (const child of node.children) {\n\t\t\tnodeOffsetEnd = lengthAdd(nodeOffsetStart, child.length);\n\t\t\tif (lengthLessThan(position, nodeOffsetEnd)) {\n\t\t\t\tconst result = getFirstBracketAfter(child, nodeOffsetStart, nodeOffsetEnd, position);\n\t\t\t\tif (result) {\n\t\t\t\t\treturn result;\n\t\t\t\t}\n\t\t\t}\n\t\t\tnodeOffsetStart = nodeOffsetEnd;\n\t\t}\n\t\treturn null;\n\t} else if (node.kind === AstNodeKind.UnexpectedClosingBracket) {\n\t\treturn null;\n\t} else if (node.kind === AstNodeKind.Bracket) {\n\t\tconst range = lengthsToRange(nodeOffsetStart, nodeOffsetEnd);\n\t\treturn {\n\t\t\tbracketInfo: node.bracketInfo,\n\t\t\trange\n\t\t};\n\t}\n\treturn null;\n}\n\nfunction collectBrackets(\n\tnode: AstNode,\n\tnodeOffsetStart: Length,\n\tnodeOffsetEnd: Length,\n\tstartOffset: Length,\n\tendOffset: Length,\n\tpush: (item: BracketInfo) => boolean,\n\tlevel: number,\n\tnestingLevelOfEqualBracketType: number,\n\tlevelPerBracketType: Map,\n\tonlyColorizedBrackets: boolean,\n\tparentPairIsIncomplete: boolean = false,\n): boolean {\n\tif (level > 200) {\n\t\treturn true;\n\t}\n\n\twhileLoop:\n\twhile (true) {\n\t\tswitch (node.kind) {\n\t\t\tcase AstNodeKind.List: {\n\t\t\t\tconst childCount = node.childrenLength;\n\t\t\t\tfor (let i = 0; i < childCount; i++) {\n\t\t\t\t\tconst child = node.getChild(i);\n\t\t\t\t\tif (!child) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tnodeOffsetEnd = lengthAdd(nodeOffsetStart, child.length);\n\t\t\t\t\tif (\n\t\t\t\t\t\tlengthLessThanEqual(nodeOffsetStart, endOffset) &&\n\t\t\t\t\t\tlengthGreaterThanEqual(nodeOffsetEnd, startOffset)\n\t\t\t\t\t) {\n\t\t\t\t\t\tconst childEndsAfterEnd = lengthGreaterThanEqual(nodeOffsetEnd, endOffset);\n\t\t\t\t\t\tif (childEndsAfterEnd) {\n\t\t\t\t\t\t\t// No child after this child in the requested window, don't recurse\n\t\t\t\t\t\t\tnode = child;\n\t\t\t\t\t\t\tcontinue whileLoop;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst shouldContinue = collectBrackets(child, nodeOffsetStart, nodeOffsetEnd, startOffset, endOffset, push, level, 0, levelPerBracketType, onlyColorizedBrackets);\n\t\t\t\t\t\tif (!shouldContinue) {\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tnodeOffsetStart = nodeOffsetEnd;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tcase AstNodeKind.Pair: {\n\t\t\t\tconst colorize = !onlyColorizedBrackets || !node.closingBracket || (node.closingBracket.bracketInfo as ClosingBracketKind).closesColorized(node.openingBracket.bracketInfo as OpeningBracketKind);\n\n\t\t\t\tlet levelPerBracket = 0;\n\t\t\t\tif (levelPerBracketType) {\n\t\t\t\t\tlet existing = levelPerBracketType.get(node.openingBracket.text);\n\t\t\t\t\tif (existing === undefined) {\n\t\t\t\t\t\texisting = 0;\n\t\t\t\t\t}\n\t\t\t\t\tlevelPerBracket = existing;\n\t\t\t\t\tif (colorize) {\n\t\t\t\t\t\texisting++;\n\t\t\t\t\t\tlevelPerBracketType.set(node.openingBracket.text, existing);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst childCount = node.childrenLength;\n\t\t\t\tfor (let i = 0; i < childCount; i++) {\n\t\t\t\t\tconst child = node.getChild(i);\n\t\t\t\t\tif (!child) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tnodeOffsetEnd = lengthAdd(nodeOffsetStart, child.length);\n\t\t\t\t\tif (\n\t\t\t\t\t\tlengthLessThanEqual(nodeOffsetStart, endOffset) &&\n\t\t\t\t\t\tlengthGreaterThanEqual(nodeOffsetEnd, startOffset)\n\t\t\t\t\t) {\n\t\t\t\t\t\tconst childEndsAfterEnd = lengthGreaterThanEqual(nodeOffsetEnd, endOffset);\n\t\t\t\t\t\tif (childEndsAfterEnd && child.kind !== AstNodeKind.Bracket) {\n\t\t\t\t\t\t\t// No child after this child in the requested window, don't recurse\n\t\t\t\t\t\t\t// Don't do this for brackets because of unclosed/unopened brackets\n\t\t\t\t\t\t\tnode = child;\n\t\t\t\t\t\t\tif (colorize) {\n\t\t\t\t\t\t\t\tlevel++;\n\t\t\t\t\t\t\t\tnestingLevelOfEqualBracketType = levelPerBracket + 1;\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tnestingLevelOfEqualBracketType = levelPerBracket;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tcontinue whileLoop;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (colorize || child.kind !== AstNodeKind.Bracket || !node.closingBracket) {\n\t\t\t\t\t\t\tconst shouldContinue = collectBrackets(\n\t\t\t\t\t\t\t\tchild,\n\t\t\t\t\t\t\t\tnodeOffsetStart,\n\t\t\t\t\t\t\t\tnodeOffsetEnd,\n\t\t\t\t\t\t\t\tstartOffset,\n\t\t\t\t\t\t\t\tendOffset,\n\t\t\t\t\t\t\t\tpush,\n\t\t\t\t\t\t\t\tcolorize ? level + 1 : level,\n\t\t\t\t\t\t\t\tcolorize ? levelPerBracket + 1 : levelPerBracket,\n\t\t\t\t\t\t\t\tlevelPerBracketType,\n\t\t\t\t\t\t\t\tonlyColorizedBrackets,\n\t\t\t\t\t\t\t\t!node.closingBracket,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tif (!shouldContinue) {\n\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tnodeOffsetStart = nodeOffsetEnd;\n\t\t\t\t}\n\n\t\t\t\tlevelPerBracketType?.set(node.openingBracket.text, levelPerBracket);\n\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tcase AstNodeKind.UnexpectedClosingBracket: {\n\t\t\t\tconst range = lengthsToRange(nodeOffsetStart, nodeOffsetEnd);\n\t\t\t\treturn push(new BracketInfo(range, level - 1, 0, true));\n\t\t\t}\n\t\t\tcase AstNodeKind.Bracket: {\n\t\t\t\tconst range = lengthsToRange(nodeOffsetStart, nodeOffsetEnd);\n\t\t\t\treturn push(new BracketInfo(range, level - 1, nestingLevelOfEqualBracketType - 1, parentPairIsIncomplete));\n\t\t\t}\n\t\t\tcase AstNodeKind.Text:\n\t\t\t\treturn true;\n\t\t}\n\t}\n}\n\nclass CollectBracketPairsContext {\n\tconstructor(\n\t\tpublic readonly push: (item: BracketPairWithMinIndentationInfo) => boolean,\n\t\tpublic readonly includeMinIndentation: boolean,\n\t\tpublic readonly textModel: ITextModel,\n\t) {\n\t}\n}\n\nfunction collectBracketPairs(\n\tnode: AstNode,\n\tnodeOffsetStart: Length,\n\tnodeOffsetEnd: Length,\n\tstartOffset: Length,\n\tendOffset: Length,\n\tcontext: CollectBracketPairsContext,\n\tlevel: number,\n\tlevelPerBracketType: Map\n): boolean {\n\tif (level > 200) {\n\t\treturn true;\n\t}\n\n\tlet shouldContinue = true;\n\n\tif (node.kind === AstNodeKind.Pair) {\n\t\tlet levelPerBracket = 0;\n\t\tif (levelPerBracketType) {\n\t\t\tlet existing = levelPerBracketType.get(node.openingBracket.text);\n\t\t\tif (existing === undefined) {\n\t\t\t\texisting = 0;\n\t\t\t}\n\t\t\tlevelPerBracket = existing;\n\t\t\texisting++;\n\t\t\tlevelPerBracketType.set(node.openingBracket.text, existing);\n\t\t}\n\n\t\tconst openingBracketEnd = lengthAdd(nodeOffsetStart, node.openingBracket.length);\n\t\tlet minIndentation = -1;\n\t\tif (context.includeMinIndentation) {\n\t\t\tminIndentation = node.computeMinIndentation(\n\t\t\t\tnodeOffsetStart,\n\t\t\t\tcontext.textModel\n\t\t\t);\n\t\t}\n\n\t\tshouldContinue = context.push(\n\t\t\tnew BracketPairWithMinIndentationInfo(\n\t\t\t\tlengthsToRange(nodeOffsetStart, nodeOffsetEnd),\n\t\t\t\tlengthsToRange(nodeOffsetStart, openingBracketEnd),\n\t\t\t\tnode.closingBracket\n\t\t\t\t\t? lengthsToRange(\n\t\t\t\t\t\tlengthAdd(openingBracketEnd, node.child?.length || lengthZero),\n\t\t\t\t\t\tnodeOffsetEnd\n\t\t\t\t\t)\n\t\t\t\t\t: undefined,\n\t\t\t\tlevel,\n\t\t\t\tlevelPerBracket,\n\t\t\t\tnode,\n\t\t\t\tminIndentation\n\t\t\t)\n\t\t);\n\n\t\tnodeOffsetStart = openingBracketEnd;\n\t\tif (shouldContinue && node.child) {\n\t\t\tconst child = node.child;\n\t\t\tnodeOffsetEnd = lengthAdd(nodeOffsetStart, child.length);\n\t\t\tif (\n\t\t\t\tlengthLessThanEqual(nodeOffsetStart, endOffset) &&\n\t\t\t\tlengthGreaterThanEqual(nodeOffsetEnd, startOffset)\n\t\t\t) {\n\t\t\t\tshouldContinue = collectBracketPairs(\n\t\t\t\t\tchild,\n\t\t\t\t\tnodeOffsetStart,\n\t\t\t\t\tnodeOffsetEnd,\n\t\t\t\t\tstartOffset,\n\t\t\t\t\tendOffset,\n\t\t\t\t\tcontext,\n\t\t\t\t\tlevel + 1,\n\t\t\t\t\tlevelPerBracketType\n\t\t\t\t);\n\t\t\t\tif (!shouldContinue) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tlevelPerBracketType?.set(node.openingBracket.text, levelPerBracket);\n\t} else {\n\t\tlet curOffset = nodeOffsetStart;\n\t\tfor (const child of node.children) {\n\t\t\tconst childOffset = curOffset;\n\t\t\tcurOffset = lengthAdd(curOffset, child.length);\n\n\t\t\tif (\n\t\t\t\tlengthLessThanEqual(childOffset, endOffset) &&\n\t\t\t\tlengthLessThanEqual(startOffset, curOffset)\n\t\t\t) {\n\t\t\t\tshouldContinue = collectBracketPairs(\n\t\t\t\t\tchild,\n\t\t\t\t\tchildOffset,\n\t\t\t\t\tcurOffset,\n\t\t\t\t\tstartOffset,\n\t\t\t\t\tendOffset,\n\t\t\t\t\tcontext,\n\t\t\t\t\tlevel,\n\t\t\t\t\tlevelPerBracketType\n\t\t\t\t);\n\t\t\t\tif (!shouldContinue) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn shouldContinue;\n}\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\nimport { IRange } from 'vs/editor/common/core/range';\nimport { Selection } from 'vs/editor/common/core/selection';\nimport { IModelDecoration, InjectedTextOptions } from 'vs/editor/common/model';\n\n/**\n * An event describing that the current language associated with a model has changed.\n */\nexport interface IModelLanguageChangedEvent {\n\t/**\n\t * Previous language\n\t */\n\treadonly oldLanguage: string;\n\t/**\n\t * New language\n\t */\n\treadonly newLanguage: string;\n\n\t/**\n\t * Source of the call that caused the event.\n\t */\n\treadonly source: string;\n}\n\n/**\n * An event describing that the language configuration associated with a model has changed.\n */\nexport interface IModelLanguageConfigurationChangedEvent {\n}\n\nexport interface IModelContentChange {\n\t/**\n\t * The range that got replaced.\n\t */\n\treadonly range: IRange;\n\t/**\n\t * The offset of the range that got replaced.\n\t */\n\treadonly rangeOffset: number;\n\t/**\n\t * The length of the range that got replaced.\n\t */\n\treadonly rangeLength: number;\n\t/**\n\t * The new text for the range.\n\t */\n\treadonly text: string;\n}\n\n/**\n * An event describing a change in the text of a model.\n */\nexport interface IModelContentChangedEvent {\n\treadonly changes: IModelContentChange[];\n\t/**\n\t * The (new) end-of-line character.\n\t */\n\treadonly eol: string;\n\t/**\n\t * The new version id the model has transitioned to.\n\t */\n\treadonly versionId: number;\n\t/**\n\t * Flag that indicates that this event was generated while undoing.\n\t */\n\treadonly isUndoing: boolean;\n\t/**\n\t * Flag that indicates that this event was generated while redoing.\n\t */\n\treadonly isRedoing: boolean;\n\t/**\n\t * Flag that indicates that all decorations were lost with this edit.\n\t * The model has been reset to a new value.\n\t */\n\treadonly isFlush: boolean;\n\n\t/**\n\t * Flag that indicates that this event describes an eol change.\n\t */\n\treadonly isEolChange: boolean;\n}\n\n/**\n * An event describing that model decorations have changed.\n */\nexport interface IModelDecorationsChangedEvent {\n\treadonly affectsMinimap: boolean;\n\treadonly affectsOverviewRuler: boolean;\n\treadonly affectsGlyphMargin: boolean;\n\treadonly affectsLineNumber: boolean;\n}\n\n/**\n * An event describing that some ranges of lines have been tokenized (their tokens have changed).\n * @internal\n */\nexport interface IModelTokensChangedEvent {\n\treadonly semanticTokensApplied: boolean;\n\treadonly ranges: {\n\t\t/**\n\t\t * The start of the range (inclusive)\n\t\t */\n\t\treadonly fromLineNumber: number;\n\t\t/**\n\t\t * The end of the range (inclusive)\n\t\t */\n\t\treadonly toLineNumber: number;\n\t}[];\n}\n\nexport interface IModelOptionsChangedEvent {\n\treadonly tabSize: boolean;\n\treadonly indentSize: boolean;\n\treadonly insertSpaces: boolean;\n\treadonly trimAutoWhitespace: boolean;\n}\n\n/**\n * @internal\n */\nexport const enum RawContentChangedType {\n\tFlush = 1,\n\tLineChanged = 2,\n\tLinesDeleted = 3,\n\tLinesInserted = 4,\n\tEOLChanged = 5\n}\n\n/**\n * An event describing that a model has been reset to a new value.\n * @internal\n */\nexport class ModelRawFlush {\n\tpublic readonly changeType = RawContentChangedType.Flush;\n}\n\n/**\n * Represents text injected on a line\n * @internal\n */\nexport class LineInjectedText {\n\tpublic static applyInjectedText(lineText: string, injectedTexts: LineInjectedText[] | null): string {\n\t\tif (!injectedTexts || injectedTexts.length === 0) {\n\t\t\treturn lineText;\n\t\t}\n\t\tlet result = '';\n\t\tlet lastOriginalOffset = 0;\n\t\tfor (const injectedText of injectedTexts) {\n\t\t\tresult += lineText.substring(lastOriginalOffset, injectedText.column - 1);\n\t\t\tlastOriginalOffset = injectedText.column - 1;\n\t\t\tresult += injectedText.options.content;\n\t\t}\n\t\tresult += lineText.substring(lastOriginalOffset);\n\t\treturn result;\n\t}\n\n\tpublic static fromDecorations(decorations: IModelDecoration[]): LineInjectedText[] {\n\t\tconst result: LineInjectedText[] = [];\n\t\tfor (const decoration of decorations) {\n\t\t\tif (decoration.options.before && decoration.options.before.content.length > 0) {\n\t\t\t\tresult.push(new LineInjectedText(\n\t\t\t\t\tdecoration.ownerId,\n\t\t\t\t\tdecoration.range.startLineNumber,\n\t\t\t\t\tdecoration.range.startColumn,\n\t\t\t\t\tdecoration.options.before,\n\t\t\t\t\t0,\n\t\t\t\t));\n\t\t\t}\n\t\t\tif (decoration.options.after && decoration.options.after.content.length > 0) {\n\t\t\t\tresult.push(new LineInjectedText(\n\t\t\t\t\tdecoration.ownerId,\n\t\t\t\t\tdecoration.range.endLineNumber,\n\t\t\t\t\tdecoration.range.endColumn,\n\t\t\t\t\tdecoration.options.after,\n\t\t\t\t\t1,\n\t\t\t\t));\n\t\t\t}\n\t\t}\n\t\tresult.sort((a, b) => {\n\t\t\tif (a.lineNumber === b.lineNumber) {\n\t\t\t\tif (a.column === b.column) {\n\t\t\t\t\treturn a.order - b.order;\n\t\t\t\t}\n\t\t\t\treturn a.column - b.column;\n\t\t\t}\n\t\t\treturn a.lineNumber - b.lineNumber;\n\t\t});\n\t\treturn result;\n\t}\n\n\tconstructor(\n\t\tpublic readonly ownerId: number,\n\t\tpublic readonly lineNumber: number,\n\t\tpublic readonly column: number,\n\t\tpublic readonly options: InjectedTextOptions,\n\t\tpublic readonly order: number\n\t) { }\n}\n\n/**\n * An event describing that a line has changed in a model.\n * @internal\n */\nexport class ModelRawLineChanged {\n\tpublic readonly changeType = RawContentChangedType.LineChanged;\n\t/**\n\t * The line that has changed.\n\t */\n\tpublic readonly lineNumber: number;\n\t/**\n\t * The new value of the line.\n\t */\n\tpublic readonly detail: string;\n\t/**\n\t * The injected text on the line.\n\t */\n\tpublic readonly injectedText: LineInjectedText[] | null;\n\n\tconstructor(lineNumber: number, detail: string, injectedText: LineInjectedText[] | null) {\n\t\tthis.lineNumber = lineNumber;\n\t\tthis.detail = detail;\n\t\tthis.injectedText = injectedText;\n\t}\n}\n\n/**\n * An event describing that line(s) have been deleted in a model.\n * @internal\n */\nexport class ModelRawLinesDeleted {\n\tpublic readonly changeType = RawContentChangedType.LinesDeleted;\n\t/**\n\t * At what line the deletion began (inclusive).\n\t */\n\tpublic readonly fromLineNumber: number;\n\t/**\n\t * At what line the deletion stopped (inclusive).\n\t */\n\tpublic readonly toLineNumber: number;\n\n\tconstructor(fromLineNumber: number, toLineNumber: number) {\n\t\tthis.fromLineNumber = fromLineNumber;\n\t\tthis.toLineNumber = toLineNumber;\n\t}\n}\n\n/**\n * An event describing that line(s) have been inserted in a model.\n * @internal\n */\nexport class ModelRawLinesInserted {\n\tpublic readonly changeType = RawContentChangedType.LinesInserted;\n\t/**\n\t * Before what line did the insertion begin\n\t */\n\tpublic readonly fromLineNumber: number;\n\t/**\n\t * `toLineNumber` - `fromLineNumber` + 1 denotes the number of lines that were inserted\n\t */\n\tpublic readonly toLineNumber: number;\n\t/**\n\t * The text that was inserted\n\t */\n\tpublic readonly detail: string[];\n\t/**\n\t * The injected texts for every inserted line.\n\t */\n\tpublic readonly injectedTexts: (LineInjectedText[] | null)[];\n\n\tconstructor(fromLineNumber: number, toLineNumber: number, detail: string[], injectedTexts: (LineInjectedText[] | null)[]) {\n\t\tthis.injectedTexts = injectedTexts;\n\t\tthis.fromLineNumber = fromLineNumber;\n\t\tthis.toLineNumber = toLineNumber;\n\t\tthis.detail = detail;\n\t}\n}\n\n/**\n * An event describing that a model has had its EOL changed.\n * @internal\n */\nexport class ModelRawEOLChanged {\n\tpublic readonly changeType = RawContentChangedType.EOLChanged;\n}\n\n/**\n * @internal\n */\nexport type ModelRawChange = ModelRawFlush | ModelRawLineChanged | ModelRawLinesDeleted | ModelRawLinesInserted | ModelRawEOLChanged;\n\n/**\n * An event describing a change in the text of a model.\n * @internal\n */\nexport class ModelRawContentChangedEvent {\n\n\tpublic readonly changes: ModelRawChange[];\n\t/**\n\t * The new version id the model has transitioned to.\n\t */\n\tpublic readonly versionId: number;\n\t/**\n\t * Flag that indicates that this event was generated while undoing.\n\t */\n\tpublic readonly isUndoing: boolean;\n\t/**\n\t * Flag that indicates that this event was generated while redoing.\n\t */\n\tpublic readonly isRedoing: boolean;\n\n\tpublic resultingSelection: Selection[] | null;\n\n\tconstructor(changes: ModelRawChange[], versionId: number, isUndoing: boolean, isRedoing: boolean) {\n\t\tthis.changes = changes;\n\t\tthis.versionId = versionId;\n\t\tthis.isUndoing = isUndoing;\n\t\tthis.isRedoing = isRedoing;\n\t\tthis.resultingSelection = null;\n\t}\n\n\tpublic containsEvent(type: RawContentChangedType): boolean {\n\t\tfor (let i = 0, len = this.changes.length; i < len; i++) {\n\t\t\tconst change = this.changes[i];\n\t\t\tif (change.changeType === type) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tpublic static merge(a: ModelRawContentChangedEvent, b: ModelRawContentChangedEvent): ModelRawContentChangedEvent {\n\t\tconst changes = ([] as ModelRawChange[]).concat(a.changes).concat(b.changes);\n\t\tconst versionId = b.versionId;\n\t\tconst isUndoing = (a.isUndoing || b.isUndoing);\n\t\tconst isRedoing = (a.isRedoing || b.isRedoing);\n\t\treturn new ModelRawContentChangedEvent(changes, versionId, isUndoing, isRedoing);\n\t}\n}\n\n/**\n * An event describing a change in injected text.\n * @internal\n */\nexport class ModelInjectedTextChangedEvent {\n\n\tpublic readonly changes: ModelRawLineChanged[];\n\n\tconstructor(changes: ModelRawLineChanged[]) {\n\t\tthis.changes = changes;\n\t}\n}\n\n/**\n * @internal\n */\nexport class InternalModelContentChangeEvent {\n\tconstructor(\n\t\tpublic readonly rawContentChangedEvent: ModelRawContentChangedEvent,\n\t\tpublic readonly contentChangedEvent: IModelContentChangedEvent,\n\t) { }\n\n\tpublic merge(other: InternalModelContentChangeEvent): InternalModelContentChangeEvent {\n\t\tconst rawContentChangedEvent = ModelRawContentChangedEvent.merge(this.rawContentChangedEvent, other.rawContentChangedEvent);\n\t\tconst contentChangedEvent = InternalModelContentChangeEvent._mergeChangeEvents(this.contentChangedEvent, other.contentChangedEvent);\n\t\treturn new InternalModelContentChangeEvent(rawContentChangedEvent, contentChangedEvent);\n\t}\n\n\tprivate static _mergeChangeEvents(a: IModelContentChangedEvent, b: IModelContentChangedEvent): IModelContentChangedEvent {\n\t\tconst changes = ([] as IModelContentChange[]).concat(a.changes).concat(b.changes);\n\t\tconst eol = b.eol;\n\t\tconst versionId = b.versionId;\n\t\tconst isUndoing = (a.isUndoing || b.isUndoing);\n\t\tconst isRedoing = (a.isRedoing || b.isRedoing);\n\t\tconst isFlush = (a.isFlush || b.isFlush);\n\t\tconst isEolChange = a.isEolChange && b.isEolChange; // both must be true to not confuse listeners who skip such edits\n\t\treturn {\n\t\t\tchanges: changes,\n\t\t\teol: eol,\n\t\t\tisEolChange: isEolChange,\n\t\t\tversionId: versionId,\n\t\t\tisUndoing: isUndoing,\n\t\t\tisRedoing: isRedoing,\n\t\t\tisFlush: isFlush,\n\t\t};\n\t}\n}\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\nimport { IPosition } from 'vs/editor/common/core/position';\n\nexport interface IGuidesTextModelPart {\n\t/**\n\t * @internal\n\t */\n\tgetActiveIndentGuide(lineNumber: number, minLineNumber: number, maxLineNumber: number): IActiveIndentGuideInfo;\n\n\t/**\n\t * @internal\n\t */\n\tgetLinesIndentGuides(startLineNumber: number, endLineNumber: number): number[];\n\n\t/**\n\t * Requests the the indent guides for the given range of lines.\n\t * `result[i]` will contain the indent guides of the `startLineNumber + i`th line.\n\t * @internal\n\t */\n\tgetLinesBracketGuides(startLineNumber: number, endLineNumber: number, activePosition: IPosition | null, options: BracketGuideOptions): IndentGuide[][];\n}\n\nexport interface IActiveIndentGuideInfo {\n\tstartLineNumber: number;\n\tendLineNumber: number;\n\tindent: number;\n}\n\nexport enum HorizontalGuidesState {\n\tDisabled,\n\tEnabledForActive,\n\tEnabled\n}\n\nexport interface BracketGuideOptions {\n\tincludeInactive: boolean;\n\thorizontalGuides: HorizontalGuidesState;\n\thighlightActive: boolean;\n}\n\nexport class IndentGuide {\n\tconstructor(\n\t\tpublic readonly visibleColumn: number | -1,\n\t\tpublic readonly column: number | -1,\n\t\tpublic readonly className: string,\n\t\t/**\n\t\t * If set, this indent guide is a horizontal guide (no vertical part).\n\t\t * It starts at visibleColumn and continues until endColumn.\n\t\t*/\n\t\tpublic readonly horizontalLine: IndentGuideHorizontalLine | null,\n\t\t/**\n\t\t * If set (!= -1), only show this guide for wrapped lines that don't contain this model column, but are after it.\n\t\t*/\n\t\tpublic readonly forWrappedLinesAfterColumn: number | -1,\n\t\tpublic readonly forWrappedLinesBeforeOrAtColumn: number | -1\n\t) {\n\t\tif ((visibleColumn !== -1) === (column !== -1)) {\n\t\t\tthrow new Error();\n\t\t}\n\t}\n}\n\nexport class IndentGuideHorizontalLine {\n\tconstructor(\n\t\tpublic readonly top: boolean,\n\t\tpublic readonly endColumn: number,\n\t) { }\n}\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\nimport { findLast } from 'vs/base/common/arraysFind';\nimport * as strings from 'vs/base/common/strings';\nimport { CursorColumns } from 'vs/editor/common/core/cursorColumns';\nimport { IPosition, Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\nimport { TextModel } from 'vs/editor/common/model/textModel';\nimport { TextModelPart } from 'vs/editor/common/model/textModelPart';\nimport { computeIndentLevel } from 'vs/editor/common/model/utils';\nimport { ILanguageConfigurationService, ResolvedLanguageConfiguration } from 'vs/editor/common/languages/languageConfigurationRegistry';\nimport { BracketGuideOptions, HorizontalGuidesState, IActiveIndentGuideInfo, IGuidesTextModelPart, IndentGuide, IndentGuideHorizontalLine } from 'vs/editor/common/textModelGuides';\nimport { BugIndicatingError } from 'vs/base/common/errors';\n\nexport class GuidesTextModelPart extends TextModelPart implements IGuidesTextModelPart {\n\tconstructor(\n\t\tprivate readonly textModel: TextModel,\n\t\tprivate readonly languageConfigurationService: ILanguageConfigurationService\n\t) {\n\t\tsuper();\n\t}\n\n\tprivate getLanguageConfiguration(\n\t\tlanguageId: string\n\t): ResolvedLanguageConfiguration {\n\t\treturn this.languageConfigurationService.getLanguageConfiguration(\n\t\t\tlanguageId\n\t\t);\n\t}\n\n\tprivate _computeIndentLevel(lineIndex: number): number {\n\t\treturn computeIndentLevel(\n\t\t\tthis.textModel.getLineContent(lineIndex + 1),\n\t\t\tthis.textModel.getOptions().tabSize\n\t\t);\n\t}\n\n\tpublic getActiveIndentGuide(\n\t\tlineNumber: number,\n\t\tminLineNumber: number,\n\t\tmaxLineNumber: number\n\t): IActiveIndentGuideInfo {\n\t\tthis.assertNotDisposed();\n\t\tconst lineCount = this.textModel.getLineCount();\n\n\t\tif (lineNumber < 1 || lineNumber > lineCount) {\n\t\t\tthrow new BugIndicatingError('Illegal value for lineNumber');\n\t\t}\n\n\t\tconst foldingRules = this.getLanguageConfiguration(\n\t\t\tthis.textModel.getLanguageId()\n\t\t).foldingRules;\n\t\tconst offSide = Boolean(foldingRules && foldingRules.offSide);\n\n\t\tlet up_aboveContentLineIndex =\n\t\t\t-2; /* -2 is a marker for not having computed it */\n\t\tlet up_aboveContentLineIndent = -1;\n\t\tlet up_belowContentLineIndex =\n\t\t\t-2; /* -2 is a marker for not having computed it */\n\t\tlet up_belowContentLineIndent = -1;\n\t\tconst up_resolveIndents = (lineNumber: number) => {\n\t\t\tif (\n\t\t\t\tup_aboveContentLineIndex !== -1 &&\n\t\t\t\t(up_aboveContentLineIndex === -2 ||\n\t\t\t\t\tup_aboveContentLineIndex > lineNumber - 1)\n\t\t\t) {\n\t\t\t\tup_aboveContentLineIndex = -1;\n\t\t\t\tup_aboveContentLineIndent = -1;\n\n\t\t\t\t// must find previous line with content\n\t\t\t\tfor (let lineIndex = lineNumber - 2; lineIndex >= 0; lineIndex--) {\n\t\t\t\t\tconst indent = this._computeIndentLevel(lineIndex);\n\t\t\t\t\tif (indent >= 0) {\n\t\t\t\t\t\tup_aboveContentLineIndex = lineIndex;\n\t\t\t\t\t\tup_aboveContentLineIndent = indent;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (up_belowContentLineIndex === -2) {\n\t\t\t\tup_belowContentLineIndex = -1;\n\t\t\t\tup_belowContentLineIndent = -1;\n\n\t\t\t\t// must find next line with content\n\t\t\t\tfor (let lineIndex = lineNumber; lineIndex < lineCount; lineIndex++) {\n\t\t\t\t\tconst indent = this._computeIndentLevel(lineIndex);\n\t\t\t\t\tif (indent >= 0) {\n\t\t\t\t\t\tup_belowContentLineIndex = lineIndex;\n\t\t\t\t\t\tup_belowContentLineIndent = indent;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tlet down_aboveContentLineIndex =\n\t\t\t-2; /* -2 is a marker for not having computed it */\n\t\tlet down_aboveContentLineIndent = -1;\n\t\tlet down_belowContentLineIndex =\n\t\t\t-2; /* -2 is a marker for not having computed it */\n\t\tlet down_belowContentLineIndent = -1;\n\t\tconst down_resolveIndents = (lineNumber: number) => {\n\t\t\tif (down_aboveContentLineIndex === -2) {\n\t\t\t\tdown_aboveContentLineIndex = -1;\n\t\t\t\tdown_aboveContentLineIndent = -1;\n\n\t\t\t\t// must find previous line with content\n\t\t\t\tfor (let lineIndex = lineNumber - 2; lineIndex >= 0; lineIndex--) {\n\t\t\t\t\tconst indent = this._computeIndentLevel(lineIndex);\n\t\t\t\t\tif (indent >= 0) {\n\t\t\t\t\t\tdown_aboveContentLineIndex = lineIndex;\n\t\t\t\t\t\tdown_aboveContentLineIndent = indent;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\tdown_belowContentLineIndex !== -1 &&\n\t\t\t\t(down_belowContentLineIndex === -2 ||\n\t\t\t\t\tdown_belowContentLineIndex < lineNumber - 1)\n\t\t\t) {\n\t\t\t\tdown_belowContentLineIndex = -1;\n\t\t\t\tdown_belowContentLineIndent = -1;\n\n\t\t\t\t// must find next line with content\n\t\t\t\tfor (let lineIndex = lineNumber; lineIndex < lineCount; lineIndex++) {\n\t\t\t\t\tconst indent = this._computeIndentLevel(lineIndex);\n\t\t\t\t\tif (indent >= 0) {\n\t\t\t\t\t\tdown_belowContentLineIndex = lineIndex;\n\t\t\t\t\t\tdown_belowContentLineIndent = indent;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tlet startLineNumber = 0;\n\t\tlet goUp = true;\n\t\tlet endLineNumber = 0;\n\t\tlet goDown = true;\n\t\tlet indent = 0;\n\n\t\tlet initialIndent = 0;\n\n\t\tfor (let distance = 0; goUp || goDown; distance++) {\n\t\t\tconst upLineNumber = lineNumber - distance;\n\t\t\tconst downLineNumber = lineNumber + distance;\n\n\t\t\tif (distance > 1 && (upLineNumber < 1 || upLineNumber < minLineNumber)) {\n\t\t\t\tgoUp = false;\n\t\t\t}\n\t\t\tif (\n\t\t\t\tdistance > 1 &&\n\t\t\t\t(downLineNumber > lineCount || downLineNumber > maxLineNumber)\n\t\t\t) {\n\t\t\t\tgoDown = false;\n\t\t\t}\n\t\t\tif (distance > 50000) {\n\t\t\t\t// stop processing\n\t\t\t\tgoUp = false;\n\t\t\t\tgoDown = false;\n\t\t\t}\n\n\t\t\tlet upLineIndentLevel: number = -1;\n\t\t\tif (goUp && upLineNumber >= 1) {\n\t\t\t\t// compute indent level going up\n\t\t\t\tconst currentIndent = this._computeIndentLevel(upLineNumber - 1);\n\t\t\t\tif (currentIndent >= 0) {\n\t\t\t\t\t// This line has content (besides whitespace)\n\t\t\t\t\t// Use the line's indent\n\t\t\t\t\tup_belowContentLineIndex = upLineNumber - 1;\n\t\t\t\t\tup_belowContentLineIndent = currentIndent;\n\t\t\t\t\tupLineIndentLevel = Math.ceil(\n\t\t\t\t\t\tcurrentIndent / this.textModel.getOptions().indentSize\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\tup_resolveIndents(upLineNumber);\n\t\t\t\t\tupLineIndentLevel = this._getIndentLevelForWhitespaceLine(\n\t\t\t\t\t\toffSide,\n\t\t\t\t\t\tup_aboveContentLineIndent,\n\t\t\t\t\t\tup_belowContentLineIndent\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet downLineIndentLevel = -1;\n\t\t\tif (goDown && downLineNumber <= lineCount) {\n\t\t\t\t// compute indent level going down\n\t\t\t\tconst currentIndent = this._computeIndentLevel(downLineNumber - 1);\n\t\t\t\tif (currentIndent >= 0) {\n\t\t\t\t\t// This line has content (besides whitespace)\n\t\t\t\t\t// Use the line's indent\n\t\t\t\t\tdown_aboveContentLineIndex = downLineNumber - 1;\n\t\t\t\t\tdown_aboveContentLineIndent = currentIndent;\n\t\t\t\t\tdownLineIndentLevel = Math.ceil(\n\t\t\t\t\t\tcurrentIndent / this.textModel.getOptions().indentSize\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\tdown_resolveIndents(downLineNumber);\n\t\t\t\t\tdownLineIndentLevel = this._getIndentLevelForWhitespaceLine(\n\t\t\t\t\t\toffSide,\n\t\t\t\t\t\tdown_aboveContentLineIndent,\n\t\t\t\t\t\tdown_belowContentLineIndent\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (distance === 0) {\n\t\t\t\tinitialIndent = upLineIndentLevel;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (distance === 1) {\n\t\t\t\tif (\n\t\t\t\t\tdownLineNumber <= lineCount &&\n\t\t\t\t\tdownLineIndentLevel >= 0 &&\n\t\t\t\t\tinitialIndent + 1 === downLineIndentLevel\n\t\t\t\t) {\n\t\t\t\t\t// This is the beginning of a scope, we have special handling here, since we want the\n\t\t\t\t\t// child scope indent to be active, not the parent scope\n\t\t\t\t\tgoUp = false;\n\t\t\t\t\tstartLineNumber = downLineNumber;\n\t\t\t\t\tendLineNumber = downLineNumber;\n\t\t\t\t\tindent = downLineIndentLevel;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (\n\t\t\t\t\tupLineNumber >= 1 &&\n\t\t\t\t\tupLineIndentLevel >= 0 &&\n\t\t\t\t\tupLineIndentLevel - 1 === initialIndent\n\t\t\t\t) {\n\t\t\t\t\t// This is the end of a scope, just like above\n\t\t\t\t\tgoDown = false;\n\t\t\t\t\tstartLineNumber = upLineNumber;\n\t\t\t\t\tendLineNumber = upLineNumber;\n\t\t\t\t\tindent = upLineIndentLevel;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tstartLineNumber = lineNumber;\n\t\t\t\tendLineNumber = lineNumber;\n\t\t\t\tindent = initialIndent;\n\t\t\t\tif (indent === 0) {\n\t\t\t\t\t// No need to continue\n\t\t\t\t\treturn { startLineNumber, endLineNumber, indent };\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (goUp) {\n\t\t\t\tif (upLineIndentLevel >= indent) {\n\t\t\t\t\tstartLineNumber = upLineNumber;\n\t\t\t\t} else {\n\t\t\t\t\tgoUp = false;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (goDown) {\n\t\t\t\tif (downLineIndentLevel >= indent) {\n\t\t\t\t\tendLineNumber = downLineNumber;\n\t\t\t\t} else {\n\t\t\t\t\tgoDown = false;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn { startLineNumber, endLineNumber, indent };\n\t}\n\n\tpublic getLinesBracketGuides(\n\t\tstartLineNumber: number,\n\t\tendLineNumber: number,\n\t\tactivePosition: IPosition | null,\n\t\toptions: BracketGuideOptions\n\t): IndentGuide[][] {\n\t\tconst result: IndentGuide[][] = [];\n\t\tfor (let lineNumber = startLineNumber; lineNumber <= endLineNumber; lineNumber++) {\n\t\t\tresult.push([]);\n\t\t}\n\n\t\t// If requested, this could be made configurable.\n\t\tconst includeSingleLinePairs = true;\n\n\t\tconst bracketPairs =\n\t\t\tthis.textModel.bracketPairs.getBracketPairsInRangeWithMinIndentation(\n\t\t\t\tnew Range(\n\t\t\t\t\tstartLineNumber,\n\t\t\t\t\t1,\n\t\t\t\t\tendLineNumber,\n\t\t\t\t\tthis.textModel.getLineMaxColumn(endLineNumber)\n\t\t\t\t)\n\t\t\t).toArray();\n\n\t\tlet activeBracketPairRange: Range | undefined = undefined;\n\t\tif (activePosition && bracketPairs.length > 0) {\n\t\t\tconst bracketsContainingActivePosition = (\n\t\t\t\tstartLineNumber <= activePosition.lineNumber &&\n\t\t\t\t\tactivePosition.lineNumber <= endLineNumber\n\t\t\t\t\t// We don't need to query the brackets again if the cursor is in the viewport\n\t\t\t\t\t? bracketPairs\n\t\t\t\t\t: this.textModel.bracketPairs.getBracketPairsInRange(\n\t\t\t\t\t\tRange.fromPositions(activePosition)\n\t\t\t\t\t).toArray()\n\t\t\t).filter((bp) => Range.strictContainsPosition(bp.range, activePosition));\n\n\t\t\tactiveBracketPairRange = findLast(\n\t\t\t\tbracketsContainingActivePosition,\n\t\t\t\t(i) => includeSingleLinePairs || i.range.startLineNumber !== i.range.endLineNumber\n\t\t\t)?.range;\n\t\t}\n\n\t\tconst independentColorPoolPerBracketType = this.textModel.getOptions().bracketPairColorizationOptions.independentColorPoolPerBracketType;\n\t\tconst colorProvider = new BracketPairGuidesClassNames();\n\n\t\tfor (const pair of bracketPairs) {\n\t\t\t/*\n\n\n\t\t\t\t\t{\n\t\t\t\t\t|\n\t\t\t\t\t}\n\n\t\t\t\t\t{\n\t\t\t\t\t|\n\t\t\t\t\t----}\n\n\t\t\t\t____{\n\t\t\t\t|test\n\t\t\t\t----}\n\n\t\t\t\trenderHorizontalEndLineAtTheBottom:\n\t\t\t\t\t{\n\t\t\t\t\t|\n\t\t\t\t\t|x}\n\t\t\t\t\t--\n\t\t\t\trenderHorizontalEndLineAtTheBottom:\n\t\t\t\t____{\n\t\t\t\t|test\n\t\t\t\t| x }\n\t\t\t\t----\n\t\t\t*/\n\n\t\t\tif (!pair.closingBracketRange) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst isActive = activeBracketPairRange && pair.range.equalsRange(activeBracketPairRange);\n\n\t\t\tif (!isActive && !options.includeInactive) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst className =\n\t\t\t\tcolorProvider.getInlineClassName(pair.nestingLevel, pair.nestingLevelOfEqualBracketType, independentColorPoolPerBracketType) +\n\t\t\t\t(options.highlightActive && isActive\n\t\t\t\t\t? ' ' + colorProvider.activeClassName\n\t\t\t\t\t: '');\n\n\n\t\t\tconst start = pair.openingBracketRange.getStartPosition();\n\t\t\tconst end = pair.closingBracketRange.getStartPosition();\n\n\t\t\tconst horizontalGuides = options.horizontalGuides === HorizontalGuidesState.Enabled || (options.horizontalGuides === HorizontalGuidesState.EnabledForActive && isActive);\n\n\t\t\tif (pair.range.startLineNumber === pair.range.endLineNumber) {\n\t\t\t\tif (includeSingleLinePairs && horizontalGuides) {\n\n\t\t\t\t\tresult[pair.range.startLineNumber - startLineNumber].push(\n\t\t\t\t\t\tnew IndentGuide(\n\t\t\t\t\t\t\t-1,\n\t\t\t\t\t\t\tpair.openingBracketRange.getEndPosition().column,\n\t\t\t\t\t\t\tclassName,\n\t\t\t\t\t\t\tnew IndentGuideHorizontalLine(false, end.column),\n\t\t\t\t\t\t\t-1,\n\t\t\t\t\t\t\t-1,\n\t\t\t\t\t\t)\n\t\t\t\t\t);\n\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst endVisibleColumn = this.getVisibleColumnFromPosition(end);\n\t\t\tconst startVisibleColumn = this.getVisibleColumnFromPosition(\n\t\t\t\tpair.openingBracketRange.getStartPosition()\n\t\t\t);\n\t\t\tconst guideVisibleColumn = Math.min(startVisibleColumn, endVisibleColumn, pair.minVisibleColumnIndentation + 1);\n\n\t\t\tlet renderHorizontalEndLineAtTheBottom = false;\n\n\n\t\t\tconst firstNonWsIndex = strings.firstNonWhitespaceIndex(\n\t\t\t\tthis.textModel.getLineContent(\n\t\t\t\t\tpair.closingBracketRange.startLineNumber\n\t\t\t\t)\n\t\t\t);\n\t\t\tconst hasTextBeforeClosingBracket = firstNonWsIndex < pair.closingBracketRange.startColumn - 1;\n\t\t\tif (hasTextBeforeClosingBracket) {\n\t\t\t\trenderHorizontalEndLineAtTheBottom = true;\n\t\t\t}\n\n\n\t\t\tconst visibleGuideStartLineNumber = Math.max(start.lineNumber, startLineNumber);\n\t\t\tconst visibleGuideEndLineNumber = Math.min(end.lineNumber, endLineNumber);\n\n\t\t\tconst offset = renderHorizontalEndLineAtTheBottom ? 1 : 0;\n\n\t\t\tfor (let l = visibleGuideStartLineNumber; l < visibleGuideEndLineNumber + offset; l++) {\n\t\t\t\tresult[l - startLineNumber].push(\n\t\t\t\t\tnew IndentGuide(\n\t\t\t\t\t\tguideVisibleColumn,\n\t\t\t\t\t\t-1,\n\t\t\t\t\t\tclassName,\n\t\t\t\t\t\tnull,\n\t\t\t\t\t\tl === start.lineNumber ? start.column : -1,\n\t\t\t\t\t\tl === end.lineNumber ? end.column : -1\n\t\t\t\t\t)\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (horizontalGuides) {\n\t\t\t\tif (start.lineNumber >= startLineNumber && startVisibleColumn > guideVisibleColumn) {\n\t\t\t\t\tresult[start.lineNumber - startLineNumber].push(\n\t\t\t\t\t\tnew IndentGuide(\n\t\t\t\t\t\t\tguideVisibleColumn,\n\t\t\t\t\t\t\t-1,\n\t\t\t\t\t\t\tclassName,\n\t\t\t\t\t\t\tnew IndentGuideHorizontalLine(false, start.column),\n\t\t\t\t\t\t\t-1,\n\t\t\t\t\t\t\t-1,\n\t\t\t\t\t\t)\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tif (end.lineNumber <= endLineNumber && endVisibleColumn > guideVisibleColumn) {\n\t\t\t\t\tresult[end.lineNumber - startLineNumber].push(\n\t\t\t\t\t\tnew IndentGuide(\n\t\t\t\t\t\t\tguideVisibleColumn,\n\t\t\t\t\t\t\t-1,\n\t\t\t\t\t\t\tclassName,\n\t\t\t\t\t\t\tnew IndentGuideHorizontalLine(!renderHorizontalEndLineAtTheBottom, end.column),\n\t\t\t\t\t\t\t-1,\n\t\t\t\t\t\t\t-1,\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}\n\n\t\tfor (const guides of result) {\n\t\t\tguides.sort((a, b) => a.visibleColumn - b.visibleColumn);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tprivate getVisibleColumnFromPosition(position: Position): number {\n\t\treturn (\n\t\t\tCursorColumns.visibleColumnFromColumn(\n\t\t\t\tthis.textModel.getLineContent(position.lineNumber),\n\t\t\t\tposition.column,\n\t\t\t\tthis.textModel.getOptions().tabSize\n\t\t\t) + 1\n\t\t);\n\t}\n\n\tpublic getLinesIndentGuides(\n\t\tstartLineNumber: number,\n\t\tendLineNumber: number\n\t): number[] {\n\t\tthis.assertNotDisposed();\n\t\tconst lineCount = this.textModel.getLineCount();\n\n\t\tif (startLineNumber < 1 || startLineNumber > lineCount) {\n\t\t\tthrow new Error('Illegal value for startLineNumber');\n\t\t}\n\t\tif (endLineNumber < 1 || endLineNumber > lineCount) {\n\t\t\tthrow new Error('Illegal value for endLineNumber');\n\t\t}\n\n\t\tconst options = this.textModel.getOptions();\n\t\tconst foldingRules = this.getLanguageConfiguration(\n\t\t\tthis.textModel.getLanguageId()\n\t\t).foldingRules;\n\t\tconst offSide = Boolean(foldingRules && foldingRules.offSide);\n\n\t\tconst result: number[] = new Array(\n\t\t\tendLineNumber - startLineNumber + 1\n\t\t);\n\n\t\tlet aboveContentLineIndex =\n\t\t\t-2; /* -2 is a marker for not having computed it */\n\t\tlet aboveContentLineIndent = -1;\n\n\t\tlet belowContentLineIndex =\n\t\t\t-2; /* -2 is a marker for not having computed it */\n\t\tlet belowContentLineIndent = -1;\n\n\t\tfor (\n\t\t\tlet lineNumber = startLineNumber;\n\t\t\tlineNumber <= endLineNumber;\n\t\t\tlineNumber++\n\t\t) {\n\t\t\tconst resultIndex = lineNumber - startLineNumber;\n\n\t\t\tconst currentIndent = this._computeIndentLevel(lineNumber - 1);\n\t\t\tif (currentIndent >= 0) {\n\t\t\t\t// This line has content (besides whitespace)\n\t\t\t\t// Use the line's indent\n\t\t\t\taboveContentLineIndex = lineNumber - 1;\n\t\t\t\taboveContentLineIndent = currentIndent;\n\t\t\t\tresult[resultIndex] = Math.ceil(currentIndent / options.indentSize);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (aboveContentLineIndex === -2) {\n\t\t\t\taboveContentLineIndex = -1;\n\t\t\t\taboveContentLineIndent = -1;\n\n\t\t\t\t// must find previous line with content\n\t\t\t\tfor (let lineIndex = lineNumber - 2; lineIndex >= 0; lineIndex--) {\n\t\t\t\t\tconst indent = this._computeIndentLevel(lineIndex);\n\t\t\t\t\tif (indent >= 0) {\n\t\t\t\t\t\taboveContentLineIndex = lineIndex;\n\t\t\t\t\t\taboveContentLineIndent = indent;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\tbelowContentLineIndex !== -1 &&\n\t\t\t\t(belowContentLineIndex === -2 || belowContentLineIndex < lineNumber - 1)\n\t\t\t) {\n\t\t\t\tbelowContentLineIndex = -1;\n\t\t\t\tbelowContentLineIndent = -1;\n\n\t\t\t\t// must find next line with content\n\t\t\t\tfor (let lineIndex = lineNumber; lineIndex < lineCount; lineIndex++) {\n\t\t\t\t\tconst indent = this._computeIndentLevel(lineIndex);\n\t\t\t\t\tif (indent >= 0) {\n\t\t\t\t\t\tbelowContentLineIndex = lineIndex;\n\t\t\t\t\t\tbelowContentLineIndent = indent;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tresult[resultIndex] = this._getIndentLevelForWhitespaceLine(\n\t\t\t\toffSide,\n\t\t\t\taboveContentLineIndent,\n\t\t\t\tbelowContentLineIndent\n\t\t\t);\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate _getIndentLevelForWhitespaceLine(\n\t\toffSide: boolean,\n\t\taboveContentLineIndent: number,\n\t\tbelowContentLineIndent: number\n\t): number {\n\t\tconst options = this.textModel.getOptions();\n\n\t\tif (aboveContentLineIndent === -1 || belowContentLineIndent === -1) {\n\t\t\t// At the top or bottom of the file\n\t\t\treturn 0;\n\t\t} else if (aboveContentLineIndent < belowContentLineIndent) {\n\t\t\t// we are inside the region above\n\t\t\treturn 1 + Math.floor(aboveContentLineIndent / options.indentSize);\n\t\t} else if (aboveContentLineIndent === belowContentLineIndent) {\n\t\t\t// we are in between two regions\n\t\t\treturn Math.ceil(belowContentLineIndent / options.indentSize);\n\t\t} else {\n\t\t\tif (offSide) {\n\t\t\t\t// same level as region below\n\t\t\t\treturn Math.ceil(belowContentLineIndent / options.indentSize);\n\t\t\t} else {\n\t\t\t\t// we are inside the region that ends below\n\t\t\t\treturn 1 + Math.floor(belowContentLineIndent / options.indentSize);\n\t\t\t}\n\t\t}\n\t}\n}\n\nexport class BracketPairGuidesClassNames {\n\tpublic readonly activeClassName = 'indent-active';\n\n\tgetInlineClassName(nestingLevel: number, nestingLevelOfEqualBracketType: number, independentColorPoolPerBracketType: boolean): string {\n\t\treturn this.getInlineClassNameOfLevel(independentColorPoolPerBracketType ? nestingLevelOfEqualBracketType : nestingLevel);\n\t}\n\n\tgetInlineClassNameOfLevel(level: number): string {\n\t\t// To support a dynamic amount of colors up to 6 colors,\n\t\t// we use a number that is a lcm of all numbers from 1 to 6.\n\t\treturn `bracket-indent-guide lvl-${level % 30}`;\n\t}\n}\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\nimport { Color } from 'vs/base/common/color';\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle';\nimport { ITokenizationRegistry, ITokenizationSupport, ITokenizationSupportChangedEvent, ILazyTokenizationSupport } from 'vs/editor/common/languages';\nimport { ColorId } from 'vs/editor/common/encodedTokenAttributes';\n\nexport class TokenizationRegistry implements ITokenizationRegistry {\n\n\tprivate readonly _tokenizationSupports = new Map();\n\tprivate readonly _factories = new Map();\n\n\tprivate readonly _onDidChange = new Emitter();\n\tpublic readonly onDidChange: Event = this._onDidChange.event;\n\n\tprivate _colorMap: Color[] | null;\n\n\tconstructor() {\n\t\tthis._colorMap = null;\n\t}\n\n\tpublic handleChange(languageIds: string[]): void {\n\t\tthis._onDidChange.fire({\n\t\t\tchangedLanguages: languageIds,\n\t\t\tchangedColorMap: false\n\t\t});\n\t}\n\n\tpublic register(languageId: string, support: ITokenizationSupport): IDisposable {\n\t\tthis._tokenizationSupports.set(languageId, support);\n\t\tthis.handleChange([languageId]);\n\t\treturn toDisposable(() => {\n\t\t\tif (this._tokenizationSupports.get(languageId) !== support) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis._tokenizationSupports.delete(languageId);\n\t\t\tthis.handleChange([languageId]);\n\t\t});\n\t}\n\n\tpublic get(languageId: string): ITokenizationSupport | null {\n\t\treturn this._tokenizationSupports.get(languageId) || null;\n\t}\n\n\tpublic registerFactory(languageId: string, factory: ILazyTokenizationSupport): IDisposable {\n\t\tthis._factories.get(languageId)?.dispose();\n\t\tconst myData = new TokenizationSupportFactoryData(this, languageId, factory);\n\t\tthis._factories.set(languageId, myData);\n\t\treturn toDisposable(() => {\n\t\t\tconst v = this._factories.get(languageId);\n\t\t\tif (!v || v !== myData) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis._factories.delete(languageId);\n\t\t\tv.dispose();\n\t\t});\n\t}\n\n\tpublic async getOrCreate(languageId: string): Promise {\n\t\t// check first if the support is already set\n\t\tconst tokenizationSupport = this.get(languageId);\n\t\tif (tokenizationSupport) {\n\t\t\treturn tokenizationSupport;\n\t\t}\n\n\t\tconst factory = this._factories.get(languageId);\n\t\tif (!factory || factory.isResolved) {\n\t\t\t// no factory or factory.resolve already finished\n\t\t\treturn null;\n\t\t}\n\n\t\tawait factory.resolve();\n\n\t\treturn this.get(languageId);\n\t}\n\n\tpublic isResolved(languageId: string): boolean {\n\t\tconst tokenizationSupport = this.get(languageId);\n\t\tif (tokenizationSupport) {\n\t\t\treturn true;\n\t\t}\n\n\t\tconst factory = this._factories.get(languageId);\n\t\tif (!factory || factory.isResolved) {\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tpublic setColorMap(colorMap: Color[]): void {\n\t\tthis._colorMap = colorMap;\n\t\tthis._onDidChange.fire({\n\t\t\tchangedLanguages: Array.from(this._tokenizationSupports.keys()),\n\t\t\tchangedColorMap: true\n\t\t});\n\t}\n\n\tpublic getColorMap(): Color[] | null {\n\t\treturn this._colorMap;\n\t}\n\n\tpublic getDefaultBackground(): Color | null {\n\t\tif (this._colorMap && this._colorMap.length > ColorId.DefaultBackground) {\n\t\t\treturn this._colorMap[ColorId.DefaultBackground];\n\t\t}\n\t\treturn null;\n\t}\n}\n\nclass TokenizationSupportFactoryData extends Disposable {\n\n\tprivate _isDisposed: boolean = false;\n\tprivate _resolvePromise: Promise | null = null;\n\tprivate _isResolved: boolean = false;\n\n\tpublic get isResolved(): boolean {\n\t\treturn this._isResolved;\n\t}\n\n\tconstructor(\n\t\tprivate readonly _registry: TokenizationRegistry,\n\t\tprivate readonly _languageId: string,\n\t\tprivate readonly _factory: ILazyTokenizationSupport,\n\t) {\n\t\tsuper();\n\t}\n\n\tpublic override dispose(): void {\n\t\tthis._isDisposed = true;\n\t\tsuper.dispose();\n\t}\n\n\tpublic async resolve(): Promise {\n\t\tif (!this._resolvePromise) {\n\t\t\tthis._resolvePromise = this._create();\n\t\t}\n\t\treturn this._resolvePromise;\n\t}\n\n\tprivate async _create(): Promise {\n\t\tconst value = await this._factory.tokenizationSupport;\n\t\tthis._isResolved = true;\n\t\tif (value && !this._isDisposed) {\n\t\t\tthis._register(this._registry.register(this._languageId, value));\n\t\t}\n\t}\n}\n","\n\n/**\n * Represents contiguous tokens over a contiguous range of lines.\n */\nexport class ContiguousMultilineTokens {\n\n\t/**\n\t * The start line number for this block of tokens.\n\t */\n\tprivate _startLineNumber: number;\n\n\t/**\n\t * The tokens are stored in a binary format. There is an element for each line,\n\t * so `tokens[index]` contains all tokens on line `startLineNumber + index`.\n\t *\n\t * On a specific line, each token occupies two array indices. For token i:\n\t * - at offset 2*i => endOffset\n\t * - at offset 2*i + 1 => metadata\n\t *\n\t */\n\tprivate _tokens: (Uint32Array | ArrayBuffer | null)[];\n\n\t/**\n\t * (Inclusive) start line number for these tokens.\n\t */\n\tpublic get startLineNumber(): number {\n\t\treturn this._startLineNumber;\n\t}\n\n\t/**\n\t * (Inclusive) end line number for these tokens.\n\t */\n\tpublic get endLineNumber(): number {\n\t\treturn this._startLineNumber + this._tokens.length - 1;\n\t}\n\n\tconstructor(startLineNumber: number, tokens: Uint32Array[]) {\n\t\tthis._startLineNumber = startLineNumber;\n\t\tthis._tokens = tokens;\n\t}\n\n\t/**\n\t * @see {@link _tokens}\n\t */\n\tpublic getLineTokens(lineNumber: number): Uint32Array | ArrayBuffer | null {\n\t\treturn this._tokens[lineNumber - this._startLineNumber];\n\t}\n\n\tpublic appendLineTokens(lineTokens: Uint32Array): void {\n\t\tthis._tokens.push(lineTokens);\n\t}\n}\n","\nimport { ContiguousMultilineTokens } from 'vs/editor/common/tokens/contiguousMultilineTokens';\n\nexport class ContiguousMultilineTokensBuilder {\n\n\tprivate readonly _tokens: ContiguousMultilineTokens[];\n\n\tconstructor() {\n\t\tthis._tokens = [];\n\t}\n\n\tpublic add(lineNumber: number, lineTokens: Uint32Array): void {\n\t\tif (this._tokens.length > 0) {\n\t\t\tconst last = this._tokens[this._tokens.length - 1];\n\t\t\tif (last.endLineNumber + 1 === lineNumber) {\n\t\t\t\t// append\n\t\t\t\tlast.appendLineTokens(lineTokens);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tthis._tokens.push(new ContiguousMultilineTokens(lineNumber, [lineTokens]));\n\t}\n\n\tpublic finalize(): ContiguousMultilineTokens[] {\n\t\treturn this._tokens;\n\t}\n}\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\nimport { ILanguageIdCodec } from 'vs/editor/common/languages';\nimport { FontStyle, ColorId, StandardTokenType, MetadataConsts, TokenMetadata, ITokenPresentation } from 'vs/editor/common/encodedTokenAttributes';\n\nexport interface IViewLineTokens {\n\tequals(other: IViewLineTokens): boolean;\n\tgetCount(): number;\n\tgetForeground(tokenIndex: number): ColorId;\n\tgetEndOffset(tokenIndex: number): number;\n\tgetClassName(tokenIndex: number): string;\n\tgetInlineStyle(tokenIndex: number, colorMap: string[]): string;\n\tgetPresentation(tokenIndex: number): ITokenPresentation;\n\tfindTokenIndexAtOffset(offset: number): number;\n\tgetLineContent(): string;\n\tgetMetadata(tokenIndex: number): number;\n\tgetLanguageId(tokenIndex: number): string;\n}\n\nexport class LineTokens implements IViewLineTokens {\n\t_lineTokensBrand: void = undefined;\n\n\tprivate readonly _tokens: Uint32Array;\n\tprivate readonly _tokensCount: number;\n\tprivate readonly _text: string;\n\tprivate readonly _languageIdCodec: ILanguageIdCodec;\n\n\tpublic static defaultTokenMetadata = (\n\t\t(FontStyle.None << MetadataConsts.FONT_STYLE_OFFSET)\n\t\t| (ColorId.DefaultForeground << MetadataConsts.FOREGROUND_OFFSET)\n\t\t| (ColorId.DefaultBackground << MetadataConsts.BACKGROUND_OFFSET)\n\t) >>> 0;\n\n\tpublic static createEmpty(lineContent: string, decoder: ILanguageIdCodec): LineTokens {\n\t\tconst defaultMetadata = LineTokens.defaultTokenMetadata;\n\n\t\tconst tokens = new Uint32Array(2);\n\t\ttokens[0] = lineContent.length;\n\t\ttokens[1] = defaultMetadata;\n\n\t\treturn new LineTokens(tokens, lineContent, decoder);\n\t}\n\n\tconstructor(tokens: Uint32Array, text: string, decoder: ILanguageIdCodec) {\n\t\tthis._tokens = tokens;\n\t\tthis._tokensCount = (this._tokens.length >>> 1);\n\t\tthis._text = text;\n\t\tthis._languageIdCodec = decoder;\n\t}\n\n\tpublic equals(other: IViewLineTokens): boolean {\n\t\tif (other instanceof LineTokens) {\n\t\t\treturn this.slicedEquals(other, 0, this._tokensCount);\n\t\t}\n\t\treturn false;\n\t}\n\n\tpublic slicedEquals(other: LineTokens, sliceFromTokenIndex: number, sliceTokenCount: number): boolean {\n\t\tif (this._text !== other._text) {\n\t\t\treturn false;\n\t\t}\n\t\tif (this._tokensCount !== other._tokensCount) {\n\t\t\treturn false;\n\t\t}\n\t\tconst from = (sliceFromTokenIndex << 1);\n\t\tconst to = from + (sliceTokenCount << 1);\n\t\tfor (let i = from; i < to; i++) {\n\t\t\tif (this._tokens[i] !== other._tokens[i]) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\tpublic getLineContent(): string {\n\t\treturn this._text;\n\t}\n\n\tpublic getCount(): number {\n\t\treturn this._tokensCount;\n\t}\n\n\tpublic getStartOffset(tokenIndex: number): number {\n\t\tif (tokenIndex > 0) {\n\t\t\treturn this._tokens[(tokenIndex - 1) << 1];\n\t\t}\n\t\treturn 0;\n\t}\n\n\tpublic getMetadata(tokenIndex: number): number {\n\t\tconst metadata = this._tokens[(tokenIndex << 1) + 1];\n\t\treturn metadata;\n\t}\n\n\tpublic getLanguageId(tokenIndex: number): string {\n\t\tconst metadata = this._tokens[(tokenIndex << 1) + 1];\n\t\tconst languageId = TokenMetadata.getLanguageId(metadata);\n\t\treturn this._languageIdCodec.decodeLanguageId(languageId);\n\t}\n\n\tpublic getStandardTokenType(tokenIndex: number): StandardTokenType {\n\t\tconst metadata = this._tokens[(tokenIndex << 1) + 1];\n\t\treturn TokenMetadata.getTokenType(metadata);\n\t}\n\n\tpublic getForeground(tokenIndex: number): ColorId {\n\t\tconst metadata = this._tokens[(tokenIndex << 1) + 1];\n\t\treturn TokenMetadata.getForeground(metadata);\n\t}\n\n\tpublic getClassName(tokenIndex: number): string {\n\t\tconst metadata = this._tokens[(tokenIndex << 1) + 1];\n\t\treturn TokenMetadata.getClassNameFromMetadata(metadata);\n\t}\n\n\tpublic getInlineStyle(tokenIndex: number, colorMap: string[]): string {\n\t\tconst metadata = this._tokens[(tokenIndex << 1) + 1];\n\t\treturn TokenMetadata.getInlineStyleFromMetadata(metadata, colorMap);\n\t}\n\n\tpublic getPresentation(tokenIndex: number): ITokenPresentation {\n\t\tconst metadata = this._tokens[(tokenIndex << 1) + 1];\n\t\treturn TokenMetadata.getPresentationFromMetadata(metadata);\n\t}\n\n\tpublic getEndOffset(tokenIndex: number): number {\n\t\treturn this._tokens[tokenIndex << 1];\n\t}\n\n\t/**\n\t * Find the token containing offset `offset`.\n\t * @param offset The search offset\n\t * @return The index of the token containing the offset.\n\t */\n\tpublic findTokenIndexAtOffset(offset: number): number {\n\t\treturn LineTokens.findIndexInTokensArray(this._tokens, offset);\n\t}\n\n\tpublic inflate(): IViewLineTokens {\n\t\treturn this;\n\t}\n\n\tpublic sliceAndInflate(startOffset: number, endOffset: number, deltaOffset: number): IViewLineTokens {\n\t\treturn new SliceLineTokens(this, startOffset, endOffset, deltaOffset);\n\t}\n\n\tpublic static convertToEndOffset(tokens: Uint32Array, lineTextLength: number): void {\n\t\tconst tokenCount = (tokens.length >>> 1);\n\t\tconst lastTokenIndex = tokenCount - 1;\n\t\tfor (let tokenIndex = 0; tokenIndex < lastTokenIndex; tokenIndex++) {\n\t\t\ttokens[tokenIndex << 1] = tokens[(tokenIndex + 1) << 1];\n\t\t}\n\t\ttokens[lastTokenIndex << 1] = lineTextLength;\n\t}\n\n\tpublic static findIndexInTokensArray(tokens: Uint32Array, desiredIndex: number): number {\n\t\tif (tokens.length <= 2) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tlet low = 0;\n\t\tlet high = (tokens.length >>> 1) - 1;\n\n\t\twhile (low < high) {\n\n\t\t\tconst mid = low + Math.floor((high - low) / 2);\n\t\t\tconst endOffset = tokens[(mid << 1)];\n\n\t\t\tif (endOffset === desiredIndex) {\n\t\t\t\treturn mid + 1;\n\t\t\t} else if (endOffset < desiredIndex) {\n\t\t\t\tlow = mid + 1;\n\t\t\t} else if (endOffset > desiredIndex) {\n\t\t\t\thigh = mid;\n\t\t\t}\n\t\t}\n\n\t\treturn low;\n\t}\n\n\t/**\n\t * @pure\n\t * @param insertTokens Must be sorted by offset.\n\t*/\n\tpublic withInserted(insertTokens: { offset: number; text: string; tokenMetadata: number }[]): LineTokens {\n\t\tif (insertTokens.length === 0) {\n\t\t\treturn this;\n\t\t}\n\n\t\tlet nextOriginalTokenIdx = 0;\n\t\tlet nextInsertTokenIdx = 0;\n\t\tlet text = '';\n\t\tconst newTokens = new Array();\n\n\t\tlet originalEndOffset = 0;\n\t\twhile (true) {\n\t\t\tconst nextOriginalTokenEndOffset = nextOriginalTokenIdx < this._tokensCount ? this._tokens[nextOriginalTokenIdx << 1] : -1;\n\t\t\tconst nextInsertToken = nextInsertTokenIdx < insertTokens.length ? insertTokens[nextInsertTokenIdx] : null;\n\n\t\t\tif (nextOriginalTokenEndOffset !== -1 && (nextInsertToken === null || nextOriginalTokenEndOffset <= nextInsertToken.offset)) {\n\t\t\t\t// original token ends before next insert token\n\t\t\t\ttext += this._text.substring(originalEndOffset, nextOriginalTokenEndOffset);\n\t\t\t\tconst metadata = this._tokens[(nextOriginalTokenIdx << 1) + 1];\n\t\t\t\tnewTokens.push(text.length, metadata);\n\t\t\t\tnextOriginalTokenIdx++;\n\t\t\t\toriginalEndOffset = nextOriginalTokenEndOffset;\n\n\t\t\t} else if (nextInsertToken) {\n\t\t\t\tif (nextInsertToken.offset > originalEndOffset) {\n\t\t\t\t\t// insert token is in the middle of the next token.\n\t\t\t\t\ttext += this._text.substring(originalEndOffset, nextInsertToken.offset);\n\t\t\t\t\tconst metadata = this._tokens[(nextOriginalTokenIdx << 1) + 1];\n\t\t\t\t\tnewTokens.push(text.length, metadata);\n\t\t\t\t\toriginalEndOffset = nextInsertToken.offset;\n\t\t\t\t}\n\n\t\t\t\ttext += nextInsertToken.text;\n\t\t\t\tnewTokens.push(text.length, nextInsertToken.tokenMetadata);\n\t\t\t\tnextInsertTokenIdx++;\n\t\t\t} else {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn new LineTokens(new Uint32Array(newTokens), text, this._languageIdCodec);\n\t}\n}\n\nclass SliceLineTokens implements IViewLineTokens {\n\n\tprivate readonly _source: LineTokens;\n\tprivate readonly _startOffset: number;\n\tprivate readonly _endOffset: number;\n\tprivate readonly _deltaOffset: number;\n\n\tprivate readonly _firstTokenIndex: number;\n\tprivate readonly _tokensCount: number;\n\n\tconstructor(source: LineTokens, startOffset: number, endOffset: number, deltaOffset: number) {\n\t\tthis._source = source;\n\t\tthis._startOffset = startOffset;\n\t\tthis._endOffset = endOffset;\n\t\tthis._deltaOffset = deltaOffset;\n\t\tthis._firstTokenIndex = source.findTokenIndexAtOffset(startOffset);\n\n\t\tthis._tokensCount = 0;\n\t\tfor (let i = this._firstTokenIndex, len = source.getCount(); i < len; i++) {\n\t\t\tconst tokenStartOffset = source.getStartOffset(i);\n\t\t\tif (tokenStartOffset >= endOffset) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tthis._tokensCount++;\n\t\t}\n\t}\n\n\tpublic getMetadata(tokenIndex: number): number {\n\t\treturn this._source.getMetadata(this._firstTokenIndex + tokenIndex);\n\t}\n\n\tpublic getLanguageId(tokenIndex: number): string {\n\t\treturn this._source.getLanguageId(this._firstTokenIndex + tokenIndex);\n\t}\n\n\tpublic getLineContent(): string {\n\t\treturn this._source.getLineContent().substring(this._startOffset, this._endOffset);\n\t}\n\n\tpublic equals(other: IViewLineTokens): boolean {\n\t\tif (other instanceof SliceLineTokens) {\n\t\t\treturn (\n\t\t\t\tthis._startOffset === other._startOffset\n\t\t\t\t&& this._endOffset === other._endOffset\n\t\t\t\t&& this._deltaOffset === other._deltaOffset\n\t\t\t\t&& this._source.slicedEquals(other._source, this._firstTokenIndex, this._tokensCount)\n\t\t\t);\n\t\t}\n\t\treturn false;\n\t}\n\n\tpublic getCount(): number {\n\t\treturn this._tokensCount;\n\t}\n\n\tpublic getForeground(tokenIndex: number): ColorId {\n\t\treturn this._source.getForeground(this._firstTokenIndex + tokenIndex);\n\t}\n\n\tpublic getEndOffset(tokenIndex: number): number {\n\t\tconst tokenEndOffset = this._source.getEndOffset(this._firstTokenIndex + tokenIndex);\n\t\treturn Math.min(this._endOffset, tokenEndOffset) - this._startOffset + this._deltaOffset;\n\t}\n\n\tpublic getClassName(tokenIndex: number): string {\n\t\treturn this._source.getClassName(this._firstTokenIndex + tokenIndex);\n\t}\n\n\tpublic getInlineStyle(tokenIndex: number, colorMap: string[]): string {\n\t\treturn this._source.getInlineStyle(this._firstTokenIndex + tokenIndex, colorMap);\n\t}\n\n\tpublic getPresentation(tokenIndex: number): ITokenPresentation {\n\t\treturn this._source.getPresentation(this._firstTokenIndex + tokenIndex);\n\t}\n\n\tpublic findTokenIndexAtOffset(offset: number): number {\n\t\treturn this._source.findTokenIndexAtOffset(offset + this._startOffset - this._deltaOffset) - this._firstTokenIndex;\n\t}\n}\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\nimport { LineTokens } from 'vs/editor/common/tokens/lineTokens';\n\nexport const EMPTY_LINE_TOKENS = (new Uint32Array(0)).buffer;\n\nexport class ContiguousTokensEditing {\n\n\tpublic static deleteBeginning(lineTokens: Uint32Array | ArrayBuffer | null, toChIndex: number): Uint32Array | ArrayBuffer | null {\n\t\tif (lineTokens === null || lineTokens === EMPTY_LINE_TOKENS) {\n\t\t\treturn lineTokens;\n\t\t}\n\t\treturn ContiguousTokensEditing.delete(lineTokens, 0, toChIndex);\n\t}\n\n\tpublic static deleteEnding(lineTokens: Uint32Array | ArrayBuffer | null, fromChIndex: number): Uint32Array | ArrayBuffer | null {\n\t\tif (lineTokens === null || lineTokens === EMPTY_LINE_TOKENS) {\n\t\t\treturn lineTokens;\n\t\t}\n\n\t\tconst tokens = toUint32Array(lineTokens);\n\t\tconst lineTextLength = tokens[tokens.length - 2];\n\t\treturn ContiguousTokensEditing.delete(lineTokens, fromChIndex, lineTextLength);\n\t}\n\n\tpublic static delete(lineTokens: Uint32Array | ArrayBuffer | null, fromChIndex: number, toChIndex: number): Uint32Array | ArrayBuffer | null {\n\t\tif (lineTokens === null || lineTokens === EMPTY_LINE_TOKENS || fromChIndex === toChIndex) {\n\t\t\treturn lineTokens;\n\t\t}\n\n\t\tconst tokens = toUint32Array(lineTokens);\n\t\tconst tokensCount = (tokens.length >>> 1);\n\n\t\t// special case: deleting everything\n\t\tif (fromChIndex === 0 && tokens[tokens.length - 2] === toChIndex) {\n\t\t\treturn EMPTY_LINE_TOKENS;\n\t\t}\n\n\t\tconst fromTokenIndex = LineTokens.findIndexInTokensArray(tokens, fromChIndex);\n\t\tconst fromTokenStartOffset = (fromTokenIndex > 0 ? tokens[(fromTokenIndex - 1) << 1] : 0);\n\t\tconst fromTokenEndOffset = tokens[fromTokenIndex << 1];\n\n\t\tif (toChIndex < fromTokenEndOffset) {\n\t\t\t// the delete range is inside a single token\n\t\t\tconst delta = (toChIndex - fromChIndex);\n\t\t\tfor (let i = fromTokenIndex; i < tokensCount; i++) {\n\t\t\t\ttokens[i << 1] -= delta;\n\t\t\t}\n\t\t\treturn lineTokens;\n\t\t}\n\n\t\tlet dest: number;\n\t\tlet lastEnd: number;\n\t\tif (fromTokenStartOffset !== fromChIndex) {\n\t\t\ttokens[fromTokenIndex << 1] = fromChIndex;\n\t\t\tdest = ((fromTokenIndex + 1) << 1);\n\t\t\tlastEnd = fromChIndex;\n\t\t} else {\n\t\t\tdest = (fromTokenIndex << 1);\n\t\t\tlastEnd = fromTokenStartOffset;\n\t\t}\n\n\t\tconst delta = (toChIndex - fromChIndex);\n\t\tfor (let tokenIndex = fromTokenIndex + 1; tokenIndex < tokensCount; tokenIndex++) {\n\t\t\tconst tokenEndOffset = tokens[tokenIndex << 1] - delta;\n\t\t\tif (tokenEndOffset > lastEnd) {\n\t\t\t\ttokens[dest++] = tokenEndOffset;\n\t\t\t\ttokens[dest++] = tokens[(tokenIndex << 1) + 1];\n\t\t\t\tlastEnd = tokenEndOffset;\n\t\t\t}\n\t\t}\n\n\t\tif (dest === tokens.length) {\n\t\t\t// nothing to trim\n\t\t\treturn lineTokens;\n\t\t}\n\n\t\tconst tmp = new Uint32Array(dest);\n\t\ttmp.set(tokens.subarray(0, dest), 0);\n\t\treturn tmp.buffer;\n\t}\n\n\tpublic static append(lineTokens: Uint32Array | ArrayBuffer | null, _otherTokens: Uint32Array | ArrayBuffer | null): Uint32Array | ArrayBuffer | null {\n\t\tif (_otherTokens === EMPTY_LINE_TOKENS) {\n\t\t\treturn lineTokens;\n\t\t}\n\t\tif (lineTokens === EMPTY_LINE_TOKENS) {\n\t\t\treturn _otherTokens;\n\t\t}\n\t\tif (lineTokens === null) {\n\t\t\treturn lineTokens;\n\t\t}\n\t\tif (_otherTokens === null) {\n\t\t\t// cannot determine combined line length...\n\t\t\treturn null;\n\t\t}\n\t\tconst myTokens = toUint32Array(lineTokens);\n\t\tconst otherTokens = toUint32Array(_otherTokens);\n\t\tconst otherTokensCount = (otherTokens.length >>> 1);\n\n\t\tconst result = new Uint32Array(myTokens.length + otherTokens.length);\n\t\tresult.set(myTokens, 0);\n\t\tlet dest = myTokens.length;\n\t\tconst delta = myTokens[myTokens.length - 2];\n\t\tfor (let i = 0; i < otherTokensCount; i++) {\n\t\t\tresult[dest++] = otherTokens[(i << 1)] + delta;\n\t\t\tresult[dest++] = otherTokens[(i << 1) + 1];\n\t\t}\n\t\treturn result.buffer;\n\t}\n\n\tpublic static insert(lineTokens: Uint32Array | ArrayBuffer | null, chIndex: number, textLength: number): Uint32Array | ArrayBuffer | null {\n\t\tif (lineTokens === null || lineTokens === EMPTY_LINE_TOKENS) {\n\t\t\t// nothing to do\n\t\t\treturn lineTokens;\n\t\t}\n\n\t\tconst tokens = toUint32Array(lineTokens);\n\t\tconst tokensCount = (tokens.length >>> 1);\n\n\t\tlet fromTokenIndex = LineTokens.findIndexInTokensArray(tokens, chIndex);\n\t\tif (fromTokenIndex > 0) {\n\t\t\tconst fromTokenStartOffset = tokens[(fromTokenIndex - 1) << 1];\n\t\t\tif (fromTokenStartOffset === chIndex) {\n\t\t\t\tfromTokenIndex--;\n\t\t\t}\n\t\t}\n\t\tfor (let tokenIndex = fromTokenIndex; tokenIndex < tokensCount; tokenIndex++) {\n\t\t\ttokens[tokenIndex << 1] += textLength;\n\t\t}\n\t\treturn lineTokens;\n\t}\n}\n\nexport function toUint32Array(arr: Uint32Array | ArrayBuffer): Uint32Array {\n\tif (arr instanceof Uint32Array) {\n\t\treturn arr;\n\t} else {\n\t\treturn new Uint32Array(arr);\n\t}\n}\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\nimport * as arrays from 'vs/base/common/arrays';\nimport { Position } from 'vs/editor/common/core/position';\nimport { IRange } from 'vs/editor/common/core/range';\nimport { ContiguousTokensEditing, EMPTY_LINE_TOKENS, toUint32Array } from 'vs/editor/common/tokens/contiguousTokensEditing';\nimport { LineTokens } from 'vs/editor/common/tokens/lineTokens';\nimport { ILanguageIdCodec } from 'vs/editor/common/languages';\nimport { LanguageId, FontStyle, ColorId, StandardTokenType, MetadataConsts, TokenMetadata } from 'vs/editor/common/encodedTokenAttributes';\nimport { ITextModel } from 'vs/editor/common/model';\nimport { ContiguousMultilineTokens } from 'vs/editor/common/tokens/contiguousMultilineTokens';\n\n/**\n * Represents contiguous tokens in a text model.\n */\nexport class ContiguousTokensStore {\n\tprivate _lineTokens: (Uint32Array | ArrayBuffer | null)[];\n\tprivate _len: number;\n\tprivate readonly _languageIdCodec: ILanguageIdCodec;\n\n\tconstructor(languageIdCodec: ILanguageIdCodec) {\n\t\tthis._lineTokens = [];\n\t\tthis._len = 0;\n\t\tthis._languageIdCodec = languageIdCodec;\n\t}\n\n\tpublic flush(): void {\n\t\tthis._lineTokens = [];\n\t\tthis._len = 0;\n\t}\n\n\tget hasTokens(): boolean {\n\t\treturn this._lineTokens.length > 0;\n\t}\n\n\tpublic getTokens(topLevelLanguageId: string, lineIndex: number, lineText: string): LineTokens {\n\t\tlet rawLineTokens: Uint32Array | ArrayBuffer | null = null;\n\t\tif (lineIndex < this._len) {\n\t\t\trawLineTokens = this._lineTokens[lineIndex];\n\t\t}\n\n\t\tif (rawLineTokens !== null && rawLineTokens !== EMPTY_LINE_TOKENS) {\n\t\t\treturn new LineTokens(toUint32Array(rawLineTokens), lineText, this._languageIdCodec);\n\t\t}\n\n\t\tconst lineTokens = new Uint32Array(2);\n\t\tlineTokens[0] = lineText.length;\n\t\tlineTokens[1] = getDefaultMetadata(this._languageIdCodec.encodeLanguageId(topLevelLanguageId));\n\t\treturn new LineTokens(lineTokens, lineText, this._languageIdCodec);\n\t}\n\n\tprivate static _massageTokens(topLevelLanguageId: LanguageId, lineTextLength: number, _tokens: Uint32Array | ArrayBuffer | null): Uint32Array | ArrayBuffer {\n\n\t\tconst tokens = _tokens ? toUint32Array(_tokens) : null;\n\n\t\tif (lineTextLength === 0) {\n\t\t\tlet hasDifferentLanguageId = false;\n\t\t\tif (tokens && tokens.length > 1) {\n\t\t\t\thasDifferentLanguageId = (TokenMetadata.getLanguageId(tokens[1]) !== topLevelLanguageId);\n\t\t\t}\n\n\t\t\tif (!hasDifferentLanguageId) {\n\t\t\t\treturn EMPTY_LINE_TOKENS;\n\t\t\t}\n\t\t}\n\n\t\tif (!tokens || tokens.length === 0) {\n\t\t\tconst tokens = new Uint32Array(2);\n\t\t\ttokens[0] = lineTextLength;\n\t\t\ttokens[1] = getDefaultMetadata(topLevelLanguageId);\n\t\t\treturn tokens.buffer;\n\t\t}\n\n\t\t// Ensure the last token covers the end of the text\n\t\ttokens[tokens.length - 2] = lineTextLength;\n\n\t\tif (tokens.byteOffset === 0 && tokens.byteLength === tokens.buffer.byteLength) {\n\t\t\t// Store directly the ArrayBuffer pointer to save an object\n\t\t\treturn tokens.buffer;\n\t\t}\n\t\treturn tokens;\n\t}\n\n\tprivate _ensureLine(lineIndex: number): void {\n\t\twhile (lineIndex >= this._len) {\n\t\t\tthis._lineTokens[this._len] = null;\n\t\t\tthis._len++;\n\t\t}\n\t}\n\n\tprivate _deleteLines(start: number, deleteCount: number): void {\n\t\tif (deleteCount === 0) {\n\t\t\treturn;\n\t\t}\n\t\tif (start + deleteCount > this._len) {\n\t\t\tdeleteCount = this._len - start;\n\t\t}\n\t\tthis._lineTokens.splice(start, deleteCount);\n\t\tthis._len -= deleteCount;\n\t}\n\n\tprivate _insertLines(insertIndex: number, insertCount: number): void {\n\t\tif (insertCount === 0) {\n\t\t\treturn;\n\t\t}\n\t\tconst lineTokens: (Uint32Array | ArrayBuffer | null)[] = [];\n\t\tfor (let i = 0; i < insertCount; i++) {\n\t\t\tlineTokens[i] = null;\n\t\t}\n\t\tthis._lineTokens = arrays.arrayInsert(this._lineTokens, insertIndex, lineTokens);\n\t\tthis._len += insertCount;\n\t}\n\n\tpublic setTokens(topLevelLanguageId: string, lineIndex: number, lineTextLength: number, _tokens: Uint32Array | ArrayBuffer | null, checkEquality: boolean): boolean {\n\t\tconst tokens = ContiguousTokensStore._massageTokens(this._languageIdCodec.encodeLanguageId(topLevelLanguageId), lineTextLength, _tokens);\n\t\tthis._ensureLine(lineIndex);\n\t\tconst oldTokens = this._lineTokens[lineIndex];\n\t\tthis._lineTokens[lineIndex] = tokens;\n\n\t\tif (checkEquality) {\n\t\t\treturn !ContiguousTokensStore._equals(oldTokens, tokens);\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate static _equals(_a: Uint32Array | ArrayBuffer | null, _b: Uint32Array | ArrayBuffer | null) {\n\t\tif (!_a || !_b) {\n\t\t\treturn !_a && !_b;\n\t\t}\n\n\t\tconst a = toUint32Array(_a);\n\t\tconst b = toUint32Array(_b);\n\n\t\tif (a.length !== b.length) {\n\t\t\treturn false;\n\t\t}\n\t\tfor (let i = 0, len = a.length; i < len; i++) {\n\t\t\tif (a[i] !== b[i]) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\t//#region Editing\n\n\tpublic acceptEdit(range: IRange, eolCount: number, firstLineLength: number): void {\n\t\tthis._acceptDeleteRange(range);\n\t\tthis._acceptInsertText(new Position(range.startLineNumber, range.startColumn), eolCount, firstLineLength);\n\t}\n\n\tprivate _acceptDeleteRange(range: IRange): void {\n\n\t\tconst firstLineIndex = range.startLineNumber - 1;\n\t\tif (firstLineIndex >= this._len) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (range.startLineNumber === range.endLineNumber) {\n\t\t\tif (range.startColumn === range.endColumn) {\n\t\t\t\t// Nothing to delete\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis._lineTokens[firstLineIndex] = ContiguousTokensEditing.delete(this._lineTokens[firstLineIndex], range.startColumn - 1, range.endColumn - 1);\n\t\t\treturn;\n\t\t}\n\n\t\tthis._lineTokens[firstLineIndex] = ContiguousTokensEditing.deleteEnding(this._lineTokens[firstLineIndex], range.startColumn - 1);\n\n\t\tconst lastLineIndex = range.endLineNumber - 1;\n\t\tlet lastLineTokens: Uint32Array | ArrayBuffer | null = null;\n\t\tif (lastLineIndex < this._len) {\n\t\t\tlastLineTokens = ContiguousTokensEditing.deleteBeginning(this._lineTokens[lastLineIndex], range.endColumn - 1);\n\t\t}\n\n\t\t// Take remaining text on last line and append it to remaining text on first line\n\t\tthis._lineTokens[firstLineIndex] = ContiguousTokensEditing.append(this._lineTokens[firstLineIndex], lastLineTokens);\n\n\t\t// Delete middle lines\n\t\tthis._deleteLines(range.startLineNumber, range.endLineNumber - range.startLineNumber);\n\t}\n\n\tprivate _acceptInsertText(position: Position, eolCount: number, firstLineLength: number): void {\n\n\t\tif (eolCount === 0 && firstLineLength === 0) {\n\t\t\t// Nothing to insert\n\t\t\treturn;\n\t\t}\n\n\t\tconst lineIndex = position.lineNumber - 1;\n\t\tif (lineIndex >= this._len) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (eolCount === 0) {\n\t\t\t// Inserting text on one line\n\t\t\tthis._lineTokens[lineIndex] = ContiguousTokensEditing.insert(this._lineTokens[lineIndex], position.column - 1, firstLineLength);\n\t\t\treturn;\n\t\t}\n\n\t\tthis._lineTokens[lineIndex] = ContiguousTokensEditing.deleteEnding(this._lineTokens[lineIndex], position.column - 1);\n\t\tthis._lineTokens[lineIndex] = ContiguousTokensEditing.insert(this._lineTokens[lineIndex], position.column - 1, firstLineLength);\n\n\t\tthis._insertLines(position.lineNumber, eolCount);\n\t}\n\n\t//#endregion\n\n\tpublic setMultilineTokens(tokens: ContiguousMultilineTokens[], textModel: ITextModel): { changes: { fromLineNumber: number; toLineNumber: number }[] } {\n\t\tif (tokens.length === 0) {\n\t\t\treturn { changes: [] };\n\t\t}\n\n\t\tconst ranges: { fromLineNumber: number; toLineNumber: number }[] = [];\n\n\t\tfor (let i = 0, len = tokens.length; i < len; i++) {\n\t\t\tconst element = tokens[i];\n\t\t\tlet minChangedLineNumber = 0;\n\t\t\tlet maxChangedLineNumber = 0;\n\t\t\tlet hasChange = false;\n\t\t\tfor (let lineNumber = element.startLineNumber; lineNumber <= element.endLineNumber; lineNumber++) {\n\t\t\t\tif (hasChange) {\n\t\t\t\t\tthis.setTokens(textModel.getLanguageId(), lineNumber - 1, textModel.getLineLength(lineNumber), element.getLineTokens(lineNumber), false);\n\t\t\t\t\tmaxChangedLineNumber = lineNumber;\n\t\t\t\t} else {\n\t\t\t\t\tconst lineHasChange = this.setTokens(textModel.getLanguageId(), lineNumber - 1, textModel.getLineLength(lineNumber), element.getLineTokens(lineNumber), true);\n\t\t\t\t\tif (lineHasChange) {\n\t\t\t\t\t\thasChange = true;\n\t\t\t\t\t\tminChangedLineNumber = lineNumber;\n\t\t\t\t\t\tmaxChangedLineNumber = lineNumber;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (hasChange) {\n\t\t\t\tranges.push({ fromLineNumber: minChangedLineNumber, toLineNumber: maxChangedLineNumber, });\n\t\t\t}\n\t\t}\n\n\t\treturn { changes: ranges };\n\t}\n}\n\nfunction getDefaultMetadata(topLevelLanguageId: LanguageId): number {\n\treturn (\n\t\t(topLevelLanguageId << MetadataConsts.LANGUAGEID_OFFSET)\n\t\t| (StandardTokenType.Other << MetadataConsts.TOKEN_TYPE_OFFSET)\n\t\t| (FontStyle.None << MetadataConsts.FONT_STYLE_OFFSET)\n\t\t| (ColorId.DefaultForeground << MetadataConsts.FOREGROUND_OFFSET)\n\t\t| (ColorId.DefaultBackground << MetadataConsts.BACKGROUND_OFFSET)\n\t\t// If there is no grammar, we just take a guess and try to match brackets.\n\t\t| (MetadataConsts.BALANCED_BRACKETS_MASK)\n\t) >>> 0;\n}\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\nimport { CharCode } from 'vs/base/common/charCode';\nimport { Position } from 'vs/editor/common/core/position';\nimport { IRange, Range } from 'vs/editor/common/core/range';\nimport { countEOL } from 'vs/editor/common/core/eolCounter';\n\n/**\n * Represents sparse tokens over a contiguous range of lines.\n */\nexport class SparseMultilineTokens {\n\n\tpublic static create(startLineNumber: number, tokens: Uint32Array): SparseMultilineTokens {\n\t\treturn new SparseMultilineTokens(startLineNumber, new SparseMultilineTokensStorage(tokens));\n\t}\n\n\tprivate _startLineNumber: number;\n\tprivate _endLineNumber: number;\n\tprivate readonly _tokens: SparseMultilineTokensStorage;\n\n\t/**\n\t * (Inclusive) start line number for these tokens.\n\t */\n\tpublic get startLineNumber(): number {\n\t\treturn this._startLineNumber;\n\t}\n\n\t/**\n\t * (Inclusive) end line number for these tokens.\n\t */\n\tpublic get endLineNumber(): number {\n\t\treturn this._endLineNumber;\n\t}\n\n\tprivate constructor(startLineNumber: number, tokens: SparseMultilineTokensStorage) {\n\t\tthis._startLineNumber = startLineNumber;\n\t\tthis._tokens = tokens;\n\t\tthis._endLineNumber = this._startLineNumber + this._tokens.getMaxDeltaLine();\n\t}\n\n\tpublic toString(): string {\n\t\treturn this._tokens.toString(this._startLineNumber);\n\t}\n\n\tprivate _updateEndLineNumber(): void {\n\t\tthis._endLineNumber = this._startLineNumber + this._tokens.getMaxDeltaLine();\n\t}\n\n\tpublic isEmpty(): boolean {\n\t\treturn this._tokens.isEmpty();\n\t}\n\n\tpublic getLineTokens(lineNumber: number): SparseLineTokens | null {\n\t\tif (this._startLineNumber <= lineNumber && lineNumber <= this._endLineNumber) {\n\t\t\treturn this._tokens.getLineTokens(lineNumber - this._startLineNumber);\n\t\t}\n\t\treturn null;\n\t}\n\n\tpublic getRange(): Range | null {\n\t\tconst deltaRange = this._tokens.getRange();\n\t\tif (!deltaRange) {\n\t\t\treturn deltaRange;\n\t\t}\n\t\treturn new Range(this._startLineNumber + deltaRange.startLineNumber, deltaRange.startColumn, this._startLineNumber + deltaRange.endLineNumber, deltaRange.endColumn);\n\t}\n\n\tpublic removeTokens(range: Range): void {\n\t\tconst startLineIndex = range.startLineNumber - this._startLineNumber;\n\t\tconst endLineIndex = range.endLineNumber - this._startLineNumber;\n\n\t\tthis._startLineNumber += this._tokens.removeTokens(startLineIndex, range.startColumn - 1, endLineIndex, range.endColumn - 1);\n\t\tthis._updateEndLineNumber();\n\t}\n\n\tpublic split(range: Range): [SparseMultilineTokens, SparseMultilineTokens] {\n\t\t// split tokens to two:\n\t\t// a) all the tokens before `range`\n\t\t// b) all the tokens after `range`\n\t\tconst startLineIndex = range.startLineNumber - this._startLineNumber;\n\t\tconst endLineIndex = range.endLineNumber - this._startLineNumber;\n\n\t\tconst [a, b, bDeltaLine] = this._tokens.split(startLineIndex, range.startColumn - 1, endLineIndex, range.endColumn - 1);\n\t\treturn [new SparseMultilineTokens(this._startLineNumber, a), new SparseMultilineTokens(this._startLineNumber + bDeltaLine, b)];\n\t}\n\n\tpublic applyEdit(range: IRange, text: string): void {\n\t\tconst [eolCount, firstLineLength, lastLineLength] = countEOL(text);\n\t\tthis.acceptEdit(range, eolCount, firstLineLength, lastLineLength, text.length > 0 ? text.charCodeAt(0) : CharCode.Null);\n\t}\n\n\tpublic acceptEdit(range: IRange, eolCount: number, firstLineLength: number, lastLineLength: number, firstCharCode: number): void {\n\t\tthis._acceptDeleteRange(range);\n\t\tthis._acceptInsertText(new Position(range.startLineNumber, range.startColumn), eolCount, firstLineLength, lastLineLength, firstCharCode);\n\t\tthis._updateEndLineNumber();\n\t}\n\n\tprivate _acceptDeleteRange(range: IRange): void {\n\t\tif (range.startLineNumber === range.endLineNumber && range.startColumn === range.endColumn) {\n\t\t\t// Nothing to delete\n\t\t\treturn;\n\t\t}\n\n\t\tconst firstLineIndex = range.startLineNumber - this._startLineNumber;\n\t\tconst lastLineIndex = range.endLineNumber - this._startLineNumber;\n\n\t\tif (lastLineIndex < 0) {\n\t\t\t// this deletion occurs entirely before this block, so we only need to adjust line numbers\n\t\t\tconst deletedLinesCount = lastLineIndex - firstLineIndex;\n\t\t\tthis._startLineNumber -= deletedLinesCount;\n\t\t\treturn;\n\t\t}\n\n\t\tconst tokenMaxDeltaLine = this._tokens.getMaxDeltaLine();\n\n\t\tif (firstLineIndex >= tokenMaxDeltaLine + 1) {\n\t\t\t// this deletion occurs entirely after this block, so there is nothing to do\n\t\t\treturn;\n\t\t}\n\n\t\tif (firstLineIndex < 0 && lastLineIndex >= tokenMaxDeltaLine + 1) {\n\t\t\t// this deletion completely encompasses this block\n\t\t\tthis._startLineNumber = 0;\n\t\t\tthis._tokens.clear();\n\t\t\treturn;\n\t\t}\n\n\t\tif (firstLineIndex < 0) {\n\t\t\tconst deletedBefore = -firstLineIndex;\n\t\t\tthis._startLineNumber -= deletedBefore;\n\n\t\t\tthis._tokens.acceptDeleteRange(range.startColumn - 1, 0, 0, lastLineIndex, range.endColumn - 1);\n\t\t} else {\n\t\t\tthis._tokens.acceptDeleteRange(0, firstLineIndex, range.startColumn - 1, lastLineIndex, range.endColumn - 1);\n\t\t}\n\t}\n\n\tprivate _acceptInsertText(position: Position, eolCount: number, firstLineLength: number, lastLineLength: number, firstCharCode: number): void {\n\n\t\tif (eolCount === 0 && firstLineLength === 0) {\n\t\t\t// Nothing to insert\n\t\t\treturn;\n\t\t}\n\n\t\tconst lineIndex = position.lineNumber - this._startLineNumber;\n\n\t\tif (lineIndex < 0) {\n\t\t\t// this insertion occurs before this block, so we only need to adjust line numbers\n\t\t\tthis._startLineNumber += eolCount;\n\t\t\treturn;\n\t\t}\n\n\t\tconst tokenMaxDeltaLine = this._tokens.getMaxDeltaLine();\n\n\t\tif (lineIndex >= tokenMaxDeltaLine + 1) {\n\t\t\t// this insertion occurs after this block, so there is nothing to do\n\t\t\treturn;\n\t\t}\n\n\t\tthis._tokens.acceptInsertText(lineIndex, position.column - 1, eolCount, firstLineLength, lastLineLength, firstCharCode);\n\t}\n}\n\nclass SparseMultilineTokensStorage {\n\t/**\n\t * The encoding of tokens is:\n\t * 4*i deltaLine (from `startLineNumber`)\n\t * 4*i+1 startCharacter (from the line start)\n\t * 4*i+2 endCharacter (from the line start)\n\t * 4*i+3 metadata\n\t */\n\tprivate readonly _tokens: Uint32Array;\n\tprivate _tokenCount: number;\n\n\tconstructor(tokens: Uint32Array) {\n\t\tthis._tokens = tokens;\n\t\tthis._tokenCount = tokens.length / 4;\n\t}\n\n\tpublic toString(startLineNumber: number): string {\n\t\tconst pieces: string[] = [];\n\t\tfor (let i = 0; i < this._tokenCount; i++) {\n\t\t\tpieces.push(`(${this._getDeltaLine(i) + startLineNumber},${this._getStartCharacter(i)}-${this._getEndCharacter(i)})`);\n\t\t}\n\t\treturn `[${pieces.join(',')}]`;\n\t}\n\n\tpublic getMaxDeltaLine(): number {\n\t\tconst tokenCount = this._getTokenCount();\n\t\tif (tokenCount === 0) {\n\t\t\treturn -1;\n\t\t}\n\t\treturn this._getDeltaLine(tokenCount - 1);\n\t}\n\n\tpublic getRange(): Range | null {\n\t\tconst tokenCount = this._getTokenCount();\n\t\tif (tokenCount === 0) {\n\t\t\treturn null;\n\t\t}\n\t\tconst startChar = this._getStartCharacter(0);\n\t\tconst maxDeltaLine = this._getDeltaLine(tokenCount - 1);\n\t\tconst endChar = this._getEndCharacter(tokenCount - 1);\n\t\treturn new Range(0, startChar + 1, maxDeltaLine, endChar + 1);\n\t}\n\n\tprivate _getTokenCount(): number {\n\t\treturn this._tokenCount;\n\t}\n\n\tprivate _getDeltaLine(tokenIndex: number): number {\n\t\treturn this._tokens[4 * tokenIndex];\n\t}\n\n\tprivate _getStartCharacter(tokenIndex: number): number {\n\t\treturn this._tokens[4 * tokenIndex + 1];\n\t}\n\n\tprivate _getEndCharacter(tokenIndex: number): number {\n\t\treturn this._tokens[4 * tokenIndex + 2];\n\t}\n\n\tpublic isEmpty(): boolean {\n\t\treturn (this._getTokenCount() === 0);\n\t}\n\n\tpublic getLineTokens(deltaLine: number): SparseLineTokens | null {\n\t\tlet low = 0;\n\t\tlet high = this._getTokenCount() - 1;\n\n\t\twhile (low < high) {\n\t\t\tconst mid = low + Math.floor((high - low) / 2);\n\t\t\tconst midDeltaLine = this._getDeltaLine(mid);\n\n\t\t\tif (midDeltaLine < deltaLine) {\n\t\t\t\tlow = mid + 1;\n\t\t\t} else if (midDeltaLine > deltaLine) {\n\t\t\t\thigh = mid - 1;\n\t\t\t} else {\n\t\t\t\tlet min = mid;\n\t\t\t\twhile (min > low && this._getDeltaLine(min - 1) === deltaLine) {\n\t\t\t\t\tmin--;\n\t\t\t\t}\n\t\t\t\tlet max = mid;\n\t\t\t\twhile (max < high && this._getDeltaLine(max + 1) === deltaLine) {\n\t\t\t\t\tmax++;\n\t\t\t\t}\n\t\t\t\treturn new SparseLineTokens(this._tokens.subarray(4 * min, 4 * max + 4));\n\t\t\t}\n\t\t}\n\n\t\tif (this._getDeltaLine(low) === deltaLine) {\n\t\t\treturn new SparseLineTokens(this._tokens.subarray(4 * low, 4 * low + 4));\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tpublic clear(): void {\n\t\tthis._tokenCount = 0;\n\t}\n\n\tpublic removeTokens(startDeltaLine: number, startChar: number, endDeltaLine: number, endChar: number): number {\n\t\tconst tokens = this._tokens;\n\t\tconst tokenCount = this._tokenCount;\n\t\tlet newTokenCount = 0;\n\t\tlet hasDeletedTokens = false;\n\t\tlet firstDeltaLine = 0;\n\t\tfor (let i = 0; i < tokenCount; i++) {\n\t\t\tconst srcOffset = 4 * i;\n\t\t\tconst tokenDeltaLine = tokens[srcOffset];\n\t\t\tconst tokenStartCharacter = tokens[srcOffset + 1];\n\t\t\tconst tokenEndCharacter = tokens[srcOffset + 2];\n\t\t\tconst tokenMetadata = tokens[srcOffset + 3];\n\n\t\t\tif (\n\t\t\t\t(tokenDeltaLine > startDeltaLine || (tokenDeltaLine === startDeltaLine && tokenEndCharacter >= startChar))\n\t\t\t\t&& (tokenDeltaLine < endDeltaLine || (tokenDeltaLine === endDeltaLine && tokenStartCharacter <= endChar))\n\t\t\t) {\n\t\t\t\thasDeletedTokens = true;\n\t\t\t} else {\n\t\t\t\tif (newTokenCount === 0) {\n\t\t\t\t\tfirstDeltaLine = tokenDeltaLine;\n\t\t\t\t}\n\t\t\t\tif (hasDeletedTokens) {\n\t\t\t\t\t// must move the token to the left\n\t\t\t\t\tconst destOffset = 4 * newTokenCount;\n\t\t\t\t\ttokens[destOffset] = tokenDeltaLine - firstDeltaLine;\n\t\t\t\t\ttokens[destOffset + 1] = tokenStartCharacter;\n\t\t\t\t\ttokens[destOffset + 2] = tokenEndCharacter;\n\t\t\t\t\ttokens[destOffset + 3] = tokenMetadata;\n\t\t\t\t}\n\t\t\t\tnewTokenCount++;\n\t\t\t}\n\t\t}\n\n\t\tthis._tokenCount = newTokenCount;\n\n\t\treturn firstDeltaLine;\n\t}\n\n\tpublic split(startDeltaLine: number, startChar: number, endDeltaLine: number, endChar: number): [SparseMultilineTokensStorage, SparseMultilineTokensStorage, number] {\n\t\tconst tokens = this._tokens;\n\t\tconst tokenCount = this._tokenCount;\n\t\tconst aTokens: number[] = [];\n\t\tconst bTokens: number[] = [];\n\t\tlet destTokens: number[] = aTokens;\n\t\tlet destOffset = 0;\n\t\tlet destFirstDeltaLine: number = 0;\n\t\tfor (let i = 0; i < tokenCount; i++) {\n\t\t\tconst srcOffset = 4 * i;\n\t\t\tconst tokenDeltaLine = tokens[srcOffset];\n\t\t\tconst tokenStartCharacter = tokens[srcOffset + 1];\n\t\t\tconst tokenEndCharacter = tokens[srcOffset + 2];\n\t\t\tconst tokenMetadata = tokens[srcOffset + 3];\n\n\t\t\tif ((tokenDeltaLine > startDeltaLine || (tokenDeltaLine === startDeltaLine && tokenEndCharacter >= startChar))) {\n\t\t\t\tif ((tokenDeltaLine < endDeltaLine || (tokenDeltaLine === endDeltaLine && tokenStartCharacter <= endChar))) {\n\t\t\t\t\t// this token is touching the range\n\t\t\t\t\tcontinue;\n\t\t\t\t} else {\n\t\t\t\t\t// this token is after the range\n\t\t\t\t\tif (destTokens !== bTokens) {\n\t\t\t\t\t\t// this token is the first token after the range\n\t\t\t\t\t\tdestTokens = bTokens;\n\t\t\t\t\t\tdestOffset = 0;\n\t\t\t\t\t\tdestFirstDeltaLine = tokenDeltaLine;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tdestTokens[destOffset++] = tokenDeltaLine - destFirstDeltaLine;\n\t\t\tdestTokens[destOffset++] = tokenStartCharacter;\n\t\t\tdestTokens[destOffset++] = tokenEndCharacter;\n\t\t\tdestTokens[destOffset++] = tokenMetadata;\n\t\t}\n\n\t\treturn [new SparseMultilineTokensStorage(new Uint32Array(aTokens)), new SparseMultilineTokensStorage(new Uint32Array(bTokens)), destFirstDeltaLine];\n\t}\n\n\tpublic acceptDeleteRange(horizontalShiftForFirstLineTokens: number, startDeltaLine: number, startCharacter: number, endDeltaLine: number, endCharacter: number): void {\n\t\t// This is a bit complex, here are the cases I used to think about this:\n\t\t//\n\t\t// 1. The token starts before the deletion range\n\t\t// 1a. The token is completely before the deletion range\n\t\t// -----------\n\t\t// xxxxxxxxxxx\n\t\t// 1b. The token starts before, the deletion range ends after the token\n\t\t// -----------\n\t\t// xxxxxxxxxxx\n\t\t// 1c. The token starts before, the deletion range ends precisely with the token\n\t\t// ---------------\n\t\t// xxxxxxxx\n\t\t// 1d. The token starts before, the deletion range is inside the token\n\t\t// ---------------\n\t\t// xxxxx\n\t\t//\n\t\t// 2. The token starts at the same position with the deletion range\n\t\t// 2a. The token starts at the same position, and ends inside the deletion range\n\t\t// -------\n\t\t// xxxxxxxxxxx\n\t\t// 2b. The token starts at the same position, and ends at the same position as the deletion range\n\t\t// ----------\n\t\t// xxxxxxxxxx\n\t\t// 2c. The token starts at the same position, and ends after the deletion range\n\t\t// -------------\n\t\t// xxxxxxx\n\t\t//\n\t\t// 3. The token starts inside the deletion range\n\t\t// 3a. The token is inside the deletion range\n\t\t// -------\n\t\t// xxxxxxxxxxxxx\n\t\t// 3b. The token starts inside the deletion range, and ends at the same position as the deletion range\n\t\t// ----------\n\t\t// xxxxxxxxxxxxx\n\t\t// 3c. The token starts inside the deletion range, and ends after the deletion range\n\t\t// ------------\n\t\t// xxxxxxxxxxx\n\t\t//\n\t\t// 4. The token starts after the deletion range\n\t\t// -----------\n\t\t// xxxxxxxx\n\t\t//\n\t\tconst tokens = this._tokens;\n\t\tconst tokenCount = this._tokenCount;\n\t\tconst deletedLineCount = (endDeltaLine - startDeltaLine);\n\t\tlet newTokenCount = 0;\n\t\tlet hasDeletedTokens = false;\n\t\tfor (let i = 0; i < tokenCount; i++) {\n\t\t\tconst srcOffset = 4 * i;\n\t\t\tlet tokenDeltaLine = tokens[srcOffset];\n\t\t\tlet tokenStartCharacter = tokens[srcOffset + 1];\n\t\t\tlet tokenEndCharacter = tokens[srcOffset + 2];\n\t\t\tconst tokenMetadata = tokens[srcOffset + 3];\n\n\t\t\tif (tokenDeltaLine < startDeltaLine || (tokenDeltaLine === startDeltaLine && tokenEndCharacter <= startCharacter)) {\n\t\t\t\t// 1a. The token is completely before the deletion range\n\t\t\t\t// => nothing to do\n\t\t\t\tnewTokenCount++;\n\t\t\t\tcontinue;\n\t\t\t} else if (tokenDeltaLine === startDeltaLine && tokenStartCharacter < startCharacter) {\n\t\t\t\t// 1b, 1c, 1d\n\t\t\t\t// => the token survives, but it needs to shrink\n\t\t\t\tif (tokenDeltaLine === endDeltaLine && tokenEndCharacter > endCharacter) {\n\t\t\t\t\t// 1d. The token starts before, the deletion range is inside the token\n\t\t\t\t\t// => the token shrinks by the deletion character count\n\t\t\t\t\ttokenEndCharacter -= (endCharacter - startCharacter);\n\t\t\t\t} else {\n\t\t\t\t\t// 1b. The token starts before, the deletion range ends after the token\n\t\t\t\t\t// 1c. The token starts before, the deletion range ends precisely with the token\n\t\t\t\t\t// => the token shrinks its ending to the deletion start\n\t\t\t\t\ttokenEndCharacter = startCharacter;\n\t\t\t\t}\n\t\t\t} else if (tokenDeltaLine === startDeltaLine && tokenStartCharacter === startCharacter) {\n\t\t\t\t// 2a, 2b, 2c\n\t\t\t\tif (tokenDeltaLine === endDeltaLine && tokenEndCharacter > endCharacter) {\n\t\t\t\t\t// 2c. The token starts at the same position, and ends after the deletion range\n\t\t\t\t\t// => the token shrinks by the deletion character count\n\t\t\t\t\ttokenEndCharacter -= (endCharacter - startCharacter);\n\t\t\t\t} else {\n\t\t\t\t\t// 2a. The token starts at the same position, and ends inside the deletion range\n\t\t\t\t\t// 2b. The token starts at the same position, and ends at the same position as the deletion range\n\t\t\t\t\t// => the token is deleted\n\t\t\t\t\thasDeletedTokens = true;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t} else if (tokenDeltaLine < endDeltaLine || (tokenDeltaLine === endDeltaLine && tokenStartCharacter < endCharacter)) {\n\t\t\t\t// 3a, 3b, 3c\n\t\t\t\tif (tokenDeltaLine === endDeltaLine && tokenEndCharacter > endCharacter) {\n\t\t\t\t\t// 3c. The token starts inside the deletion range, and ends after the deletion range\n\t\t\t\t\t// => the token moves to continue right after the deletion\n\t\t\t\t\ttokenDeltaLine = startDeltaLine;\n\t\t\t\t\ttokenStartCharacter = startCharacter;\n\t\t\t\t\ttokenEndCharacter = tokenStartCharacter + (tokenEndCharacter - endCharacter);\n\t\t\t\t} else {\n\t\t\t\t\t// 3a. The token is inside the deletion range\n\t\t\t\t\t// 3b. The token starts inside the deletion range, and ends at the same position as the deletion range\n\t\t\t\t\t// => the token is deleted\n\t\t\t\t\thasDeletedTokens = true;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t} else if (tokenDeltaLine > endDeltaLine) {\n\t\t\t\t// 4. (partial) The token starts after the deletion range, on a line below...\n\t\t\t\tif (deletedLineCount === 0 && !hasDeletedTokens) {\n\t\t\t\t\t// early stop, there is no need to walk all the tokens and do nothing...\n\t\t\t\t\tnewTokenCount = tokenCount;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\ttokenDeltaLine -= deletedLineCount;\n\t\t\t} else if (tokenDeltaLine === endDeltaLine && tokenStartCharacter >= endCharacter) {\n\t\t\t\t// 4. (continued) The token starts after the deletion range, on the last line where a deletion occurs\n\t\t\t\tif (horizontalShiftForFirstLineTokens && tokenDeltaLine === 0) {\n\t\t\t\t\ttokenStartCharacter += horizontalShiftForFirstLineTokens;\n\t\t\t\t\ttokenEndCharacter += horizontalShiftForFirstLineTokens;\n\t\t\t\t}\n\t\t\t\ttokenDeltaLine -= deletedLineCount;\n\t\t\t\ttokenStartCharacter -= (endCharacter - startCharacter);\n\t\t\t\ttokenEndCharacter -= (endCharacter - startCharacter);\n\t\t\t} else {\n\t\t\t\tthrow new Error(`Not possible!`);\n\t\t\t}\n\n\t\t\tconst destOffset = 4 * newTokenCount;\n\t\t\ttokens[destOffset] = tokenDeltaLine;\n\t\t\ttokens[destOffset + 1] = tokenStartCharacter;\n\t\t\ttokens[destOffset + 2] = tokenEndCharacter;\n\t\t\ttokens[destOffset + 3] = tokenMetadata;\n\t\t\tnewTokenCount++;\n\t\t}\n\n\t\tthis._tokenCount = newTokenCount;\n\t}\n\n\tpublic acceptInsertText(deltaLine: number, character: number, eolCount: number, firstLineLength: number, lastLineLength: number, firstCharCode: number): void {\n\t\t// Here are the cases I used to think about this:\n\t\t//\n\t\t// 1. The token is completely before the insertion point\n\t\t// ----------- |\n\t\t// 2. The token ends precisely at the insertion point\n\t\t// -----------|\n\t\t// 3. The token contains the insertion point\n\t\t// -----|------\n\t\t// 4. The token starts precisely at the insertion point\n\t\t// |-----------\n\t\t// 5. The token is completely after the insertion point\n\t\t// | -----------\n\t\t//\n\t\tconst isInsertingPreciselyOneWordCharacter = (\n\t\t\teolCount === 0\n\t\t\t&& firstLineLength === 1\n\t\t\t&& (\n\t\t\t\t(firstCharCode >= CharCode.Digit0 && firstCharCode <= CharCode.Digit9)\n\t\t\t\t|| (firstCharCode >= CharCode.A && firstCharCode <= CharCode.Z)\n\t\t\t\t|| (firstCharCode >= CharCode.a && firstCharCode <= CharCode.z)\n\t\t\t)\n\t\t);\n\t\tconst tokens = this._tokens;\n\t\tconst tokenCount = this._tokenCount;\n\t\tfor (let i = 0; i < tokenCount; i++) {\n\t\t\tconst offset = 4 * i;\n\t\t\tlet tokenDeltaLine = tokens[offset];\n\t\t\tlet tokenStartCharacter = tokens[offset + 1];\n\t\t\tlet tokenEndCharacter = tokens[offset + 2];\n\n\t\t\tif (tokenDeltaLine < deltaLine || (tokenDeltaLine === deltaLine && tokenEndCharacter < character)) {\n\t\t\t\t// 1. The token is completely before the insertion point\n\t\t\t\t// => nothing to do\n\t\t\t\tcontinue;\n\t\t\t} else if (tokenDeltaLine === deltaLine && tokenEndCharacter === character) {\n\t\t\t\t// 2. The token ends precisely at the insertion point\n\t\t\t\t// => expand the end character only if inserting precisely one character that is a word character\n\t\t\t\tif (isInsertingPreciselyOneWordCharacter) {\n\t\t\t\t\ttokenEndCharacter += 1;\n\t\t\t\t} else {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t} else if (tokenDeltaLine === deltaLine && tokenStartCharacter < character && character < tokenEndCharacter) {\n\t\t\t\t// 3. The token contains the insertion point\n\t\t\t\tif (eolCount === 0) {\n\t\t\t\t\t// => just expand the end character\n\t\t\t\t\ttokenEndCharacter += firstLineLength;\n\t\t\t\t} else {\n\t\t\t\t\t// => cut off the token\n\t\t\t\t\ttokenEndCharacter = character;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// 4. or 5.\n\t\t\t\tif (tokenDeltaLine === deltaLine && tokenStartCharacter === character) {\n\t\t\t\t\t// 4. The token starts precisely at the insertion point\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\n\t\t\t\t\t// => otherwise behave as in case 5.\n\t\t\t\t\tif (isInsertingPreciselyOneWordCharacter) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// => the token must move and keep its size constant\n\t\t\t\tif (tokenDeltaLine === deltaLine) {\n\t\t\t\t\ttokenDeltaLine += eolCount;\n\t\t\t\t\t// this token is on the line where the insertion is taking place\n\t\t\t\t\tif (eolCount === 0) {\n\t\t\t\t\t\ttokenStartCharacter += firstLineLength;\n\t\t\t\t\t\ttokenEndCharacter += firstLineLength;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconst tokenLength = tokenEndCharacter - tokenStartCharacter;\n\t\t\t\t\t\ttokenStartCharacter = lastLineLength + (tokenStartCharacter - character);\n\t\t\t\t\t\ttokenEndCharacter = tokenStartCharacter + tokenLength;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\ttokenDeltaLine += eolCount;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttokens[offset] = tokenDeltaLine;\n\t\t\ttokens[offset + 1] = tokenStartCharacter;\n\t\t\ttokens[offset + 2] = tokenEndCharacter;\n\t\t}\n\t}\n}\n\nexport class SparseLineTokens {\n\n\tprivate readonly _tokens: Uint32Array;\n\n\tconstructor(tokens: Uint32Array) {\n\t\tthis._tokens = tokens;\n\t}\n\n\tpublic getCount(): number {\n\t\treturn this._tokens.length / 4;\n\t}\n\n\tpublic getStartCharacter(tokenIndex: number): number {\n\t\treturn this._tokens[4 * tokenIndex + 1];\n\t}\n\n\tpublic getEndCharacter(tokenIndex: number): number {\n\t\treturn this._tokens[4 * tokenIndex + 2];\n\t}\n\n\tpublic getMetadata(tokenIndex: number): number {\n\t\treturn this._tokens[4 * tokenIndex + 3];\n\t}\n}\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\nimport * as arrays from 'vs/base/common/arrays';\nimport { IRange, Range } from 'vs/editor/common/core/range';\nimport { LineTokens } from 'vs/editor/common/tokens/lineTokens';\nimport { SparseMultilineTokens } from 'vs/editor/common/tokens/sparseMultilineTokens';\nimport { ILanguageIdCodec } from 'vs/editor/common/languages';\nimport { MetadataConsts } from 'vs/editor/common/encodedTokenAttributes';\n\n/**\n * Represents sparse tokens in a text model.\n */\nexport class SparseTokensStore {\n\n\tprivate _pieces: SparseMultilineTokens[];\n\tprivate _isComplete: boolean;\n\tprivate readonly _languageIdCodec: ILanguageIdCodec;\n\n\tconstructor(languageIdCodec: ILanguageIdCodec) {\n\t\tthis._pieces = [];\n\t\tthis._isComplete = false;\n\t\tthis._languageIdCodec = languageIdCodec;\n\t}\n\n\tpublic flush(): void {\n\t\tthis._pieces = [];\n\t\tthis._isComplete = false;\n\t}\n\n\tpublic isEmpty(): boolean {\n\t\treturn (this._pieces.length === 0);\n\t}\n\n\tpublic set(pieces: SparseMultilineTokens[] | null, isComplete: boolean): void {\n\t\tthis._pieces = pieces || [];\n\t\tthis._isComplete = isComplete;\n\t}\n\n\tpublic setPartial(_range: Range, pieces: SparseMultilineTokens[]): Range {\n\t\t// console.log(`setPartial ${_range} ${pieces.map(p => p.toString()).join(', ')}`);\n\n\t\tlet range = _range;\n\t\tif (pieces.length > 0) {\n\t\t\tconst _firstRange = pieces[0].getRange();\n\t\t\tconst _lastRange = pieces[pieces.length - 1].getRange();\n\t\t\tif (!_firstRange || !_lastRange) {\n\t\t\t\treturn _range;\n\t\t\t}\n\t\t\trange = _range.plusRange(_firstRange).plusRange(_lastRange);\n\t\t}\n\n\t\tlet insertPosition: { index: number } | null = null;\n\t\tfor (let i = 0, len = this._pieces.length; i < len; i++) {\n\t\t\tconst piece = this._pieces[i];\n\t\t\tif (piece.endLineNumber < range.startLineNumber) {\n\t\t\t\t// this piece is before the range\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (piece.startLineNumber > range.endLineNumber) {\n\t\t\t\t// this piece is after the range, so mark the spot before this piece\n\t\t\t\t// as a good insertion position and stop looping\n\t\t\t\tinsertPosition = insertPosition || { index: i };\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// this piece might intersect with the range\n\t\t\tpiece.removeTokens(range);\n\n\t\t\tif (piece.isEmpty()) {\n\t\t\t\t// remove the piece if it became empty\n\t\t\t\tthis._pieces.splice(i, 1);\n\t\t\t\ti--;\n\t\t\t\tlen--;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (piece.endLineNumber < range.startLineNumber) {\n\t\t\t\t// after removal, this piece is before the range\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (piece.startLineNumber > range.endLineNumber) {\n\t\t\t\t// after removal, this piece is after the range\n\t\t\t\tinsertPosition = insertPosition || { index: i };\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// after removal, this piece contains the range\n\t\t\tconst [a, b] = piece.split(range);\n\t\t\tif (a.isEmpty()) {\n\t\t\t\t// this piece is actually after the range\n\t\t\t\tinsertPosition = insertPosition || { index: i };\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (b.isEmpty()) {\n\t\t\t\t// this piece is actually before the range\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tthis._pieces.splice(i, 1, a, b);\n\t\t\ti++;\n\t\t\tlen++;\n\n\t\t\tinsertPosition = insertPosition || { index: i };\n\t\t}\n\n\t\tinsertPosition = insertPosition || { index: this._pieces.length };\n\n\t\tif (pieces.length > 0) {\n\t\t\tthis._pieces = arrays.arrayInsert(this._pieces, insertPosition.index, pieces);\n\t\t}\n\n\t\t// console.log(`I HAVE ${this._pieces.length} pieces`);\n\t\t// console.log(`${this._pieces.map(p => p.toString()).join('\\n')}`);\n\n\t\treturn range;\n\t}\n\n\tpublic isComplete(): boolean {\n\t\treturn this._isComplete;\n\t}\n\n\tpublic addSparseTokens(lineNumber: number, aTokens: LineTokens): LineTokens {\n\t\tif (aTokens.getLineContent().length === 0) {\n\t\t\t// Don't do anything for empty lines\n\t\t\treturn aTokens;\n\t\t}\n\n\t\tconst pieces = this._pieces;\n\n\t\tif (pieces.length === 0) {\n\t\t\treturn aTokens;\n\t\t}\n\n\t\tconst pieceIndex = SparseTokensStore._findFirstPieceWithLine(pieces, lineNumber);\n\t\tconst bTokens = pieces[pieceIndex].getLineTokens(lineNumber);\n\n\t\tif (!bTokens) {\n\t\t\treturn aTokens;\n\t\t}\n\n\t\tconst aLen = aTokens.getCount();\n\t\tconst bLen = bTokens.getCount();\n\n\t\tlet aIndex = 0;\n\t\tconst result: number[] = [];\n\t\tlet resultLen = 0;\n\t\tlet lastEndOffset = 0;\n\n\t\tconst emitToken = (endOffset: number, metadata: number) => {\n\t\t\tif (endOffset === lastEndOffset) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tlastEndOffset = endOffset;\n\t\t\tresult[resultLen++] = endOffset;\n\t\t\tresult[resultLen++] = metadata;\n\t\t};\n\n\t\tfor (let bIndex = 0; bIndex < bLen; bIndex++) {\n\t\t\tconst bStartCharacter = bTokens.getStartCharacter(bIndex);\n\t\t\tconst bEndCharacter = bTokens.getEndCharacter(bIndex);\n\t\t\tconst bMetadata = bTokens.getMetadata(bIndex);\n\n\t\t\tconst bMask = (\n\t\t\t\t((bMetadata & MetadataConsts.SEMANTIC_USE_ITALIC) ? MetadataConsts.ITALIC_MASK : 0)\n\t\t\t\t| ((bMetadata & MetadataConsts.SEMANTIC_USE_BOLD) ? MetadataConsts.BOLD_MASK : 0)\n\t\t\t\t| ((bMetadata & MetadataConsts.SEMANTIC_USE_UNDERLINE) ? MetadataConsts.UNDERLINE_MASK : 0)\n\t\t\t\t| ((bMetadata & MetadataConsts.SEMANTIC_USE_STRIKETHROUGH) ? MetadataConsts.STRIKETHROUGH_MASK : 0)\n\t\t\t\t| ((bMetadata & MetadataConsts.SEMANTIC_USE_FOREGROUND) ? MetadataConsts.FOREGROUND_MASK : 0)\n\t\t\t\t| ((bMetadata & MetadataConsts.SEMANTIC_USE_BACKGROUND) ? MetadataConsts.BACKGROUND_MASK : 0)\n\t\t\t) >>> 0;\n\t\t\tconst aMask = (~bMask) >>> 0;\n\n\t\t\t// push any token from `a` that is before `b`\n\t\t\twhile (aIndex < aLen && aTokens.getEndOffset(aIndex) <= bStartCharacter) {\n\t\t\t\temitToken(aTokens.getEndOffset(aIndex), aTokens.getMetadata(aIndex));\n\t\t\t\taIndex++;\n\t\t\t}\n\n\t\t\t// push the token from `a` if it intersects the token from `b`\n\t\t\tif (aIndex < aLen && aTokens.getStartOffset(aIndex) < bStartCharacter) {\n\t\t\t\temitToken(bStartCharacter, aTokens.getMetadata(aIndex));\n\t\t\t}\n\n\t\t\t// skip any tokens from `a` that are contained inside `b`\n\t\t\twhile (aIndex < aLen && aTokens.getEndOffset(aIndex) < bEndCharacter) {\n\t\t\t\temitToken(aTokens.getEndOffset(aIndex), (aTokens.getMetadata(aIndex) & aMask) | (bMetadata & bMask));\n\t\t\t\taIndex++;\n\t\t\t}\n\n\t\t\tif (aIndex < aLen) {\n\t\t\t\temitToken(bEndCharacter, (aTokens.getMetadata(aIndex) & aMask) | (bMetadata & bMask));\n\t\t\t\tif (aTokens.getEndOffset(aIndex) === bEndCharacter) {\n\t\t\t\t\t// `a` ends exactly at the same spot as `b`!\n\t\t\t\t\taIndex++;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst aMergeIndex = Math.min(Math.max(0, aIndex - 1), aLen - 1);\n\n\t\t\t\t// push the token from `b`\n\t\t\t\temitToken(bEndCharacter, (aTokens.getMetadata(aMergeIndex) & aMask) | (bMetadata & bMask));\n\t\t\t}\n\t\t}\n\n\t\t// push the remaining tokens from `a`\n\t\twhile (aIndex < aLen) {\n\t\t\temitToken(aTokens.getEndOffset(aIndex), aTokens.getMetadata(aIndex));\n\t\t\taIndex++;\n\t\t}\n\n\t\treturn new LineTokens(new Uint32Array(result), aTokens.getLineContent(), this._languageIdCodec);\n\t}\n\n\tprivate static _findFirstPieceWithLine(pieces: SparseMultilineTokens[], lineNumber: number): number {\n\t\tlet low = 0;\n\t\tlet high = pieces.length - 1;\n\n\t\twhile (low < high) {\n\t\t\tlet mid = low + Math.floor((high - low) / 2);\n\n\t\t\tif (pieces[mid].endLineNumber < lineNumber) {\n\t\t\t\tlow = mid + 1;\n\t\t\t} else if (pieces[mid].startLineNumber > lineNumber) {\n\t\t\t\thigh = mid - 1;\n\t\t\t} else {\n\t\t\t\twhile (mid > low && pieces[mid - 1].startLineNumber <= lineNumber && lineNumber <= pieces[mid - 1].endLineNumber) {\n\t\t\t\t\tmid--;\n\t\t\t\t}\n\t\t\t\treturn mid;\n\t\t\t}\n\t\t}\n\n\t\treturn low;\n\t}\n\n\tpublic acceptEdit(range: IRange, eolCount: number, firstLineLength: number, lastLineLength: number, firstCharCode: number): void {\n\t\tfor (const piece of this._pieces) {\n\t\t\tpiece.acceptEdit(range, eolCount, firstLineLength, lastLineLength, firstCharCode);\n\t\t}\n\t}\n}\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\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport * as viewEvents from 'vs/editor/common/viewEvents';\n\nexport class ViewEventHandler extends Disposable {\n\n\tprivate _shouldRender: boolean;\n\n\tconstructor() {\n\t\tsuper();\n\t\tthis._shouldRender = true;\n\t}\n\n\tpublic shouldRender(): boolean {\n\t\treturn this._shouldRender;\n\t}\n\n\tpublic forceShouldRender(): void {\n\t\tthis._shouldRender = true;\n\t}\n\n\tprotected setShouldRender(): void {\n\t\tthis._shouldRender = true;\n\t}\n\n\tpublic onDidRender(): void {\n\t\tthis._shouldRender = false;\n\t}\n\n\t// --- begin event handlers\n\n\tpublic onCompositionStart(e: viewEvents.ViewCompositionStartEvent): boolean {\n\t\treturn false;\n\t}\n\tpublic onCompositionEnd(e: viewEvents.ViewCompositionEndEvent): boolean {\n\t\treturn false;\n\t}\n\tpublic onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {\n\t\treturn false;\n\t}\n\tpublic onCursorStateChanged(e: viewEvents.ViewCursorStateChangedEvent): boolean {\n\t\treturn false;\n\t}\n\tpublic onDecorationsChanged(e: viewEvents.ViewDecorationsChangedEvent): boolean {\n\t\treturn false;\n\t}\n\tpublic onFlushed(e: viewEvents.ViewFlushedEvent): boolean {\n\t\treturn false;\n\t}\n\tpublic onFocusChanged(e: viewEvents.ViewFocusChangedEvent): boolean {\n\t\treturn false;\n\t}\n\tpublic onLanguageConfigurationChanged(e: viewEvents.ViewLanguageConfigurationEvent): boolean {\n\t\treturn false;\n\t}\n\tpublic onLineMappingChanged(e: viewEvents.ViewLineMappingChangedEvent): boolean {\n\t\treturn false;\n\t}\n\tpublic onLinesChanged(e: viewEvents.ViewLinesChangedEvent): boolean {\n\t\treturn false;\n\t}\n\tpublic onLinesDeleted(e: viewEvents.ViewLinesDeletedEvent): boolean {\n\t\treturn false;\n\t}\n\tpublic onLinesInserted(e: viewEvents.ViewLinesInsertedEvent): boolean {\n\t\treturn false;\n\t}\n\tpublic onRevealRangeRequest(e: viewEvents.ViewRevealRangeRequestEvent): boolean {\n\t\treturn false;\n\t}\n\tpublic onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean {\n\t\treturn false;\n\t}\n\tpublic onThemeChanged(e: viewEvents.ViewThemeChangedEvent): boolean {\n\t\treturn false;\n\t}\n\tpublic onTokensChanged(e: viewEvents.ViewTokensChangedEvent): boolean {\n\t\treturn false;\n\t}\n\tpublic onTokensColorsChanged(e: viewEvents.ViewTokensColorsChangedEvent): boolean {\n\t\treturn false;\n\t}\n\tpublic onZonesChanged(e: viewEvents.ViewZonesChangedEvent): boolean {\n\t\treturn false;\n\t}\n\n\t// --- end event handlers\n\n\tpublic handleEvents(events: viewEvents.ViewEvent[]): void {\n\n\t\tlet shouldRender = false;\n\n\t\tfor (let i = 0, len = events.length; i < len; i++) {\n\t\t\tconst e = events[i];\n\n\t\t\tswitch (e.type) {\n\n\t\t\t\tcase viewEvents.ViewEventType.ViewCompositionStart:\n\t\t\t\t\tif (this.onCompositionStart(e)) {\n\t\t\t\t\t\tshouldRender = true;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase viewEvents.ViewEventType.ViewCompositionEnd:\n\t\t\t\t\tif (this.onCompositionEnd(e)) {\n\t\t\t\t\t\tshouldRender = true;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase viewEvents.ViewEventType.ViewConfigurationChanged:\n\t\t\t\t\tif (this.onConfigurationChanged(e)) {\n\t\t\t\t\t\tshouldRender = true;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase viewEvents.ViewEventType.ViewCursorStateChanged:\n\t\t\t\t\tif (this.onCursorStateChanged(e)) {\n\t\t\t\t\t\tshouldRender = true;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase viewEvents.ViewEventType.ViewDecorationsChanged:\n\t\t\t\t\tif (this.onDecorationsChanged(e)) {\n\t\t\t\t\t\tshouldRender = true;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase viewEvents.ViewEventType.ViewFlushed:\n\t\t\t\t\tif (this.onFlushed(e)) {\n\t\t\t\t\t\tshouldRender = true;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase viewEvents.ViewEventType.ViewFocusChanged:\n\t\t\t\t\tif (this.onFocusChanged(e)) {\n\t\t\t\t\t\tshouldRender = true;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase viewEvents.ViewEventType.ViewLanguageConfigurationChanged:\n\t\t\t\t\tif (this.onLanguageConfigurationChanged(e)) {\n\t\t\t\t\t\tshouldRender = true;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase viewEvents.ViewEventType.ViewLineMappingChanged:\n\t\t\t\t\tif (this.onLineMappingChanged(e)) {\n\t\t\t\t\t\tshouldRender = true;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase viewEvents.ViewEventType.ViewLinesChanged:\n\t\t\t\t\tif (this.onLinesChanged(e)) {\n\t\t\t\t\t\tshouldRender = true;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase viewEvents.ViewEventType.ViewLinesDeleted:\n\t\t\t\t\tif (this.onLinesDeleted(e)) {\n\t\t\t\t\t\tshouldRender = true;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase viewEvents.ViewEventType.ViewLinesInserted:\n\t\t\t\t\tif (this.onLinesInserted(e)) {\n\t\t\t\t\t\tshouldRender = true;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase viewEvents.ViewEventType.ViewRevealRangeRequest:\n\t\t\t\t\tif (this.onRevealRangeRequest(e)) {\n\t\t\t\t\t\tshouldRender = true;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase viewEvents.ViewEventType.ViewScrollChanged:\n\t\t\t\t\tif (this.onScrollChanged(e)) {\n\t\t\t\t\t\tshouldRender = true;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase viewEvents.ViewEventType.ViewTokensChanged:\n\t\t\t\t\tif (this.onTokensChanged(e)) {\n\t\t\t\t\t\tshouldRender = true;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase viewEvents.ViewEventType.ViewThemeChanged:\n\t\t\t\t\tif (this.onThemeChanged(e)) {\n\t\t\t\t\t\tshouldRender = true;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase viewEvents.ViewEventType.ViewTokensColorsChanged:\n\t\t\t\t\tif (this.onTokensColorsChanged(e)) {\n\t\t\t\t\t\tshouldRender = true;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase viewEvents.ViewEventType.ViewZonesChanged:\n\t\t\t\t\tif (this.onZonesChanged(e)) {\n\t\t\t\t\t\tshouldRender = true;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tconsole.info('View received unknown event: ');\n\t\t\t\t\tconsole.info(e);\n\t\t\t}\n\t\t}\n\n\t\tif (shouldRender) {\n\t\t\tthis._shouldRender = true;\n\t\t}\n\t}\n}\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\nimport { RenderingContext } from 'vs/editor/browser/view/renderingContext';\nimport { ViewEventHandler } from 'vs/editor/common/viewEventHandler';\n\nexport abstract class DynamicViewOverlay extends ViewEventHandler {\n\n\tpublic abstract prepareRender(ctx: RenderingContext): void;\n\n\tpublic abstract render(startLineNumber: number, lineNumber: number): string;\n\n}\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\nimport { FastDomNode } from 'vs/base/browser/fastDomNode';\nimport { RenderingContext, RestrictedRenderingContext } from 'vs/editor/browser/view/renderingContext';\nimport { ViewContext } from 'vs/editor/common/viewModel/viewContext';\nimport { ViewEventHandler } from 'vs/editor/common/viewEventHandler';\n\nexport abstract class ViewPart extends ViewEventHandler {\n\n\t_context: ViewContext;\n\n\tconstructor(context: ViewContext) {\n\t\tsuper();\n\t\tthis._context = context;\n\t\tthis._context.addEventHandler(this);\n\t}\n\n\tpublic override dispose(): void {\n\t\tthis._context.removeEventHandler(this);\n\t\tsuper.dispose();\n\t}\n\n\tpublic abstract prepareRender(ctx: RenderingContext): void;\n\tpublic abstract render(ctx: RestrictedRenderingContext): void;\n}\n\nexport const enum PartFingerprint {\n\tNone,\n\tContentWidgets,\n\tOverflowingContentWidgets,\n\tOverflowGuard,\n\tOverlayWidgets,\n\tOverflowingOverlayWidgets,\n\tScrollableElement,\n\tTextArea,\n\tViewLines,\n\tMinimap\n}\n\nexport class PartFingerprints {\n\n\tpublic static write(target: Element | FastDomNode, partId: PartFingerprint) {\n\t\ttarget.setAttribute('data-mprt', String(partId));\n\t}\n\n\tpublic static read(target: Element): PartFingerprint {\n\t\tconst r = target.getAttribute('data-mprt');\n\t\tif (r === null) {\n\t\t\treturn PartFingerprint.None;\n\t\t}\n\t\treturn parseInt(r, 10);\n\t}\n\n\tpublic static collect(child: Element | null, stopAt: Element): Uint8Array {\n\t\tconst result: PartFingerprint[] = [];\n\t\tlet resultLen = 0;\n\n\t\twhile (child && child !== child.ownerDocument.body) {\n\t\t\tif (child === stopAt) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (child.nodeType === child.ELEMENT_NODE) {\n\t\t\t\tresult[resultLen++] = this.read(child);\n\t\t\t}\n\t\t\tchild = child.parentElement;\n\t\t}\n\n\t\tconst r = new Uint8Array(resultLen);\n\t\tfor (let i = 0; i < resultLen; i++) {\n\t\t\tr[i] = result[resultLen - i - 1];\n\t\t}\n\t\treturn r;\n\t}\n}\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\nimport { createFastDomNode, FastDomNode } from 'vs/base/browser/fastDomNode';\nimport 'vs/css!./blockDecorations';\nimport { RenderingContext, RestrictedRenderingContext } from 'vs/editor/browser/view/renderingContext';\nimport { ViewPart } from 'vs/editor/browser/view/viewPart';\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\nimport * as viewEvents from 'vs/editor/common/viewEvents';\nimport { ViewContext } from 'vs/editor/common/viewModel/viewContext';\n\nexport class BlockDecorations extends ViewPart {\n\n\tpublic domNode: FastDomNode;\n\n\tprivate readonly blocks: FastDomNode[] = [];\n\n\tprivate contentWidth: number = -1;\n\tprivate contentLeft: number = 0;\n\n\tconstructor(context: ViewContext) {\n\t\tsuper(context);\n\n\t\tthis.domNode = createFastDomNode(document.createElement('div'));\n\t\tthis.domNode.setAttribute('role', 'presentation');\n\t\tthis.domNode.setAttribute('aria-hidden', 'true');\n\t\tthis.domNode.setClassName('blockDecorations-container');\n\n\t\tthis.update();\n\t}\n\n\tprivate update(): boolean {\n\t\tlet didChange = false;\n\t\tconst options = this._context.configuration.options;\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\n\t\tconst newContentWidth = layoutInfo.contentWidth - layoutInfo.verticalScrollbarWidth;\n\n\t\tif (this.contentWidth !== newContentWidth) {\n\t\t\tthis.contentWidth = newContentWidth;\n\t\t\tdidChange = true;\n\t\t}\n\n\t\tconst newContentLeft = layoutInfo.contentLeft;\n\t\tif (this.contentLeft !== newContentLeft) {\n\t\t\tthis.contentLeft = newContentLeft;\n\t\t\tdidChange = true;\n\t\t}\n\n\t\treturn didChange;\n\t}\n\n\tpublic override dispose(): void {\n\t\tsuper.dispose();\n\t}\n\n\t// --- begin event handlers\n\n\tpublic override onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {\n\t\treturn this.update();\n\t}\n\tpublic override onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean {\n\t\treturn e.scrollTopChanged || e.scrollLeftChanged;\n\t}\n\tpublic override onDecorationsChanged(e: viewEvents.ViewDecorationsChangedEvent): boolean {\n\t\treturn true;\n\t}\n\n\tpublic override onZonesChanged(e: viewEvents.ViewZonesChangedEvent): boolean {\n\t\treturn true;\n\t}\n\n\t// --- end event handlers\n\tpublic prepareRender(ctx: RenderingContext): void {\n\t\t// Nothing to read\n\t}\n\n\tpublic render(ctx: RestrictedRenderingContext): void {\n\t\tlet count = 0;\n\t\tconst decorations = ctx.getDecorationsInViewport();\n\t\tfor (const decoration of decorations) {\n\t\t\tif (!decoration.options.blockClassName) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tlet block = this.blocks[count];\n\t\t\tif (!block) {\n\t\t\t\tblock = this.blocks[count] = createFastDomNode(document.createElement('div'));\n\t\t\t\tthis.domNode.appendChild(block);\n\t\t\t}\n\n\t\t\tlet top: number;\n\t\t\tlet bottom: number;\n\n\t\t\tif (decoration.options.blockIsAfterEnd) {\n\t\t\t\t// range must be empty\n\t\t\t\ttop = ctx.getVerticalOffsetAfterLineNumber(decoration.range.endLineNumber, false);\n\t\t\t\tbottom = ctx.getVerticalOffsetAfterLineNumber(decoration.range.endLineNumber, true);\n\t\t\t} else {\n\t\t\t\ttop = ctx.getVerticalOffsetForLineNumber(decoration.range.startLineNumber, true);\n\t\t\t\tbottom = decoration.range.isEmpty() && !decoration.options.blockDoesNotCollapse\n\t\t\t\t\t? ctx.getVerticalOffsetForLineNumber(decoration.range.startLineNumber, false)\n\t\t\t\t\t: ctx.getVerticalOffsetAfterLineNumber(decoration.range.endLineNumber, true);\n\t\t\t}\n\n\t\t\tconst [paddingTop, paddingRight, paddingBottom, paddingLeft] = decoration.options.blockPadding ?? [0, 0, 0, 0];\n\n\t\t\tblock.setClassName('blockDecorations-block ' + decoration.options.blockClassName);\n\t\t\tblock.setLeft(this.contentLeft - paddingLeft);\n\t\t\tblock.setWidth(this.contentWidth + paddingLeft + paddingRight);\n\t\t\tblock.setTop(top - ctx.scrollTop - paddingTop);\n\t\t\tblock.setHeight(bottom - top + paddingTop + paddingBottom);\n\n\t\t\tcount++;\n\t\t}\n\n\t\tfor (let i = count; i < this.blocks.length; i++) {\n\t\t\tthis.blocks[i].domNode.remove();\n\t\t}\n\t\tthis.blocks.length = count;\n\t}\n}\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\nimport 'vs/css!./decorations';\nimport { DynamicViewOverlay } from 'vs/editor/browser/view/dynamicViewOverlay';\nimport { HorizontalRange, RenderingContext } from 'vs/editor/browser/view/renderingContext';\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\nimport { Range } from 'vs/editor/common/core/range';\nimport * as viewEvents from 'vs/editor/common/viewEvents';\nimport { ViewModelDecoration } from 'vs/editor/common/viewModel';\nimport { ViewContext } from 'vs/editor/common/viewModel/viewContext';\n\nexport class DecorationsOverlay extends DynamicViewOverlay {\n\n\tprivate readonly _context: ViewContext;\n\tprivate _typicalHalfwidthCharacterWidth: number;\n\tprivate _renderResult: string[] | null;\n\n\tconstructor(context: ViewContext) {\n\t\tsuper();\n\t\tthis._context = context;\n\t\tconst options = this._context.configuration.options;\n\t\tthis._typicalHalfwidthCharacterWidth = options.get(EditorOption.fontInfo).typicalHalfwidthCharacterWidth;\n\t\tthis._renderResult = null;\n\n\t\tthis._context.addEventHandler(this);\n\t}\n\n\tpublic override dispose(): void {\n\t\tthis._context.removeEventHandler(this);\n\t\tthis._renderResult = null;\n\t\tsuper.dispose();\n\t}\n\n\t// --- begin event handlers\n\n\tpublic override onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {\n\t\tconst options = this._context.configuration.options;\n\t\tthis._typicalHalfwidthCharacterWidth = options.get(EditorOption.fontInfo).typicalHalfwidthCharacterWidth;\n\t\treturn true;\n\t}\n\tpublic override onDecorationsChanged(e: viewEvents.ViewDecorationsChangedEvent): boolean {\n\t\treturn true;\n\t}\n\tpublic override onFlushed(e: viewEvents.ViewFlushedEvent): boolean {\n\t\treturn true;\n\t}\n\tpublic override onLinesChanged(e: viewEvents.ViewLinesChangedEvent): boolean {\n\t\treturn true;\n\t}\n\tpublic override onLinesDeleted(e: viewEvents.ViewLinesDeletedEvent): boolean {\n\t\treturn true;\n\t}\n\tpublic override onLinesInserted(e: viewEvents.ViewLinesInsertedEvent): boolean {\n\t\treturn true;\n\t}\n\tpublic override onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean {\n\t\treturn e.scrollTopChanged || e.scrollWidthChanged;\n\t}\n\tpublic override onZonesChanged(e: viewEvents.ViewZonesChangedEvent): boolean {\n\t\treturn true;\n\t}\n\t// --- end event handlers\n\n\tpublic prepareRender(ctx: RenderingContext): void {\n\t\tconst _decorations = ctx.getDecorationsInViewport();\n\n\t\t// Keep only decorations with `className`\n\t\tlet decorations: ViewModelDecoration[] = [];\n\t\tlet decorationsLen = 0;\n\t\tfor (let i = 0, len = _decorations.length; i < len; i++) {\n\t\t\tconst d = _decorations[i];\n\t\t\tif (d.options.className) {\n\t\t\t\tdecorations[decorationsLen++] = d;\n\t\t\t}\n\t\t}\n\n\t\t// Sort decorations for consistent render output\n\t\tdecorations = decorations.sort((a, b) => {\n\t\t\tif (a.options.zIndex! < b.options.zIndex!) {\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t\tif (a.options.zIndex! > b.options.zIndex!) {\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\tconst aClassName = a.options.className!;\n\t\t\tconst bClassName = b.options.className!;\n\n\t\t\tif (aClassName < bClassName) {\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t\tif (aClassName > bClassName) {\n\t\t\t\treturn 1;\n\t\t\t}\n\n\t\t\treturn Range.compareRangesUsingStarts(a.range, b.range);\n\t\t});\n\n\t\tconst visibleStartLineNumber = ctx.visibleRange.startLineNumber;\n\t\tconst visibleEndLineNumber = ctx.visibleRange.endLineNumber;\n\t\tconst output: string[] = [];\n\t\tfor (let lineNumber = visibleStartLineNumber; lineNumber <= visibleEndLineNumber; lineNumber++) {\n\t\t\tconst lineIndex = lineNumber - visibleStartLineNumber;\n\t\t\toutput[lineIndex] = '';\n\t\t}\n\n\t\t// Render first whole line decorations and then regular decorations\n\t\tthis._renderWholeLineDecorations(ctx, decorations, output);\n\t\tthis._renderNormalDecorations(ctx, decorations, output);\n\t\tthis._renderResult = output;\n\t}\n\n\tprivate _renderWholeLineDecorations(ctx: RenderingContext, decorations: ViewModelDecoration[], output: string[]): void {\n\t\tconst visibleStartLineNumber = ctx.visibleRange.startLineNumber;\n\t\tconst visibleEndLineNumber = ctx.visibleRange.endLineNumber;\n\n\t\tfor (let i = 0, lenI = decorations.length; i < lenI; i++) {\n\t\t\tconst d = decorations[i];\n\n\t\t\tif (!d.options.isWholeLine) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst decorationOutput = (\n\t\t\t\t'
    '\n\t\t\t);\n\n\t\t\tconst startLineNumber = Math.max(d.range.startLineNumber, visibleStartLineNumber);\n\t\t\tconst endLineNumber = Math.min(d.range.endLineNumber, visibleEndLineNumber);\n\t\t\tfor (let j = startLineNumber; j <= endLineNumber; j++) {\n\t\t\t\tconst lineIndex = j - visibleStartLineNumber;\n\t\t\t\toutput[lineIndex] += decorationOutput;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate _renderNormalDecorations(ctx: RenderingContext, decorations: ViewModelDecoration[], output: string[]): void {\n\t\tconst visibleStartLineNumber = ctx.visibleRange.startLineNumber;\n\n\t\tlet prevClassName: string | null = null;\n\t\tlet prevShowIfCollapsed: boolean = false;\n\t\tlet prevRange: Range | null = null;\n\t\tlet prevShouldFillLineOnLineBreak: boolean = false;\n\n\t\tfor (let i = 0, lenI = decorations.length; i < lenI; i++) {\n\t\t\tconst d = decorations[i];\n\n\t\t\tif (d.options.isWholeLine) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst className = d.options.className!;\n\t\t\tconst showIfCollapsed = Boolean(d.options.showIfCollapsed);\n\n\t\t\tlet range = d.range;\n\t\t\tif (showIfCollapsed && range.endColumn === 1 && range.endLineNumber !== range.startLineNumber) {\n\t\t\t\trange = new Range(range.startLineNumber, range.startColumn, range.endLineNumber - 1, this._context.viewModel.getLineMaxColumn(range.endLineNumber - 1));\n\t\t\t}\n\n\t\t\tif (prevClassName === className && prevShowIfCollapsed === showIfCollapsed && Range.areIntersectingOrTouching(prevRange!, range)) {\n\t\t\t\t// merge into previous decoration\n\t\t\t\tprevRange = Range.plusRange(prevRange!, range);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// flush previous decoration\n\t\t\tif (prevClassName !== null) {\n\t\t\t\tthis._renderNormalDecoration(ctx, prevRange!, prevClassName, prevShouldFillLineOnLineBreak, prevShowIfCollapsed, visibleStartLineNumber, output);\n\t\t\t}\n\n\t\t\tprevClassName = className;\n\t\t\tprevShowIfCollapsed = showIfCollapsed;\n\t\t\tprevRange = range;\n\t\t\tprevShouldFillLineOnLineBreak = d.options.shouldFillLineOnLineBreak ?? false;\n\t\t}\n\n\t\tif (prevClassName !== null) {\n\t\t\tthis._renderNormalDecoration(ctx, prevRange!, prevClassName, prevShouldFillLineOnLineBreak, prevShowIfCollapsed, visibleStartLineNumber, output);\n\t\t}\n\t}\n\n\tprivate _renderNormalDecoration(ctx: RenderingContext, range: Range, className: string, shouldFillLineOnLineBreak: boolean, showIfCollapsed: boolean, visibleStartLineNumber: number, output: string[]): void {\n\t\tconst linesVisibleRanges = ctx.linesVisibleRangesForRange(range, /*TODO@Alex*/className === 'findMatch');\n\t\tif (!linesVisibleRanges) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor (let j = 0, lenJ = linesVisibleRanges.length; j < lenJ; j++) {\n\t\t\tconst lineVisibleRanges = linesVisibleRanges[j];\n\t\t\tif (lineVisibleRanges.outsideRenderedLine) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst lineIndex = lineVisibleRanges.lineNumber - visibleStartLineNumber;\n\n\t\t\tif (showIfCollapsed && lineVisibleRanges.ranges.length === 1) {\n\t\t\t\tconst singleVisibleRange = lineVisibleRanges.ranges[0];\n\t\t\t\tif (singleVisibleRange.width < this._typicalHalfwidthCharacterWidth) {\n\t\t\t\t\t// collapsed/very small range case => make the decoration visible by expanding its width\n\t\t\t\t\t// expand its size on both sides (both to the left and to the right, keeping it centered)\n\t\t\t\t\tconst center = Math.round(singleVisibleRange.left + singleVisibleRange.width / 2);\n\t\t\t\t\tconst left = Math.max(0, Math.round(center - this._typicalHalfwidthCharacterWidth / 2));\n\t\t\t\t\tlineVisibleRanges.ranges[0] = new HorizontalRange(left, this._typicalHalfwidthCharacterWidth);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (let k = 0, lenK = lineVisibleRanges.ranges.length; k < lenK; k++) {\n\t\t\t\tconst expandToLeft = shouldFillLineOnLineBreak && lineVisibleRanges.continuesOnNextLine && lenK === 1;\n\t\t\t\tconst visibleRange = lineVisibleRanges.ranges[k];\n\t\t\t\tconst decorationOutput = (\n\t\t\t\t\t'
    '\n\t\t\t\t);\n\t\t\t\toutput[lineIndex] += decorationOutput;\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic render(startLineNumber: number, lineNumber: number): string {\n\t\tif (!this._renderResult) {\n\t\t\treturn '';\n\t\t}\n\t\tconst lineIndex = lineNumber - startLineNumber;\n\t\tif (lineIndex < 0 || lineIndex >= this._renderResult.length) {\n\t\t\treturn '';\n\t\t}\n\t\treturn this._renderResult[lineIndex];\n\t}\n}\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\nimport { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';\nimport { ArrayQueue } from 'vs/base/common/arrays';\nimport 'vs/css!./glyphMargin';\nimport { IGlyphMarginWidget, IGlyphMarginWidgetPosition } from 'vs/editor/browser/editorBrowser';\nimport { DynamicViewOverlay } from 'vs/editor/browser/view/dynamicViewOverlay';\nimport { RenderingContext, RestrictedRenderingContext } from 'vs/editor/browser/view/renderingContext';\nimport { ViewPart } from 'vs/editor/browser/view/viewPart';\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\nimport { Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\nimport { GlyphMarginLane } from 'vs/editor/common/model';\nimport * as viewEvents from 'vs/editor/common/viewEvents';\nimport { ViewContext } from 'vs/editor/common/viewModel/viewContext';\n\n/**\n * Represents a decoration that should be shown along the lines from `startLineNumber` to `endLineNumber`.\n * This can end up producing multiple `LineDecorationToRender`.\n */\nexport class DecorationToRender {\n\tpublic readonly _decorationToRenderBrand: void = undefined;\n\n\tpublic readonly zIndex: number;\n\n\tconstructor(\n\t\tpublic readonly startLineNumber: number,\n\t\tpublic readonly endLineNumber: number,\n\t\tpublic readonly className: string,\n\t\tpublic readonly tooltip: string | null,\n\t\tzIndex: number | undefined,\n\t) {\n\t\tthis.zIndex = zIndex ?? 0;\n\t}\n}\n\n/**\n * A decoration that should be shown along a line.\n */\nexport class LineDecorationToRender {\n\tconstructor(\n\t\tpublic readonly className: string,\n\t\tpublic readonly zIndex: number,\n\t\tpublic readonly tooltip: string | null,\n\t) { }\n}\n\n/**\n * Decorations to render on a visible line.\n */\nexport class VisibleLineDecorationsToRender {\n\n\tprivate readonly decorations: LineDecorationToRender[] = [];\n\n\tpublic add(decoration: LineDecorationToRender) {\n\t\tthis.decorations.push(decoration);\n\t}\n\n\tpublic getDecorations(): LineDecorationToRender[] {\n\t\treturn this.decorations;\n\t}\n}\n\nexport abstract class DedupOverlay extends DynamicViewOverlay {\n\n\t/**\n\t * Returns an array with an element for each visible line number.\n\t */\n\tprotected _render(visibleStartLineNumber: number, visibleEndLineNumber: number, decorations: DecorationToRender[]): VisibleLineDecorationsToRender[] {\n\n\t\tconst output: VisibleLineDecorationsToRender[] = [];\n\t\tfor (let lineNumber = visibleStartLineNumber; lineNumber <= visibleEndLineNumber; lineNumber++) {\n\t\t\tconst lineIndex = lineNumber - visibleStartLineNumber;\n\t\t\toutput[lineIndex] = new VisibleLineDecorationsToRender();\n\t\t}\n\n\t\tif (decorations.length === 0) {\n\t\t\treturn output;\n\t\t}\n\n\t\t// Sort decorations by className, then by startLineNumber and then by endLineNumber\n\t\tdecorations.sort((a, b) => {\n\t\t\tif (a.className === b.className) {\n\t\t\t\tif (a.startLineNumber === b.startLineNumber) {\n\t\t\t\t\treturn a.endLineNumber - b.endLineNumber;\n\t\t\t\t}\n\t\t\t\treturn a.startLineNumber - b.startLineNumber;\n\t\t\t}\n\t\t\treturn (a.className < b.className ? -1 : 1);\n\t\t});\n\n\t\tlet prevClassName: string | null = null;\n\t\tlet prevEndLineIndex = 0;\n\t\tfor (let i = 0, len = decorations.length; i < len; i++) {\n\t\t\tconst d = decorations[i];\n\t\t\tconst className = d.className;\n\t\t\tconst zIndex = d.zIndex;\n\t\t\tlet startLineIndex = Math.max(d.startLineNumber, visibleStartLineNumber) - visibleStartLineNumber;\n\t\t\tconst endLineIndex = Math.min(d.endLineNumber, visibleEndLineNumber) - visibleStartLineNumber;\n\n\t\t\tif (prevClassName === className) {\n\t\t\t\t// Here we avoid rendering the same className multiple times on the same line\n\t\t\t\tstartLineIndex = Math.max(prevEndLineIndex + 1, startLineIndex);\n\t\t\t\tprevEndLineIndex = Math.max(prevEndLineIndex, endLineIndex);\n\t\t\t} else {\n\t\t\t\tprevClassName = className;\n\t\t\t\tprevEndLineIndex = endLineIndex;\n\t\t\t}\n\n\t\t\tfor (let i = startLineIndex; i <= prevEndLineIndex; i++) {\n\t\t\t\toutput[i].add(new LineDecorationToRender(className, zIndex, d.tooltip));\n\t\t\t}\n\t\t}\n\n\t\treturn output;\n\t}\n}\n\nexport class GlyphMarginWidgets extends ViewPart {\n\n\tpublic domNode: FastDomNode;\n\n\tprivate _lineHeight: number;\n\tprivate _glyphMargin: boolean;\n\tprivate _glyphMarginLeft: number;\n\tprivate _glyphMarginWidth: number;\n\tprivate _glyphMarginDecorationLaneCount: number;\n\n\tprivate _managedDomNodes: FastDomNode[];\n\tprivate _decorationGlyphsToRender: DecorationBasedGlyph[];\n\n\tprivate _widgets: { [key: string]: IWidgetData } = {};\n\n\tconstructor(context: ViewContext) {\n\t\tsuper(context);\n\t\tthis._context = context;\n\n\t\tconst options = this._context.configuration.options;\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\n\n\t\tthis.domNode = createFastDomNode(document.createElement('div'));\n\t\tthis.domNode.setClassName('glyph-margin-widgets');\n\t\tthis.domNode.setPosition('absolute');\n\t\tthis.domNode.setTop(0);\n\n\t\tthis._lineHeight = options.get(EditorOption.lineHeight);\n\t\tthis._glyphMargin = options.get(EditorOption.glyphMargin);\n\t\tthis._glyphMarginLeft = layoutInfo.glyphMarginLeft;\n\t\tthis._glyphMarginWidth = layoutInfo.glyphMarginWidth;\n\t\tthis._glyphMarginDecorationLaneCount = layoutInfo.glyphMarginDecorationLaneCount;\n\t\tthis._managedDomNodes = [];\n\t\tthis._decorationGlyphsToRender = [];\n\t}\n\n\tpublic override dispose(): void {\n\t\tthis._managedDomNodes = [];\n\t\tthis._decorationGlyphsToRender = [];\n\t\tthis._widgets = {};\n\t\tsuper.dispose();\n\t}\n\n\tpublic getWidgets(): IWidgetData[] {\n\t\treturn Object.values(this._widgets);\n\t}\n\n\t// --- begin event handlers\n\tpublic override onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {\n\t\tconst options = this._context.configuration.options;\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\n\n\t\tthis._lineHeight = options.get(EditorOption.lineHeight);\n\t\tthis._glyphMargin = options.get(EditorOption.glyphMargin);\n\t\tthis._glyphMarginLeft = layoutInfo.glyphMarginLeft;\n\t\tthis._glyphMarginWidth = layoutInfo.glyphMarginWidth;\n\t\tthis._glyphMarginDecorationLaneCount = layoutInfo.glyphMarginDecorationLaneCount;\n\t\treturn true;\n\t}\n\tpublic override onDecorationsChanged(e: viewEvents.ViewDecorationsChangedEvent): boolean {\n\t\treturn true;\n\t}\n\tpublic override onFlushed(e: viewEvents.ViewFlushedEvent): boolean {\n\t\treturn true;\n\t}\n\tpublic override onLinesChanged(e: viewEvents.ViewLinesChangedEvent): boolean {\n\t\treturn true;\n\t}\n\tpublic override onLinesDeleted(e: viewEvents.ViewLinesDeletedEvent): boolean {\n\t\treturn true;\n\t}\n\tpublic override onLinesInserted(e: viewEvents.ViewLinesInsertedEvent): boolean {\n\t\treturn true;\n\t}\n\tpublic override onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean {\n\t\treturn e.scrollTopChanged;\n\t}\n\tpublic override onZonesChanged(e: viewEvents.ViewZonesChangedEvent): boolean {\n\t\treturn true;\n\t}\n\n\t// --- end event handlers\n\n\t// --- begin widget management\n\n\tpublic addWidget(widget: IGlyphMarginWidget): void {\n\t\tconst domNode = createFastDomNode(widget.getDomNode());\n\n\t\tthis._widgets[widget.getId()] = {\n\t\t\twidget: widget,\n\t\t\tpreference: widget.getPosition(),\n\t\t\tdomNode: domNode,\n\t\t\trenderInfo: null\n\t\t};\n\n\t\tdomNode.setPosition('absolute');\n\t\tdomNode.setDisplay('none');\n\t\tdomNode.setAttribute('widgetId', widget.getId());\n\t\tthis.domNode.appendChild(domNode);\n\n\t\tthis.setShouldRender();\n\t}\n\n\tpublic setWidgetPosition(widget: IGlyphMarginWidget, preference: IGlyphMarginWidgetPosition): boolean {\n\t\tconst myWidget = this._widgets[widget.getId()];\n\t\tif (myWidget.preference.lane === preference.lane\n\t\t\t&& myWidget.preference.zIndex === preference.zIndex\n\t\t\t&& Range.equalsRange(myWidget.preference.range, preference.range)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tmyWidget.preference = preference;\n\t\tthis.setShouldRender();\n\n\t\treturn true;\n\t}\n\n\tpublic removeWidget(widget: IGlyphMarginWidget): void {\n\t\tconst widgetId = widget.getId();\n\t\tif (this._widgets[widgetId]) {\n\t\t\tconst widgetData = this._widgets[widgetId];\n\t\t\tconst domNode = widgetData.domNode.domNode;\n\t\t\tdelete this._widgets[widgetId];\n\n\t\t\tdomNode.parentNode?.removeChild(domNode);\n\t\t\tthis.setShouldRender();\n\t\t}\n\t}\n\n\t// --- end widget management\n\n\tprivate _collectDecorationBasedGlyphRenderRequest(ctx: RenderingContext, requests: GlyphRenderRequest[]): void {\n\t\tconst visibleStartLineNumber = ctx.visibleRange.startLineNumber;\n\t\tconst visibleEndLineNumber = ctx.visibleRange.endLineNumber;\n\t\tconst decorations = ctx.getDecorationsInViewport();\n\n\t\tfor (const d of decorations) {\n\t\t\tconst glyphMarginClassName = d.options.glyphMarginClassName;\n\t\t\tif (!glyphMarginClassName) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst startLineNumber = Math.max(d.range.startLineNumber, visibleStartLineNumber);\n\t\t\tconst endLineNumber = Math.min(d.range.endLineNumber, visibleEndLineNumber);\n\t\t\tconst lane = d.options.glyphMargin?.position ?? GlyphMarginLane.Center;\n\t\t\tconst zIndex = d.options.zIndex ?? 0;\n\n\t\t\tfor (let lineNumber = startLineNumber; lineNumber <= endLineNumber; lineNumber++) {\n\t\t\t\tconst modelPosition = this._context.viewModel.coordinatesConverter.convertViewPositionToModelPosition(new Position(lineNumber, 0));\n\t\t\t\tconst laneIndex = this._context.viewModel.glyphLanes.getLanesAtLine(modelPosition.lineNumber).indexOf(lane);\n\t\t\t\trequests.push(new DecorationBasedGlyphRenderRequest(lineNumber, laneIndex, zIndex, glyphMarginClassName));\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate _collectWidgetBasedGlyphRenderRequest(ctx: RenderingContext, requests: GlyphRenderRequest[]): void {\n\t\tconst visibleStartLineNumber = ctx.visibleRange.startLineNumber;\n\t\tconst visibleEndLineNumber = ctx.visibleRange.endLineNumber;\n\n\t\tfor (const widget of Object.values(this._widgets)) {\n\t\t\tconst range = widget.preference.range;\n\t\t\tconst { startLineNumber, endLineNumber } = this._context.viewModel.coordinatesConverter.convertModelRangeToViewRange(Range.lift(range));\n\t\t\tif (!startLineNumber || !endLineNumber || endLineNumber < visibleStartLineNumber || startLineNumber > visibleEndLineNumber) {\n\t\t\t\t// The widget is not in the viewport\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// The widget is in the viewport, find a good line for it\n\t\t\tconst widgetLineNumber = Math.max(startLineNumber, visibleStartLineNumber);\n\t\t\tconst modelPosition = this._context.viewModel.coordinatesConverter.convertViewPositionToModelPosition(new Position(widgetLineNumber, 0));\n\t\t\tconst laneIndex = this._context.viewModel.glyphLanes.getLanesAtLine(modelPosition.lineNumber).indexOf(widget.preference.lane);\n\t\t\trequests.push(new WidgetBasedGlyphRenderRequest(widgetLineNumber, laneIndex, widget.preference.zIndex, widget));\n\t\t}\n\t}\n\n\tprivate _collectSortedGlyphRenderRequests(ctx: RenderingContext): GlyphRenderRequest[] {\n\n\t\tconst requests: GlyphRenderRequest[] = [];\n\n\t\tthis._collectDecorationBasedGlyphRenderRequest(ctx, requests);\n\t\tthis._collectWidgetBasedGlyphRenderRequest(ctx, requests);\n\n\t\t// sort requests by lineNumber ASC, lane ASC, zIndex DESC, type DESC (widgets first), className ASC\n\t\t// don't change this sort unless you understand `prepareRender` below.\n\t\trequests.sort((a, b) => {\n\t\t\tif (a.lineNumber === b.lineNumber) {\n\t\t\t\tif (a.laneIndex === b.laneIndex) {\n\t\t\t\t\tif (a.zIndex === b.zIndex) {\n\t\t\t\t\t\tif (b.type === a.type) {\n\t\t\t\t\t\t\tif (a.type === GlyphRenderRequestType.Decoration && b.type === GlyphRenderRequestType.Decoration) {\n\t\t\t\t\t\t\t\treturn (a.className < b.className ? -1 : 1);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn 0;\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn b.type - a.type;\n\t\t\t\t\t}\n\t\t\t\t\treturn b.zIndex - a.zIndex;\n\t\t\t\t}\n\t\t\t\treturn a.laneIndex - b.laneIndex;\n\t\t\t}\n\t\t\treturn a.lineNumber - b.lineNumber;\n\t\t});\n\n\t\treturn requests;\n\t}\n\n\t/**\n\t * Will store render information in each widget's renderInfo and in `_decorationGlyphsToRender`.\n\t */\n\tpublic prepareRender(ctx: RenderingContext): void {\n\t\tif (!this._glyphMargin) {\n\t\t\tthis._decorationGlyphsToRender = [];\n\t\t\treturn;\n\t\t}\n\n\t\tfor (const widget of Object.values(this._widgets)) {\n\t\t\twidget.renderInfo = null;\n\t\t}\n\n\t\tconst requests = new ArrayQueue(this._collectSortedGlyphRenderRequests(ctx));\n\t\tconst decorationGlyphsToRender: DecorationBasedGlyph[] = [];\n\t\twhile (requests.length > 0) {\n\t\t\tconst first = requests.peek();\n\t\t\tif (!first) {\n\t\t\t\t// not possible\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// Requests are sorted by lineNumber and lane, so we read all requests for this particular location\n\t\t\tconst requestsAtLocation = requests.takeWhile((el) => el.lineNumber === first.lineNumber && el.laneIndex === first.laneIndex);\n\t\t\tif (!requestsAtLocation || requestsAtLocation.length === 0) {\n\t\t\t\t// not possible\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tconst winner = requestsAtLocation[0];\n\t\t\tif (winner.type === GlyphRenderRequestType.Decoration) {\n\t\t\t\t// combine all decorations with the same z-index\n\n\t\t\t\tconst classNames: string[] = [];\n\t\t\t\t// requests are sorted by zIndex, type, and className so we can dedup className by looking at the previous one\n\t\t\t\tfor (const request of requestsAtLocation) {\n\t\t\t\t\tif (request.zIndex !== winner.zIndex || request.type !== winner.type) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tif (classNames.length === 0 || classNames[classNames.length - 1] !== request.className) {\n\t\t\t\t\t\tclassNames.push(request.className);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tdecorationGlyphsToRender.push(winner.accept(classNames.join(' '))); // TODO@joyceerhl Implement overflow for remaining decorations\n\t\t\t} else {\n\t\t\t\t// widgets cannot be combined\n\t\t\t\twinner.widget.renderInfo = {\n\t\t\t\t\tlineNumber: winner.lineNumber,\n\t\t\t\t\tlaneIndex: winner.laneIndex,\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t\tthis._decorationGlyphsToRender = decorationGlyphsToRender;\n\t}\n\n\tpublic render(ctx: RestrictedRenderingContext): void {\n\t\tif (!this._glyphMargin) {\n\t\t\tfor (const widget of Object.values(this._widgets)) {\n\t\t\t\twidget.domNode.setDisplay('none');\n\t\t\t}\n\t\t\twhile (this._managedDomNodes.length > 0) {\n\t\t\t\tconst domNode = this._managedDomNodes.pop();\n\t\t\t\tdomNode?.domNode.remove();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tconst width = (Math.round(this._glyphMarginWidth / this._glyphMarginDecorationLaneCount));\n\n\t\t// Render widgets\n\t\tfor (const widget of Object.values(this._widgets)) {\n\t\t\tif (!widget.renderInfo) {\n\t\t\t\t// this widget is not visible\n\t\t\t\twidget.domNode.setDisplay('none');\n\t\t\t} else {\n\t\t\t\tconst top = ctx.viewportData.relativeVerticalOffset[widget.renderInfo.lineNumber - ctx.viewportData.startLineNumber];\n\t\t\t\tconst left = this._glyphMarginLeft + widget.renderInfo.laneIndex * this._lineHeight;\n\n\t\t\t\twidget.domNode.setDisplay('block');\n\t\t\t\twidget.domNode.setTop(top);\n\t\t\t\twidget.domNode.setLeft(left);\n\t\t\t\twidget.domNode.setWidth(width);\n\t\t\t\twidget.domNode.setHeight(this._lineHeight);\n\t\t\t}\n\t\t}\n\n\t\t// Render decorations, reusing previous dom nodes as possible\n\t\tfor (let i = 0; i < this._decorationGlyphsToRender.length; i++) {\n\t\t\tconst dec = this._decorationGlyphsToRender[i];\n\t\t\tconst top = ctx.viewportData.relativeVerticalOffset[dec.lineNumber - ctx.viewportData.startLineNumber];\n\t\t\tconst left = this._glyphMarginLeft + dec.laneIndex * this._lineHeight;\n\n\t\t\tlet domNode: FastDomNode;\n\t\t\tif (i < this._managedDomNodes.length) {\n\t\t\t\tdomNode = this._managedDomNodes[i];\n\t\t\t} else {\n\t\t\t\tdomNode = createFastDomNode(document.createElement('div'));\n\t\t\t\tthis._managedDomNodes.push(domNode);\n\t\t\t\tthis.domNode.appendChild(domNode);\n\t\t\t}\n\n\t\t\tdomNode.setClassName(`cgmr codicon ` + dec.combinedClassName);\n\t\t\tdomNode.setPosition(`absolute`);\n\t\t\tdomNode.setTop(top);\n\t\t\tdomNode.setLeft(left);\n\t\t\tdomNode.setWidth(width);\n\t\t\tdomNode.setHeight(this._lineHeight);\n\t\t}\n\n\t\t// remove extra dom nodes\n\t\twhile (this._managedDomNodes.length > this._decorationGlyphsToRender.length) {\n\t\t\tconst domNode = this._managedDomNodes.pop();\n\t\t\tdomNode?.domNode.remove();\n\t\t}\n\t}\n}\n\nexport interface IWidgetData {\n\twidget: IGlyphMarginWidget;\n\tpreference: IGlyphMarginWidgetPosition;\n\tdomNode: FastDomNode;\n\t/**\n\t * it will contain the location where to render the widget\n\t * or null if the widget is not visible\n\t */\n\trenderInfo: IRenderInfo | null;\n}\n\nexport interface IRenderInfo {\n\tlineNumber: number;\n\tlaneIndex: number;\n}\n\nconst enum GlyphRenderRequestType {\n\tDecoration = 0,\n\tWidget = 1\n}\n\n/**\n * A request to render a decoration in the glyph margin at a certain location.\n */\nclass DecorationBasedGlyphRenderRequest {\n\tpublic readonly type = GlyphRenderRequestType.Decoration;\n\n\tconstructor(\n\t\tpublic readonly lineNumber: number,\n\t\tpublic readonly laneIndex: number,\n\t\tpublic readonly zIndex: number,\n\t\tpublic readonly className: string,\n\t) { }\n\n\taccept(combinedClassName: string): DecorationBasedGlyph {\n\t\treturn new DecorationBasedGlyph(this.lineNumber, this.laneIndex, combinedClassName);\n\t}\n}\n\n/**\n * A request to render a widget in the glyph margin at a certain location.\n */\nclass WidgetBasedGlyphRenderRequest {\n\tpublic readonly type = GlyphRenderRequestType.Widget;\n\n\tconstructor(\n\t\tpublic readonly lineNumber: number,\n\t\tpublic readonly laneIndex: number,\n\t\tpublic readonly zIndex: number,\n\t\tpublic readonly widget: IWidgetData,\n\t) { }\n}\n\ntype GlyphRenderRequest = DecorationBasedGlyphRenderRequest | WidgetBasedGlyphRenderRequest;\n\nclass DecorationBasedGlyph {\n\tconstructor(\n\t\tpublic readonly lineNumber: number,\n\t\tpublic readonly laneIndex: number,\n\t\tpublic readonly combinedClassName: string\n\t) { }\n}\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\nimport 'vs/css!./linesDecorations';\nimport { DecorationToRender, DedupOverlay } from 'vs/editor/browser/viewParts/glyphMargin/glyphMargin';\nimport { RenderingContext } from 'vs/editor/browser/view/renderingContext';\nimport { ViewContext } from 'vs/editor/common/viewModel/viewContext';\nimport * as viewEvents from 'vs/editor/common/viewEvents';\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\n\n\nexport class LinesDecorationsOverlay extends DedupOverlay {\n\n\tprivate readonly _context: ViewContext;\n\n\tprivate _decorationsLeft: number;\n\tprivate _decorationsWidth: number;\n\tprivate _renderResult: string[] | null;\n\n\tconstructor(context: ViewContext) {\n\t\tsuper();\n\t\tthis._context = context;\n\t\tconst options = this._context.configuration.options;\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\n\t\tthis._decorationsLeft = layoutInfo.decorationsLeft;\n\t\tthis._decorationsWidth = layoutInfo.decorationsWidth;\n\t\tthis._renderResult = null;\n\t\tthis._context.addEventHandler(this);\n\t}\n\n\tpublic override dispose(): void {\n\t\tthis._context.removeEventHandler(this);\n\t\tthis._renderResult = null;\n\t\tsuper.dispose();\n\t}\n\n\t// --- begin event handlers\n\n\tpublic override onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {\n\t\tconst options = this._context.configuration.options;\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\n\t\tthis._decorationsLeft = layoutInfo.decorationsLeft;\n\t\tthis._decorationsWidth = layoutInfo.decorationsWidth;\n\t\treturn true;\n\t}\n\tpublic override onDecorationsChanged(e: viewEvents.ViewDecorationsChangedEvent): boolean {\n\t\treturn true;\n\t}\n\tpublic override onFlushed(e: viewEvents.ViewFlushedEvent): boolean {\n\t\treturn true;\n\t}\n\tpublic override onLinesChanged(e: viewEvents.ViewLinesChangedEvent): boolean {\n\t\treturn true;\n\t}\n\tpublic override onLinesDeleted(e: viewEvents.ViewLinesDeletedEvent): boolean {\n\t\treturn true;\n\t}\n\tpublic override onLinesInserted(e: viewEvents.ViewLinesInsertedEvent): boolean {\n\t\treturn true;\n\t}\n\tpublic override onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean {\n\t\treturn e.scrollTopChanged;\n\t}\n\tpublic override onZonesChanged(e: viewEvents.ViewZonesChangedEvent): boolean {\n\t\treturn true;\n\t}\n\n\t// --- end event handlers\n\n\tprotected _getDecorations(ctx: RenderingContext): DecorationToRender[] {\n\t\tconst decorations = ctx.getDecorationsInViewport();\n\t\tconst r: DecorationToRender[] = [];\n\t\tlet rLen = 0;\n\t\tfor (let i = 0, len = decorations.length; i < len; i++) {\n\t\t\tconst d = decorations[i];\n\t\t\tconst linesDecorationsClassName = d.options.linesDecorationsClassName;\n\t\t\tconst zIndex = d.options.zIndex;\n\t\t\tif (linesDecorationsClassName) {\n\t\t\t\tr[rLen++] = new DecorationToRender(d.range.startLineNumber, d.range.endLineNumber, linesDecorationsClassName, d.options.linesDecorationsTooltip ?? null, zIndex);\n\t\t\t}\n\t\t\tconst firstLineDecorationClassName = d.options.firstLineDecorationClassName;\n\t\t\tif (firstLineDecorationClassName) {\n\t\t\t\tr[rLen++] = new DecorationToRender(d.range.startLineNumber, d.range.startLineNumber, firstLineDecorationClassName, d.options.linesDecorationsTooltip ?? null, zIndex);\n\t\t\t}\n\t\t}\n\t\treturn r;\n\t}\n\n\tpublic prepareRender(ctx: RenderingContext): void {\n\t\tconst visibleStartLineNumber = ctx.visibleRange.startLineNumber;\n\t\tconst visibleEndLineNumber = ctx.visibleRange.endLineNumber;\n\t\tconst toRender = this._render(visibleStartLineNumber, visibleEndLineNumber, this._getDecorations(ctx));\n\n\t\tconst left = this._decorationsLeft.toString();\n\t\tconst width = this._decorationsWidth.toString();\n\t\tconst common = '\" style=\"left:' + left + 'px;width:' + width + 'px;\">
    ';\n\n\t\tconst output: string[] = [];\n\t\tfor (let lineNumber = visibleStartLineNumber; lineNumber <= visibleEndLineNumber; lineNumber++) {\n\t\t\tconst lineIndex = lineNumber - visibleStartLineNumber;\n\t\t\tconst decorations = toRender[lineIndex].getDecorations();\n\t\t\tlet lineOutput = '';\n\t\t\tfor (const decoration of decorations) {\n\t\t\t\tlet addition = '
    ;\n\tprivate _canUseLayerHinting: boolean;\n\tprivate _contentLeft: number;\n\tprivate _glyphMarginLeft: number;\n\tprivate _glyphMarginWidth: number;\n\tprivate _glyphMarginBackgroundDomNode: FastDomNode;\n\n\tconstructor(context: ViewContext) {\n\t\tsuper(context);\n\t\tconst options = this._context.configuration.options;\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\n\n\t\tthis._canUseLayerHinting = !options.get(EditorOption.disableLayerHinting);\n\t\tthis._contentLeft = layoutInfo.contentLeft;\n\t\tthis._glyphMarginLeft = layoutInfo.glyphMarginLeft;\n\t\tthis._glyphMarginWidth = layoutInfo.glyphMarginWidth;\n\n\t\tthis._domNode = createFastDomNode(document.createElement('div'));\n\t\tthis._domNode.setClassName(Margin.OUTER_CLASS_NAME);\n\t\tthis._domNode.setPosition('absolute');\n\t\tthis._domNode.setAttribute('role', 'presentation');\n\t\tthis._domNode.setAttribute('aria-hidden', 'true');\n\n\t\tthis._glyphMarginBackgroundDomNode = createFastDomNode(document.createElement('div'));\n\t\tthis._glyphMarginBackgroundDomNode.setClassName(Margin.CLASS_NAME);\n\n\t\tthis._domNode.appendChild(this._glyphMarginBackgroundDomNode);\n\t}\n\n\tpublic override dispose(): void {\n\t\tsuper.dispose();\n\t}\n\n\tpublic getDomNode(): FastDomNode {\n\t\treturn this._domNode;\n\t}\n\n\t// --- begin event handlers\n\n\tpublic override onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {\n\t\tconst options = this._context.configuration.options;\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\n\n\t\tthis._canUseLayerHinting = !options.get(EditorOption.disableLayerHinting);\n\t\tthis._contentLeft = layoutInfo.contentLeft;\n\t\tthis._glyphMarginLeft = layoutInfo.glyphMarginLeft;\n\t\tthis._glyphMarginWidth = layoutInfo.glyphMarginWidth;\n\n\t\treturn true;\n\t}\n\tpublic override onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean {\n\t\treturn super.onScrollChanged(e) || e.scrollTopChanged;\n\t}\n\n\t// --- end event handlers\n\n\tpublic prepareRender(ctx: RenderingContext): void {\n\t\t// Nothing to read\n\t}\n\n\tpublic render(ctx: RestrictedRenderingContext): void {\n\t\tthis._domNode.setLayerHinting(this._canUseLayerHinting);\n\t\tthis._domNode.setContain('strict');\n\t\tconst adjustedScrollTop = ctx.scrollTop - ctx.bigNumbersDelta;\n\t\tthis._domNode.setTop(-adjustedScrollTop);\n\n\t\tconst height = Math.min(ctx.scrollHeight, 1000000);\n\t\tthis._domNode.setHeight(height);\n\t\tthis._domNode.setWidth(this._contentLeft);\n\n\t\tthis._glyphMarginBackgroundDomNode.setLeft(this._glyphMarginLeft);\n\t\tthis._glyphMarginBackgroundDomNode.setWidth(this._glyphMarginWidth);\n\t\tthis._glyphMarginBackgroundDomNode.setHeight(height);\n\t}\n}\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\nimport 'vs/css!./marginDecorations';\nimport { DecorationToRender, DedupOverlay } from 'vs/editor/browser/viewParts/glyphMargin/glyphMargin';\nimport { RenderingContext } from 'vs/editor/browser/view/renderingContext';\nimport { ViewContext } from 'vs/editor/common/viewModel/viewContext';\nimport * as viewEvents from 'vs/editor/common/viewEvents';\n\nexport class MarginViewLineDecorationsOverlay extends DedupOverlay {\n\tprivate readonly _context: ViewContext;\n\tprivate _renderResult: string[] | null;\n\n\tconstructor(context: ViewContext) {\n\t\tsuper();\n\t\tthis._context = context;\n\t\tthis._renderResult = null;\n\t\tthis._context.addEventHandler(this);\n\t}\n\n\tpublic override dispose(): void {\n\t\tthis._context.removeEventHandler(this);\n\t\tthis._renderResult = null;\n\t\tsuper.dispose();\n\t}\n\n\t// --- begin event handlers\n\n\tpublic override onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {\n\t\treturn true;\n\t}\n\tpublic override onDecorationsChanged(e: viewEvents.ViewDecorationsChangedEvent): boolean {\n\t\treturn true;\n\t}\n\tpublic override onFlushed(e: viewEvents.ViewFlushedEvent): boolean {\n\t\treturn true;\n\t}\n\tpublic override onLinesChanged(e: viewEvents.ViewLinesChangedEvent): boolean {\n\t\treturn true;\n\t}\n\tpublic override onLinesDeleted(e: viewEvents.ViewLinesDeletedEvent): boolean {\n\t\treturn true;\n\t}\n\tpublic override onLinesInserted(e: viewEvents.ViewLinesInsertedEvent): boolean {\n\t\treturn true;\n\t}\n\tpublic override onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean {\n\t\treturn e.scrollTopChanged;\n\t}\n\tpublic override onZonesChanged(e: viewEvents.ViewZonesChangedEvent): boolean {\n\t\treturn true;\n\t}\n\n\t// --- end event handlers\n\n\tprotected _getDecorations(ctx: RenderingContext): DecorationToRender[] {\n\t\tconst decorations = ctx.getDecorationsInViewport();\n\t\tconst r: DecorationToRender[] = [];\n\t\tlet rLen = 0;\n\t\tfor (let i = 0, len = decorations.length; i < len; i++) {\n\t\t\tconst d = decorations[i];\n\t\t\tconst marginClassName = d.options.marginClassName;\n\t\t\tconst zIndex = d.options.zIndex;\n\t\t\tif (marginClassName) {\n\t\t\t\tr[rLen++] = new DecorationToRender(d.range.startLineNumber, d.range.endLineNumber, marginClassName, null, zIndex);\n\t\t\t}\n\t\t}\n\t\treturn r;\n\t}\n\n\tpublic prepareRender(ctx: RenderingContext): void {\n\t\tconst visibleStartLineNumber = ctx.visibleRange.startLineNumber;\n\t\tconst visibleEndLineNumber = ctx.visibleRange.endLineNumber;\n\t\tconst toRender = this._render(visibleStartLineNumber, visibleEndLineNumber, this._getDecorations(ctx));\n\n\t\tconst output: string[] = [];\n\t\tfor (let lineNumber = visibleStartLineNumber; lineNumber <= visibleEndLineNumber; lineNumber++) {\n\t\t\tconst lineIndex = lineNumber - visibleStartLineNumber;\n\t\t\tconst decorations = toRender[lineIndex].getDecorations();\n\t\t\tlet lineOutput = '';\n\t\t\tfor (const decoration of decorations) {\n\t\t\t\tlineOutput += '
    ';\n\t\t\t}\n\t\t\toutput[lineIndex] = lineOutput;\n\t\t}\n\n\t\tthis._renderResult = output;\n\t}\n\n\tpublic render(startLineNumber: number, lineNumber: number): string {\n\t\tif (!this._renderResult) {\n\t\t\treturn '';\n\t\t}\n\t\treturn this._renderResult[lineNumber - startLineNumber];\n\t}\n}\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\nimport 'vs/css!./rulers';\nimport { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';\nimport { ViewPart } from 'vs/editor/browser/view/viewPart';\nimport { RenderingContext, RestrictedRenderingContext } from 'vs/editor/browser/view/renderingContext';\nimport { ViewContext } from 'vs/editor/common/viewModel/viewContext';\nimport * as viewEvents from 'vs/editor/common/viewEvents';\nimport { EditorOption, IRulerOption } from 'vs/editor/common/config/editorOptions';\n\nexport class Rulers extends ViewPart {\n\n\tpublic domNode: FastDomNode;\n\tprivate readonly _renderedRulers: FastDomNode[];\n\tprivate _rulers: IRulerOption[];\n\tprivate _typicalHalfwidthCharacterWidth: number;\n\n\tconstructor(context: ViewContext) {\n\t\tsuper(context);\n\t\tthis.domNode = createFastDomNode(document.createElement('div'));\n\t\tthis.domNode.setAttribute('role', 'presentation');\n\t\tthis.domNode.setAttribute('aria-hidden', 'true');\n\t\tthis.domNode.setClassName('view-rulers');\n\t\tthis._renderedRulers = [];\n\t\tconst options = this._context.configuration.options;\n\t\tthis._rulers = options.get(EditorOption.rulers);\n\t\tthis._typicalHalfwidthCharacterWidth = options.get(EditorOption.fontInfo).typicalHalfwidthCharacterWidth;\n\t}\n\n\tpublic override dispose(): void {\n\t\tsuper.dispose();\n\t}\n\n\t// --- begin event handlers\n\n\tpublic override onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {\n\t\tconst options = this._context.configuration.options;\n\t\tthis._rulers = options.get(EditorOption.rulers);\n\t\tthis._typicalHalfwidthCharacterWidth = options.get(EditorOption.fontInfo).typicalHalfwidthCharacterWidth;\n\t\treturn true;\n\t}\n\tpublic override onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean {\n\t\treturn e.scrollHeightChanged;\n\t}\n\n\t// --- end event handlers\n\n\tpublic prepareRender(ctx: RenderingContext): void {\n\t\t// Nothing to read\n\t}\n\n\tprivate _ensureRulersCount(): void {\n\t\tconst currentCount = this._renderedRulers.length;\n\t\tconst desiredCount = this._rulers.length;\n\n\t\tif (currentCount === desiredCount) {\n\t\t\t// Nothing to do\n\t\t\treturn;\n\t\t}\n\n\t\tif (currentCount < desiredCount) {\n\t\t\tconst { tabSize } = this._context.viewModel.model.getOptions();\n\t\t\tconst rulerWidth = tabSize;\n\t\t\tlet addCount = desiredCount - currentCount;\n\t\t\twhile (addCount > 0) {\n\t\t\t\tconst node = createFastDomNode(document.createElement('div'));\n\t\t\t\tnode.setClassName('view-ruler');\n\t\t\t\tnode.setWidth(rulerWidth);\n\t\t\t\tthis.domNode.appendChild(node);\n\t\t\t\tthis._renderedRulers.push(node);\n\t\t\t\taddCount--;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tlet removeCount = currentCount - desiredCount;\n\t\twhile (removeCount > 0) {\n\t\t\tconst node = this._renderedRulers.pop()!;\n\t\t\tthis.domNode.removeChild(node);\n\t\t\tremoveCount--;\n\t\t}\n\t}\n\n\tpublic render(ctx: RestrictedRenderingContext): void {\n\n\t\tthis._ensureRulersCount();\n\n\t\tfor (let i = 0, len = this._rulers.length; i < len; i++) {\n\t\t\tconst node = this._renderedRulers[i];\n\t\t\tconst ruler = this._rulers[i];\n\n\t\t\tnode.setBoxShadow(ruler.color ? `1px 0 0 0 ${ruler.color} inset` : ``);\n\t\t\tnode.setHeight(Math.min(ctx.scrollHeight, 1000000));\n\t\t\tnode.setLeft(ruler.column * this._typicalHalfwidthCharacterWidth);\n\t\t}\n\t}\n}\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\nimport 'vs/css!./scrollDecoration';\nimport { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';\nimport { ViewPart } from 'vs/editor/browser/view/viewPart';\nimport { RenderingContext, RestrictedRenderingContext } from 'vs/editor/browser/view/renderingContext';\nimport { ViewContext } from 'vs/editor/common/viewModel/viewContext';\nimport * as viewEvents from 'vs/editor/common/viewEvents';\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\n\n\nexport class ScrollDecorationViewPart extends ViewPart {\n\n\tprivate readonly _domNode: FastDomNode;\n\tprivate _scrollTop: number;\n\tprivate _width: number;\n\tprivate _shouldShow: boolean;\n\tprivate _useShadows: boolean;\n\n\tconstructor(context: ViewContext) {\n\t\tsuper(context);\n\n\t\tthis._scrollTop = 0;\n\t\tthis._width = 0;\n\t\tthis._updateWidth();\n\t\tthis._shouldShow = false;\n\t\tconst options = this._context.configuration.options;\n\t\tconst scrollbar = options.get(EditorOption.scrollbar);\n\t\tthis._useShadows = scrollbar.useShadows;\n\t\tthis._domNode = createFastDomNode(document.createElement('div'));\n\t\tthis._domNode.setAttribute('role', 'presentation');\n\t\tthis._domNode.setAttribute('aria-hidden', 'true');\n\t}\n\n\tpublic override dispose(): void {\n\t\tsuper.dispose();\n\t}\n\n\tprivate _updateShouldShow(): boolean {\n\t\tconst newShouldShow = (this._useShadows && this._scrollTop > 0);\n\t\tif (this._shouldShow !== newShouldShow) {\n\t\t\tthis._shouldShow = newShouldShow;\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tpublic getDomNode(): FastDomNode {\n\t\treturn this._domNode;\n\t}\n\n\tprivate _updateWidth(): void {\n\t\tconst options = this._context.configuration.options;\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\n\n\t\tif (layoutInfo.minimap.renderMinimap === 0 || (layoutInfo.minimap.minimapWidth > 0 && layoutInfo.minimap.minimapLeft === 0)) {\n\t\t\tthis._width = layoutInfo.width;\n\t\t} else {\n\t\t\tthis._width = layoutInfo.width - layoutInfo.verticalScrollbarWidth;\n\t\t}\n\t}\n\n\t// --- begin event handlers\n\n\tpublic override onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {\n\t\tconst options = this._context.configuration.options;\n\t\tconst scrollbar = options.get(EditorOption.scrollbar);\n\t\tthis._useShadows = scrollbar.useShadows;\n\t\tthis._updateWidth();\n\t\tthis._updateShouldShow();\n\t\treturn true;\n\t}\n\tpublic override onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean {\n\t\tthis._scrollTop = e.scrollTop;\n\t\treturn this._updateShouldShow();\n\t}\n\n\t// --- end event handlers\n\n\tpublic prepareRender(ctx: RenderingContext): void {\n\t\t// Nothing to read\n\t}\n\n\tpublic render(ctx: RestrictedRenderingContext): void {\n\t\tthis._domNode.setWidth(this._width);\n\t\tthis._domNode.setClassName(this._shouldShow ? 'scroll-decoration' : '');\n\t}\n}\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\nimport { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';\nimport { onUnexpectedError } from 'vs/base/common/errors';\nimport { IViewZone, IViewZoneChangeAccessor } from 'vs/editor/browser/editorBrowser';\nimport { ViewPart } from 'vs/editor/browser/view/viewPart';\nimport { Position } from 'vs/editor/common/core/position';\nimport { RenderingContext, RestrictedRenderingContext } from 'vs/editor/browser/view/renderingContext';\nimport { ViewContext } from 'vs/editor/common/viewModel/viewContext';\nimport * as viewEvents from 'vs/editor/common/viewEvents';\nimport { IEditorWhitespace, IViewWhitespaceViewportData, IWhitespaceChangeAccessor } from 'vs/editor/common/viewModel';\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\n\ninterface IMyViewZone {\n\twhitespaceId: string;\n\tdelegate: IViewZone;\n\tisInHiddenArea: boolean;\n\tisVisible: boolean;\n\tdomNode: FastDomNode;\n\tmarginDomNode: FastDomNode | null;\n}\n\ninterface IComputedViewZoneProps {\n\tisInHiddenArea: boolean;\n\tafterViewLineNumber: number;\n\theightInPx: number;\n\tminWidthInPx: number;\n}\n\nconst invalidFunc = () => { throw new Error(`Invalid change accessor`); };\n\nexport class ViewZones extends ViewPart {\n\n\tprivate _zones: { [id: string]: IMyViewZone };\n\tprivate _lineHeight: number;\n\tprivate _contentWidth: number;\n\tprivate _contentLeft: number;\n\n\tpublic domNode: FastDomNode;\n\n\tpublic marginDomNode: FastDomNode;\n\n\tconstructor(context: ViewContext) {\n\t\tsuper(context);\n\t\tconst options = this._context.configuration.options;\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\n\n\t\tthis._lineHeight = options.get(EditorOption.lineHeight);\n\t\tthis._contentWidth = layoutInfo.contentWidth;\n\t\tthis._contentLeft = layoutInfo.contentLeft;\n\n\t\tthis.domNode = createFastDomNode(document.createElement('div'));\n\t\tthis.domNode.setClassName('view-zones');\n\t\tthis.domNode.setPosition('absolute');\n\t\tthis.domNode.setAttribute('role', 'presentation');\n\t\tthis.domNode.setAttribute('aria-hidden', 'true');\n\n\t\tthis.marginDomNode = createFastDomNode(document.createElement('div'));\n\t\tthis.marginDomNode.setClassName('margin-view-zones');\n\t\tthis.marginDomNode.setPosition('absolute');\n\t\tthis.marginDomNode.setAttribute('role', 'presentation');\n\t\tthis.marginDomNode.setAttribute('aria-hidden', 'true');\n\n\t\tthis._zones = {};\n\t}\n\n\tpublic override dispose(): void {\n\t\tsuper.dispose();\n\t\tthis._zones = {};\n\t}\n\n\t// ---- begin view event handlers\n\n\tprivate _recomputeWhitespacesProps(): boolean {\n\t\tconst whitespaces = this._context.viewLayout.getWhitespaces();\n\t\tconst oldWhitespaces = new Map();\n\t\tfor (const whitespace of whitespaces) {\n\t\t\toldWhitespaces.set(whitespace.id, whitespace);\n\t\t}\n\t\tlet hadAChange = false;\n\t\tthis._context.viewModel.changeWhitespace((whitespaceAccessor: IWhitespaceChangeAccessor) => {\n\t\t\tconst keys = Object.keys(this._zones);\n\t\t\tfor (let i = 0, len = keys.length; i < len; i++) {\n\t\t\t\tconst id = keys[i];\n\t\t\t\tconst zone = this._zones[id];\n\t\t\t\tconst props = this._computeWhitespaceProps(zone.delegate);\n\t\t\t\tzone.isInHiddenArea = props.isInHiddenArea;\n\t\t\t\tconst oldWhitespace = oldWhitespaces.get(id);\n\t\t\t\tif (oldWhitespace && (oldWhitespace.afterLineNumber !== props.afterViewLineNumber || oldWhitespace.height !== props.heightInPx)) {\n\t\t\t\t\twhitespaceAccessor.changeOneWhitespace(id, props.afterViewLineNumber, props.heightInPx);\n\t\t\t\t\tthis._safeCallOnComputedHeight(zone.delegate, props.heightInPx);\n\t\t\t\t\thadAChange = true;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\treturn hadAChange;\n\t}\n\n\tpublic override onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {\n\t\tconst options = this._context.configuration.options;\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\n\n\t\tthis._lineHeight = options.get(EditorOption.lineHeight);\n\t\tthis._contentWidth = layoutInfo.contentWidth;\n\t\tthis._contentLeft = layoutInfo.contentLeft;\n\n\t\tif (e.hasChanged(EditorOption.lineHeight)) {\n\t\t\tthis._recomputeWhitespacesProps();\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tpublic override onLineMappingChanged(e: viewEvents.ViewLineMappingChangedEvent): boolean {\n\t\treturn this._recomputeWhitespacesProps();\n\t}\n\n\tpublic override onLinesDeleted(e: viewEvents.ViewLinesDeletedEvent): boolean {\n\t\treturn true;\n\t}\n\n\tpublic override onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean {\n\t\treturn e.scrollTopChanged || e.scrollWidthChanged;\n\t}\n\n\tpublic override onZonesChanged(e: viewEvents.ViewZonesChangedEvent): boolean {\n\t\treturn true;\n\t}\n\n\tpublic override onLinesInserted(e: viewEvents.ViewLinesInsertedEvent): boolean {\n\t\treturn true;\n\t}\n\n\t// ---- end view event handlers\n\n\tprivate _getZoneOrdinal(zone: IViewZone): number {\n\t\treturn zone.ordinal ?? zone.afterColumn ?? 10000;\n\t}\n\n\tprivate _computeWhitespaceProps(zone: IViewZone): IComputedViewZoneProps {\n\t\tif (zone.afterLineNumber === 0) {\n\t\t\treturn {\n\t\t\t\tisInHiddenArea: false,\n\t\t\t\tafterViewLineNumber: 0,\n\t\t\t\theightInPx: this._heightInPixels(zone),\n\t\t\t\tminWidthInPx: this._minWidthInPixels(zone)\n\t\t\t};\n\t\t}\n\n\t\tlet zoneAfterModelPosition: Position;\n\t\tif (typeof zone.afterColumn !== 'undefined') {\n\t\t\tzoneAfterModelPosition = this._context.viewModel.model.validatePosition({\n\t\t\t\tlineNumber: zone.afterLineNumber,\n\t\t\t\tcolumn: zone.afterColumn\n\t\t\t});\n\t\t} else {\n\t\t\tconst validAfterLineNumber = this._context.viewModel.model.validatePosition({\n\t\t\t\tlineNumber: zone.afterLineNumber,\n\t\t\t\tcolumn: 1\n\t\t\t}).lineNumber;\n\n\t\t\tzoneAfterModelPosition = new Position(\n\t\t\t\tvalidAfterLineNumber,\n\t\t\t\tthis._context.viewModel.model.getLineMaxColumn(validAfterLineNumber)\n\t\t\t);\n\t\t}\n\n\t\tlet zoneBeforeModelPosition: Position;\n\t\tif (zoneAfterModelPosition.column === this._context.viewModel.model.getLineMaxColumn(zoneAfterModelPosition.lineNumber)) {\n\t\t\tzoneBeforeModelPosition = this._context.viewModel.model.validatePosition({\n\t\t\t\tlineNumber: zoneAfterModelPosition.lineNumber + 1,\n\t\t\t\tcolumn: 1\n\t\t\t});\n\t\t} else {\n\t\t\tzoneBeforeModelPosition = this._context.viewModel.model.validatePosition({\n\t\t\t\tlineNumber: zoneAfterModelPosition.lineNumber,\n\t\t\t\tcolumn: zoneAfterModelPosition.column + 1\n\t\t\t});\n\t\t}\n\n\t\tconst viewPosition = this._context.viewModel.coordinatesConverter.convertModelPositionToViewPosition(zoneAfterModelPosition, zone.afterColumnAffinity, true);\n\t\tconst isVisible = zone.showInHiddenAreas || this._context.viewModel.coordinatesConverter.modelPositionIsVisible(zoneBeforeModelPosition);\n\t\treturn {\n\t\t\tisInHiddenArea: !isVisible,\n\t\t\tafterViewLineNumber: viewPosition.lineNumber,\n\t\t\theightInPx: (isVisible ? this._heightInPixels(zone) : 0),\n\t\t\tminWidthInPx: this._minWidthInPixels(zone)\n\t\t};\n\t}\n\n\tpublic changeViewZones(callback: (changeAccessor: IViewZoneChangeAccessor) => any): boolean {\n\t\tlet zonesHaveChanged = false;\n\n\t\tthis._context.viewModel.changeWhitespace((whitespaceAccessor: IWhitespaceChangeAccessor) => {\n\n\t\t\tconst changeAccessor: IViewZoneChangeAccessor = {\n\t\t\t\taddZone: (zone: IViewZone): string => {\n\t\t\t\t\tzonesHaveChanged = true;\n\t\t\t\t\treturn this._addZone(whitespaceAccessor, zone);\n\t\t\t\t},\n\t\t\t\tremoveZone: (id: string): void => {\n\t\t\t\t\tif (!id) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tzonesHaveChanged = this._removeZone(whitespaceAccessor, id) || zonesHaveChanged;\n\t\t\t\t},\n\t\t\t\tlayoutZone: (id: string): void => {\n\t\t\t\t\tif (!id) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tzonesHaveChanged = this._layoutZone(whitespaceAccessor, id) || zonesHaveChanged;\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tsafeInvoke1Arg(callback, changeAccessor);\n\n\t\t\t// Invalidate changeAccessor\n\t\t\tchangeAccessor.addZone = invalidFunc;\n\t\t\tchangeAccessor.removeZone = invalidFunc;\n\t\t\tchangeAccessor.layoutZone = invalidFunc;\n\t\t});\n\n\t\treturn zonesHaveChanged;\n\t}\n\n\tprivate _addZone(whitespaceAccessor: IWhitespaceChangeAccessor, zone: IViewZone): string {\n\t\tconst props = this._computeWhitespaceProps(zone);\n\t\tconst whitespaceId = whitespaceAccessor.insertWhitespace(props.afterViewLineNumber, this._getZoneOrdinal(zone), props.heightInPx, props.minWidthInPx);\n\n\t\tconst myZone: IMyViewZone = {\n\t\t\twhitespaceId: whitespaceId,\n\t\t\tdelegate: zone,\n\t\t\tisInHiddenArea: props.isInHiddenArea,\n\t\t\tisVisible: false,\n\t\t\tdomNode: createFastDomNode(zone.domNode),\n\t\t\tmarginDomNode: zone.marginDomNode ? createFastDomNode(zone.marginDomNode) : null\n\t\t};\n\n\t\tthis._safeCallOnComputedHeight(myZone.delegate, props.heightInPx);\n\n\t\tmyZone.domNode.setPosition('absolute');\n\t\tmyZone.domNode.domNode.style.width = '100%';\n\t\tmyZone.domNode.setDisplay('none');\n\t\tmyZone.domNode.setAttribute('monaco-view-zone', myZone.whitespaceId);\n\t\tthis.domNode.appendChild(myZone.domNode);\n\n\t\tif (myZone.marginDomNode) {\n\t\t\tmyZone.marginDomNode.setPosition('absolute');\n\t\t\tmyZone.marginDomNode.domNode.style.width = '100%';\n\t\t\tmyZone.marginDomNode.setDisplay('none');\n\t\t\tmyZone.marginDomNode.setAttribute('monaco-view-zone', myZone.whitespaceId);\n\t\t\tthis.marginDomNode.appendChild(myZone.marginDomNode);\n\t\t}\n\n\t\tthis._zones[myZone.whitespaceId] = myZone;\n\n\n\t\tthis.setShouldRender();\n\n\t\treturn myZone.whitespaceId;\n\t}\n\n\tprivate _removeZone(whitespaceAccessor: IWhitespaceChangeAccessor, id: string): boolean {\n\t\tif (this._zones.hasOwnProperty(id)) {\n\t\t\tconst zone = this._zones[id];\n\t\t\tdelete this._zones[id];\n\t\t\twhitespaceAccessor.removeWhitespace(zone.whitespaceId);\n\n\t\t\tzone.domNode.removeAttribute('monaco-visible-view-zone');\n\t\t\tzone.domNode.removeAttribute('monaco-view-zone');\n\t\t\tzone.domNode.domNode.parentNode!.removeChild(zone.domNode.domNode);\n\n\t\t\tif (zone.marginDomNode) {\n\t\t\t\tzone.marginDomNode.removeAttribute('monaco-visible-view-zone');\n\t\t\t\tzone.marginDomNode.removeAttribute('monaco-view-zone');\n\t\t\t\tzone.marginDomNode.domNode.parentNode!.removeChild(zone.marginDomNode.domNode);\n\t\t\t}\n\n\t\t\tthis.setShouldRender();\n\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate _layoutZone(whitespaceAccessor: IWhitespaceChangeAccessor, id: string): boolean {\n\t\tif (this._zones.hasOwnProperty(id)) {\n\t\t\tconst zone = this._zones[id];\n\t\t\tconst props = this._computeWhitespaceProps(zone.delegate);\n\t\t\tzone.isInHiddenArea = props.isInHiddenArea;\n\t\t\t// const newOrdinal = this._getZoneOrdinal(zone.delegate);\n\t\t\twhitespaceAccessor.changeOneWhitespace(zone.whitespaceId, props.afterViewLineNumber, props.heightInPx);\n\t\t\t// TODO@Alex: change `newOrdinal` too\n\n\t\t\tthis._safeCallOnComputedHeight(zone.delegate, props.heightInPx);\n\t\t\tthis.setShouldRender();\n\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tpublic shouldSuppressMouseDownOnViewZone(id: string): boolean {\n\t\tif (this._zones.hasOwnProperty(id)) {\n\t\t\tconst zone = this._zones[id];\n\t\t\treturn Boolean(zone.delegate.suppressMouseDown);\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate _heightInPixels(zone: IViewZone): number {\n\t\tif (typeof zone.heightInPx === 'number') {\n\t\t\treturn zone.heightInPx;\n\t\t}\n\t\tif (typeof zone.heightInLines === 'number') {\n\t\t\treturn this._lineHeight * zone.heightInLines;\n\t\t}\n\t\treturn this._lineHeight;\n\t}\n\n\tprivate _minWidthInPixels(zone: IViewZone): number {\n\t\tif (typeof zone.minWidthInPx === 'number') {\n\t\t\treturn zone.minWidthInPx;\n\t\t}\n\t\treturn 0;\n\t}\n\n\tprivate _safeCallOnComputedHeight(zone: IViewZone, height: number): void {\n\t\tif (typeof zone.onComputedHeight === 'function') {\n\t\t\ttry {\n\t\t\t\tzone.onComputedHeight(height);\n\t\t\t} catch (e) {\n\t\t\t\tonUnexpectedError(e);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate _safeCallOnDomNodeTop(zone: IViewZone, top: number): void {\n\t\tif (typeof zone.onDomNodeTop === 'function') {\n\t\t\ttry {\n\t\t\t\tzone.onDomNodeTop(top);\n\t\t\t} catch (e) {\n\t\t\t\tonUnexpectedError(e);\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic prepareRender(ctx: RenderingContext): void {\n\t\t// Nothing to read\n\t}\n\n\tpublic render(ctx: RestrictedRenderingContext): void {\n\t\tconst visibleWhitespaces = ctx.viewportData.whitespaceViewportData;\n\t\tconst visibleZones: { [id: string]: IViewWhitespaceViewportData } = {};\n\n\t\tlet hasVisibleZone = false;\n\t\tfor (const visibleWhitespace of visibleWhitespaces) {\n\t\t\tif (this._zones[visibleWhitespace.id].isInHiddenArea) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tvisibleZones[visibleWhitespace.id] = visibleWhitespace;\n\t\t\thasVisibleZone = true;\n\t\t}\n\n\t\tconst keys = Object.keys(this._zones);\n\t\tfor (let i = 0, len = keys.length; i < len; i++) {\n\t\t\tconst id = keys[i];\n\t\t\tconst zone = this._zones[id];\n\n\t\t\tlet newTop = 0;\n\t\t\tlet newHeight = 0;\n\t\t\tlet newDisplay = 'none';\n\t\t\tif (visibleZones.hasOwnProperty(id)) {\n\t\t\t\tnewTop = visibleZones[id].verticalOffset - ctx.bigNumbersDelta;\n\t\t\t\tnewHeight = visibleZones[id].height;\n\t\t\t\tnewDisplay = 'block';\n\t\t\t\t// zone is visible\n\t\t\t\tif (!zone.isVisible) {\n\t\t\t\t\tzone.domNode.setAttribute('monaco-visible-view-zone', 'true');\n\t\t\t\t\tzone.isVisible = true;\n\t\t\t\t}\n\t\t\t\tthis._safeCallOnDomNodeTop(zone.delegate, ctx.getScrolledTopFromAbsoluteTop(visibleZones[id].verticalOffset));\n\t\t\t} else {\n\t\t\t\tif (zone.isVisible) {\n\t\t\t\t\tzone.domNode.removeAttribute('monaco-visible-view-zone');\n\t\t\t\t\tzone.isVisible = false;\n\t\t\t\t}\n\t\t\t\tthis._safeCallOnDomNodeTop(zone.delegate, ctx.getScrolledTopFromAbsoluteTop(-1000000));\n\t\t\t}\n\t\t\tzone.domNode.setTop(newTop);\n\t\t\tzone.domNode.setHeight(newHeight);\n\t\t\tzone.domNode.setDisplay(newDisplay);\n\n\t\t\tif (zone.marginDomNode) {\n\t\t\t\tzone.marginDomNode.setTop(newTop);\n\t\t\t\tzone.marginDomNode.setHeight(newHeight);\n\t\t\t\tzone.marginDomNode.setDisplay(newDisplay);\n\t\t\t}\n\t\t}\n\n\t\tif (hasVisibleZone) {\n\t\t\tthis.domNode.setWidth(Math.max(ctx.scrollWidth, this._contentWidth));\n\t\t\tthis.marginDomNode.setWidth(this._contentLeft);\n\t\t}\n\t}\n}\n\nfunction safeInvoke1Arg(func: Function, arg1: any): any {\n\ttry {\n\t\treturn func(arg1);\n\t} catch (e) {\n\t\tonUnexpectedError(e);\n\t}\n}\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\nimport { ScrollEvent } from 'vs/base/common/scrollable';\nimport { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions';\nimport { Range } from 'vs/editor/common/core/range';\nimport { Selection } from 'vs/editor/common/core/selection';\nimport { CursorChangeReason } from 'vs/editor/common/cursorEvents';\nimport { ScrollType } from 'vs/editor/common/editorCommon';\nimport { IModelDecorationsChangedEvent } from 'vs/editor/common/textModelEvents';\nimport { IColorTheme } from 'vs/platform/theme/common/themeService';\n\nexport const enum ViewEventType {\n\tViewCompositionStart,\n\tViewCompositionEnd,\n\tViewConfigurationChanged,\n\tViewCursorStateChanged,\n\tViewDecorationsChanged,\n\tViewFlushed,\n\tViewFocusChanged,\n\tViewLanguageConfigurationChanged,\n\tViewLineMappingChanged,\n\tViewLinesChanged,\n\tViewLinesDeleted,\n\tViewLinesInserted,\n\tViewRevealRangeRequest,\n\tViewScrollChanged,\n\tViewThemeChanged,\n\tViewTokensChanged,\n\tViewTokensColorsChanged,\n\tViewZonesChanged,\n}\n\nexport class ViewCompositionStartEvent {\n\tpublic readonly type = ViewEventType.ViewCompositionStart;\n\tconstructor() { }\n}\n\nexport class ViewCompositionEndEvent {\n\tpublic readonly type = ViewEventType.ViewCompositionEnd;\n\tconstructor() { }\n}\n\nexport class ViewConfigurationChangedEvent {\n\n\tpublic readonly type = ViewEventType.ViewConfigurationChanged;\n\n\tpublic readonly _source: ConfigurationChangedEvent;\n\n\tconstructor(source: ConfigurationChangedEvent) {\n\t\tthis._source = source;\n\t}\n\n\tpublic hasChanged(id: EditorOption): boolean {\n\t\treturn this._source.hasChanged(id);\n\t}\n}\n\nexport class ViewCursorStateChangedEvent {\n\n\tpublic readonly type = ViewEventType.ViewCursorStateChanged;\n\n\tconstructor(\n\t\tpublic readonly selections: Selection[],\n\t\tpublic readonly modelSelections: Selection[],\n\t\tpublic readonly reason: CursorChangeReason\n\t) { }\n}\n\nexport class ViewDecorationsChangedEvent {\n\n\tpublic readonly type = ViewEventType.ViewDecorationsChanged;\n\n\treadonly affectsMinimap: boolean;\n\treadonly affectsOverviewRuler: boolean;\n\treadonly affectsGlyphMargin: boolean;\n\treadonly affectsLineNumber: boolean;\n\n\tconstructor(source: IModelDecorationsChangedEvent | null) {\n\t\tif (source) {\n\t\t\tthis.affectsMinimap = source.affectsMinimap;\n\t\t\tthis.affectsOverviewRuler = source.affectsOverviewRuler;\n\t\t\tthis.affectsGlyphMargin = source.affectsGlyphMargin;\n\t\t\tthis.affectsLineNumber = source.affectsLineNumber;\n\t\t} else {\n\t\t\tthis.affectsMinimap = true;\n\t\t\tthis.affectsOverviewRuler = true;\n\t\t\tthis.affectsGlyphMargin = true;\n\t\t\tthis.affectsLineNumber = true;\n\t\t}\n\t}\n}\n\nexport class ViewFlushedEvent {\n\n\tpublic readonly type = ViewEventType.ViewFlushed;\n\n\tconstructor() {\n\t\t// Nothing to do\n\t}\n}\n\nexport class ViewFocusChangedEvent {\n\n\tpublic readonly type = ViewEventType.ViewFocusChanged;\n\n\tpublic readonly isFocused: boolean;\n\n\tconstructor(isFocused: boolean) {\n\t\tthis.isFocused = isFocused;\n\t}\n}\n\nexport class ViewLanguageConfigurationEvent {\n\n\tpublic readonly type = ViewEventType.ViewLanguageConfigurationChanged;\n}\n\nexport class ViewLineMappingChangedEvent {\n\n\tpublic readonly type = ViewEventType.ViewLineMappingChanged;\n\n\tconstructor() {\n\t\t// Nothing to do\n\t}\n}\n\nexport class ViewLinesChangedEvent {\n\n\tpublic readonly type = ViewEventType.ViewLinesChanged;\n\n\tconstructor(\n\t\t/**\n\t\t * The first line that has changed.\n\t\t */\n\t\tpublic readonly fromLineNumber: number,\n\t\t/**\n\t\t * The number of lines that have changed.\n\t\t */\n\t\tpublic readonly count: number,\n\t) { }\n}\n\nexport class ViewLinesDeletedEvent {\n\n\tpublic readonly type = ViewEventType.ViewLinesDeleted;\n\n\t/**\n\t * At what line the deletion began (inclusive).\n\t */\n\tpublic readonly fromLineNumber: number;\n\t/**\n\t * At what line the deletion stopped (inclusive).\n\t */\n\tpublic readonly toLineNumber: number;\n\n\tconstructor(fromLineNumber: number, toLineNumber: number) {\n\t\tthis.fromLineNumber = fromLineNumber;\n\t\tthis.toLineNumber = toLineNumber;\n\t}\n}\n\nexport class ViewLinesInsertedEvent {\n\n\tpublic readonly type = ViewEventType.ViewLinesInserted;\n\n\t/**\n\t * Before what line did the insertion begin\n\t */\n\tpublic readonly fromLineNumber: number;\n\t/**\n\t * `toLineNumber` - `fromLineNumber` + 1 denotes the number of lines that were inserted\n\t */\n\tpublic readonly toLineNumber: number;\n\n\tconstructor(fromLineNumber: number, toLineNumber: number) {\n\t\tthis.fromLineNumber = fromLineNumber;\n\t\tthis.toLineNumber = toLineNumber;\n\t}\n}\n\nexport const enum VerticalRevealType {\n\tSimple = 0,\n\tCenter = 1,\n\tCenterIfOutsideViewport = 2,\n\tTop = 3,\n\tBottom = 4,\n\tNearTop = 5,\n\tNearTopIfOutsideViewport = 6,\n}\n\nexport class ViewRevealRangeRequestEvent {\n\n\tpublic readonly type = ViewEventType.ViewRevealRangeRequest;\n\n\n\tconstructor(\n\t\t/**\n\t\t * Source of the call that caused the event.\n\t\t */\n\t\tpublic readonly source: string | null | undefined,\n\t\t/**\n\t\t * Reduce the revealing to a minimum (e.g. avoid scrolling if the bounding box is visible and near the viewport edge).\n\t\t */\n\t\tpublic readonly minimalReveal: boolean,\n\t\t/**\n\t\t * Range to be reavealed.\n\t\t */\n\t\tpublic readonly range: Range | null,\n\t\t/**\n\t\t * Selections to be revealed.\n\t\t */\n\t\tpublic readonly selections: Selection[] | null,\n\t\t/**\n\t\t * The vertical reveal strategy.\n\t\t */\n\t\tpublic readonly verticalType: VerticalRevealType,\n\t\t/**\n\t\t * If true: there should be a horizontal & vertical revealing.\n\t\t * If false: there should be just a vertical revealing.\n\t\t */\n\t\tpublic readonly revealHorizontal: boolean,\n\t\t/**\n\t\t * The scroll type.\n\t\t */\n\t\tpublic readonly scrollType: ScrollType\n\t) { }\n}\n\nexport class ViewScrollChangedEvent {\n\n\tpublic readonly type = ViewEventType.ViewScrollChanged;\n\n\tpublic readonly scrollWidth: number;\n\tpublic readonly scrollLeft: number;\n\tpublic readonly scrollHeight: number;\n\tpublic readonly scrollTop: number;\n\n\tpublic readonly scrollWidthChanged: boolean;\n\tpublic readonly scrollLeftChanged: boolean;\n\tpublic readonly scrollHeightChanged: boolean;\n\tpublic readonly scrollTopChanged: boolean;\n\n\tconstructor(source: ScrollEvent) {\n\t\tthis.scrollWidth = source.scrollWidth;\n\t\tthis.scrollLeft = source.scrollLeft;\n\t\tthis.scrollHeight = source.scrollHeight;\n\t\tthis.scrollTop = source.scrollTop;\n\n\t\tthis.scrollWidthChanged = source.scrollWidthChanged;\n\t\tthis.scrollLeftChanged = source.scrollLeftChanged;\n\t\tthis.scrollHeightChanged = source.scrollHeightChanged;\n\t\tthis.scrollTopChanged = source.scrollTopChanged;\n\t}\n}\n\nexport class ViewThemeChangedEvent {\n\n\tpublic readonly type = ViewEventType.ViewThemeChanged;\n\n\tconstructor(\n\t\tpublic readonly theme: IColorTheme\n\t) { }\n}\n\nexport class ViewTokensChangedEvent {\n\n\tpublic readonly type = ViewEventType.ViewTokensChanged;\n\n\tpublic readonly ranges: {\n\t\t/**\n\t\t * Start line number of range\n\t\t */\n\t\treadonly fromLineNumber: number;\n\t\t/**\n\t\t * End line number of range\n\t\t */\n\t\treadonly toLineNumber: number;\n\t}[];\n\n\tconstructor(ranges: { fromLineNumber: number; toLineNumber: number }[]) {\n\t\tthis.ranges = ranges;\n\t}\n}\n\nexport class ViewTokensColorsChangedEvent {\n\n\tpublic readonly type = ViewEventType.ViewTokensColorsChanged;\n\n\tconstructor() {\n\t\t// Nothing to do\n\t}\n}\n\nexport class ViewZonesChangedEvent {\n\n\tpublic readonly type = ViewEventType.ViewZonesChanged;\n\n\tconstructor() {\n\t\t// Nothing to do\n\t}\n}\n\nexport type ViewEvent = (\n\tViewCompositionStartEvent\n\t| ViewCompositionEndEvent\n\t| ViewConfigurationChangedEvent\n\t| ViewCursorStateChangedEvent\n\t| ViewDecorationsChangedEvent\n\t| ViewFlushedEvent\n\t| ViewFocusChangedEvent\n\t| ViewLanguageConfigurationEvent\n\t| ViewLineMappingChangedEvent\n\t| ViewLinesChangedEvent\n\t| ViewLinesDeletedEvent\n\t| ViewLinesInsertedEvent\n\t| ViewRevealRangeRequestEvent\n\t| ViewScrollChangedEvent\n\t| ViewThemeChangedEvent\n\t| ViewTokensChangedEvent\n\t| ViewTokensColorsChangedEvent\n\t| ViewZonesChangedEvent\n);\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\nimport * as strings from 'vs/base/common/strings';\nimport { Constants } from 'vs/base/common/uint';\nimport { LinePartMetadata } from 'vs/editor/common/viewLayout/linePart';\nimport { InlineDecoration, InlineDecorationType } from 'vs/editor/common/viewModel';\n\nexport class LineDecoration {\n\t_lineDecorationBrand: void = undefined;\n\n\tconstructor(\n\t\tpublic readonly startColumn: number,\n\t\tpublic readonly endColumn: number,\n\t\tpublic readonly className: string,\n\t\tpublic readonly type: InlineDecorationType\n\t) {\n\t}\n\n\tprivate static _equals(a: LineDecoration, b: LineDecoration): boolean {\n\t\treturn (\n\t\t\ta.startColumn === b.startColumn\n\t\t\t&& a.endColumn === b.endColumn\n\t\t\t&& a.className === b.className\n\t\t\t&& a.type === b.type\n\t\t);\n\t}\n\n\tpublic static equalsArr(a: LineDecoration[], b: LineDecoration[]): boolean {\n\t\tconst aLen = a.length;\n\t\tconst bLen = b.length;\n\t\tif (aLen !== bLen) {\n\t\t\treturn false;\n\t\t}\n\t\tfor (let i = 0; i < aLen; i++) {\n\t\t\tif (!LineDecoration._equals(a[i], b[i])) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\tpublic static extractWrapped(arr: LineDecoration[], startOffset: number, endOffset: number): LineDecoration[] {\n\t\tif (arr.length === 0) {\n\t\t\treturn arr;\n\t\t}\n\t\tconst startColumn = startOffset + 1;\n\t\tconst endColumn = endOffset + 1;\n\t\tconst lineLength = endOffset - startOffset;\n\t\tconst r = [];\n\t\tlet rLength = 0;\n\t\tfor (const dec of arr) {\n\t\t\tif (dec.endColumn <= startColumn || dec.startColumn >= endColumn) {\n\t\t\t\tcontinue;\n\t\t\t}\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);\n\t\t}\n\t\treturn r;\n\t}\n\n\tpublic static filter(lineDecorations: InlineDecoration[], lineNumber: number, minLineColumn: number, maxLineColumn: number): LineDecoration[] {\n\t\tif (lineDecorations.length === 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst result: LineDecoration[] = [];\n\t\tlet resultLen = 0;\n\n\t\tfor (let i = 0, len = lineDecorations.length; i < len; i++) {\n\t\t\tconst d = lineDecorations[i];\n\t\t\tconst range = d.range;\n\n\t\t\tif (range.endLineNumber < lineNumber || range.startLineNumber > lineNumber) {\n\t\t\t\t// Ignore decorations that sit outside this line\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (range.isEmpty() && (d.type === InlineDecorationType.Regular || d.type === InlineDecorationType.RegularAffectingLetterSpacing)) {\n\t\t\t\t// Ignore empty range decorations\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst startColumn = (range.startLineNumber === lineNumber ? range.startColumn : minLineColumn);\n\t\t\tconst endColumn = (range.endLineNumber === lineNumber ? range.endColumn : maxLineColumn);\n\n\t\t\tresult[resultLen++] = new LineDecoration(startColumn, endColumn, d.inlineClassName, d.type);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tprivate static _typeCompare(a: InlineDecorationType, b: InlineDecorationType): number {\n\t\tconst ORDER = [2, 0, 1, 3];\n\t\treturn ORDER[a] - ORDER[b];\n\t}\n\n\tpublic static compare(a: LineDecoration, b: LineDecoration): number {\n\t\tif (a.startColumn !== b.startColumn) {\n\t\t\treturn a.startColumn - b.startColumn;\n\t\t}\n\n\t\tif (a.endColumn !== b.endColumn) {\n\t\t\treturn a.endColumn - b.endColumn;\n\t\t}\n\n\t\tconst typeCmp = LineDecoration._typeCompare(a.type, b.type);\n\t\tif (typeCmp !== 0) {\n\t\t\treturn typeCmp;\n\t\t}\n\n\t\tif (a.className !== b.className) {\n\t\t\treturn a.className < b.className ? -1 : 1;\n\t\t}\n\n\t\treturn 0;\n\t}\n}\n\nexport class DecorationSegment {\n\tstartOffset: number;\n\tendOffset: number;\n\tclassName: string;\n\tmetadata: number;\n\n\tconstructor(startOffset: number, endOffset: number, className: string, metadata: number) {\n\t\tthis.startOffset = startOffset;\n\t\tthis.endOffset = endOffset;\n\t\tthis.className = className;\n\t\tthis.metadata = metadata;\n\t}\n}\n\nclass Stack {\n\tpublic count: number;\n\tprivate readonly stopOffsets: number[];\n\tprivate readonly classNames: string[];\n\tprivate readonly metadata: number[];\n\n\tconstructor() {\n\t\tthis.stopOffsets = [];\n\t\tthis.classNames = [];\n\t\tthis.metadata = [];\n\t\tthis.count = 0;\n\t}\n\n\tprivate static _metadata(metadata: number[]): number {\n\t\tlet result = 0;\n\t\tfor (let i = 0, len = metadata.length; i < len; i++) {\n\t\t\tresult |= metadata[i];\n\t\t}\n\t\treturn result;\n\t}\n\n\tpublic consumeLowerThan(maxStopOffset: number, nextStartOffset: number, result: DecorationSegment[]): number {\n\n\t\twhile (this.count > 0 && this.stopOffsets[0] < maxStopOffset) {\n\t\t\tlet i = 0;\n\n\t\t\t// Take all equal stopping offsets\n\t\t\twhile (i + 1 < this.count && this.stopOffsets[i] === this.stopOffsets[i + 1]) {\n\t\t\t\ti++;\n\t\t\t}\n\n\t\t\t// Basically we are consuming the first i + 1 elements of the stack\n\t\t\tresult.push(new DecorationSegment(nextStartOffset, this.stopOffsets[i], this.classNames.join(' '), Stack._metadata(this.metadata)));\n\t\t\tnextStartOffset = this.stopOffsets[i] + 1;\n\n\t\t\t// Consume them\n\t\t\tthis.stopOffsets.splice(0, i + 1);\n\t\t\tthis.classNames.splice(0, i + 1);\n\t\t\tthis.metadata.splice(0, i + 1);\n\t\t\tthis.count -= (i + 1);\n\t\t}\n\n\t\tif (this.count > 0 && nextStartOffset < maxStopOffset) {\n\t\t\tresult.push(new DecorationSegment(nextStartOffset, maxStopOffset - 1, this.classNames.join(' '), Stack._metadata(this.metadata)));\n\t\t\tnextStartOffset = maxStopOffset;\n\t\t}\n\n\t\treturn nextStartOffset;\n\t}\n\n\tpublic insert(stopOffset: number, className: string, metadata: number): void {\n\t\tif (this.count === 0 || this.stopOffsets[this.count - 1] <= stopOffset) {\n\t\t\t// Insert at the end\n\t\t\tthis.stopOffsets.push(stopOffset);\n\t\t\tthis.classNames.push(className);\n\t\t\tthis.metadata.push(metadata);\n\t\t} else {\n\t\t\t// Find the insertion position for `stopOffset`\n\t\t\tfor (let i = 0; i < this.count; i++) {\n\t\t\t\tif (this.stopOffsets[i] >= stopOffset) {\n\t\t\t\t\tthis.stopOffsets.splice(i, 0, stopOffset);\n\t\t\t\t\tthis.classNames.splice(i, 0, className);\n\t\t\t\t\tthis.metadata.splice(i, 0, metadata);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tthis.count++;\n\t\treturn;\n\t}\n}\n\nexport class LineDecorationsNormalizer {\n\t/**\n\t * Normalize line decorations. Overlapping decorations will generate multiple segments\n\t */\n\tpublic static normalize(lineContent: string, lineDecorations: LineDecoration[]): DecorationSegment[] {\n\t\tif (lineDecorations.length === 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst result: DecorationSegment[] = [];\n\n\t\tconst stack = new Stack();\n\t\tlet nextStartOffset = 0;\n\n\t\tfor (let i = 0, len = lineDecorations.length; i < len; i++) {\n\t\t\tconst d = lineDecorations[i];\n\t\t\tlet startColumn = d.startColumn;\n\t\t\tlet endColumn = d.endColumn;\n\t\t\tconst className = d.className;\n\t\t\tconst metadata = (\n\t\t\t\td.type === InlineDecorationType.Before\n\t\t\t\t\t? LinePartMetadata.PSEUDO_BEFORE\n\t\t\t\t\t: d.type === InlineDecorationType.After\n\t\t\t\t\t\t? LinePartMetadata.PSEUDO_AFTER\n\t\t\t\t\t\t: 0\n\t\t\t);\n\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\n\t\t\tif (startColumn > 1) {\n\t\t\t\tconst charCodeBefore = lineContent.charCodeAt(startColumn - 2);\n\t\t\t\tif (strings.isHighSurrogate(charCodeBefore)) {\n\t\t\t\t\tstartColumn--;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (endColumn > 1) {\n\t\t\t\tconst charCodeBefore = lineContent.charCodeAt(endColumn - 2);\n\t\t\t\tif (strings.isHighSurrogate(charCodeBefore)) {\n\t\t\t\t\tendColumn--;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst currentStartOffset = startColumn - 1;\n\t\t\tconst currentEndOffset = endColumn - 2;\n\n\t\t\tnextStartOffset = stack.consumeLowerThan(currentStartOffset, nextStartOffset, result);\n\n\t\t\tif (stack.count === 0) {\n\t\t\t\tnextStartOffset = currentStartOffset;\n\t\t\t}\n\t\t\tstack.insert(currentEndOffset, className, metadata);\n\t\t}\n\n\t\tstack.consumeLowerThan(Constants.MAX_SAFE_SMALL_INTEGER, nextStartOffset, result);\n\n\t\treturn result;\n\t}\n\n}\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\nexport const enum LinePartMetadata {\n\tIS_WHITESPACE = 1,\n\tPSEUDO_BEFORE = 2,\n\tPSEUDO_AFTER = 4,\n\n\tIS_WHITESPACE_MASK = 0b001,\n\tPSEUDO_BEFORE_MASK = 0b010,\n\tPSEUDO_AFTER_MASK = 0b100,\n}\n\nexport class LinePart {\n\t_linePartBrand: void = undefined;\n\n\tconstructor(\n\t\t/**\n\t\t * last char index of this token (not inclusive).\n\t\t */\n\t\tpublic readonly endIndex: number,\n\t\tpublic readonly type: string,\n\t\tpublic readonly metadata: number,\n\t\tpublic readonly containsRTL: boolean\n\t) { }\n\n\tpublic isWhitespace(): boolean {\n\t\treturn (this.metadata & LinePartMetadata.IS_WHITESPACE_MASK ? true : false);\n\t}\n\n\tpublic isPseudoAfter(): boolean {\n\t\treturn (this.metadata & LinePartMetadata.PSEUDO_AFTER_MASK ? true : false);\n\t}\n}\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\nimport { IEditorWhitespace, IPartialViewLinesViewportData, IViewWhitespaceViewportData, IWhitespaceChangeAccessor } from 'vs/editor/common/viewModel';\nimport * as strings from 'vs/base/common/strings';\n\ninterface IPendingChange { id: string; newAfterLineNumber: number; newHeight: number }\ninterface IPendingRemove { id: string }\n\nclass PendingChanges {\n\tprivate _hasPending: boolean;\n\tprivate _inserts: EditorWhitespace[];\n\tprivate _changes: IPendingChange[];\n\tprivate _removes: IPendingRemove[];\n\n\tconstructor() {\n\t\tthis._hasPending = false;\n\t\tthis._inserts = [];\n\t\tthis._changes = [];\n\t\tthis._removes = [];\n\t}\n\n\tpublic insert(x: EditorWhitespace): void {\n\t\tthis._hasPending = true;\n\t\tthis._inserts.push(x);\n\t}\n\n\tpublic change(x: IPendingChange): void {\n\t\tthis._hasPending = true;\n\t\tthis._changes.push(x);\n\t}\n\n\tpublic remove(x: IPendingRemove): void {\n\t\tthis._hasPending = true;\n\t\tthis._removes.push(x);\n\t}\n\n\tpublic mustCommit(): boolean {\n\t\treturn this._hasPending;\n\t}\n\n\tpublic commit(linesLayout: LinesLayout): void {\n\t\tif (!this._hasPending) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst inserts = this._inserts;\n\t\tconst changes = this._changes;\n\t\tconst removes = this._removes;\n\n\t\tthis._hasPending = false;\n\t\tthis._inserts = [];\n\t\tthis._changes = [];\n\t\tthis._removes = [];\n\n\t\tlinesLayout._commitPendingChanges(inserts, changes, removes);\n\t}\n}\n\nexport class EditorWhitespace implements IEditorWhitespace {\n\tpublic id: string;\n\tpublic afterLineNumber: number;\n\tpublic ordinal: number;\n\tpublic height: number;\n\tpublic minWidth: number;\n\tpublic prefixSum: number;\n\n\tconstructor(id: string, afterLineNumber: number, ordinal: number, height: number, minWidth: number) {\n\t\tthis.id = id;\n\t\tthis.afterLineNumber = afterLineNumber;\n\t\tthis.ordinal = ordinal;\n\t\tthis.height = height;\n\t\tthis.minWidth = minWidth;\n\t\tthis.prefixSum = 0;\n\t}\n}\n\n/**\n * Layouting of objects that take vertical space (by having a height) and push down other objects.\n *\n * These objects are basically either text (lines) or spaces between those lines (whitespaces).\n * This provides commodity operations for working with lines that contain whitespace that pushes lines lower (vertically).\n */\nexport class LinesLayout {\n\n\tprivate static INSTANCE_COUNT = 0;\n\n\tprivate readonly _instanceId: string;\n\tprivate readonly _pendingChanges: PendingChanges;\n\tprivate _lastWhitespaceId: number;\n\tprivate _arr: EditorWhitespace[];\n\tprivate _prefixSumValidIndex: number;\n\tprivate _minWidth: number;\n\tprivate _lineCount: number;\n\tprivate _lineHeight: number;\n\tprivate _paddingTop: number;\n\tprivate _paddingBottom: number;\n\n\tconstructor(lineCount: number, lineHeight: number, paddingTop: number, paddingBottom: number) {\n\t\tthis._instanceId = strings.singleLetterHash(++LinesLayout.INSTANCE_COUNT);\n\t\tthis._pendingChanges = new PendingChanges();\n\t\tthis._lastWhitespaceId = 0;\n\t\tthis._arr = [];\n\t\tthis._prefixSumValidIndex = -1;\n\t\tthis._minWidth = -1; /* marker for not being computed */\n\t\tthis._lineCount = lineCount;\n\t\tthis._lineHeight = lineHeight;\n\t\tthis._paddingTop = paddingTop;\n\t\tthis._paddingBottom = paddingBottom;\n\t}\n\n\t/**\n\t * Find the insertion index for a new value inside a sorted array of values.\n\t * If the value is already present in the sorted array, the insertion index will be after the already existing value.\n\t */\n\tpublic static findInsertionIndex(arr: EditorWhitespace[], afterLineNumber: number, ordinal: number): number {\n\t\tlet low = 0;\n\t\tlet high = arr.length;\n\n\t\twhile (low < high) {\n\t\t\tconst mid = ((low + high) >>> 1);\n\n\t\t\tif (afterLineNumber === arr[mid].afterLineNumber) {\n\t\t\t\tif (ordinal < arr[mid].ordinal) {\n\t\t\t\t\thigh = mid;\n\t\t\t\t} else {\n\t\t\t\t\tlow = mid + 1;\n\t\t\t\t}\n\t\t\t} else if (afterLineNumber < arr[mid].afterLineNumber) {\n\t\t\t\thigh = mid;\n\t\t\t} else {\n\t\t\t\tlow = mid + 1;\n\t\t\t}\n\t\t}\n\n\t\treturn low;\n\t}\n\n\t/**\n\t * Change the height of a line in pixels.\n\t */\n\tpublic setLineHeight(lineHeight: number): void {\n\t\tthis._checkPendingChanges();\n\t\tthis._lineHeight = lineHeight;\n\t}\n\n\t/**\n\t * Changes the padding used to calculate vertical offsets.\n\t */\n\tpublic setPadding(paddingTop: number, paddingBottom: number): void {\n\t\tthis._paddingTop = paddingTop;\n\t\tthis._paddingBottom = paddingBottom;\n\t}\n\n\t/**\n\t * Set the number of lines.\n\t *\n\t * @param lineCount New number of lines.\n\t */\n\tpublic onFlushed(lineCount: number): void {\n\t\tthis._checkPendingChanges();\n\t\tthis._lineCount = lineCount;\n\t}\n\n\tpublic changeWhitespace(callback: (accessor: IWhitespaceChangeAccessor) => void): boolean {\n\t\tlet hadAChange = false;\n\t\ttry {\n\t\t\tconst accessor: IWhitespaceChangeAccessor = {\n\t\t\t\tinsertWhitespace: (afterLineNumber: number, ordinal: number, heightInPx: number, minWidth: number): string => {\n\t\t\t\t\thadAChange = true;\n\t\t\t\t\tafterLineNumber = afterLineNumber | 0;\n\t\t\t\t\tordinal = ordinal | 0;\n\t\t\t\t\theightInPx = heightInPx | 0;\n\t\t\t\t\tminWidth = minWidth | 0;\n\t\t\t\t\tconst id = this._instanceId + (++this._lastWhitespaceId);\n\t\t\t\t\tthis._pendingChanges.insert(new EditorWhitespace(id, afterLineNumber, ordinal, heightInPx, minWidth));\n\t\t\t\t\treturn id;\n\t\t\t\t},\n\t\t\t\tchangeOneWhitespace: (id: string, newAfterLineNumber: number, newHeight: number): void => {\n\t\t\t\t\thadAChange = true;\n\t\t\t\t\tnewAfterLineNumber = newAfterLineNumber | 0;\n\t\t\t\t\tnewHeight = newHeight | 0;\n\t\t\t\t\tthis._pendingChanges.change({ id, newAfterLineNumber, newHeight });\n\t\t\t\t},\n\t\t\t\tremoveWhitespace: (id: string): void => {\n\t\t\t\t\thadAChange = true;\n\t\t\t\t\tthis._pendingChanges.remove({ id });\n\t\t\t\t}\n\t\t\t};\n\t\t\tcallback(accessor);\n\t\t} finally {\n\t\t\tthis._pendingChanges.commit(this);\n\t\t}\n\t\treturn hadAChange;\n\t}\n\n\tpublic _commitPendingChanges(inserts: EditorWhitespace[], changes: IPendingChange[], removes: IPendingRemove[]): void {\n\t\tif (inserts.length > 0 || removes.length > 0) {\n\t\t\tthis._minWidth = -1; /* marker for not being computed */\n\t\t}\n\n\t\tif (inserts.length + changes.length + removes.length <= 1) {\n\t\t\t// when only one thing happened, handle it \"delicately\"\n\t\t\tfor (const insert of inserts) {\n\t\t\t\tthis._insertWhitespace(insert);\n\t\t\t}\n\t\t\tfor (const change of changes) {\n\t\t\t\tthis._changeOneWhitespace(change.id, change.newAfterLineNumber, change.newHeight);\n\t\t\t}\n\t\t\tfor (const remove of removes) {\n\t\t\t\tconst index = this._findWhitespaceIndex(remove.id);\n\t\t\t\tif (index === -1) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tthis._removeWhitespace(index);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// simply rebuild the entire datastructure\n\n\t\tconst toRemove = new Set();\n\t\tfor (const remove of removes) {\n\t\t\ttoRemove.add(remove.id);\n\t\t}\n\n\t\tconst toChange = new Map();\n\t\tfor (const change of changes) {\n\t\t\ttoChange.set(change.id, change);\n\t\t}\n\n\t\tconst applyRemoveAndChange = (whitespaces: EditorWhitespace[]): EditorWhitespace[] => {\n\t\t\tconst result: EditorWhitespace[] = [];\n\t\t\tfor (const whitespace of whitespaces) {\n\t\t\t\tif (toRemove.has(whitespace.id)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (toChange.has(whitespace.id)) {\n\t\t\t\t\tconst change = toChange.get(whitespace.id)!;\n\t\t\t\t\twhitespace.afterLineNumber = change.newAfterLineNumber;\n\t\t\t\t\twhitespace.height = change.newHeight;\n\t\t\t\t}\n\t\t\t\tresult.push(whitespace);\n\t\t\t}\n\t\t\treturn result;\n\t\t};\n\n\t\tconst result = applyRemoveAndChange(this._arr).concat(applyRemoveAndChange(inserts));\n\t\tresult.sort((a, b) => {\n\t\t\tif (a.afterLineNumber === b.afterLineNumber) {\n\t\t\t\treturn a.ordinal - b.ordinal;\n\t\t\t}\n\t\t\treturn a.afterLineNumber - b.afterLineNumber;\n\t\t});\n\n\t\tthis._arr = result;\n\t\tthis._prefixSumValidIndex = -1;\n\t}\n\n\tprivate _checkPendingChanges(): void {\n\t\tif (this._pendingChanges.mustCommit()) {\n\t\t\tthis._pendingChanges.commit(this);\n\t\t}\n\t}\n\n\tprivate _insertWhitespace(whitespace: EditorWhitespace): void {\n\t\tconst insertIndex = LinesLayout.findInsertionIndex(this._arr, whitespace.afterLineNumber, whitespace.ordinal);\n\t\tthis._arr.splice(insertIndex, 0, whitespace);\n\t\tthis._prefixSumValidIndex = Math.min(this._prefixSumValidIndex, insertIndex - 1);\n\t}\n\n\tprivate _findWhitespaceIndex(id: string): number {\n\t\tconst arr = this._arr;\n\t\tfor (let i = 0, len = arr.length; i < len; i++) {\n\t\t\tif (arr[i].id === id) {\n\t\t\t\treturn i;\n\t\t\t}\n\t\t}\n\t\treturn -1;\n\t}\n\n\tprivate _changeOneWhitespace(id: string, newAfterLineNumber: number, newHeight: number): void {\n\t\tconst index = this._findWhitespaceIndex(id);\n\t\tif (index === -1) {\n\t\t\treturn;\n\t\t}\n\t\tif (this._arr[index].height !== newHeight) {\n\t\t\tthis._arr[index].height = newHeight;\n\t\t\tthis._prefixSumValidIndex = Math.min(this._prefixSumValidIndex, index - 1);\n\t\t}\n\t\tif (this._arr[index].afterLineNumber !== newAfterLineNumber) {\n\t\t\t// `afterLineNumber` changed for this whitespace\n\n\t\t\t// Record old whitespace\n\t\t\tconst whitespace = this._arr[index];\n\n\t\t\t// Since changing `afterLineNumber` can trigger a reordering, we're gonna remove this whitespace\n\t\t\tthis._removeWhitespace(index);\n\n\t\t\twhitespace.afterLineNumber = newAfterLineNumber;\n\n\t\t\t// And add it again\n\t\t\tthis._insertWhitespace(whitespace);\n\t\t}\n\t}\n\n\tprivate _removeWhitespace(removeIndex: number): void {\n\t\tthis._arr.splice(removeIndex, 1);\n\t\tthis._prefixSumValidIndex = Math.min(this._prefixSumValidIndex, removeIndex - 1);\n\t}\n\n\t/**\n\t * Notify the layouter that lines have been deleted (a continuous zone of lines).\n\t *\n\t * @param fromLineNumber The line number at which the deletion started, inclusive\n\t * @param toLineNumber The line number at which the deletion ended, inclusive\n\t */\n\tpublic onLinesDeleted(fromLineNumber: number, toLineNumber: number): void {\n\t\tthis._checkPendingChanges();\n\t\tfromLineNumber = fromLineNumber | 0;\n\t\ttoLineNumber = toLineNumber | 0;\n\n\t\tthis._lineCount -= (toLineNumber - fromLineNumber + 1);\n\t\tfor (let i = 0, len = this._arr.length; i < len; i++) {\n\t\t\tconst afterLineNumber = this._arr[i].afterLineNumber;\n\n\t\t\tif (fromLineNumber <= afterLineNumber && afterLineNumber <= toLineNumber) {\n\t\t\t\t// The line this whitespace was after has been deleted\n\t\t\t\t// => move whitespace to before first deleted line\n\t\t\t\tthis._arr[i].afterLineNumber = fromLineNumber - 1;\n\t\t\t} else if (afterLineNumber > toLineNumber) {\n\t\t\t\t// The line this whitespace was after has been moved up\n\t\t\t\t// => move whitespace up\n\t\t\t\tthis._arr[i].afterLineNumber -= (toLineNumber - fromLineNumber + 1);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Notify the layouter that lines have been inserted (a continuous zone of lines).\n\t *\n\t * @param fromLineNumber The line number at which the insertion started, inclusive\n\t * @param toLineNumber The line number at which the insertion ended, inclusive.\n\t */\n\tpublic onLinesInserted(fromLineNumber: number, toLineNumber: number): void {\n\t\tthis._checkPendingChanges();\n\t\tfromLineNumber = fromLineNumber | 0;\n\t\ttoLineNumber = toLineNumber | 0;\n\n\t\tthis._lineCount += (toLineNumber - fromLineNumber + 1);\n\t\tfor (let i = 0, len = this._arr.length; i < len; i++) {\n\t\t\tconst afterLineNumber = this._arr[i].afterLineNumber;\n\n\t\t\tif (fromLineNumber <= afterLineNumber) {\n\t\t\t\tthis._arr[i].afterLineNumber += (toLineNumber - fromLineNumber + 1);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Get the sum of all the whitespaces.\n\t */\n\tpublic getWhitespacesTotalHeight(): number {\n\t\tthis._checkPendingChanges();\n\t\tif (this._arr.length === 0) {\n\t\t\treturn 0;\n\t\t}\n\t\treturn this.getWhitespacesAccumulatedHeight(this._arr.length - 1);\n\t}\n\n\t/**\n\t * Return the sum of the heights of the whitespaces at [0..index].\n\t * This includes the whitespace at `index`.\n\t *\n\t * @param index The index of the whitespace.\n\t * @return The sum of the heights of all whitespaces before the one at `index`, including the one at `index`.\n\t */\n\tpublic getWhitespacesAccumulatedHeight(index: number): number {\n\t\tthis._checkPendingChanges();\n\t\tindex = index | 0;\n\n\t\tlet startIndex = Math.max(0, this._prefixSumValidIndex + 1);\n\t\tif (startIndex === 0) {\n\t\t\tthis._arr[0].prefixSum = this._arr[0].height;\n\t\t\tstartIndex++;\n\t\t}\n\n\t\tfor (let i = startIndex; i <= index; i++) {\n\t\t\tthis._arr[i].prefixSum = this._arr[i - 1].prefixSum + this._arr[i].height;\n\t\t}\n\t\tthis._prefixSumValidIndex = Math.max(this._prefixSumValidIndex, index);\n\t\treturn this._arr[index].prefixSum;\n\t}\n\n\t/**\n\t * Get the sum of heights for all objects.\n\t *\n\t * @return The sum of heights for all objects.\n\t */\n\tpublic getLinesTotalHeight(): number {\n\t\tthis._checkPendingChanges();\n\t\tconst linesHeight = this._lineHeight * this._lineCount;\n\t\tconst whitespacesHeight = this.getWhitespacesTotalHeight();\n\n\t\treturn linesHeight + whitespacesHeight + this._paddingTop + this._paddingBottom;\n\t}\n\n\t/**\n\t * Returns the accumulated height of whitespaces before the given line number.\n\t *\n\t * @param lineNumber The line number\n\t */\n\tpublic getWhitespaceAccumulatedHeightBeforeLineNumber(lineNumber: number): number {\n\t\tthis._checkPendingChanges();\n\t\tlineNumber = lineNumber | 0;\n\n\t\tconst lastWhitespaceBeforeLineNumber = this._findLastWhitespaceBeforeLineNumber(lineNumber);\n\n\t\tif (lastWhitespaceBeforeLineNumber === -1) {\n\t\t\treturn 0;\n\t\t}\n\n\t\treturn this.getWhitespacesAccumulatedHeight(lastWhitespaceBeforeLineNumber);\n\t}\n\n\tprivate _findLastWhitespaceBeforeLineNumber(lineNumber: number): number {\n\t\tlineNumber = lineNumber | 0;\n\n\t\t// Find the whitespace before line number\n\t\tconst arr = this._arr;\n\t\tlet low = 0;\n\t\tlet high = arr.length - 1;\n\n\t\twhile (low <= high) {\n\t\t\tconst delta = (high - low) | 0;\n\t\t\tconst halfDelta = (delta / 2) | 0;\n\t\t\tconst mid = (low + halfDelta) | 0;\n\n\t\t\tif (arr[mid].afterLineNumber < lineNumber) {\n\t\t\t\tif (mid + 1 >= arr.length || arr[mid + 1].afterLineNumber >= lineNumber) {\n\t\t\t\t\treturn mid;\n\t\t\t\t} else {\n\t\t\t\t\tlow = (mid + 1) | 0;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\thigh = (mid - 1) | 0;\n\t\t\t}\n\t\t}\n\n\t\treturn -1;\n\t}\n\n\tprivate _findFirstWhitespaceAfterLineNumber(lineNumber: number): number {\n\t\tlineNumber = lineNumber | 0;\n\n\t\tconst lastWhitespaceBeforeLineNumber = this._findLastWhitespaceBeforeLineNumber(lineNumber);\n\t\tconst firstWhitespaceAfterLineNumber = lastWhitespaceBeforeLineNumber + 1;\n\n\t\tif (firstWhitespaceAfterLineNumber < this._arr.length) {\n\t\t\treturn firstWhitespaceAfterLineNumber;\n\t\t}\n\n\t\treturn -1;\n\t}\n\n\t/**\n\t * Find the index of the first whitespace which has `afterLineNumber` >= `lineNumber`.\n\t * @return The index of the first whitespace with `afterLineNumber` >= `lineNumber` or -1 if no whitespace is found.\n\t */\n\tpublic getFirstWhitespaceIndexAfterLineNumber(lineNumber: number): number {\n\t\tthis._checkPendingChanges();\n\t\tlineNumber = lineNumber | 0;\n\n\t\treturn this._findFirstWhitespaceAfterLineNumber(lineNumber);\n\t}\n\n\t/**\n\t * Get the vertical offset (the sum of heights for all objects above) a certain line number.\n\t *\n\t * @param lineNumber The line number\n\t * @return The sum of heights for all objects above `lineNumber`.\n\t */\n\tpublic getVerticalOffsetForLineNumber(lineNumber: number, includeViewZones = false): number {\n\t\tthis._checkPendingChanges();\n\t\tlineNumber = lineNumber | 0;\n\n\t\tlet previousLinesHeight: number;\n\t\tif (lineNumber > 1) {\n\t\t\tpreviousLinesHeight = this._lineHeight * (lineNumber - 1);\n\t\t} else {\n\t\t\tpreviousLinesHeight = 0;\n\t\t}\n\n\t\tconst previousWhitespacesHeight = this.getWhitespaceAccumulatedHeightBeforeLineNumber(lineNumber - (includeViewZones ? 1 : 0));\n\n\t\treturn previousLinesHeight + previousWhitespacesHeight + this._paddingTop;\n\t}\n\n\t/**\n\t * Get the vertical offset (the sum of heights for all objects above) a certain line number.\n\t *\n\t * @param lineNumber The line number\n\t * @return The sum of heights for all objects above `lineNumber`.\n\t */\n\tpublic getVerticalOffsetAfterLineNumber(lineNumber: number, includeViewZones = false): number {\n\t\tthis._checkPendingChanges();\n\t\tlineNumber = lineNumber | 0;\n\t\tconst previousLinesHeight = this._lineHeight * lineNumber;\n\t\tconst previousWhitespacesHeight = this.getWhitespaceAccumulatedHeightBeforeLineNumber(lineNumber + (includeViewZones ? 1 : 0));\n\t\treturn previousLinesHeight + previousWhitespacesHeight + this._paddingTop;\n\t}\n\n\t/**\n\t * The maximum min width for all whitespaces.\n\t */\n\tpublic getWhitespaceMinWidth(): number {\n\t\tthis._checkPendingChanges();\n\t\tif (this._minWidth === -1) {\n\t\t\tlet minWidth = 0;\n\t\t\tfor (let i = 0, len = this._arr.length; i < len; i++) {\n\t\t\t\tminWidth = Math.max(minWidth, this._arr[i].minWidth);\n\t\t\t}\n\t\t\tthis._minWidth = minWidth;\n\t\t}\n\t\treturn this._minWidth;\n\t}\n\n\t/**\n\t * Check if `verticalOffset` is below all lines.\n\t */\n\tpublic isAfterLines(verticalOffset: number): boolean {\n\t\tthis._checkPendingChanges();\n\t\tconst totalHeight = this.getLinesTotalHeight();\n\t\treturn verticalOffset > totalHeight;\n\t}\n\n\tpublic isInTopPadding(verticalOffset: number): boolean {\n\t\tif (this._paddingTop === 0) {\n\t\t\treturn false;\n\t\t}\n\t\tthis._checkPendingChanges();\n\t\treturn (verticalOffset < this._paddingTop);\n\t}\n\n\tpublic isInBottomPadding(verticalOffset: number): boolean {\n\t\tif (this._paddingBottom === 0) {\n\t\t\treturn false;\n\t\t}\n\t\tthis._checkPendingChanges();\n\t\tconst totalHeight = this.getLinesTotalHeight();\n\t\treturn (verticalOffset >= totalHeight - this._paddingBottom);\n\t}\n\n\t/**\n\t * Find the first line number that is at or after vertical offset `verticalOffset`.\n\t * i.e. if getVerticalOffsetForLine(line) is x and getVerticalOffsetForLine(line + 1) is y, then\n\t * getLineNumberAtOrAfterVerticalOffset(i) = line, x <= i < y.\n\t *\n\t * @param verticalOffset The vertical offset to search at.\n\t * @return The line number at or after vertical offset `verticalOffset`.\n\t */\n\tpublic getLineNumberAtOrAfterVerticalOffset(verticalOffset: number): number {\n\t\tthis._checkPendingChanges();\n\t\tverticalOffset = verticalOffset | 0;\n\n\t\tif (verticalOffset < 0) {\n\t\t\treturn 1;\n\t\t}\n\n\t\tconst linesCount = this._lineCount | 0;\n\t\tconst lineHeight = this._lineHeight;\n\t\tlet minLineNumber = 1;\n\t\tlet maxLineNumber = linesCount;\n\n\t\twhile (minLineNumber < maxLineNumber) {\n\t\t\tconst midLineNumber = ((minLineNumber + maxLineNumber) / 2) | 0;\n\n\t\t\tconst midLineNumberVerticalOffset = this.getVerticalOffsetForLineNumber(midLineNumber) | 0;\n\n\t\t\tif (verticalOffset >= midLineNumberVerticalOffset + lineHeight) {\n\t\t\t\t// vertical offset is after mid line number\n\t\t\t\tminLineNumber = midLineNumber + 1;\n\t\t\t} else if (verticalOffset >= midLineNumberVerticalOffset) {\n\t\t\t\t// Hit\n\t\t\t\treturn midLineNumber;\n\t\t\t} else {\n\t\t\t\t// vertical offset is before mid line number, but mid line number could still be what we're searching for\n\t\t\t\tmaxLineNumber = midLineNumber;\n\t\t\t}\n\t\t}\n\n\t\tif (minLineNumber > linesCount) {\n\t\t\treturn linesCount;\n\t\t}\n\n\t\treturn minLineNumber;\n\t}\n\n\t/**\n\t * Get all the lines and their relative vertical offsets that are positioned between `verticalOffset1` and `verticalOffset2`.\n\t *\n\t * @param verticalOffset1 The beginning of the viewport.\n\t * @param verticalOffset2 The end of the viewport.\n\t * @return A structure describing the lines positioned between `verticalOffset1` and `verticalOffset2`.\n\t */\n\tpublic getLinesViewportData(verticalOffset1: number, verticalOffset2: number): IPartialViewLinesViewportData {\n\t\tthis._checkPendingChanges();\n\t\tverticalOffset1 = verticalOffset1 | 0;\n\t\tverticalOffset2 = verticalOffset2 | 0;\n\t\tconst lineHeight = this._lineHeight;\n\n\t\t// Find first line number\n\t\t// We don't live in a perfect world, so the line number might start before or after verticalOffset1\n\t\tconst startLineNumber = this.getLineNumberAtOrAfterVerticalOffset(verticalOffset1) | 0;\n\t\tconst startLineNumberVerticalOffset = this.getVerticalOffsetForLineNumber(startLineNumber) | 0;\n\n\t\tlet endLineNumber = this._lineCount | 0;\n\n\t\t// Also keep track of what whitespace we've got\n\t\tlet whitespaceIndex = this.getFirstWhitespaceIndexAfterLineNumber(startLineNumber) | 0;\n\t\tconst whitespaceCount = this.getWhitespacesCount() | 0;\n\t\tlet currentWhitespaceHeight: number;\n\t\tlet currentWhitespaceAfterLineNumber: number;\n\n\t\tif (whitespaceIndex === -1) {\n\t\t\twhitespaceIndex = whitespaceCount;\n\t\t\tcurrentWhitespaceAfterLineNumber = endLineNumber + 1;\n\t\t\tcurrentWhitespaceHeight = 0;\n\t\t} else {\n\t\t\tcurrentWhitespaceAfterLineNumber = this.getAfterLineNumberForWhitespaceIndex(whitespaceIndex) | 0;\n\t\t\tcurrentWhitespaceHeight = this.getHeightForWhitespaceIndex(whitespaceIndex) | 0;\n\t\t}\n\n\t\tlet currentVerticalOffset = startLineNumberVerticalOffset;\n\t\tlet currentLineRelativeOffset = currentVerticalOffset;\n\n\t\t// IE (all versions) cannot handle units above about 1,533,908 px, so every 500k pixels bring numbers down\n\t\tconst STEP_SIZE = 500000;\n\t\tlet bigNumbersDelta = 0;\n\t\tif (startLineNumberVerticalOffset >= STEP_SIZE) {\n\t\t\t// Compute a delta that guarantees that lines are positioned at `lineHeight` increments\n\t\t\tbigNumbersDelta = Math.floor(startLineNumberVerticalOffset / STEP_SIZE) * STEP_SIZE;\n\t\t\tbigNumbersDelta = Math.floor(bigNumbersDelta / lineHeight) * lineHeight;\n\n\t\t\tcurrentLineRelativeOffset -= bigNumbersDelta;\n\t\t}\n\n\t\tconst linesOffsets: number[] = [];\n\n\t\tconst verticalCenter = verticalOffset1 + (verticalOffset2 - verticalOffset1) / 2;\n\t\tlet centeredLineNumber = -1;\n\n\t\t// Figure out how far the lines go\n\t\tfor (let lineNumber = startLineNumber; lineNumber <= endLineNumber; lineNumber++) {\n\n\t\t\tif (centeredLineNumber === -1) {\n\t\t\t\tconst currentLineTop = currentVerticalOffset;\n\t\t\t\tconst currentLineBottom = currentVerticalOffset + lineHeight;\n\t\t\t\tif ((currentLineTop <= verticalCenter && verticalCenter < currentLineBottom) || currentLineTop > verticalCenter) {\n\t\t\t\t\tcenteredLineNumber = lineNumber;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Count current line height in the vertical offsets\n\t\t\tcurrentVerticalOffset += lineHeight;\n\t\t\tlinesOffsets[lineNumber - startLineNumber] = currentLineRelativeOffset;\n\n\t\t\t// Next line starts immediately after this one\n\t\t\tcurrentLineRelativeOffset += lineHeight;\n\t\t\twhile (currentWhitespaceAfterLineNumber === lineNumber) {\n\t\t\t\t// Push down next line with the height of the current whitespace\n\t\t\t\tcurrentLineRelativeOffset += currentWhitespaceHeight;\n\n\t\t\t\t// Count current whitespace in the vertical offsets\n\t\t\t\tcurrentVerticalOffset += currentWhitespaceHeight;\n\t\t\t\twhitespaceIndex++;\n\n\t\t\t\tif (whitespaceIndex >= whitespaceCount) {\n\t\t\t\t\tcurrentWhitespaceAfterLineNumber = endLineNumber + 1;\n\t\t\t\t} else {\n\t\t\t\t\tcurrentWhitespaceAfterLineNumber = this.getAfterLineNumberForWhitespaceIndex(whitespaceIndex) | 0;\n\t\t\t\t\tcurrentWhitespaceHeight = this.getHeightForWhitespaceIndex(whitespaceIndex) | 0;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (currentVerticalOffset >= verticalOffset2) {\n\t\t\t\t// We have covered the entire viewport area, time to stop\n\t\t\t\tendLineNumber = lineNumber;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (centeredLineNumber === -1) {\n\t\t\tcenteredLineNumber = endLineNumber;\n\t\t}\n\n\t\tconst endLineNumberVerticalOffset = this.getVerticalOffsetForLineNumber(endLineNumber) | 0;\n\n\t\tlet completelyVisibleStartLineNumber = startLineNumber;\n\t\tlet completelyVisibleEndLineNumber = endLineNumber;\n\n\t\tif (completelyVisibleStartLineNumber < completelyVisibleEndLineNumber) {\n\t\t\tif (startLineNumberVerticalOffset < verticalOffset1) {\n\t\t\t\tcompletelyVisibleStartLineNumber++;\n\t\t\t}\n\t\t}\n\t\tif (completelyVisibleStartLineNumber < completelyVisibleEndLineNumber) {\n\t\t\tif (endLineNumberVerticalOffset + lineHeight > verticalOffset2) {\n\t\t\t\tcompletelyVisibleEndLineNumber--;\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tbigNumbersDelta: bigNumbersDelta,\n\t\t\tstartLineNumber: startLineNumber,\n\t\t\tendLineNumber: endLineNumber,\n\t\t\trelativeVerticalOffset: linesOffsets,\n\t\t\tcenteredLineNumber: centeredLineNumber,\n\t\t\tcompletelyVisibleStartLineNumber: completelyVisibleStartLineNumber,\n\t\t\tcompletelyVisibleEndLineNumber: completelyVisibleEndLineNumber,\n\t\t\tlineHeight: this._lineHeight,\n\t\t};\n\t}\n\n\tpublic getVerticalOffsetForWhitespaceIndex(whitespaceIndex: number): number {\n\t\tthis._checkPendingChanges();\n\t\twhitespaceIndex = whitespaceIndex | 0;\n\n\t\tconst afterLineNumber = this.getAfterLineNumberForWhitespaceIndex(whitespaceIndex);\n\n\t\tlet previousLinesHeight: number;\n\t\tif (afterLineNumber >= 1) {\n\t\t\tpreviousLinesHeight = this._lineHeight * afterLineNumber;\n\t\t} else {\n\t\t\tpreviousLinesHeight = 0;\n\t\t}\n\n\t\tlet previousWhitespacesHeight: number;\n\t\tif (whitespaceIndex > 0) {\n\t\t\tpreviousWhitespacesHeight = this.getWhitespacesAccumulatedHeight(whitespaceIndex - 1);\n\t\t} else {\n\t\t\tpreviousWhitespacesHeight = 0;\n\t\t}\n\t\treturn previousLinesHeight + previousWhitespacesHeight + this._paddingTop;\n\t}\n\n\tpublic getWhitespaceIndexAtOrAfterVerticallOffset(verticalOffset: number): number {\n\t\tthis._checkPendingChanges();\n\t\tverticalOffset = verticalOffset | 0;\n\n\t\tlet minWhitespaceIndex = 0;\n\t\tlet maxWhitespaceIndex = this.getWhitespacesCount() - 1;\n\n\t\tif (maxWhitespaceIndex < 0) {\n\t\t\treturn -1;\n\t\t}\n\n\t\t// Special case: nothing to be found\n\t\tconst maxWhitespaceVerticalOffset = this.getVerticalOffsetForWhitespaceIndex(maxWhitespaceIndex);\n\t\tconst maxWhitespaceHeight = this.getHeightForWhitespaceIndex(maxWhitespaceIndex);\n\t\tif (verticalOffset >= maxWhitespaceVerticalOffset + maxWhitespaceHeight) {\n\t\t\treturn -1;\n\t\t}\n\n\t\twhile (minWhitespaceIndex < maxWhitespaceIndex) {\n\t\t\tconst midWhitespaceIndex = Math.floor((minWhitespaceIndex + maxWhitespaceIndex) / 2);\n\n\t\t\tconst midWhitespaceVerticalOffset = this.getVerticalOffsetForWhitespaceIndex(midWhitespaceIndex);\n\t\t\tconst midWhitespaceHeight = this.getHeightForWhitespaceIndex(midWhitespaceIndex);\n\n\t\t\tif (verticalOffset >= midWhitespaceVerticalOffset + midWhitespaceHeight) {\n\t\t\t\t// vertical offset is after whitespace\n\t\t\t\tminWhitespaceIndex = midWhitespaceIndex + 1;\n\t\t\t} else if (verticalOffset >= midWhitespaceVerticalOffset) {\n\t\t\t\t// Hit\n\t\t\t\treturn midWhitespaceIndex;\n\t\t\t} else {\n\t\t\t\t// vertical offset is before whitespace, but midWhitespaceIndex might still be what we're searching for\n\t\t\t\tmaxWhitespaceIndex = midWhitespaceIndex;\n\t\t\t}\n\t\t}\n\t\treturn minWhitespaceIndex;\n\t}\n\n\t/**\n\t * Get exactly the whitespace that is layouted at `verticalOffset`.\n\t *\n\t * @param verticalOffset The vertical offset.\n\t * @return Precisely the whitespace that is layouted at `verticaloffset` or null.\n\t */\n\tpublic getWhitespaceAtVerticalOffset(verticalOffset: number): IViewWhitespaceViewportData | null {\n\t\tthis._checkPendingChanges();\n\t\tverticalOffset = verticalOffset | 0;\n\n\t\tconst candidateIndex = this.getWhitespaceIndexAtOrAfterVerticallOffset(verticalOffset);\n\n\t\tif (candidateIndex < 0) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif (candidateIndex >= this.getWhitespacesCount()) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst candidateTop = this.getVerticalOffsetForWhitespaceIndex(candidateIndex);\n\n\t\tif (candidateTop > verticalOffset) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst candidateHeight = this.getHeightForWhitespaceIndex(candidateIndex);\n\t\tconst candidateId = this.getIdForWhitespaceIndex(candidateIndex);\n\t\tconst candidateAfterLineNumber = this.getAfterLineNumberForWhitespaceIndex(candidateIndex);\n\n\t\treturn {\n\t\t\tid: candidateId,\n\t\t\tafterLineNumber: candidateAfterLineNumber,\n\t\t\tverticalOffset: candidateTop,\n\t\t\theight: candidateHeight\n\t\t};\n\t}\n\n\t/**\n\t * Get a list of whitespaces that are positioned between `verticalOffset1` and `verticalOffset2`.\n\t *\n\t * @param verticalOffset1 The beginning of the viewport.\n\t * @param verticalOffset2 The end of the viewport.\n\t * @return An array with all the whitespaces in the viewport. If no whitespace is in viewport, the array is empty.\n\t */\n\tpublic getWhitespaceViewportData(verticalOffset1: number, verticalOffset2: number): IViewWhitespaceViewportData[] {\n\t\tthis._checkPendingChanges();\n\t\tverticalOffset1 = verticalOffset1 | 0;\n\t\tverticalOffset2 = verticalOffset2 | 0;\n\n\t\tconst startIndex = this.getWhitespaceIndexAtOrAfterVerticallOffset(verticalOffset1);\n\t\tconst endIndex = this.getWhitespacesCount() - 1;\n\n\t\tif (startIndex < 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst result: IViewWhitespaceViewportData[] = [];\n\t\tfor (let i = startIndex; i <= endIndex; i++) {\n\t\t\tconst top = this.getVerticalOffsetForWhitespaceIndex(i);\n\t\t\tconst height = this.getHeightForWhitespaceIndex(i);\n\t\t\tif (top >= verticalOffset2) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tresult.push({\n\t\t\t\tid: this.getIdForWhitespaceIndex(i),\n\t\t\t\tafterLineNumber: this.getAfterLineNumberForWhitespaceIndex(i),\n\t\t\t\tverticalOffset: top,\n\t\t\t\theight: height\n\t\t\t});\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t/**\n\t * Get all whitespaces.\n\t */\n\tpublic getWhitespaces(): IEditorWhitespace[] {\n\t\tthis._checkPendingChanges();\n\t\treturn this._arr.slice(0);\n\t}\n\n\t/**\n\t * The number of whitespaces.\n\t */\n\tpublic getWhitespacesCount(): number {\n\t\tthis._checkPendingChanges();\n\t\treturn this._arr.length;\n\t}\n\n\t/**\n\t * Get the `id` for whitespace at index `index`.\n\t *\n\t * @param index The index of the whitespace.\n\t * @return `id` of whitespace at `index`.\n\t */\n\tpublic getIdForWhitespaceIndex(index: number): string {\n\t\tthis._checkPendingChanges();\n\t\tindex = index | 0;\n\n\t\treturn this._arr[index].id;\n\t}\n\n\t/**\n\t * Get the `afterLineNumber` for whitespace at index `index`.\n\t *\n\t * @param index The index of the whitespace.\n\t * @return `afterLineNumber` of whitespace at `index`.\n\t */\n\tpublic getAfterLineNumberForWhitespaceIndex(index: number): number {\n\t\tthis._checkPendingChanges();\n\t\tindex = index | 0;\n\n\t\treturn this._arr[index].afterLineNumber;\n\t}\n\n\t/**\n\t * Get the `height` for whitespace at index `index`.\n\t *\n\t * @param index The index of the whitespace.\n\t * @return `height` of whitespace at `index`.\n\t */\n\tpublic getHeightForWhitespaceIndex(index: number): number {\n\t\tthis._checkPendingChanges();\n\t\tindex = index | 0;\n\n\t\treturn this._arr[index].height;\n\t}\n}\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\nimport { Range } from 'vs/editor/common/core/range';\nimport { Selection } from 'vs/editor/common/core/selection';\nimport { IPartialViewLinesViewportData, IViewModel, IViewWhitespaceViewportData, ViewLineRenderingData, ViewModelDecoration } from 'vs/editor/common/viewModel';\n\n/**\n * Contains all data needed to render at a specific viewport.\n */\nexport class ViewportData {\n\n\tpublic readonly selections: Selection[];\n\n\t/**\n\t * The line number at which to start rendering (inclusive).\n\t */\n\tpublic readonly startLineNumber: number;\n\n\t/**\n\t * The line number at which to end rendering (inclusive).\n\t */\n\tpublic readonly endLineNumber: number;\n\n\t/**\n\t * relativeVerticalOffset[i] is the `top` position for line at `i` + `startLineNumber`.\n\t */\n\tpublic readonly relativeVerticalOffset: number[];\n\n\t/**\n\t * The viewport as a range (startLineNumber,1) -> (endLineNumber,maxColumn(endLineNumber)).\n\t */\n\tpublic readonly visibleRange: Range;\n\n\t/**\n\t * Value to be substracted from `scrollTop` (in order to vertical offset numbers < 1MM)\n\t */\n\tpublic readonly bigNumbersDelta: number;\n\n\t/**\n\t * Positioning information about gaps whitespace.\n\t */\n\tpublic readonly whitespaceViewportData: IViewWhitespaceViewportData[];\n\n\tprivate readonly _model: IViewModel;\n\n\tpublic readonly lineHeight: number;\n\n\tconstructor(\n\t\tselections: Selection[],\n\t\tpartialData: IPartialViewLinesViewportData,\n\t\twhitespaceViewportData: IViewWhitespaceViewportData[],\n\t\tmodel: IViewModel\n\t) {\n\t\tthis.selections = selections;\n\t\tthis.startLineNumber = partialData.startLineNumber | 0;\n\t\tthis.endLineNumber = partialData.endLineNumber | 0;\n\t\tthis.relativeVerticalOffset = partialData.relativeVerticalOffset;\n\t\tthis.bigNumbersDelta = partialData.bigNumbersDelta | 0;\n\t\tthis.lineHeight = partialData.lineHeight | 0;\n\t\tthis.whitespaceViewportData = whitespaceViewportData;\n\n\t\tthis._model = model;\n\n\t\tthis.visibleRange = new Range(\n\t\t\tpartialData.startLineNumber,\n\t\t\tthis._model.getLineMinColumn(partialData.startLineNumber),\n\t\t\tpartialData.endLineNumber,\n\t\t\tthis._model.getLineMaxColumn(partialData.endLineNumber)\n\t\t);\n\t}\n\n\tpublic getViewLineRenderingData(lineNumber: number): ViewLineRenderingData {\n\t\treturn this._model.getViewportViewLineRenderingData(this.visibleRange, lineNumber);\n\t}\n\n\tpublic getDecorationsInViewport(): ViewModelDecoration[] {\n\t\treturn this._model.getDecorationsInViewport(this.visibleRange);\n\t}\n}\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\nimport * as arrays from 'vs/base/common/arrays';\nimport { IScrollPosition, Scrollable } from 'vs/base/common/scrollable';\nimport * as strings from 'vs/base/common/strings';\nimport { IPosition, Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\nimport { CursorConfiguration, CursorState, EditOperationType, IColumnSelectData, ICursorSimpleModel, PartialCursorState } from 'vs/editor/common/cursorCommon';\nimport { CursorChangeReason } from 'vs/editor/common/cursorEvents';\nimport { INewScrollPosition, ScrollType } from 'vs/editor/common/editorCommon';\nimport { EditorTheme } from 'vs/editor/common/editorTheme';\nimport { EndOfLinePreference, IGlyphMarginLanesModel, IModelDecorationOptions, ITextModel, PositionAffinity } from 'vs/editor/common/model';\nimport { ILineBreaksComputer, InjectedText } from 'vs/editor/common/modelLineProjectionData';\nimport { BracketGuideOptions, IActiveIndentGuideInfo, IndentGuide } from 'vs/editor/common/textModelGuides';\nimport { IViewLineTokens } from 'vs/editor/common/tokens/lineTokens';\nimport { ViewEventHandler } from 'vs/editor/common/viewEventHandler';\nimport { VerticalRevealType } from 'vs/editor/common/viewEvents';\n\nexport interface IViewModel extends ICursorSimpleModel {\n\n\treadonly model: ITextModel;\n\n\treadonly coordinatesConverter: ICoordinatesConverter;\n\n\treadonly viewLayout: IViewLayout;\n\n\treadonly cursorConfig: CursorConfiguration;\n\n\treadonly glyphLanes: IGlyphMarginLanesModel;\n\n\taddViewEventHandler(eventHandler: ViewEventHandler): void;\n\tremoveViewEventHandler(eventHandler: ViewEventHandler): void;\n\n\t/**\n\t * Gives a hint that a lot of requests are about to come in for these line numbers.\n\t */\n\tsetViewport(startLineNumber: number, endLineNumber: number, centeredLineNumber: number): void;\n\tvisibleLinesStabilized(): void;\n\tsetHasFocus(hasFocus: boolean): void;\n\tonCompositionStart(): void;\n\tonCompositionEnd(): void;\n\n\tgetMinimapDecorationsInRange(range: Range): ViewModelDecoration[];\n\tgetDecorationsInViewport(visibleRange: Range): ViewModelDecoration[];\n\tgetViewportViewLineRenderingData(visibleRange: Range, lineNumber: number): ViewLineRenderingData;\n\tgetViewLineRenderingData(lineNumber: number): ViewLineRenderingData;\n\tgetViewLineData(lineNumber: number): ViewLineData;\n\tgetMinimapLinesRenderingData(startLineNumber: number, endLineNumber: number, needed: boolean[]): MinimapLinesRenderingData;\n\tgetCompletelyVisibleViewRange(): Range;\n\tgetCompletelyVisibleViewRangeAtScrollTop(scrollTop: number): Range;\n\n\tgetHiddenAreas(): Range[];\n\n\tgetLineCount(): number;\n\tgetLineContent(lineNumber: number): string;\n\tgetLineLength(lineNumber: number): number;\n\tgetActiveIndentGuide(lineNumber: number, minLineNumber: number, maxLineNumber: number): IActiveIndentGuideInfo;\n\tgetLinesIndentGuides(startLineNumber: number, endLineNumber: number): number[];\n\tgetBracketGuidesInRangeByLine(startLineNumber: number, endLineNumber: number, activePosition: IPosition | null, options: BracketGuideOptions): IndentGuide[][];\n\tgetLineMinColumn(lineNumber: number): number;\n\tgetLineMaxColumn(lineNumber: number): number;\n\tgetLineFirstNonWhitespaceColumn(lineNumber: number): number;\n\tgetLineLastNonWhitespaceColumn(lineNumber: number): number;\n\tgetAllOverviewRulerDecorations(theme: EditorTheme): OverviewRulerDecorationsGroup[];\n\tgetValueInRange(range: Range, eol: EndOfLinePreference): string;\n\tgetValueLengthInRange(range: Range, eol: EndOfLinePreference): number;\n\tmodifyPosition(position: Position, offset: number): Position;\n\n\tgetInjectedTextAt(viewPosition: Position): InjectedText | null;\n\n\tdeduceModelPositionRelativeToViewPosition(viewAnchorPosition: Position, deltaOffset: number, lineFeedCnt: number): Position;\n\tgetPlainTextToCopy(modelRanges: Range[], emptySelectionClipboard: boolean, forceCRLF: boolean): string | string[];\n\tgetRichTextToCopy(modelRanges: Range[], emptySelectionClipboard: boolean): { html: string; mode: string } | null;\n\n\tcreateLineBreaksComputer(): ILineBreaksComputer;\n\n\t//#region cursor\n\tgetPrimaryCursorState(): CursorState;\n\tgetLastAddedCursorIndex(): number;\n\tgetCursorStates(): CursorState[];\n\tsetCursorStates(source: string | null | undefined, reason: CursorChangeReason, states: PartialCursorState[] | null): boolean;\n\tgetCursorColumnSelectData(): IColumnSelectData;\n\tgetCursorAutoClosedCharacters(): Range[];\n\tsetCursorColumnSelectData(columnSelectData: IColumnSelectData): void;\n\tgetPrevEditOperationType(): EditOperationType;\n\tsetPrevEditOperationType(type: EditOperationType): void;\n\trevealAllCursors(source: string | null | undefined, revealHorizontal: boolean, minimalReveal?: boolean): void;\n\trevealPrimaryCursor(source: string | null | undefined, revealHorizontal: boolean, minimalReveal?: boolean): void;\n\trevealTopMostCursor(source: string | null | undefined): void;\n\trevealBottomMostCursor(source: string | null | undefined): void;\n\trevealRange(source: string | null | undefined, revealHorizontal: boolean, viewRange: Range, verticalType: VerticalRevealType, scrollType: ScrollType): void;\n\t//#endregion\n\n\t//#region viewLayout\n\tchangeWhitespace(callback: (accessor: IWhitespaceChangeAccessor) => void): void;\n}\n\nexport interface IViewLayout {\n\n\tgetScrollable(): Scrollable;\n\n\tgetScrollWidth(): number;\n\tgetScrollHeight(): number;\n\n\tgetCurrentScrollLeft(): number;\n\tgetCurrentScrollTop(): number;\n\tgetCurrentViewport(): Viewport;\n\n\tgetFutureViewport(): Viewport;\n\n\tsetScrollPosition(position: INewScrollPosition, type: ScrollType): void;\n\tdeltaScrollNow(deltaScrollLeft: number, deltaScrollTop: number): void;\n\n\tvalidateScrollPosition(scrollPosition: INewScrollPosition): IScrollPosition;\n\n\tsetMaxLineWidth(maxLineWidth: number): void;\n\tsetOverlayWidgetsMinWidth(overlayWidgetsMinWidth: number): void;\n\n\tgetLinesViewportData(): IPartialViewLinesViewportData;\n\tgetWhitespaces(): IEditorWhitespace[];\n\n\tisAfterLines(verticalOffset: number): boolean;\n\tisInTopPadding(verticalOffset: number): boolean;\n\tisInBottomPadding(verticalOffset: number): boolean;\n\tgetLineNumberAtVerticalOffset(verticalOffset: number): number;\n\tgetVerticalOffsetForLineNumber(lineNumber: number, includeViewZones?: boolean): number;\n\tgetVerticalOffsetAfterLineNumber(lineNumber: number, includeViewZones?: boolean): number;\n\tgetWhitespaceAtVerticalOffset(verticalOffset: number): IViewWhitespaceViewportData | null;\n\n\t/**\n\t * Get the layout information for whitespaces currently in the viewport\n\t */\n\tgetWhitespaceViewportData(): IViewWhitespaceViewportData[];\n}\n\nexport interface IEditorWhitespace {\n\treadonly id: string;\n\treadonly afterLineNumber: number;\n\treadonly height: number;\n}\n\n/**\n * An accessor that allows for whitespace to be added, removed or changed in bulk.\n */\nexport interface IWhitespaceChangeAccessor {\n\tinsertWhitespace(afterLineNumber: number, ordinal: number, heightInPx: number, minWidth: number): string;\n\tchangeOneWhitespace(id: string, newAfterLineNumber: number, newHeight: number): void;\n\tremoveWhitespace(id: string): void;\n}\n\nexport interface IPartialViewLinesViewportData {\n\t/**\n\t * Value to be substracted from `scrollTop` (in order to vertical offset numbers < 1MM)\n\t */\n\treadonly bigNumbersDelta: number;\n\t/**\n\t * The first (partially) visible line number.\n\t */\n\treadonly startLineNumber: number;\n\t/**\n\t * The last (partially) visible line number.\n\t */\n\treadonly endLineNumber: number;\n\t/**\n\t * relativeVerticalOffset[i] is the `top` position for line at `i` + `startLineNumber`.\n\t */\n\treadonly relativeVerticalOffset: number[];\n\t/**\n\t * The centered line in the viewport.\n\t */\n\treadonly centeredLineNumber: number;\n\t/**\n\t * The first completely visible line number.\n\t */\n\treadonly completelyVisibleStartLineNumber: number;\n\t/**\n\t * The last completely visible line number.\n\t */\n\treadonly completelyVisibleEndLineNumber: number;\n\n\t/**\n\t * The height of a line.\n\t */\n\treadonly lineHeight: number;\n}\n\nexport interface IViewWhitespaceViewportData {\n\treadonly id: string;\n\treadonly afterLineNumber: number;\n\treadonly verticalOffset: number;\n\treadonly height: number;\n}\n\nexport class Viewport {\n\treadonly _viewportBrand: void = undefined;\n\n\treadonly top: number;\n\treadonly left: number;\n\treadonly width: number;\n\treadonly height: number;\n\n\tconstructor(top: number, left: number, width: number, height: number) {\n\t\tthis.top = top | 0;\n\t\tthis.left = left | 0;\n\t\tthis.width = width | 0;\n\t\tthis.height = height | 0;\n\t}\n}\n\nexport interface ICoordinatesConverter {\n\t// View -> Model conversion and related methods\n\tconvertViewPositionToModelPosition(viewPosition: Position): Position;\n\tconvertViewRangeToModelRange(viewRange: Range): Range;\n\tvalidateViewPosition(viewPosition: Position, expectedModelPosition: Position): Position;\n\tvalidateViewRange(viewRange: Range, expectedModelRange: Range): Range;\n\n\t// Model -> View conversion and related methods\n\t/**\n\t * @param allowZeroLineNumber Should it return 0 when there are hidden lines at the top and the position is in the hidden area?\n\t * @param belowHiddenRanges When the model position is in a hidden area, should it return the first view position after or before?\n\t */\n\tconvertModelPositionToViewPosition(modelPosition: Position, affinity?: PositionAffinity, allowZeroLineNumber?: boolean, belowHiddenRanges?: boolean): Position;\n\t/**\n\t * @param affinity Only has an effect if the range is empty.\n\t*/\n\tconvertModelRangeToViewRange(modelRange: Range, affinity?: PositionAffinity): Range;\n\tmodelPositionIsVisible(modelPosition: Position): boolean;\n\tgetModelLineViewLineCount(modelLineNumber: number): number;\n\tgetViewLineNumberOfModelPosition(modelLineNumber: number, modelColumn: number): number;\n}\n\nexport class MinimapLinesRenderingData {\n\tpublic readonly tabSize: number;\n\tpublic readonly data: Array;\n\n\tconstructor(\n\t\ttabSize: number,\n\t\tdata: Array\n\t) {\n\t\tthis.tabSize = tabSize;\n\t\tthis.data = data;\n\t}\n}\n\nexport class ViewLineData {\n\t_viewLineDataBrand: void = undefined;\n\n\t/**\n\t * The content at this view line.\n\t */\n\tpublic readonly content: string;\n\t/**\n\t * Does this line continue with a wrapped line?\n\t */\n\tpublic readonly continuesWithWrappedLine: boolean;\n\t/**\n\t * The minimum allowed column at this view line.\n\t */\n\tpublic readonly minColumn: number;\n\t/**\n\t * The maximum allowed column at this view line.\n\t */\n\tpublic readonly maxColumn: number;\n\t/**\n\t * The visible column at the start of the line (after the fauxIndent).\n\t */\n\tpublic readonly startVisibleColumn: number;\n\t/**\n\t * The tokens at this view line.\n\t */\n\tpublic readonly tokens: IViewLineTokens;\n\n\t/**\n\t * Additional inline decorations for this line.\n\t*/\n\tpublic readonly inlineDecorations: readonly SingleLineInlineDecoration[] | null;\n\n\tconstructor(\n\t\tcontent: string,\n\t\tcontinuesWithWrappedLine: boolean,\n\t\tminColumn: number,\n\t\tmaxColumn: number,\n\t\tstartVisibleColumn: number,\n\t\ttokens: IViewLineTokens,\n\t\tinlineDecorations: readonly SingleLineInlineDecoration[] | null\n\t) {\n\t\tthis.content = content;\n\t\tthis.continuesWithWrappedLine = continuesWithWrappedLine;\n\t\tthis.minColumn = minColumn;\n\t\tthis.maxColumn = maxColumn;\n\t\tthis.startVisibleColumn = startVisibleColumn;\n\t\tthis.tokens = tokens;\n\t\tthis.inlineDecorations = inlineDecorations;\n\t}\n}\n\nexport class ViewLineRenderingData {\n\t/**\n\t * The minimum allowed column at this view line.\n\t */\n\tpublic readonly minColumn: number;\n\t/**\n\t * The maximum allowed column at this view line.\n\t */\n\tpublic readonly maxColumn: number;\n\t/**\n\t * The content at this view line.\n\t */\n\tpublic readonly content: string;\n\t/**\n\t * Does this line continue with a wrapped line?\n\t */\n\tpublic readonly continuesWithWrappedLine: boolean;\n\t/**\n\t * Describes if `content` contains RTL characters.\n\t */\n\tpublic readonly containsRTL: boolean;\n\t/**\n\t * Describes if `content` contains non basic ASCII chars.\n\t */\n\tpublic readonly isBasicASCII: boolean;\n\t/**\n\t * The tokens at this view line.\n\t */\n\tpublic readonly tokens: IViewLineTokens;\n\t/**\n\t * Inline decorations at this view line.\n\t */\n\tpublic readonly inlineDecorations: InlineDecoration[];\n\t/**\n\t * The tab size for this view model.\n\t */\n\tpublic readonly tabSize: number;\n\t/**\n\t * The visible column at the start of the line (after the fauxIndent)\n\t */\n\tpublic readonly startVisibleColumn: number;\n\n\tconstructor(\n\t\tminColumn: number,\n\t\tmaxColumn: number,\n\t\tcontent: string,\n\t\tcontinuesWithWrappedLine: boolean,\n\t\tmightContainRTL: boolean,\n\t\tmightContainNonBasicASCII: boolean,\n\t\ttokens: IViewLineTokens,\n\t\tinlineDecorations: InlineDecoration[],\n\t\ttabSize: number,\n\t\tstartVisibleColumn: number,\n\t) {\n\t\tthis.minColumn = minColumn;\n\t\tthis.maxColumn = maxColumn;\n\t\tthis.content = content;\n\t\tthis.continuesWithWrappedLine = continuesWithWrappedLine;\n\n\t\tthis.isBasicASCII = ViewLineRenderingData.isBasicASCII(content, mightContainNonBasicASCII);\n\t\tthis.containsRTL = ViewLineRenderingData.containsRTL(content, this.isBasicASCII, mightContainRTL);\n\n\t\tthis.tokens = tokens;\n\t\tthis.inlineDecorations = inlineDecorations;\n\t\tthis.tabSize = tabSize;\n\t\tthis.startVisibleColumn = startVisibleColumn;\n\t}\n\n\tpublic static isBasicASCII(lineContent: string, mightContainNonBasicASCII: boolean): boolean {\n\t\tif (mightContainNonBasicASCII) {\n\t\t\treturn strings.isBasicASCII(lineContent);\n\t\t}\n\t\treturn true;\n\t}\n\n\tpublic static containsRTL(lineContent: string, isBasicASCII: boolean, mightContainRTL: boolean): boolean {\n\t\tif (!isBasicASCII && mightContainRTL) {\n\t\t\treturn strings.containsRTL(lineContent);\n\t\t}\n\t\treturn false;\n\t}\n}\n\nexport const enum InlineDecorationType {\n\tRegular = 0,\n\tBefore = 1,\n\tAfter = 2,\n\tRegularAffectingLetterSpacing = 3\n}\n\nexport class InlineDecoration {\n\tconstructor(\n\t\tpublic readonly range: Range,\n\t\tpublic readonly inlineClassName: string,\n\t\tpublic readonly type: InlineDecorationType\n\t) {\n\t}\n}\n\nexport class SingleLineInlineDecoration {\n\tconstructor(\n\t\tpublic readonly startOffset: number,\n\t\tpublic readonly endOffset: number,\n\t\tpublic readonly inlineClassName: string,\n\t\tpublic readonly inlineClassNameAffectsLetterSpacing: boolean\n\t) {\n\t}\n\n\ttoInlineDecoration(lineNumber: number): InlineDecoration {\n\t\treturn new InlineDecoration(\n\t\t\tnew Range(lineNumber, this.startOffset + 1, lineNumber, this.endOffset + 1),\n\t\t\tthis.inlineClassName,\n\t\t\tthis.inlineClassNameAffectsLetterSpacing ? InlineDecorationType.RegularAffectingLetterSpacing : InlineDecorationType.Regular\n\t\t);\n\t}\n}\n\nexport class ViewModelDecoration {\n\t_viewModelDecorationBrand: void = undefined;\n\n\tpublic readonly range: Range;\n\tpublic readonly options: IModelDecorationOptions;\n\n\tconstructor(range: Range, options: IModelDecorationOptions) {\n\t\tthis.range = range;\n\t\tthis.options = options;\n\t}\n}\n\nexport class OverviewRulerDecorationsGroup {\n\n\tconstructor(\n\t\tpublic readonly color: string,\n\t\tpublic readonly zIndex: number,\n\t\t/**\n\t\t * Decorations are encoded in a number array using the following scheme:\n\t\t * - 3*i = lane\n\t\t * - 3*i+1 = startLineNumber\n\t\t * - 3*i+2 = endLineNumber\n\t\t */\n\t\tpublic readonly data: number[]\n\t) { }\n\n\tpublic static compareByRenderingProps(a: OverviewRulerDecorationsGroup, b: OverviewRulerDecorationsGroup): number {\n\t\tif (a.zIndex === b.zIndex) {\n\t\t\tif (a.color < b.color) {\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t\tif (a.color > b.color) {\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\treturn 0;\n\t\t}\n\t\treturn a.zIndex - b.zIndex;\n\t}\n\n\tpublic static equals(a: OverviewRulerDecorationsGroup, b: OverviewRulerDecorationsGroup): boolean {\n\t\treturn (\n\t\t\ta.color === b.color\n\t\t\t&& a.zIndex === b.zIndex\n\t\t\t&& arrays.equals(a.data, b.data)\n\t\t);\n\t}\n\n\tpublic static equalsArr(a: OverviewRulerDecorationsGroup[], b: OverviewRulerDecorationsGroup[]): boolean {\n\t\treturn arrays.equals(a, b, OverviewRulerDecorationsGroup.equals);\n\t}\n}\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\nimport { Range } from 'vs/editor/common/core/range';\nimport { GlyphMarginLane, IGlyphMarginLanesModel } from 'vs/editor/common/model';\n\n\nconst MAX_LANE = GlyphMarginLane.Right;\n\nexport class GlyphMarginLanesModel implements IGlyphMarginLanesModel {\n\tprivate lanes: Uint8Array;\n\tprivate persist = 0;\n\tprivate _requiredLanes = 1; // always render at least one lane\n\n\tconstructor(maxLine: number) {\n\t\tthis.lanes = new Uint8Array(Math.ceil(((maxLine + 1) * MAX_LANE) / 8));\n\t}\n\n\tpublic reset(maxLine: number) {\n\t\tconst bytes = Math.ceil(((maxLine + 1) * MAX_LANE) / 8);\n\t\tif (this.lanes.length < bytes) {\n\t\t\tthis.lanes = new Uint8Array(bytes);\n\t\t} else {\n\t\t\tthis.lanes.fill(0);\n\t\t}\n\t\tthis._requiredLanes = 1;\n\t}\n\n\tpublic get requiredLanes() {\n\t\treturn this._requiredLanes;\n\t}\n\n\tpublic push(lane: GlyphMarginLane, range: Range, persist?: boolean): void {\n\t\tif (persist) {\n\t\t\tthis.persist |= (1 << (lane - 1));\n\t\t}\n\t\tfor (let i = range.startLineNumber; i <= range.endLineNumber; i++) {\n\t\t\tconst bit = (MAX_LANE * i) + (lane - 1);\n\t\t\tthis.lanes[bit >>> 3] |= (1 << (bit % 8));\n\t\t\tthis._requiredLanes = Math.max(this._requiredLanes, this.countAtLine(i));\n\t\t}\n\t}\n\n\tpublic getLanesAtLine(lineNumber: number): GlyphMarginLane[] {\n\t\tconst lanes: GlyphMarginLane[] = [];\n\t\tlet bit = MAX_LANE * lineNumber;\n\t\tfor (let i = 0; i < MAX_LANE; i++) {\n\t\t\tif (this.persist & (1 << i) || this.lanes[bit >>> 3] & (1 << (bit % 8))) {\n\t\t\t\tlanes.push(i + 1);\n\t\t\t}\n\t\t\tbit++;\n\t\t}\n\n\t\treturn lanes.length ? lanes : [GlyphMarginLane.Center];\n\t}\n\n\tprivate countAtLine(lineNumber: number): number {\n\t\tlet bit = MAX_LANE * lineNumber;\n\t\tlet count = 0;\n\t\tfor (let i = 0; i < MAX_LANE; i++) {\n\t\t\tif (this.persist & (1 << i) || this.lanes[bit >>> 3] & (1 << (bit % 8))) {\n\t\t\t\tcount++;\n\t\t\t}\n\t\t\tbit++;\n\t\t}\n\t\treturn count;\n\t}\n}\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\nimport { LineTokens } from 'vs/editor/common/tokens/lineTokens';\nimport { Position } from 'vs/editor/common/core/position';\nimport { IRange } from 'vs/editor/common/core/range';\nimport { EndOfLinePreference, ITextModel, PositionAffinity } from 'vs/editor/common/model';\nimport { LineInjectedText } from 'vs/editor/common/textModelEvents';\nimport { InjectedText, ModelLineProjectionData } from 'vs/editor/common/modelLineProjectionData';\nimport { SingleLineInlineDecoration, ViewLineData } from 'vs/editor/common/viewModel';\n\nexport interface IModelLineProjection {\n\tisVisible(): boolean;\n\n\t/**\n\t * This invalidates the current instance (potentially reuses and returns it again).\n\t*/\n\tsetVisible(isVisible: boolean): IModelLineProjection;\n\n\tgetProjectionData(): ModelLineProjectionData | null;\n\tgetViewLineCount(): number;\n\tgetViewLineContent(model: ISimpleModel, modelLineNumber: number, outputLineIndex: number): string;\n\tgetViewLineLength(model: ISimpleModel, modelLineNumber: number, outputLineIndex: number): number;\n\tgetViewLineMinColumn(model: ISimpleModel, modelLineNumber: number, outputLineIndex: number): number;\n\tgetViewLineMaxColumn(model: ISimpleModel, modelLineNumber: number, outputLineIndex: number): number;\n\tgetViewLineData(model: ISimpleModel, modelLineNumber: number, outputLineIndex: number): ViewLineData;\n\tgetViewLinesData(model: ISimpleModel, modelLineNumber: number, outputLineIdx: number, lineCount: number, globalStartIndex: number, needed: boolean[], result: Array): void;\n\n\tgetModelColumnOfViewPosition(outputLineIndex: number, outputColumn: number): number;\n\tgetViewPositionOfModelPosition(deltaLineNumber: number, inputColumn: number, affinity?: PositionAffinity): Position;\n\tgetViewLineNumberOfModelPosition(deltaLineNumber: number, inputColumn: number): number;\n\tnormalizePosition(outputLineIndex: number, outputPosition: Position, affinity: PositionAffinity): Position;\n\n\tgetInjectedTextAt(outputLineIndex: number, column: number): InjectedText | null;\n}\n\nexport interface ISimpleModel {\n\ttokenization: {\n\t\tgetLineTokens(lineNumber: number): LineTokens;\n\t};\n\tgetLineContent(lineNumber: number): string;\n\tgetLineLength(lineNumber: number): number;\n\tgetLineMinColumn(lineNumber: number): number;\n\tgetLineMaxColumn(lineNumber: number): number;\n\tgetValueInRange(range: IRange, eol?: EndOfLinePreference): string;\n}\n\nexport function createModelLineProjection(lineBreakData: ModelLineProjectionData | null, isVisible: boolean): IModelLineProjection {\n\tif (lineBreakData === null) {\n\t\t// No mapping needed\n\t\tif (isVisible) {\n\t\t\treturn IdentityModelLineProjection.INSTANCE;\n\t\t}\n\t\treturn HiddenModelLineProjection.INSTANCE;\n\t} else {\n\t\treturn new ModelLineProjection(lineBreakData, isVisible);\n\t}\n}\n\n/**\n * This projection is used to\n * * wrap model lines\n * * inject text\n */\nclass ModelLineProjection implements IModelLineProjection {\n\tprivate readonly _projectionData: ModelLineProjectionData;\n\tprivate _isVisible: boolean;\n\n\tconstructor(lineBreakData: ModelLineProjectionData, isVisible: boolean) {\n\t\tthis._projectionData = lineBreakData;\n\t\tthis._isVisible = isVisible;\n\t}\n\n\tpublic isVisible(): boolean {\n\t\treturn this._isVisible;\n\t}\n\n\tpublic setVisible(isVisible: boolean): IModelLineProjection {\n\t\tthis._isVisible = isVisible;\n\t\treturn this;\n\t}\n\n\tpublic getProjectionData(): ModelLineProjectionData | null {\n\t\treturn this._projectionData;\n\t}\n\n\tpublic getViewLineCount(): number {\n\t\tif (!this._isVisible) {\n\t\t\treturn 0;\n\t\t}\n\t\treturn this._projectionData.getOutputLineCount();\n\t}\n\n\tpublic getViewLineContent(model: ISimpleModel, modelLineNumber: number, outputLineIndex: number): string {\n\t\tthis._assertVisible();\n\n\t\tconst startOffsetInInputWithInjections = outputLineIndex > 0 ? this._projectionData.breakOffsets[outputLineIndex - 1] : 0;\n\t\tconst endOffsetInInputWithInjections = this._projectionData.breakOffsets[outputLineIndex];\n\n\t\tlet r: string;\n\t\tif (this._projectionData.injectionOffsets !== null) {\n\t\t\tconst injectedTexts = this._projectionData.injectionOffsets.map(\n\t\t\t\t(offset, idx) => new LineInjectedText(\n\t\t\t\t\t0,\n\t\t\t\t\t0,\n\t\t\t\t\toffset + 1,\n\t\t\t\t\tthis._projectionData.injectionOptions![idx],\n\t\t\t\t\t0\n\t\t\t\t)\n\t\t\t);\n\t\t\tconst lineWithInjections = LineInjectedText.applyInjectedText(\n\t\t\t\tmodel.getLineContent(modelLineNumber),\n\t\t\t\tinjectedTexts\n\t\t\t);\n\t\t\tr = lineWithInjections.substring(startOffsetInInputWithInjections, endOffsetInInputWithInjections);\n\t\t} else {\n\t\t\tr = model.getValueInRange({\n\t\t\t\tstartLineNumber: modelLineNumber,\n\t\t\t\tstartColumn: startOffsetInInputWithInjections + 1,\n\t\t\t\tendLineNumber: modelLineNumber,\n\t\t\t\tendColumn: endOffsetInInputWithInjections + 1\n\t\t\t});\n\t\t}\n\n\t\tif (outputLineIndex > 0) {\n\t\t\tr = spaces(this._projectionData.wrappedTextIndentLength) + r;\n\t\t}\n\n\t\treturn r;\n\t}\n\n\tpublic getViewLineLength(model: ISimpleModel, modelLineNumber: number, outputLineIndex: number): number {\n\t\tthis._assertVisible();\n\t\treturn this._projectionData.getLineLength(outputLineIndex);\n\t}\n\n\tpublic getViewLineMinColumn(_model: ITextModel, _modelLineNumber: number, outputLineIndex: number): number {\n\t\tthis._assertVisible();\n\t\treturn this._projectionData.getMinOutputOffset(outputLineIndex) + 1;\n\t}\n\n\tpublic getViewLineMaxColumn(model: ISimpleModel, modelLineNumber: number, outputLineIndex: number): number {\n\t\tthis._assertVisible();\n\t\treturn this._projectionData.getMaxOutputOffset(outputLineIndex) + 1;\n\t}\n\n\t/**\n\t * Try using {@link getViewLinesData} instead.\n\t*/\n\tpublic getViewLineData(model: ISimpleModel, modelLineNumber: number, outputLineIndex: number): ViewLineData {\n\t\tconst arr = new Array();\n\t\tthis.getViewLinesData(model, modelLineNumber, outputLineIndex, 1, 0, [true], arr);\n\t\treturn arr[0];\n\t}\n\n\tpublic getViewLinesData(model: ISimpleModel, modelLineNumber: number, outputLineIdx: number, lineCount: number, globalStartIndex: number, needed: boolean[], result: Array): void {\n\t\tthis._assertVisible();\n\n\t\tconst lineBreakData = this._projectionData;\n\n\t\tconst injectionOffsets = lineBreakData.injectionOffsets;\n\t\tconst injectionOptions = lineBreakData.injectionOptions;\n\n\t\tlet inlineDecorationsPerOutputLine: SingleLineInlineDecoration[][] | null = null;\n\n\t\tif (injectionOffsets) {\n\t\t\tinlineDecorationsPerOutputLine = [];\n\t\t\tlet totalInjectedTextLengthBefore = 0;\n\t\t\tlet currentInjectedOffset = 0;\n\n\t\t\tfor (let outputLineIndex = 0; outputLineIndex < lineBreakData.getOutputLineCount(); outputLineIndex++) {\n\t\t\t\tconst inlineDecorations = new Array();\n\t\t\t\tinlineDecorationsPerOutputLine[outputLineIndex] = inlineDecorations;\n\n\t\t\t\tconst lineStartOffsetInInputWithInjections = outputLineIndex > 0 ? lineBreakData.breakOffsets[outputLineIndex - 1] : 0;\n\t\t\t\tconst lineEndOffsetInInputWithInjections = lineBreakData.breakOffsets[outputLineIndex];\n\n\t\t\t\twhile (currentInjectedOffset < injectionOffsets.length) {\n\t\t\t\t\tconst length = injectionOptions![currentInjectedOffset].content.length;\n\t\t\t\t\tconst injectedTextStartOffsetInInputWithInjections = injectionOffsets[currentInjectedOffset] + totalInjectedTextLengthBefore;\n\t\t\t\t\tconst injectedTextEndOffsetInInputWithInjections = injectedTextStartOffsetInInputWithInjections + length;\n\n\t\t\t\t\tif (injectedTextStartOffsetInInputWithInjections > lineEndOffsetInInputWithInjections) {\n\t\t\t\t\t\t// Injected text only starts in later wrapped lines.\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (lineStartOffsetInInputWithInjections < injectedTextEndOffsetInInputWithInjections) {\n\t\t\t\t\t\t// Injected text ends after or in this line (but also starts in or before this line).\n\t\t\t\t\t\tconst options = injectionOptions![currentInjectedOffset];\n\t\t\t\t\t\tif (options.inlineClassName) {\n\t\t\t\t\t\t\tconst offset = (outputLineIndex > 0 ? lineBreakData.wrappedTextIndentLength : 0);\n\t\t\t\t\t\t\tconst start = offset + Math.max(injectedTextStartOffsetInInputWithInjections - lineStartOffsetInInputWithInjections, 0);\n\t\t\t\t\t\t\tconst end = offset + Math.min(injectedTextEndOffsetInInputWithInjections - lineStartOffsetInInputWithInjections, lineEndOffsetInInputWithInjections - lineStartOffsetInInputWithInjections);\n\t\t\t\t\t\t\tif (start !== end) {\n\t\t\t\t\t\t\t\tinlineDecorations.push(new SingleLineInlineDecoration(start, end, options.inlineClassName, options.inlineClassNameAffectsLetterSpacing!));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (injectedTextEndOffsetInInputWithInjections <= lineEndOffsetInInputWithInjections) {\n\t\t\t\t\t\ttotalInjectedTextLengthBefore += length;\n\t\t\t\t\t\tcurrentInjectedOffset++;\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// injected text breaks into next line, process it again\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tlet lineWithInjections: LineTokens;\n\t\tif (injectionOffsets) {\n\t\t\tlineWithInjections = model.tokenization.getLineTokens(modelLineNumber).withInserted(injectionOffsets.map((offset, idx) => ({\n\t\t\t\toffset,\n\t\t\t\ttext: injectionOptions![idx].content,\n\t\t\t\ttokenMetadata: LineTokens.defaultTokenMetadata\n\t\t\t})));\n\t\t} else {\n\t\t\tlineWithInjections = model.tokenization.getLineTokens(modelLineNumber);\n\t\t}\n\n\t\tfor (let outputLineIndex = outputLineIdx; outputLineIndex < outputLineIdx + lineCount; outputLineIndex++) {\n\t\t\tconst globalIndex = globalStartIndex + outputLineIndex - outputLineIdx;\n\t\t\tif (!needed[globalIndex]) {\n\t\t\t\tresult[globalIndex] = null;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tresult[globalIndex] = this._getViewLineData(lineWithInjections, inlineDecorationsPerOutputLine ? inlineDecorationsPerOutputLine[outputLineIndex] : null, outputLineIndex);\n\t\t}\n\t}\n\n\tprivate _getViewLineData(lineWithInjections: LineTokens, inlineDecorations: null | SingleLineInlineDecoration[], outputLineIndex: number): ViewLineData {\n\t\tthis._assertVisible();\n\t\tconst lineBreakData = this._projectionData;\n\t\tconst deltaStartIndex = (outputLineIndex > 0 ? lineBreakData.wrappedTextIndentLength : 0);\n\n\t\tconst lineStartOffsetInInputWithInjections = outputLineIndex > 0 ? lineBreakData.breakOffsets[outputLineIndex - 1] : 0;\n\t\tconst lineEndOffsetInInputWithInjections = lineBreakData.breakOffsets[outputLineIndex];\n\t\tconst tokens = lineWithInjections.sliceAndInflate(lineStartOffsetInInputWithInjections, lineEndOffsetInInputWithInjections, deltaStartIndex);\n\n\t\tlet lineContent = tokens.getLineContent();\n\t\tif (outputLineIndex > 0) {\n\t\t\tlineContent = spaces(lineBreakData.wrappedTextIndentLength) + lineContent;\n\t\t}\n\n\t\tconst minColumn = this._projectionData.getMinOutputOffset(outputLineIndex) + 1;\n\t\tconst maxColumn = lineContent.length + 1;\n\t\tconst continuesWithWrappedLine = (outputLineIndex + 1 < this.getViewLineCount());\n\t\tconst startVisibleColumn = (outputLineIndex === 0 ? 0 : lineBreakData.breakOffsetsVisibleColumn[outputLineIndex - 1]);\n\n\t\treturn new ViewLineData(\n\t\t\tlineContent,\n\t\t\tcontinuesWithWrappedLine,\n\t\t\tminColumn,\n\t\t\tmaxColumn,\n\t\t\tstartVisibleColumn,\n\t\t\ttokens,\n\t\t\tinlineDecorations\n\t\t);\n\t}\n\n\tpublic getModelColumnOfViewPosition(outputLineIndex: number, outputColumn: number): number {\n\t\tthis._assertVisible();\n\t\treturn this._projectionData.translateToInputOffset(outputLineIndex, outputColumn - 1) + 1;\n\t}\n\n\tpublic getViewPositionOfModelPosition(deltaLineNumber: number, inputColumn: number, affinity: PositionAffinity = PositionAffinity.None): Position {\n\t\tthis._assertVisible();\n\t\tconst r = this._projectionData.translateToOutputPosition(inputColumn - 1, affinity);\n\t\treturn r.toPosition(deltaLineNumber);\n\t}\n\n\tpublic getViewLineNumberOfModelPosition(deltaLineNumber: number, inputColumn: number): number {\n\t\tthis._assertVisible();\n\t\tconst r = this._projectionData.translateToOutputPosition(inputColumn - 1);\n\t\treturn deltaLineNumber + r.outputLineIndex;\n\t}\n\n\tpublic normalizePosition(outputLineIndex: number, outputPosition: Position, affinity: PositionAffinity): Position {\n\t\tconst baseViewLineNumber = outputPosition.lineNumber - outputLineIndex;\n\t\tconst normalizedOutputPosition = this._projectionData.normalizeOutputPosition(outputLineIndex, outputPosition.column - 1, affinity);\n\t\tconst result = normalizedOutputPosition.toPosition(baseViewLineNumber);\n\t\treturn result;\n\t}\n\n\tpublic getInjectedTextAt(outputLineIndex: number, outputColumn: number): InjectedText | null {\n\t\treturn this._projectionData.getInjectedText(outputLineIndex, outputColumn - 1);\n\t}\n\n\tprivate _assertVisible() {\n\t\tif (!this._isVisible) {\n\t\t\tthrow new Error('Not supported');\n\t\t}\n\t}\n}\n\n/**\n * This projection does not change the model line.\n*/\nclass IdentityModelLineProjection implements IModelLineProjection {\n\tpublic static readonly INSTANCE = new IdentityModelLineProjection();\n\n\tprivate constructor() { }\n\n\tpublic isVisible(): boolean {\n\t\treturn true;\n\t}\n\n\tpublic setVisible(isVisible: boolean): IModelLineProjection {\n\t\tif (isVisible) {\n\t\t\treturn this;\n\t\t}\n\t\treturn HiddenModelLineProjection.INSTANCE;\n\t}\n\n\tpublic getProjectionData(): ModelLineProjectionData | null {\n\t\treturn null;\n\t}\n\n\tpublic getViewLineCount(): number {\n\t\treturn 1;\n\t}\n\n\tpublic getViewLineContent(model: ISimpleModel, modelLineNumber: number, _outputLineIndex: number): string {\n\t\treturn model.getLineContent(modelLineNumber);\n\t}\n\n\tpublic getViewLineLength(model: ISimpleModel, modelLineNumber: number, _outputLineIndex: number): number {\n\t\treturn model.getLineLength(modelLineNumber);\n\t}\n\n\tpublic getViewLineMinColumn(model: ISimpleModel, modelLineNumber: number, _outputLineIndex: number): number {\n\t\treturn model.getLineMinColumn(modelLineNumber);\n\t}\n\n\tpublic getViewLineMaxColumn(model: ISimpleModel, modelLineNumber: number, _outputLineIndex: number): number {\n\t\treturn model.getLineMaxColumn(modelLineNumber);\n\t}\n\n\tpublic getViewLineData(model: ISimpleModel, modelLineNumber: number, _outputLineIndex: number): ViewLineData {\n\t\tconst lineTokens = model.tokenization.getLineTokens(modelLineNumber);\n\t\tconst lineContent = lineTokens.getLineContent();\n\t\treturn new ViewLineData(\n\t\t\tlineContent,\n\t\t\tfalse,\n\t\t\t1,\n\t\t\tlineContent.length + 1,\n\t\t\t0,\n\t\t\tlineTokens.inflate(),\n\t\t\tnull\n\t\t);\n\t}\n\n\tpublic getViewLinesData(model: ISimpleModel, modelLineNumber: number, _fromOuputLineIndex: number, _toOutputLineIndex: number, globalStartIndex: number, needed: boolean[], result: Array): void {\n\t\tif (!needed[globalStartIndex]) {\n\t\t\tresult[globalStartIndex] = null;\n\t\t\treturn;\n\t\t}\n\t\tresult[globalStartIndex] = this.getViewLineData(model, modelLineNumber, 0);\n\t}\n\n\tpublic getModelColumnOfViewPosition(_outputLineIndex: number, outputColumn: number): number {\n\t\treturn outputColumn;\n\t}\n\n\tpublic getViewPositionOfModelPosition(deltaLineNumber: number, inputColumn: number): Position {\n\t\treturn new Position(deltaLineNumber, inputColumn);\n\t}\n\n\tpublic getViewLineNumberOfModelPosition(deltaLineNumber: number, _inputColumn: number): number {\n\t\treturn deltaLineNumber;\n\t}\n\n\tpublic normalizePosition(outputLineIndex: number, outputPosition: Position, affinity: PositionAffinity): Position {\n\t\treturn outputPosition;\n\t}\n\n\tpublic getInjectedTextAt(_outputLineIndex: number, _outputColumn: number): InjectedText | null {\n\t\treturn null;\n\t}\n}\n\n/**\n * This projection hides the model line.\n */\nclass HiddenModelLineProjection implements IModelLineProjection {\n\tpublic static readonly INSTANCE = new HiddenModelLineProjection();\n\n\tprivate constructor() { }\n\n\tpublic isVisible(): boolean {\n\t\treturn false;\n\t}\n\n\tpublic setVisible(isVisible: boolean): IModelLineProjection {\n\t\tif (!isVisible) {\n\t\t\treturn this;\n\t\t}\n\t\treturn IdentityModelLineProjection.INSTANCE;\n\t}\n\n\tpublic getProjectionData(): ModelLineProjectionData | null {\n\t\treturn null;\n\t}\n\n\tpublic getViewLineCount(): number {\n\t\treturn 0;\n\t}\n\n\tpublic getViewLineContent(_model: ISimpleModel, _modelLineNumber: number, _outputLineIndex: number): string {\n\t\tthrow new Error('Not supported');\n\t}\n\n\tpublic getViewLineLength(_model: ISimpleModel, _modelLineNumber: number, _outputLineIndex: number): number {\n\t\tthrow new Error('Not supported');\n\t}\n\n\tpublic getViewLineMinColumn(_model: ISimpleModel, _modelLineNumber: number, _outputLineIndex: number): number {\n\t\tthrow new Error('Not supported');\n\t}\n\n\tpublic getViewLineMaxColumn(_model: ISimpleModel, _modelLineNumber: number, _outputLineIndex: number): number {\n\t\tthrow new Error('Not supported');\n\t}\n\n\tpublic getViewLineData(_model: ISimpleModel, _modelLineNumber: number, _outputLineIndex: number): ViewLineData {\n\t\tthrow new Error('Not supported');\n\t}\n\n\tpublic getViewLinesData(_model: ISimpleModel, _modelLineNumber: number, _fromOuputLineIndex: number, _toOutputLineIndex: number, _globalStartIndex: number, _needed: boolean[], _result: ViewLineData[]): void {\n\t\tthrow new Error('Not supported');\n\t}\n\n\tpublic getModelColumnOfViewPosition(_outputLineIndex: number, _outputColumn: number): number {\n\t\tthrow new Error('Not supported');\n\t}\n\n\tpublic getViewPositionOfModelPosition(_deltaLineNumber: number, _inputColumn: number): Position {\n\t\tthrow new Error('Not supported');\n\t}\n\n\tpublic getViewLineNumberOfModelPosition(_deltaLineNumber: number, _inputColumn: number): number {\n\t\tthrow new Error('Not supported');\n\t}\n\n\tpublic normalizePosition(outputLineIndex: number, outputPosition: Position, affinity: PositionAffinity): Position {\n\t\tthrow new Error('Not supported');\n\t}\n\n\tpublic getInjectedTextAt(_outputLineIndex: number, _outputColumn: number): InjectedText | null {\n\t\tthrow new Error('Not supported');\n\t}\n}\n\nconst _spaces: string[] = [''];\nfunction spaces(count: number): string {\n\tif (count >= _spaces.length) {\n\t\tfor (let i = 1; i <= count; i++) {\n\t\t\t_spaces[i] = _makeSpaces(i);\n\t\t}\n\t}\n\treturn _spaces[count];\n}\n\nfunction _makeSpaces(count: number): string {\n\treturn new Array(count + 1).join(' ');\n}\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\nimport { CharCode } from 'vs/base/common/charCode';\nimport * as strings from 'vs/base/common/strings';\nimport { WrappingIndent, IComputedEditorOptions, EditorOption } from 'vs/editor/common/config/editorOptions';\nimport { CharacterClassifier } from 'vs/editor/common/core/characterClassifier';\nimport { FontInfo } from 'vs/editor/common/config/fontInfo';\nimport { LineInjectedText } from 'vs/editor/common/textModelEvents';\nimport { InjectedTextOptions } from 'vs/editor/common/model';\nimport { ILineBreaksComputerFactory, ILineBreaksComputer, ModelLineProjectionData } from 'vs/editor/common/modelLineProjectionData';\n\nexport class MonospaceLineBreaksComputerFactory implements ILineBreaksComputerFactory {\n\tpublic static create(options: IComputedEditorOptions): MonospaceLineBreaksComputerFactory {\n\t\treturn new MonospaceLineBreaksComputerFactory(\n\t\t\toptions.get(EditorOption.wordWrapBreakBeforeCharacters),\n\t\t\toptions.get(EditorOption.wordWrapBreakAfterCharacters)\n\t\t);\n\t}\n\n\tprivate readonly classifier: WrappingCharacterClassifier;\n\n\tconstructor(breakBeforeChars: string, breakAfterChars: string) {\n\t\tthis.classifier = new WrappingCharacterClassifier(breakBeforeChars, breakAfterChars);\n\t}\n\n\tpublic createLineBreaksComputer(fontInfo: FontInfo, tabSize: number, wrappingColumn: number, wrappingIndent: WrappingIndent, wordBreak: 'normal' | 'keepAll'): ILineBreaksComputer {\n\t\tconst requests: string[] = [];\n\t\tconst injectedTexts: (LineInjectedText[] | null)[] = [];\n\t\tconst previousBreakingData: (ModelLineProjectionData | null)[] = [];\n\t\treturn {\n\t\t\taddRequest: (lineText: string, injectedText: LineInjectedText[] | null, previousLineBreakData: ModelLineProjectionData | null) => {\n\t\t\t\trequests.push(lineText);\n\t\t\t\tinjectedTexts.push(injectedText);\n\t\t\t\tpreviousBreakingData.push(previousLineBreakData);\n\t\t\t},\n\t\t\tfinalize: () => {\n\t\t\t\tconst columnsForFullWidthChar = fontInfo.typicalFullwidthCharacterWidth / fontInfo.typicalHalfwidthCharacterWidth;\n\t\t\t\tconst result: (ModelLineProjectionData | null)[] = [];\n\t\t\t\tfor (let i = 0, len = requests.length; i < len; i++) {\n\t\t\t\t\tconst injectedText = injectedTexts[i];\n\t\t\t\t\tconst previousLineBreakData = previousBreakingData[i];\n\t\t\t\t\tif (previousLineBreakData && !previousLineBreakData.injectionOptions && !injectedText) {\n\t\t\t\t\t\tresult[i] = createLineBreaksFromPreviousLineBreaks(this.classifier, previousLineBreakData, requests[i], tabSize, wrappingColumn, columnsForFullWidthChar, wrappingIndent, wordBreak);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tresult[i] = createLineBreaks(this.classifier, requests[i], injectedText, tabSize, wrappingColumn, columnsForFullWidthChar, wrappingIndent, wordBreak);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tarrPool1.length = 0;\n\t\t\t\tarrPool2.length = 0;\n\t\t\t\treturn result;\n\t\t\t}\n\t\t};\n\t}\n}\n\nconst enum CharacterClass {\n\tNONE = 0,\n\tBREAK_BEFORE = 1,\n\tBREAK_AFTER = 2,\n\tBREAK_IDEOGRAPHIC = 3 // for Han and Kana.\n}\n\nclass WrappingCharacterClassifier extends CharacterClassifier {\n\n\tconstructor(BREAK_BEFORE: string, BREAK_AFTER: string) {\n\t\tsuper(CharacterClass.NONE);\n\n\t\tfor (let i = 0; i < BREAK_BEFORE.length; i++) {\n\t\t\tthis.set(BREAK_BEFORE.charCodeAt(i), CharacterClass.BREAK_BEFORE);\n\t\t}\n\n\t\tfor (let i = 0; i < BREAK_AFTER.length; i++) {\n\t\t\tthis.set(BREAK_AFTER.charCodeAt(i), CharacterClass.BREAK_AFTER);\n\t\t}\n\t}\n\n\tpublic override get(charCode: number): CharacterClass {\n\t\tif (charCode >= 0 && charCode < 256) {\n\t\t\treturn this._asciiMap[charCode];\n\t\t} else {\n\t\t\t// Initialize CharacterClass.BREAK_IDEOGRAPHIC for these Unicode ranges:\n\t\t\t// 1. CJK Unified Ideographs (0x4E00 -- 0x9FFF)\n\t\t\t// 2. CJK Unified Ideographs Extension A (0x3400 -- 0x4DBF)\n\t\t\t// 3. Hiragana and Katakana (0x3040 -- 0x30FF)\n\t\t\tif (\n\t\t\t\t(charCode >= 0x3040 && charCode <= 0x30FF)\n\t\t\t\t|| (charCode >= 0x3400 && charCode <= 0x4DBF)\n\t\t\t\t|| (charCode >= 0x4E00 && charCode <= 0x9FFF)\n\t\t\t) {\n\t\t\t\treturn CharacterClass.BREAK_IDEOGRAPHIC;\n\t\t\t}\n\n\t\t\treturn (this._map.get(charCode) || this._defaultValue);\n\t\t}\n\t}\n}\n\nlet arrPool1: number[] = [];\nlet arrPool2: number[] = [];\n\nfunction createLineBreaksFromPreviousLineBreaks(classifier: WrappingCharacterClassifier, previousBreakingData: ModelLineProjectionData, lineText: string, tabSize: number, firstLineBreakColumn: number, columnsForFullWidthChar: number, wrappingIndent: WrappingIndent, wordBreak: 'normal' | 'keepAll'): ModelLineProjectionData | null {\n\tif (firstLineBreakColumn === -1) {\n\t\treturn null;\n\t}\n\n\tconst len = lineText.length;\n\tif (len <= 1) {\n\t\treturn null;\n\t}\n\n\tconst isKeepAll = (wordBreak === 'keepAll');\n\n\tconst prevBreakingOffsets = previousBreakingData.breakOffsets;\n\tconst prevBreakingOffsetsVisibleColumn = previousBreakingData.breakOffsetsVisibleColumn;\n\n\tconst wrappedTextIndentLength = computeWrappedTextIndentLength(lineText, tabSize, firstLineBreakColumn, columnsForFullWidthChar, wrappingIndent);\n\tconst wrappedLineBreakColumn = firstLineBreakColumn - wrappedTextIndentLength;\n\n\tconst breakingOffsets: number[] = arrPool1;\n\tconst breakingOffsetsVisibleColumn: number[] = arrPool2;\n\tlet breakingOffsetsCount = 0;\n\tlet lastBreakingOffset = 0;\n\tlet lastBreakingOffsetVisibleColumn = 0;\n\n\tlet breakingColumn = firstLineBreakColumn;\n\tconst prevLen = prevBreakingOffsets.length;\n\tlet prevIndex = 0;\n\n\tif (prevIndex >= 0) {\n\t\tlet bestDistance = Math.abs(prevBreakingOffsetsVisibleColumn[prevIndex] - breakingColumn);\n\t\twhile (prevIndex + 1 < prevLen) {\n\t\t\tconst distance = Math.abs(prevBreakingOffsetsVisibleColumn[prevIndex + 1] - breakingColumn);\n\t\t\tif (distance >= bestDistance) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tbestDistance = distance;\n\t\t\tprevIndex++;\n\t\t}\n\t}\n\n\twhile (prevIndex < prevLen) {\n\t\t// Allow for prevIndex to be -1 (for the case where we hit a tab when walking backwards from the first break)\n\t\tlet prevBreakOffset = prevIndex < 0 ? 0 : prevBreakingOffsets[prevIndex];\n\t\tlet prevBreakOffsetVisibleColumn = prevIndex < 0 ? 0 : prevBreakingOffsetsVisibleColumn[prevIndex];\n\t\tif (lastBreakingOffset > prevBreakOffset) {\n\t\t\tprevBreakOffset = lastBreakingOffset;\n\t\t\tprevBreakOffsetVisibleColumn = lastBreakingOffsetVisibleColumn;\n\t\t}\n\n\t\tlet breakOffset = 0;\n\t\tlet breakOffsetVisibleColumn = 0;\n\n\t\tlet forcedBreakOffset = 0;\n\t\tlet forcedBreakOffsetVisibleColumn = 0;\n\n\t\t// initially, we search as much as possible to the right (if it fits)\n\t\tif (prevBreakOffsetVisibleColumn <= breakingColumn) {\n\t\t\tlet visibleColumn = prevBreakOffsetVisibleColumn;\n\t\t\tlet prevCharCode = prevBreakOffset === 0 ? CharCode.Null : lineText.charCodeAt(prevBreakOffset - 1);\n\t\t\tlet prevCharCodeClass = prevBreakOffset === 0 ? CharacterClass.NONE : classifier.get(prevCharCode);\n\t\t\tlet entireLineFits = true;\n\t\t\tfor (let i = prevBreakOffset; i < len; i++) {\n\t\t\t\tconst charStartOffset = i;\n\t\t\t\tconst charCode = lineText.charCodeAt(i);\n\t\t\t\tlet charCodeClass: number;\n\t\t\t\tlet charWidth: number;\n\n\t\t\t\tif (strings.isHighSurrogate(charCode)) {\n\t\t\t\t\t// A surrogate pair must always be considered as a single unit, so it is never to be broken\n\t\t\t\t\ti++;\n\t\t\t\t\tcharCodeClass = CharacterClass.NONE;\n\t\t\t\t\tcharWidth = 2;\n\t\t\t\t} else {\n\t\t\t\t\tcharCodeClass = classifier.get(charCode);\n\t\t\t\t\tcharWidth = computeCharWidth(charCode, visibleColumn, tabSize, columnsForFullWidthChar);\n\t\t\t\t}\n\n\t\t\t\tif (charStartOffset > lastBreakingOffset && canBreak(prevCharCode, prevCharCodeClass, charCode, charCodeClass, isKeepAll)) {\n\t\t\t\t\tbreakOffset = charStartOffset;\n\t\t\t\t\tbreakOffsetVisibleColumn = visibleColumn;\n\t\t\t\t}\n\n\t\t\t\tvisibleColumn += charWidth;\n\n\t\t\t\t// check if adding character at `i` will go over the breaking column\n\t\t\t\tif (visibleColumn > breakingColumn) {\n\t\t\t\t\t// We need to break at least before character at `i`:\n\t\t\t\t\tif (charStartOffset > lastBreakingOffset) {\n\t\t\t\t\t\tforcedBreakOffset = charStartOffset;\n\t\t\t\t\t\tforcedBreakOffsetVisibleColumn = visibleColumn - charWidth;\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// we need to advance at least by one character\n\t\t\t\t\t\tforcedBreakOffset = i + 1;\n\t\t\t\t\t\tforcedBreakOffsetVisibleColumn = visibleColumn;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (visibleColumn - breakOffsetVisibleColumn > wrappedLineBreakColumn) {\n\t\t\t\t\t\t// Cannot break at `breakOffset` => reset it if it was set\n\t\t\t\t\t\tbreakOffset = 0;\n\t\t\t\t\t}\n\n\t\t\t\t\tentireLineFits = false;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tprevCharCode = charCode;\n\t\t\t\tprevCharCodeClass = charCodeClass;\n\t\t\t}\n\n\t\t\tif (entireLineFits) {\n\t\t\t\t// there is no more need to break => stop the outer loop!\n\t\t\t\tif (breakingOffsetsCount > 0) {\n\t\t\t\t\t// Add last segment, no need to assign to `lastBreakingOffset` and `lastBreakingOffsetVisibleColumn`\n\t\t\t\t\tbreakingOffsets[breakingOffsetsCount] = prevBreakingOffsets[prevBreakingOffsets.length - 1];\n\t\t\t\t\tbreakingOffsetsVisibleColumn[breakingOffsetsCount] = prevBreakingOffsetsVisibleColumn[prevBreakingOffsets.length - 1];\n\t\t\t\t\tbreakingOffsetsCount++;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (breakOffset === 0) {\n\t\t\t// must search left\n\t\t\tlet visibleColumn = prevBreakOffsetVisibleColumn;\n\t\t\tlet charCode = lineText.charCodeAt(prevBreakOffset);\n\t\t\tlet charCodeClass = classifier.get(charCode);\n\t\t\tlet hitATabCharacter = false;\n\t\t\tfor (let i = prevBreakOffset - 1; i >= lastBreakingOffset; i--) {\n\t\t\t\tconst charStartOffset = i + 1;\n\t\t\t\tconst prevCharCode = lineText.charCodeAt(i);\n\n\t\t\t\tif (prevCharCode === CharCode.Tab) {\n\t\t\t\t\t// cannot determine the width of a tab when going backwards, so we must go forwards\n\t\t\t\t\thitATabCharacter = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tlet prevCharCodeClass: number;\n\t\t\t\tlet prevCharWidth: number;\n\n\t\t\t\tif (strings.isLowSurrogate(prevCharCode)) {\n\t\t\t\t\t// A surrogate pair must always be considered as a single unit, so it is never to be broken\n\t\t\t\t\ti--;\n\t\t\t\t\tprevCharCodeClass = CharacterClass.NONE;\n\t\t\t\t\tprevCharWidth = 2;\n\t\t\t\t} else {\n\t\t\t\t\tprevCharCodeClass = classifier.get(prevCharCode);\n\t\t\t\t\tprevCharWidth = (strings.isFullWidthCharacter(prevCharCode) ? columnsForFullWidthChar : 1);\n\t\t\t\t}\n\n\t\t\t\tif (visibleColumn <= breakingColumn) {\n\t\t\t\t\tif (forcedBreakOffset === 0) {\n\t\t\t\t\t\tforcedBreakOffset = charStartOffset;\n\t\t\t\t\t\tforcedBreakOffsetVisibleColumn = visibleColumn;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (visibleColumn <= breakingColumn - wrappedLineBreakColumn) {\n\t\t\t\t\t\t// went too far!\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (canBreak(prevCharCode, prevCharCodeClass, charCode, charCodeClass, isKeepAll)) {\n\t\t\t\t\t\tbreakOffset = charStartOffset;\n\t\t\t\t\t\tbreakOffsetVisibleColumn = visibleColumn;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tvisibleColumn -= prevCharWidth;\n\t\t\t\tcharCode = prevCharCode;\n\t\t\t\tcharCodeClass = prevCharCodeClass;\n\t\t\t}\n\n\t\t\tif (breakOffset !== 0) {\n\t\t\t\tconst remainingWidthOfNextLine = wrappedLineBreakColumn - (forcedBreakOffsetVisibleColumn - breakOffsetVisibleColumn);\n\t\t\t\tif (remainingWidthOfNextLine <= tabSize) {\n\t\t\t\t\tconst charCodeAtForcedBreakOffset = lineText.charCodeAt(forcedBreakOffset);\n\t\t\t\t\tlet charWidth: number;\n\t\t\t\t\tif (strings.isHighSurrogate(charCodeAtForcedBreakOffset)) {\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\n\t\t\t\t\t\tcharWidth = 2;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tcharWidth = computeCharWidth(charCodeAtForcedBreakOffset, forcedBreakOffsetVisibleColumn, tabSize, columnsForFullWidthChar);\n\t\t\t\t\t}\n\t\t\t\t\tif (remainingWidthOfNextLine - charWidth < 0) {\n\t\t\t\t\t\t// it is not worth it to break at breakOffset, it just introduces an extra needless line!\n\t\t\t\t\t\tbreakOffset = 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (hitATabCharacter) {\n\t\t\t\t// cannot determine the width of a tab when going backwards, so we must go forwards from the previous break\n\t\t\t\tprevIndex--;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\tif (breakOffset === 0) {\n\t\t\t// Could not find a good breaking point\n\t\t\tbreakOffset = forcedBreakOffset;\n\t\t\tbreakOffsetVisibleColumn = forcedBreakOffsetVisibleColumn;\n\t\t}\n\n\t\tif (breakOffset <= lastBreakingOffset) {\n\t\t\t// Make sure that we are advancing (at least one character)\n\t\t\tconst charCode = lineText.charCodeAt(lastBreakingOffset);\n\t\t\tif (strings.isHighSurrogate(charCode)) {\n\t\t\t\t// A surrogate pair must always be considered as a single unit, so it is never to be broken\n\t\t\t\tbreakOffset = lastBreakingOffset + 2;\n\t\t\t\tbreakOffsetVisibleColumn = lastBreakingOffsetVisibleColumn + 2;\n\t\t\t} else {\n\t\t\t\tbreakOffset = lastBreakingOffset + 1;\n\t\t\t\tbreakOffsetVisibleColumn = lastBreakingOffsetVisibleColumn + computeCharWidth(charCode, lastBreakingOffsetVisibleColumn, tabSize, columnsForFullWidthChar);\n\t\t\t}\n\t\t}\n\n\t\tlastBreakingOffset = breakOffset;\n\t\tbreakingOffsets[breakingOffsetsCount] = breakOffset;\n\t\tlastBreakingOffsetVisibleColumn = breakOffsetVisibleColumn;\n\t\tbreakingOffsetsVisibleColumn[breakingOffsetsCount] = breakOffsetVisibleColumn;\n\t\tbreakingOffsetsCount++;\n\t\tbreakingColumn = breakOffsetVisibleColumn + wrappedLineBreakColumn;\n\n\t\twhile (prevIndex < 0 || (prevIndex < prevLen && prevBreakingOffsetsVisibleColumn[prevIndex] < breakOffsetVisibleColumn)) {\n\t\t\tprevIndex++;\n\t\t}\n\n\t\tlet bestDistance = Math.abs(prevBreakingOffsetsVisibleColumn[prevIndex] - breakingColumn);\n\t\twhile (prevIndex + 1 < prevLen) {\n\t\t\tconst distance = Math.abs(prevBreakingOffsetsVisibleColumn[prevIndex + 1] - breakingColumn);\n\t\t\tif (distance >= bestDistance) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tbestDistance = distance;\n\t\t\tprevIndex++;\n\t\t}\n\t}\n\n\tif (breakingOffsetsCount === 0) {\n\t\treturn null;\n\t}\n\n\t// Doing here some object reuse which ends up helping a huge deal with GC pauses!\n\tbreakingOffsets.length = breakingOffsetsCount;\n\tbreakingOffsetsVisibleColumn.length = breakingOffsetsCount;\n\tarrPool1 = previousBreakingData.breakOffsets;\n\tarrPool2 = previousBreakingData.breakOffsetsVisibleColumn;\n\tpreviousBreakingData.breakOffsets = breakingOffsets;\n\tpreviousBreakingData.breakOffsetsVisibleColumn = breakingOffsetsVisibleColumn;\n\tpreviousBreakingData.wrappedTextIndentLength = wrappedTextIndentLength;\n\treturn previousBreakingData;\n}\n\nfunction createLineBreaks(classifier: WrappingCharacterClassifier, _lineText: string, injectedTexts: LineInjectedText[] | null, tabSize: number, firstLineBreakColumn: number, columnsForFullWidthChar: number, wrappingIndent: WrappingIndent, wordBreak: 'normal' | 'keepAll'): ModelLineProjectionData | null {\n\tconst lineText = LineInjectedText.applyInjectedText(_lineText, injectedTexts);\n\n\tlet injectionOptions: InjectedTextOptions[] | null;\n\tlet injectionOffsets: number[] | null;\n\tif (injectedTexts && injectedTexts.length > 0) {\n\t\tinjectionOptions = injectedTexts.map(t => t.options);\n\t\tinjectionOffsets = injectedTexts.map(text => text.column - 1);\n\t} else {\n\t\tinjectionOptions = null;\n\t\tinjectionOffsets = null;\n\t}\n\n\tif (firstLineBreakColumn === -1) {\n\t\tif (!injectionOptions) {\n\t\t\treturn null;\n\t\t}\n\t\t// creating a `LineBreakData` with an invalid `breakOffsetsVisibleColumn` is OK\n\t\t// because `breakOffsetsVisibleColumn` will never be used because it contains injected text\n\t\treturn new ModelLineProjectionData(injectionOffsets, injectionOptions, [lineText.length], [], 0);\n\t}\n\n\tconst len = lineText.length;\n\tif (len <= 1) {\n\t\tif (!injectionOptions) {\n\t\t\treturn null;\n\t\t}\n\t\t// creating a `LineBreakData` with an invalid `breakOffsetsVisibleColumn` is OK\n\t\t// because `breakOffsetsVisibleColumn` will never be used because it contains injected text\n\t\treturn new ModelLineProjectionData(injectionOffsets, injectionOptions, [lineText.length], [], 0);\n\t}\n\n\tconst isKeepAll = (wordBreak === 'keepAll');\n\tconst wrappedTextIndentLength = computeWrappedTextIndentLength(lineText, tabSize, firstLineBreakColumn, columnsForFullWidthChar, wrappingIndent);\n\tconst wrappedLineBreakColumn = firstLineBreakColumn - wrappedTextIndentLength;\n\n\tconst breakingOffsets: number[] = [];\n\tconst breakingOffsetsVisibleColumn: number[] = [];\n\tlet breakingOffsetsCount: number = 0;\n\tlet breakOffset = 0;\n\tlet breakOffsetVisibleColumn = 0;\n\n\tlet breakingColumn = firstLineBreakColumn;\n\tlet prevCharCode = lineText.charCodeAt(0);\n\tlet prevCharCodeClass = classifier.get(prevCharCode);\n\tlet visibleColumn = computeCharWidth(prevCharCode, 0, tabSize, columnsForFullWidthChar);\n\n\tlet startOffset = 1;\n\tif (strings.isHighSurrogate(prevCharCode)) {\n\t\t// A surrogate pair must always be considered as a single unit, so it is never to be broken\n\t\tvisibleColumn += 1;\n\t\tprevCharCode = lineText.charCodeAt(1);\n\t\tprevCharCodeClass = classifier.get(prevCharCode);\n\t\tstartOffset++;\n\t}\n\n\tfor (let i = startOffset; i < len; i++) {\n\t\tconst charStartOffset = i;\n\t\tconst charCode = lineText.charCodeAt(i);\n\t\tlet charCodeClass: CharacterClass;\n\t\tlet charWidth: number;\n\n\t\tif (strings.isHighSurrogate(charCode)) {\n\t\t\t// A surrogate pair must always be considered as a single unit, so it is never to be broken\n\t\t\ti++;\n\t\t\tcharCodeClass = CharacterClass.NONE;\n\t\t\tcharWidth = 2;\n\t\t} else {\n\t\t\tcharCodeClass = classifier.get(charCode);\n\t\t\tcharWidth = computeCharWidth(charCode, visibleColumn, tabSize, columnsForFullWidthChar);\n\t\t}\n\n\t\tif (canBreak(prevCharCode, prevCharCodeClass, charCode, charCodeClass, isKeepAll)) {\n\t\t\tbreakOffset = charStartOffset;\n\t\t\tbreakOffsetVisibleColumn = visibleColumn;\n\t\t}\n\n\t\tvisibleColumn += charWidth;\n\n\t\t// check if adding character at `i` will go over the breaking column\n\t\tif (visibleColumn > breakingColumn) {\n\t\t\t// We need to break at least before character at `i`:\n\n\t\t\tif (breakOffset === 0 || visibleColumn - breakOffsetVisibleColumn > wrappedLineBreakColumn) {\n\t\t\t\t// Cannot break at `breakOffset`, must break at `i`\n\t\t\t\tbreakOffset = charStartOffset;\n\t\t\t\tbreakOffsetVisibleColumn = visibleColumn - charWidth;\n\t\t\t}\n\n\t\t\tbreakingOffsets[breakingOffsetsCount] = breakOffset;\n\t\t\tbreakingOffsetsVisibleColumn[breakingOffsetsCount] = breakOffsetVisibleColumn;\n\t\t\tbreakingOffsetsCount++;\n\t\t\tbreakingColumn = breakOffsetVisibleColumn + wrappedLineBreakColumn;\n\t\t\tbreakOffset = 0;\n\t\t}\n\n\t\tprevCharCode = charCode;\n\t\tprevCharCodeClass = charCodeClass;\n\t}\n\n\tif (breakingOffsetsCount === 0 && (!injectedTexts || injectedTexts.length === 0)) {\n\t\treturn null;\n\t}\n\n\t// Add last segment\n\tbreakingOffsets[breakingOffsetsCount] = len;\n\tbreakingOffsetsVisibleColumn[breakingOffsetsCount] = visibleColumn;\n\n\treturn new ModelLineProjectionData(injectionOffsets, injectionOptions, breakingOffsets, breakingOffsetsVisibleColumn, wrappedTextIndentLength);\n}\n\nfunction computeCharWidth(charCode: number, visibleColumn: number, tabSize: number, columnsForFullWidthChar: number): number {\n\tif (charCode === CharCode.Tab) {\n\t\treturn (tabSize - (visibleColumn % tabSize));\n\t}\n\tif (strings.isFullWidthCharacter(charCode)) {\n\t\treturn columnsForFullWidthChar;\n\t}\n\tif (charCode < 32) {\n\t\t// when using `editor.renderControlCharacters`, the substitutions are often wide\n\t\treturn columnsForFullWidthChar;\n\t}\n\treturn 1;\n}\n\nfunction tabCharacterWidth(visibleColumn: number, tabSize: number): number {\n\treturn (tabSize - (visibleColumn % tabSize));\n}\n\n/**\n * Kinsoku Shori : Don't break after a leading character, like an open bracket\n * Kinsoku Shori : Don't break before a trailing character, like a period\n */\nfunction canBreak(prevCharCode: number, prevCharCodeClass: CharacterClass, charCode: number, charCodeClass: CharacterClass, isKeepAll: boolean): boolean {\n\treturn (\n\t\tcharCode !== CharCode.Space\n\t\t&& (\n\t\t\t(prevCharCodeClass === CharacterClass.BREAK_AFTER && charCodeClass !== CharacterClass.BREAK_AFTER) // break at the end of multiple BREAK_AFTER\n\t\t\t|| (prevCharCodeClass !== CharacterClass.BREAK_BEFORE && charCodeClass === CharacterClass.BREAK_BEFORE) // break at the start of multiple BREAK_BEFORE\n\t\t\t|| (!isKeepAll && prevCharCodeClass === CharacterClass.BREAK_IDEOGRAPHIC && charCodeClass !== CharacterClass.BREAK_AFTER)\n\t\t\t|| (!isKeepAll && charCodeClass === CharacterClass.BREAK_IDEOGRAPHIC && prevCharCodeClass !== CharacterClass.BREAK_BEFORE)\n\t\t)\n\t);\n}\n\nfunction computeWrappedTextIndentLength(lineText: string, tabSize: number, firstLineBreakColumn: number, columnsForFullWidthChar: number, wrappingIndent: WrappingIndent): number {\n\tlet wrappedTextIndentLength = 0;\n\tif (wrappingIndent !== WrappingIndent.None) {\n\t\tconst firstNonWhitespaceIndex = strings.firstNonWhitespaceIndex(lineText);\n\t\tif (firstNonWhitespaceIndex !== -1) {\n\t\t\t// Track existing indent\n\n\t\t\tfor (let i = 0; i < firstNonWhitespaceIndex; i++) {\n\t\t\t\tconst charWidth = (lineText.charCodeAt(i) === CharCode.Tab ? tabCharacterWidth(wrappedTextIndentLength, tabSize) : 1);\n\t\t\t\twrappedTextIndentLength += charWidth;\n\t\t\t}\n\n\t\t\t// Increase indent of continuation lines, if desired\n\t\t\tconst numberOfAdditionalTabs = (wrappingIndent === WrappingIndent.DeepIndent ? 2 : wrappingIndent === WrappingIndent.Indent ? 1 : 0);\n\t\t\tfor (let i = 0; i < numberOfAdditionalTabs; i++) {\n\t\t\t\tconst charWidth = tabCharacterWidth(wrappedTextIndentLength, tabSize);\n\t\t\t\twrappedTextIndentLength += charWidth;\n\t\t\t}\n\n\t\t\t// Force sticking to beginning of line if no character would fit except for the indentation\n\t\t\tif (wrappedTextIndentLength + columnsForFullWidthChar > firstLineBreakColumn) {\n\t\t\t\twrappedTextIndentLength = 0;\n\t\t\t}\n\t\t}\n\t}\n\treturn wrappedTextIndentLength;\n}\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\nconst enum Constants {\n\tMINIMUM_HEIGHT = 4\n}\n\nexport class ColorZone {\n\t_colorZoneBrand: void = undefined;\n\n\tpublic readonly from: number;\n\tpublic readonly to: number;\n\tpublic readonly colorId: number;\n\n\tconstructor(from: number, to: number, colorId: number) {\n\t\tthis.from = from | 0;\n\t\tthis.to = to | 0;\n\t\tthis.colorId = colorId | 0;\n\t}\n\n\tpublic static compare(a: ColorZone, b: ColorZone): number {\n\t\tif (a.colorId === b.colorId) {\n\t\t\tif (a.from === b.from) {\n\t\t\t\treturn a.to - b.to;\n\t\t\t}\n\t\t\treturn a.from - b.from;\n\t\t}\n\t\treturn a.colorId - b.colorId;\n\t}\n}\n\n/**\n * A zone in the overview ruler\n */\nexport class OverviewRulerZone {\n\t_overviewRulerZoneBrand: void = undefined;\n\n\tpublic readonly startLineNumber: number;\n\tpublic readonly endLineNumber: number;\n\t/**\n\t * If set to 0, the height in lines will be determined based on `endLineNumber`.\n\t */\n\tpublic readonly heightInLines: number;\n\tpublic readonly color: string;\n\n\tprivate _colorZone: ColorZone | null;\n\n\tconstructor(\n\t\tstartLineNumber: number,\n\t\tendLineNumber: number,\n\t\theightInLines: number,\n\t\tcolor: string\n\t) {\n\t\tthis.startLineNumber = startLineNumber;\n\t\tthis.endLineNumber = endLineNumber;\n\t\tthis.heightInLines = heightInLines;\n\t\tthis.color = color;\n\t\tthis._colorZone = null;\n\t}\n\n\tpublic static compare(a: OverviewRulerZone, b: OverviewRulerZone): number {\n\t\tif (a.color === b.color) {\n\t\t\tif (a.startLineNumber === b.startLineNumber) {\n\t\t\t\tif (a.heightInLines === b.heightInLines) {\n\t\t\t\t\treturn a.endLineNumber - b.endLineNumber;\n\t\t\t\t}\n\t\t\t\treturn a.heightInLines - b.heightInLines;\n\t\t\t}\n\t\t\treturn a.startLineNumber - b.startLineNumber;\n\t\t}\n\t\treturn a.color < b.color ? -1 : 1;\n\t}\n\n\tpublic setColorZone(colorZone: ColorZone): void {\n\t\tthis._colorZone = colorZone;\n\t}\n\n\tpublic getColorZones(): ColorZone | null {\n\t\treturn this._colorZone;\n\t}\n}\n\nexport class OverviewZoneManager {\n\n\tprivate readonly _getVerticalOffsetForLine: (lineNumber: number) => number;\n\tprivate _zones: OverviewRulerZone[];\n\tprivate _colorZonesInvalid: boolean;\n\tprivate _lineHeight: number;\n\tprivate _domWidth: number;\n\tprivate _domHeight: number;\n\tprivate _outerHeight: number;\n\tprivate _pixelRatio: number;\n\n\tprivate _lastAssignedId: number;\n\tprivate readonly _color2Id: { [color: string]: number };\n\tprivate readonly _id2Color: string[];\n\n\tconstructor(getVerticalOffsetForLine: (lineNumber: number) => number) {\n\t\tthis._getVerticalOffsetForLine = getVerticalOffsetForLine;\n\t\tthis._zones = [];\n\t\tthis._colorZonesInvalid = false;\n\t\tthis._lineHeight = 0;\n\t\tthis._domWidth = 0;\n\t\tthis._domHeight = 0;\n\t\tthis._outerHeight = 0;\n\t\tthis._pixelRatio = 1;\n\n\t\tthis._lastAssignedId = 0;\n\t\tthis._color2Id = Object.create(null);\n\t\tthis._id2Color = [];\n\t}\n\n\tpublic getId2Color(): string[] {\n\t\treturn this._id2Color;\n\t}\n\n\tpublic setZones(newZones: OverviewRulerZone[]): void {\n\t\tthis._zones = newZones;\n\t\tthis._zones.sort(OverviewRulerZone.compare);\n\t}\n\n\tpublic setLineHeight(lineHeight: number): boolean {\n\t\tif (this._lineHeight === lineHeight) {\n\t\t\treturn false;\n\t\t}\n\t\tthis._lineHeight = lineHeight;\n\t\tthis._colorZonesInvalid = true;\n\t\treturn true;\n\t}\n\n\tpublic setPixelRatio(pixelRatio: number): void {\n\t\tthis._pixelRatio = pixelRatio;\n\t\tthis._colorZonesInvalid = true;\n\t}\n\n\tpublic getDOMWidth(): number {\n\t\treturn this._domWidth;\n\t}\n\n\tpublic getCanvasWidth(): number {\n\t\treturn this._domWidth * this._pixelRatio;\n\t}\n\n\tpublic setDOMWidth(width: number): boolean {\n\t\tif (this._domWidth === width) {\n\t\t\treturn false;\n\t\t}\n\t\tthis._domWidth = width;\n\t\tthis._colorZonesInvalid = true;\n\t\treturn true;\n\t}\n\n\tpublic getDOMHeight(): number {\n\t\treturn this._domHeight;\n\t}\n\n\tpublic getCanvasHeight(): number {\n\t\treturn this._domHeight * this._pixelRatio;\n\t}\n\n\tpublic setDOMHeight(height: number): boolean {\n\t\tif (this._domHeight === height) {\n\t\t\treturn false;\n\t\t}\n\t\tthis._domHeight = height;\n\t\tthis._colorZonesInvalid = true;\n\t\treturn true;\n\t}\n\n\tpublic getOuterHeight(): number {\n\t\treturn this._outerHeight;\n\t}\n\n\tpublic setOuterHeight(outerHeight: number): boolean {\n\t\tif (this._outerHeight === outerHeight) {\n\t\t\treturn false;\n\t\t}\n\t\tthis._outerHeight = outerHeight;\n\t\tthis._colorZonesInvalid = true;\n\t\treturn true;\n\t}\n\n\tpublic resolveColorZones(): ColorZone[] {\n\t\tconst colorZonesInvalid = this._colorZonesInvalid;\n\t\tconst lineHeight = Math.floor(this._lineHeight);\n\t\tconst totalHeight = Math.floor(this.getCanvasHeight());\n\t\tconst outerHeight = Math.floor(this._outerHeight);\n\t\tconst heightRatio = totalHeight / outerHeight;\n\t\tconst halfMinimumHeight = Math.floor(Constants.MINIMUM_HEIGHT * this._pixelRatio / 2);\n\n\t\tconst allColorZones: ColorZone[] = [];\n\t\tfor (let i = 0, len = this._zones.length; i < len; i++) {\n\t\t\tconst zone = this._zones[i];\n\n\t\t\tif (!colorZonesInvalid) {\n\t\t\t\tconst colorZone = zone.getColorZones();\n\t\t\t\tif (colorZone) {\n\t\t\t\t\tallColorZones.push(colorZone);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst offset1 = this._getVerticalOffsetForLine(zone.startLineNumber);\n\t\t\tconst offset2 = (\n\t\t\t\tzone.heightInLines === 0\n\t\t\t\t\t? this._getVerticalOffsetForLine(zone.endLineNumber) + lineHeight\n\t\t\t\t\t: offset1 + zone.heightInLines * lineHeight\n\t\t\t);\n\n\t\t\tconst y1 = Math.floor(heightRatio * offset1);\n\t\t\tconst y2 = Math.floor(heightRatio * offset2);\n\n\t\t\tlet ycenter = Math.floor((y1 + y2) / 2);\n\t\t\tlet halfHeight = (y2 - ycenter);\n\n\t\t\tif (halfHeight < halfMinimumHeight) {\n\t\t\t\thalfHeight = halfMinimumHeight;\n\t\t\t}\n\n\t\t\tif (ycenter - halfHeight < 0) {\n\t\t\t\tycenter = halfHeight;\n\t\t\t}\n\t\t\tif (ycenter + halfHeight > totalHeight) {\n\t\t\t\tycenter = totalHeight - halfHeight;\n\t\t\t}\n\n\t\t\tconst color = zone.color;\n\t\t\tlet colorId = this._color2Id[color];\n\t\t\tif (!colorId) {\n\t\t\t\tcolorId = (++this._lastAssignedId);\n\t\t\t\tthis._color2Id[color] = colorId;\n\t\t\t\tthis._id2Color[colorId] = color;\n\t\t\t}\n\t\t\tconst colorZone = new ColorZone(ycenter - halfHeight, ycenter + halfHeight, colorId);\n\n\t\t\tzone.setColorZone(colorZone);\n\t\t\tallColorZones.push(colorZone);\n\t\t}\n\n\t\tthis._colorZonesInvalid = false;\n\n\t\tallColorZones.sort(ColorZone.compare);\n\t\treturn allColorZones;\n\t}\n}\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\nimport { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';\nimport { IOverviewRuler } from 'vs/editor/browser/editorBrowser';\nimport { OverviewRulerPosition, EditorOption } from 'vs/editor/common/config/editorOptions';\nimport { ColorZone, OverviewRulerZone, OverviewZoneManager } from 'vs/editor/common/viewModel/overviewZoneManager';\nimport { ViewContext } from 'vs/editor/common/viewModel/viewContext';\nimport * as viewEvents from 'vs/editor/common/viewEvents';\nimport { ViewEventHandler } from 'vs/editor/common/viewEventHandler';\n\nexport class OverviewRuler extends ViewEventHandler implements IOverviewRuler {\n\n\tprivate readonly _context: ViewContext;\n\tprivate readonly _domNode: FastDomNode;\n\tprivate readonly _zoneManager: OverviewZoneManager;\n\n\tconstructor(context: ViewContext, cssClassName: string) {\n\t\tsuper();\n\t\tthis._context = context;\n\t\tconst options = this._context.configuration.options;\n\n\t\tthis._domNode = createFastDomNode(document.createElement('canvas'));\n\t\tthis._domNode.setClassName(cssClassName);\n\t\tthis._domNode.setPosition('absolute');\n\t\tthis._domNode.setLayerHinting(true);\n\t\tthis._domNode.setContain('strict');\n\n\t\tthis._zoneManager = new OverviewZoneManager((lineNumber: number) => this._context.viewLayout.getVerticalOffsetForLineNumber(lineNumber));\n\t\tthis._zoneManager.setDOMWidth(0);\n\t\tthis._zoneManager.setDOMHeight(0);\n\t\tthis._zoneManager.setOuterHeight(this._context.viewLayout.getScrollHeight());\n\t\tthis._zoneManager.setLineHeight(options.get(EditorOption.lineHeight));\n\n\t\tthis._zoneManager.setPixelRatio(options.get(EditorOption.pixelRatio));\n\n\t\tthis._context.addEventHandler(this);\n\t}\n\n\tpublic override dispose(): void {\n\t\tthis._context.removeEventHandler(this);\n\t\tsuper.dispose();\n\t}\n\n\t// ---- begin view event handlers\n\n\tpublic override onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {\n\t\tconst options = this._context.configuration.options;\n\n\t\tif (e.hasChanged(EditorOption.lineHeight)) {\n\t\t\tthis._zoneManager.setLineHeight(options.get(EditorOption.lineHeight));\n\t\t\tthis._render();\n\t\t}\n\n\t\tif (e.hasChanged(EditorOption.pixelRatio)) {\n\t\t\tthis._zoneManager.setPixelRatio(options.get(EditorOption.pixelRatio));\n\t\t\tthis._domNode.setWidth(this._zoneManager.getDOMWidth());\n\t\t\tthis._domNode.setHeight(this._zoneManager.getDOMHeight());\n\t\t\tthis._domNode.domNode.width = this._zoneManager.getCanvasWidth();\n\t\t\tthis._domNode.domNode.height = this._zoneManager.getCanvasHeight();\n\t\t\tthis._render();\n\t\t}\n\n\t\treturn true;\n\t}\n\tpublic override onFlushed(e: viewEvents.ViewFlushedEvent): boolean {\n\t\tthis._render();\n\t\treturn true;\n\t}\n\tpublic override onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean {\n\t\tif (e.scrollHeightChanged) {\n\t\t\tthis._zoneManager.setOuterHeight(e.scrollHeight);\n\t\t\tthis._render();\n\t\t}\n\t\treturn true;\n\t}\n\tpublic override onZonesChanged(e: viewEvents.ViewZonesChangedEvent): boolean {\n\t\tthis._render();\n\t\treturn true;\n\t}\n\n\t// ---- end view event handlers\n\n\tpublic getDomNode(): HTMLElement {\n\t\treturn this._domNode.domNode;\n\t}\n\n\tpublic setLayout(position: OverviewRulerPosition): void {\n\t\tthis._domNode.setTop(position.top);\n\t\tthis._domNode.setRight(position.right);\n\n\t\tlet hasChanged = false;\n\t\thasChanged = this._zoneManager.setDOMWidth(position.width) || hasChanged;\n\t\thasChanged = this._zoneManager.setDOMHeight(position.height) || hasChanged;\n\n\t\tif (hasChanged) {\n\t\t\tthis._domNode.setWidth(this._zoneManager.getDOMWidth());\n\t\t\tthis._domNode.setHeight(this._zoneManager.getDOMHeight());\n\t\t\tthis._domNode.domNode.width = this._zoneManager.getCanvasWidth();\n\t\t\tthis._domNode.domNode.height = this._zoneManager.getCanvasHeight();\n\n\t\t\tthis._render();\n\t\t}\n\t}\n\n\tpublic setZones(zones: OverviewRulerZone[]): void {\n\t\tthis._zoneManager.setZones(zones);\n\t\tthis._render();\n\t}\n\n\tprivate _render(): boolean {\n\t\tif (this._zoneManager.getOuterHeight() === 0) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst width = this._zoneManager.getCanvasWidth();\n\t\tconst height = this._zoneManager.getCanvasHeight();\n\n\t\tconst colorZones = this._zoneManager.resolveColorZones();\n\t\tconst id2Color = this._zoneManager.getId2Color();\n\n\t\tconst ctx = this._domNode.domNode.getContext('2d')!;\n\t\tctx.clearRect(0, 0, width, height);\n\t\tif (colorZones.length > 0) {\n\t\t\tthis._renderOneLane(ctx, colorZones, id2Color, width);\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tprivate _renderOneLane(ctx: CanvasRenderingContext2D, colorZones: ColorZone[], id2Color: string[], width: number): void {\n\n\t\tlet currentColorId = 0;\n\t\tlet currentFrom = 0;\n\t\tlet currentTo = 0;\n\n\t\tfor (const zone of colorZones) {\n\n\t\t\tconst zoneColorId = zone.colorId;\n\t\t\tconst zoneFrom = zone.from;\n\t\t\tconst zoneTo = zone.to;\n\n\t\t\tif (zoneColorId !== currentColorId) {\n\t\t\t\tctx.fillRect(0, currentFrom, width, currentTo - currentFrom);\n\n\t\t\t\tcurrentColorId = zoneColorId;\n\t\t\t\tctx.fillStyle = id2Color[currentColorId];\n\t\t\t\tcurrentFrom = zoneFrom;\n\t\t\t\tcurrentTo = zoneTo;\n\t\t\t} else {\n\t\t\t\tif (currentTo >= zoneFrom) {\n\t\t\t\t\tcurrentTo = Math.max(currentTo, zoneTo);\n\t\t\t\t} else {\n\t\t\t\t\tctx.fillRect(0, currentFrom, width, currentTo - currentFrom);\n\t\t\t\t\tcurrentFrom = zoneFrom;\n\t\t\t\t\tcurrentTo = zoneTo;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tctx.fillRect(0, currentFrom, width, currentTo - currentFrom);\n\n\t}\n}\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\nimport { IEditorConfiguration } from 'vs/editor/common/config/editorConfiguration';\nimport { ViewEventHandler } from 'vs/editor/common/viewEventHandler';\nimport { IViewLayout, IViewModel } from 'vs/editor/common/viewModel';\nimport { IColorTheme } from 'vs/platform/theme/common/themeService';\nimport { EditorTheme } from 'vs/editor/common/editorTheme';\n\nexport class ViewContext {\n\n\tpublic readonly configuration: IEditorConfiguration;\n\tpublic readonly viewModel: IViewModel;\n\tpublic readonly viewLayout: IViewLayout;\n\tpublic readonly theme: EditorTheme;\n\n\tconstructor(\n\t\tconfiguration: IEditorConfiguration,\n\t\ttheme: IColorTheme,\n\t\tmodel: IViewModel\n\t) {\n\t\tthis.configuration = configuration;\n\t\tthis.theme = new EditorTheme(theme);\n\t\tthis.viewModel = model;\n\t\tthis.viewLayout = model.viewLayout;\n\t}\n\n\tpublic addEventHandler(eventHandler: ViewEventHandler): void {\n\t\tthis.viewModel.addViewEventHandler(eventHandler);\n\t}\n\n\tpublic removeEventHandler(eventHandler: ViewEventHandler): void {\n\t\tthis.viewModel.removeViewEventHandler(eventHandler);\n\t}\n}\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\nimport { ViewEventHandler } from 'vs/editor/common/viewEventHandler';\nimport { ViewEvent } from 'vs/editor/common/viewEvents';\nimport { IContentSizeChangedEvent } from 'vs/editor/common/editorCommon';\nimport { Emitter } from 'vs/base/common/event';\nimport { Selection } from 'vs/editor/common/core/selection';\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport { CursorChangeReason } from 'vs/editor/common/cursorEvents';\nimport { IModelContentChangedEvent, IModelDecorationsChangedEvent, IModelLanguageChangedEvent, IModelLanguageConfigurationChangedEvent, IModelOptionsChangedEvent, IModelTokensChangedEvent } from 'vs/editor/common/textModelEvents';\n\nexport class ViewModelEventDispatcher extends Disposable {\n\n\tprivate readonly _onEvent = this._register(new Emitter());\n\tpublic readonly onEvent = this._onEvent.event;\n\n\tprivate readonly _eventHandlers: ViewEventHandler[];\n\tprivate _viewEventQueue: ViewEvent[] | null;\n\tprivate _isConsumingViewEventQueue: boolean;\n\tprivate _collector: ViewModelEventsCollector | null;\n\tprivate _collectorCnt: number;\n\tprivate _outgoingEvents: OutgoingViewModelEvent[];\n\n\tconstructor() {\n\t\tsuper();\n\t\tthis._eventHandlers = [];\n\t\tthis._viewEventQueue = null;\n\t\tthis._isConsumingViewEventQueue = false;\n\t\tthis._collector = null;\n\t\tthis._collectorCnt = 0;\n\t\tthis._outgoingEvents = [];\n\t}\n\n\tpublic emitOutgoingEvent(e: OutgoingViewModelEvent): void {\n\t\tthis._addOutgoingEvent(e);\n\t\tthis._emitOutgoingEvents();\n\t}\n\n\tprivate _addOutgoingEvent(e: OutgoingViewModelEvent): void {\n\t\tfor (let i = 0, len = this._outgoingEvents.length; i < len; i++) {\n\t\t\tconst mergeResult = (this._outgoingEvents[i].kind === e.kind ? this._outgoingEvents[i].attemptToMerge(e) : null);\n\t\t\tif (mergeResult) {\n\t\t\t\tthis._outgoingEvents[i] = mergeResult;\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\t// not merged\n\t\tthis._outgoingEvents.push(e);\n\t}\n\n\tprivate _emitOutgoingEvents(): void {\n\t\twhile (this._outgoingEvents.length > 0) {\n\t\t\tif (this._collector || this._isConsumingViewEventQueue) {\n\t\t\t\t// right now collecting or emitting view events, so let's postpone emitting\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst event = this._outgoingEvents.shift()!;\n\t\t\tif (event.isNoOp()) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tthis._onEvent.fire(event);\n\t\t}\n\t}\n\n\tpublic addViewEventHandler(eventHandler: ViewEventHandler): void {\n\t\tfor (let i = 0, len = this._eventHandlers.length; i < len; i++) {\n\t\t\tif (this._eventHandlers[i] === eventHandler) {\n\t\t\t\tconsole.warn('Detected duplicate listener in ViewEventDispatcher', eventHandler);\n\t\t\t}\n\t\t}\n\t\tthis._eventHandlers.push(eventHandler);\n\t}\n\n\tpublic removeViewEventHandler(eventHandler: ViewEventHandler): void {\n\t\tfor (let i = 0; i < this._eventHandlers.length; i++) {\n\t\t\tif (this._eventHandlers[i] === eventHandler) {\n\t\t\t\tthis._eventHandlers.splice(i, 1);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic beginEmitViewEvents(): ViewModelEventsCollector {\n\t\tthis._collectorCnt++;\n\t\tif (this._collectorCnt === 1) {\n\t\t\tthis._collector = new ViewModelEventsCollector();\n\t\t}\n\t\treturn this._collector!;\n\t}\n\n\tpublic endEmitViewEvents(): void {\n\t\tthis._collectorCnt--;\n\t\tif (this._collectorCnt === 0) {\n\t\t\tconst outgoingEvents = this._collector!.outgoingEvents;\n\t\t\tconst viewEvents = this._collector!.viewEvents;\n\t\t\tthis._collector = null;\n\n\t\t\tfor (const outgoingEvent of outgoingEvents) {\n\t\t\t\tthis._addOutgoingEvent(outgoingEvent);\n\t\t\t}\n\n\t\t\tif (viewEvents.length > 0) {\n\t\t\t\tthis._emitMany(viewEvents);\n\t\t\t}\n\t\t}\n\t\tthis._emitOutgoingEvents();\n\t}\n\n\tpublic emitSingleViewEvent(event: ViewEvent): void {\n\t\ttry {\n\t\t\tconst eventsCollector = this.beginEmitViewEvents();\n\t\t\teventsCollector.emitViewEvent(event);\n\t\t} finally {\n\t\t\tthis.endEmitViewEvents();\n\t\t}\n\t}\n\n\tprivate _emitMany(events: ViewEvent[]): void {\n\t\tif (this._viewEventQueue) {\n\t\t\tthis._viewEventQueue = this._viewEventQueue.concat(events);\n\t\t} else {\n\t\t\tthis._viewEventQueue = events;\n\t\t}\n\n\t\tif (!this._isConsumingViewEventQueue) {\n\t\t\tthis._consumeViewEventQueue();\n\t\t}\n\t}\n\n\tprivate _consumeViewEventQueue(): void {\n\t\ttry {\n\t\t\tthis._isConsumingViewEventQueue = true;\n\t\t\tthis._doConsumeQueue();\n\t\t} finally {\n\t\t\tthis._isConsumingViewEventQueue = false;\n\t\t}\n\t}\n\n\tprivate _doConsumeQueue(): void {\n\t\twhile (this._viewEventQueue) {\n\t\t\t// Empty event queue, as events might come in while sending these off\n\t\t\tconst events = this._viewEventQueue;\n\t\t\tthis._viewEventQueue = null;\n\n\t\t\t// Use a clone of the event handlers list, as they might remove themselves\n\t\t\tconst eventHandlers = this._eventHandlers.slice(0);\n\t\t\tfor (const eventHandler of eventHandlers) {\n\t\t\t\teventHandler.handleEvents(events);\n\t\t\t}\n\t\t}\n\t}\n}\n\nexport class ViewModelEventsCollector {\n\n\tpublic readonly viewEvents: ViewEvent[];\n\tpublic readonly outgoingEvents: OutgoingViewModelEvent[];\n\n\tconstructor() {\n\t\tthis.viewEvents = [];\n\t\tthis.outgoingEvents = [];\n\t}\n\n\tpublic emitViewEvent(event: ViewEvent) {\n\t\tthis.viewEvents.push(event);\n\t}\n\n\tpublic emitOutgoingEvent(e: OutgoingViewModelEvent): void {\n\t\tthis.outgoingEvents.push(e);\n\t}\n}\n\nexport type OutgoingViewModelEvent = (\n\tContentSizeChangedEvent\n\t| FocusChangedEvent\n\t| ScrollChangedEvent\n\t| ViewZonesChangedEvent\n\t| HiddenAreasChangedEvent\n\t| ReadOnlyEditAttemptEvent\n\t| CursorStateChangedEvent\n\t| ModelDecorationsChangedEvent\n\t| ModelLanguageChangedEvent\n\t| ModelLanguageConfigurationChangedEvent\n\t| ModelContentChangedEvent\n\t| ModelOptionsChangedEvent\n\t| ModelTokensChangedEvent\n);\n\nexport const enum OutgoingViewModelEventKind {\n\tContentSizeChanged,\n\tFocusChanged,\n\tScrollChanged,\n\tViewZonesChanged,\n\tHiddenAreasChanged,\n\tReadOnlyEditAttempt,\n\tCursorStateChanged,\n\tModelDecorationsChanged,\n\tModelLanguageChanged,\n\tModelLanguageConfigurationChanged,\n\tModelContentChanged,\n\tModelOptionsChanged,\n\tModelTokensChanged,\n}\n\nexport class ContentSizeChangedEvent implements IContentSizeChangedEvent {\n\n\tpublic readonly kind = OutgoingViewModelEventKind.ContentSizeChanged;\n\n\tprivate readonly _oldContentWidth: number;\n\tprivate readonly _oldContentHeight: number;\n\n\treadonly contentWidth: number;\n\treadonly contentHeight: number;\n\treadonly contentWidthChanged: boolean;\n\treadonly contentHeightChanged: boolean;\n\n\tconstructor(oldContentWidth: number, oldContentHeight: number, contentWidth: number, contentHeight: number) {\n\t\tthis._oldContentWidth = oldContentWidth;\n\t\tthis._oldContentHeight = oldContentHeight;\n\t\tthis.contentWidth = contentWidth;\n\t\tthis.contentHeight = contentHeight;\n\t\tthis.contentWidthChanged = (this._oldContentWidth !== this.contentWidth);\n\t\tthis.contentHeightChanged = (this._oldContentHeight !== this.contentHeight);\n\t}\n\n\tpublic isNoOp(): boolean {\n\t\treturn (!this.contentWidthChanged && !this.contentHeightChanged);\n\t}\n\n\tpublic attemptToMerge(other: OutgoingViewModelEvent): OutgoingViewModelEvent | null {\n\t\tif (other.kind !== this.kind) {\n\t\t\treturn null;\n\t\t}\n\t\treturn new ContentSizeChangedEvent(this._oldContentWidth, this._oldContentHeight, other.contentWidth, other.contentHeight);\n\t}\n}\n\nexport class FocusChangedEvent {\n\n\tpublic readonly kind = OutgoingViewModelEventKind.FocusChanged;\n\n\treadonly oldHasFocus: boolean;\n\treadonly hasFocus: boolean;\n\n\tconstructor(oldHasFocus: boolean, hasFocus: boolean) {\n\t\tthis.oldHasFocus = oldHasFocus;\n\t\tthis.hasFocus = hasFocus;\n\t}\n\n\tpublic isNoOp(): boolean {\n\t\treturn (this.oldHasFocus === this.hasFocus);\n\t}\n\n\tpublic attemptToMerge(other: OutgoingViewModelEvent): OutgoingViewModelEvent | null {\n\t\tif (other.kind !== this.kind) {\n\t\t\treturn null;\n\t\t}\n\t\treturn new FocusChangedEvent(this.oldHasFocus, other.hasFocus);\n\t}\n}\n\nexport class ScrollChangedEvent {\n\n\tpublic readonly kind = OutgoingViewModelEventKind.ScrollChanged;\n\n\tprivate readonly _oldScrollWidth: number;\n\tprivate readonly _oldScrollLeft: number;\n\tprivate readonly _oldScrollHeight: number;\n\tprivate readonly _oldScrollTop: number;\n\n\tpublic readonly scrollWidth: number;\n\tpublic readonly scrollLeft: number;\n\tpublic readonly scrollHeight: number;\n\tpublic readonly scrollTop: number;\n\n\tpublic readonly scrollWidthChanged: boolean;\n\tpublic readonly scrollLeftChanged: boolean;\n\tpublic readonly scrollHeightChanged: boolean;\n\tpublic readonly scrollTopChanged: boolean;\n\n\tconstructor(\n\t\toldScrollWidth: number, oldScrollLeft: number, oldScrollHeight: number, oldScrollTop: number,\n\t\tscrollWidth: number, scrollLeft: number, scrollHeight: number, scrollTop: number,\n\t) {\n\t\tthis._oldScrollWidth = oldScrollWidth;\n\t\tthis._oldScrollLeft = oldScrollLeft;\n\t\tthis._oldScrollHeight = oldScrollHeight;\n\t\tthis._oldScrollTop = oldScrollTop;\n\n\t\tthis.scrollWidth = scrollWidth;\n\t\tthis.scrollLeft = scrollLeft;\n\t\tthis.scrollHeight = scrollHeight;\n\t\tthis.scrollTop = scrollTop;\n\n\t\tthis.scrollWidthChanged = (this._oldScrollWidth !== this.scrollWidth);\n\t\tthis.scrollLeftChanged = (this._oldScrollLeft !== this.scrollLeft);\n\t\tthis.scrollHeightChanged = (this._oldScrollHeight !== this.scrollHeight);\n\t\tthis.scrollTopChanged = (this._oldScrollTop !== this.scrollTop);\n\t}\n\n\tpublic isNoOp(): boolean {\n\t\treturn (!this.scrollWidthChanged && !this.scrollLeftChanged && !this.scrollHeightChanged && !this.scrollTopChanged);\n\t}\n\n\tpublic attemptToMerge(other: OutgoingViewModelEvent): OutgoingViewModelEvent | null {\n\t\tif (other.kind !== this.kind) {\n\t\t\treturn null;\n\t\t}\n\t\treturn new ScrollChangedEvent(\n\t\t\tthis._oldScrollWidth, this._oldScrollLeft, this._oldScrollHeight, this._oldScrollTop,\n\t\t\tother.scrollWidth, other.scrollLeft, other.scrollHeight, other.scrollTop\n\t\t);\n\t}\n}\n\nexport class ViewZonesChangedEvent {\n\n\tpublic readonly kind = OutgoingViewModelEventKind.ViewZonesChanged;\n\n\tconstructor() {\n\t}\n\n\tpublic isNoOp(): boolean {\n\t\treturn false;\n\t}\n\n\tpublic attemptToMerge(other: OutgoingViewModelEvent): OutgoingViewModelEvent | null {\n\t\tif (other.kind !== this.kind) {\n\t\t\treturn null;\n\t\t}\n\t\treturn this;\n\t}\n}\n\nexport class HiddenAreasChangedEvent {\n\n\tpublic readonly kind = OutgoingViewModelEventKind.HiddenAreasChanged;\n\n\tconstructor() {\n\t}\n\n\tpublic isNoOp(): boolean {\n\t\treturn false;\n\t}\n\n\tpublic attemptToMerge(other: OutgoingViewModelEvent): OutgoingViewModelEvent | null {\n\t\tif (other.kind !== this.kind) {\n\t\t\treturn null;\n\t\t}\n\t\treturn this;\n\t}\n}\n\nexport class CursorStateChangedEvent {\n\n\tpublic readonly kind = OutgoingViewModelEventKind.CursorStateChanged;\n\n\tpublic readonly oldSelections: Selection[] | null;\n\tpublic readonly selections: Selection[];\n\tpublic readonly oldModelVersionId: number;\n\tpublic readonly modelVersionId: number;\n\tpublic readonly source: string;\n\tpublic readonly reason: CursorChangeReason;\n\tpublic readonly reachedMaxCursorCount: boolean;\n\n\tconstructor(oldSelections: Selection[] | null, selections: Selection[], oldModelVersionId: number, modelVersionId: number, source: string, reason: CursorChangeReason, reachedMaxCursorCount: boolean) {\n\t\tthis.oldSelections = oldSelections;\n\t\tthis.selections = selections;\n\t\tthis.oldModelVersionId = oldModelVersionId;\n\t\tthis.modelVersionId = modelVersionId;\n\t\tthis.source = source;\n\t\tthis.reason = reason;\n\t\tthis.reachedMaxCursorCount = reachedMaxCursorCount;\n\t}\n\n\tprivate static _selectionsAreEqual(a: Selection[] | null, b: Selection[] | null): boolean {\n\t\tif (!a && !b) {\n\t\t\treturn true;\n\t\t}\n\t\tif (!a || !b) {\n\t\t\treturn false;\n\t\t}\n\t\tconst aLen = a.length;\n\t\tconst bLen = b.length;\n\t\tif (aLen !== bLen) {\n\t\t\treturn false;\n\t\t}\n\t\tfor (let i = 0; i < aLen; i++) {\n\t\t\tif (!a[i].equalsSelection(b[i])) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\tpublic isNoOp(): boolean {\n\t\treturn (\n\t\t\tCursorStateChangedEvent._selectionsAreEqual(this.oldSelections, this.selections)\n\t\t\t&& this.oldModelVersionId === this.modelVersionId\n\t\t);\n\t}\n\n\tpublic attemptToMerge(other: OutgoingViewModelEvent): OutgoingViewModelEvent | null {\n\t\tif (other.kind !== this.kind) {\n\t\t\treturn null;\n\t\t}\n\t\treturn new CursorStateChangedEvent(\n\t\t\tthis.oldSelections, other.selections, this.oldModelVersionId, other.modelVersionId, other.source, other.reason, this.reachedMaxCursorCount || other.reachedMaxCursorCount\n\t\t);\n\t}\n}\n\nexport class ReadOnlyEditAttemptEvent {\n\n\tpublic readonly kind = OutgoingViewModelEventKind.ReadOnlyEditAttempt;\n\n\tconstructor() {\n\t}\n\n\tpublic isNoOp(): boolean {\n\t\treturn false;\n\t}\n\n\tpublic attemptToMerge(other: OutgoingViewModelEvent): OutgoingViewModelEvent | null {\n\t\tif (other.kind !== this.kind) {\n\t\t\treturn null;\n\t\t}\n\t\treturn this;\n\t}\n}\n\nexport class ModelDecorationsChangedEvent {\n\tpublic readonly kind = OutgoingViewModelEventKind.ModelDecorationsChanged;\n\n\tconstructor(\n\t\tpublic readonly event: IModelDecorationsChangedEvent\n\t) { }\n\n\tpublic isNoOp(): boolean {\n\t\treturn false;\n\t}\n\n\tpublic attemptToMerge(other: OutgoingViewModelEvent): OutgoingViewModelEvent | null {\n\t\treturn null;\n\t}\n}\n\nexport class ModelLanguageChangedEvent {\n\tpublic readonly kind = OutgoingViewModelEventKind.ModelLanguageChanged;\n\n\tconstructor(\n\t\tpublic readonly event: IModelLanguageChangedEvent\n\t) { }\n\n\tpublic isNoOp(): boolean {\n\t\treturn false;\n\t}\n\n\tpublic attemptToMerge(other: OutgoingViewModelEvent): OutgoingViewModelEvent | null {\n\t\treturn null;\n\t}\n}\n\nexport class ModelLanguageConfigurationChangedEvent {\n\tpublic readonly kind = OutgoingViewModelEventKind.ModelLanguageConfigurationChanged;\n\n\tconstructor(\n\t\tpublic readonly event: IModelLanguageConfigurationChangedEvent\n\t) { }\n\n\tpublic isNoOp(): boolean {\n\t\treturn false;\n\t}\n\n\tpublic attemptToMerge(other: OutgoingViewModelEvent): OutgoingViewModelEvent | null {\n\t\treturn null;\n\t}\n}\n\nexport class ModelContentChangedEvent {\n\tpublic readonly kind = OutgoingViewModelEventKind.ModelContentChanged;\n\n\tconstructor(\n\t\tpublic readonly event: IModelContentChangedEvent\n\t) { }\n\n\tpublic isNoOp(): boolean {\n\t\treturn false;\n\t}\n\n\tpublic attemptToMerge(other: OutgoingViewModelEvent): OutgoingViewModelEvent | null {\n\t\treturn null;\n\t}\n}\n\nexport class ModelOptionsChangedEvent {\n\tpublic readonly kind = OutgoingViewModelEventKind.ModelOptionsChanged;\n\n\tconstructor(\n\t\tpublic readonly event: IModelOptionsChangedEvent\n\t) { }\n\n\tpublic isNoOp(): boolean {\n\t\treturn false;\n\t}\n\n\tpublic attemptToMerge(other: OutgoingViewModelEvent): OutgoingViewModelEvent | null {\n\t\treturn null;\n\t}\n}\n\nexport class ModelTokensChangedEvent {\n\tpublic readonly kind = OutgoingViewModelEventKind.ModelTokensChanged;\n\n\tconstructor(\n\t\tpublic readonly event: IModelTokensChangedEvent\n\t) { }\n\n\tpublic isNoOp(): boolean {\n\t\treturn false;\n\t}\n\n\tpublic attemptToMerge(other: OutgoingViewModelEvent): OutgoingViewModelEvent | null {\n\t\treturn null;\n\t}\n}\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\nimport { Event, Emitter } from 'vs/base/common/event';\nimport { Disposable, IDisposable } from 'vs/base/common/lifecycle';\nimport { IScrollPosition, ScrollEvent, Scrollable, ScrollbarVisibility, INewScrollPosition } from 'vs/base/common/scrollable';\nimport { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions';\nimport { ScrollType } from 'vs/editor/common/editorCommon';\nimport { IEditorConfiguration } from 'vs/editor/common/config/editorConfiguration';\nimport { LinesLayout } from 'vs/editor/common/viewLayout/linesLayout';\nimport { IEditorWhitespace, IPartialViewLinesViewportData, IViewLayout, IViewWhitespaceViewportData, IWhitespaceChangeAccessor, Viewport } from 'vs/editor/common/viewModel';\nimport { ContentSizeChangedEvent } from 'vs/editor/common/viewModelEventDispatcher';\n\nconst SMOOTH_SCROLLING_TIME = 125;\n\nclass EditorScrollDimensions {\n\n\tpublic readonly width: number;\n\tpublic readonly contentWidth: number;\n\tpublic readonly scrollWidth: number;\n\n\tpublic readonly height: number;\n\tpublic readonly contentHeight: number;\n\tpublic readonly scrollHeight: number;\n\n\tconstructor(\n\t\twidth: number,\n\t\tcontentWidth: number,\n\t\theight: number,\n\t\tcontentHeight: number,\n\t) {\n\t\twidth = width | 0;\n\t\tcontentWidth = contentWidth | 0;\n\t\theight = height | 0;\n\t\tcontentHeight = contentHeight | 0;\n\n\t\tif (width < 0) {\n\t\t\twidth = 0;\n\t\t}\n\t\tif (contentWidth < 0) {\n\t\t\tcontentWidth = 0;\n\t\t}\n\n\t\tif (height < 0) {\n\t\t\theight = 0;\n\t\t}\n\t\tif (contentHeight < 0) {\n\t\t\tcontentHeight = 0;\n\t\t}\n\n\t\tthis.width = width;\n\t\tthis.contentWidth = contentWidth;\n\t\tthis.scrollWidth = Math.max(width, contentWidth);\n\n\t\tthis.height = height;\n\t\tthis.contentHeight = contentHeight;\n\t\tthis.scrollHeight = Math.max(height, contentHeight);\n\t}\n\n\tpublic equals(other: EditorScrollDimensions): boolean {\n\t\treturn (\n\t\t\tthis.width === other.width\n\t\t\t&& this.contentWidth === other.contentWidth\n\t\t\t&& this.height === other.height\n\t\t\t&& this.contentHeight === other.contentHeight\n\t\t);\n\t}\n}\n\nclass EditorScrollable extends Disposable {\n\n\tprivate readonly _scrollable: Scrollable;\n\tprivate _dimensions: EditorScrollDimensions;\n\n\tpublic readonly onDidScroll: Event;\n\n\tprivate readonly _onDidContentSizeChange = this._register(new Emitter());\n\tpublic readonly onDidContentSizeChange: Event = this._onDidContentSizeChange.event;\n\n\tconstructor(smoothScrollDuration: number, scheduleAtNextAnimationFrame: (callback: () => void) => IDisposable) {\n\t\tsuper();\n\t\tthis._dimensions = new EditorScrollDimensions(0, 0, 0, 0);\n\t\tthis._scrollable = this._register(new Scrollable({\n\t\t\tforceIntegerValues: true,\n\t\t\tsmoothScrollDuration,\n\t\t\tscheduleAtNextAnimationFrame\n\t\t}));\n\t\tthis.onDidScroll = this._scrollable.onScroll;\n\t}\n\n\tpublic getScrollable(): Scrollable {\n\t\treturn this._scrollable;\n\t}\n\n\tpublic setSmoothScrollDuration(smoothScrollDuration: number): void {\n\t\tthis._scrollable.setSmoothScrollDuration(smoothScrollDuration);\n\t}\n\n\tpublic validateScrollPosition(scrollPosition: INewScrollPosition): IScrollPosition {\n\t\treturn this._scrollable.validateScrollPosition(scrollPosition);\n\t}\n\n\tpublic getScrollDimensions(): EditorScrollDimensions {\n\t\treturn this._dimensions;\n\t}\n\n\tpublic setScrollDimensions(dimensions: EditorScrollDimensions): void {\n\t\tif (this._dimensions.equals(dimensions)) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst oldDimensions = this._dimensions;\n\t\tthis._dimensions = dimensions;\n\n\t\tthis._scrollable.setScrollDimensions({\n\t\t\twidth: dimensions.width,\n\t\t\tscrollWidth: dimensions.scrollWidth,\n\t\t\theight: dimensions.height,\n\t\t\tscrollHeight: dimensions.scrollHeight\n\t\t}, true);\n\n\t\tconst contentWidthChanged = (oldDimensions.contentWidth !== dimensions.contentWidth);\n\t\tconst contentHeightChanged = (oldDimensions.contentHeight !== dimensions.contentHeight);\n\t\tif (contentWidthChanged || contentHeightChanged) {\n\t\t\tthis._onDidContentSizeChange.fire(new ContentSizeChangedEvent(\n\t\t\t\toldDimensions.contentWidth, oldDimensions.contentHeight,\n\t\t\t\tdimensions.contentWidth, dimensions.contentHeight\n\t\t\t));\n\t\t}\n\t}\n\n\tpublic getFutureScrollPosition(): IScrollPosition {\n\t\treturn this._scrollable.getFutureScrollPosition();\n\t}\n\n\tpublic getCurrentScrollPosition(): IScrollPosition {\n\t\treturn this._scrollable.getCurrentScrollPosition();\n\t}\n\n\tpublic setScrollPositionNow(update: INewScrollPosition): void {\n\t\tthis._scrollable.setScrollPositionNow(update);\n\t}\n\n\tpublic setScrollPositionSmooth(update: INewScrollPosition): void {\n\t\tthis._scrollable.setScrollPositionSmooth(update);\n\t}\n\n\tpublic hasPendingScrollAnimation(): boolean {\n\t\treturn this._scrollable.hasPendingScrollAnimation();\n\t}\n}\n\nexport class ViewLayout extends Disposable implements IViewLayout {\n\n\tprivate readonly _configuration: IEditorConfiguration;\n\tprivate readonly _linesLayout: LinesLayout;\n\tprivate _maxLineWidth: number;\n\tprivate _overlayWidgetsMinWidth: number;\n\n\tprivate readonly _scrollable: EditorScrollable;\n\tpublic readonly onDidScroll: Event;\n\tpublic readonly onDidContentSizeChange: Event;\n\n\tconstructor(configuration: IEditorConfiguration, lineCount: number, scheduleAtNextAnimationFrame: (callback: () => void) => IDisposable) {\n\t\tsuper();\n\n\t\tthis._configuration = configuration;\n\t\tconst options = this._configuration.options;\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\n\t\tconst padding = options.get(EditorOption.padding);\n\n\t\tthis._linesLayout = new LinesLayout(lineCount, options.get(EditorOption.lineHeight), padding.top, padding.bottom);\n\t\tthis._maxLineWidth = 0;\n\t\tthis._overlayWidgetsMinWidth = 0;\n\n\t\tthis._scrollable = this._register(new EditorScrollable(0, scheduleAtNextAnimationFrame));\n\t\tthis._configureSmoothScrollDuration();\n\n\t\tthis._scrollable.setScrollDimensions(new EditorScrollDimensions(\n\t\t\tlayoutInfo.contentWidth,\n\t\t\t0,\n\t\t\tlayoutInfo.height,\n\t\t\t0\n\t\t));\n\t\tthis.onDidScroll = this._scrollable.onDidScroll;\n\t\tthis.onDidContentSizeChange = this._scrollable.onDidContentSizeChange;\n\n\t\tthis._updateHeight();\n\t}\n\n\tpublic override dispose(): void {\n\t\tsuper.dispose();\n\t}\n\n\tpublic getScrollable(): Scrollable {\n\t\treturn this._scrollable.getScrollable();\n\t}\n\n\tpublic onHeightMaybeChanged(): void {\n\t\tthis._updateHeight();\n\t}\n\n\tprivate _configureSmoothScrollDuration(): void {\n\t\tthis._scrollable.setSmoothScrollDuration(this._configuration.options.get(EditorOption.smoothScrolling) ? SMOOTH_SCROLLING_TIME : 0);\n\t}\n\n\t// ---- begin view event handlers\n\n\tpublic onConfigurationChanged(e: ConfigurationChangedEvent): void {\n\t\tconst options = this._configuration.options;\n\t\tif (e.hasChanged(EditorOption.lineHeight)) {\n\t\t\tthis._linesLayout.setLineHeight(options.get(EditorOption.lineHeight));\n\t\t}\n\t\tif (e.hasChanged(EditorOption.padding)) {\n\t\t\tconst padding = options.get(EditorOption.padding);\n\t\t\tthis._linesLayout.setPadding(padding.top, padding.bottom);\n\t\t}\n\t\tif (e.hasChanged(EditorOption.layoutInfo)) {\n\t\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\n\t\t\tconst width = layoutInfo.contentWidth;\n\t\t\tconst height = layoutInfo.height;\n\t\t\tconst scrollDimensions = this._scrollable.getScrollDimensions();\n\t\t\tconst contentWidth = scrollDimensions.contentWidth;\n\t\t\tthis._scrollable.setScrollDimensions(new EditorScrollDimensions(\n\t\t\t\twidth,\n\t\t\t\tscrollDimensions.contentWidth,\n\t\t\t\theight,\n\t\t\t\tthis._getContentHeight(width, height, contentWidth)\n\t\t\t));\n\t\t} else {\n\t\t\tthis._updateHeight();\n\t\t}\n\t\tif (e.hasChanged(EditorOption.smoothScrolling)) {\n\t\t\tthis._configureSmoothScrollDuration();\n\t\t}\n\t}\n\tpublic onFlushed(lineCount: number): void {\n\t\tthis._linesLayout.onFlushed(lineCount);\n\t}\n\tpublic onLinesDeleted(fromLineNumber: number, toLineNumber: number): void {\n\t\tthis._linesLayout.onLinesDeleted(fromLineNumber, toLineNumber);\n\t}\n\tpublic onLinesInserted(fromLineNumber: number, toLineNumber: number): void {\n\t\tthis._linesLayout.onLinesInserted(fromLineNumber, toLineNumber);\n\t}\n\n\t// ---- end view event handlers\n\n\tprivate _getHorizontalScrollbarHeight(width: number, scrollWidth: number): number {\n\t\tconst options = this._configuration.options;\n\t\tconst scrollbar = options.get(EditorOption.scrollbar);\n\t\tif (scrollbar.horizontal === ScrollbarVisibility.Hidden) {\n\t\t\t// horizontal scrollbar not visible\n\t\t\treturn 0;\n\t\t}\n\t\tif (width >= scrollWidth) {\n\t\t\t// horizontal scrollbar not visible\n\t\t\treturn 0;\n\t\t}\n\t\treturn scrollbar.horizontalScrollbarSize;\n\t}\n\n\tprivate _getContentHeight(width: number, height: number, contentWidth: number): number {\n\t\tconst options = this._configuration.options;\n\n\t\tlet result = this._linesLayout.getLinesTotalHeight();\n\t\tif (options.get(EditorOption.scrollBeyondLastLine)) {\n\t\t\tresult += Math.max(0, height - options.get(EditorOption.lineHeight) - options.get(EditorOption.padding).bottom);\n\t\t} else if (!options.get(EditorOption.scrollbar).ignoreHorizontalScrollbarInContentHeight) {\n\t\t\tresult += this._getHorizontalScrollbarHeight(width, contentWidth);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tprivate _updateHeight(): void {\n\t\tconst scrollDimensions = this._scrollable.getScrollDimensions();\n\t\tconst width = scrollDimensions.width;\n\t\tconst height = scrollDimensions.height;\n\t\tconst contentWidth = scrollDimensions.contentWidth;\n\t\tthis._scrollable.setScrollDimensions(new EditorScrollDimensions(\n\t\t\twidth,\n\t\t\tscrollDimensions.contentWidth,\n\t\t\theight,\n\t\t\tthis._getContentHeight(width, height, contentWidth)\n\t\t));\n\t}\n\n\t// ---- Layouting logic\n\n\tpublic getCurrentViewport(): Viewport {\n\t\tconst scrollDimensions = this._scrollable.getScrollDimensions();\n\t\tconst currentScrollPosition = this._scrollable.getCurrentScrollPosition();\n\t\treturn new Viewport(\n\t\t\tcurrentScrollPosition.scrollTop,\n\t\t\tcurrentScrollPosition.scrollLeft,\n\t\t\tscrollDimensions.width,\n\t\t\tscrollDimensions.height\n\t\t);\n\t}\n\n\tpublic getFutureViewport(): Viewport {\n\t\tconst scrollDimensions = this._scrollable.getScrollDimensions();\n\t\tconst currentScrollPosition = this._scrollable.getFutureScrollPosition();\n\t\treturn new Viewport(\n\t\t\tcurrentScrollPosition.scrollTop,\n\t\t\tcurrentScrollPosition.scrollLeft,\n\t\t\tscrollDimensions.width,\n\t\t\tscrollDimensions.height\n\t\t);\n\t}\n\n\tprivate _computeContentWidth(): number {\n\t\tconst options = this._configuration.options;\n\t\tconst maxLineWidth = this._maxLineWidth;\n\t\tconst wrappingInfo = options.get(EditorOption.wrappingInfo);\n\t\tconst fontInfo = options.get(EditorOption.fontInfo);\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\n\t\tif (wrappingInfo.isViewportWrapping) {\n\t\t\tconst minimap = options.get(EditorOption.minimap);\n\t\t\tif (maxLineWidth > layoutInfo.contentWidth + fontInfo.typicalHalfwidthCharacterWidth) {\n\t\t\t\t// This is a case where viewport wrapping is on, but the line extends above the viewport\n\t\t\t\tif (minimap.enabled && minimap.side === 'right') {\n\t\t\t\t\t// We need to accomodate the scrollbar width\n\t\t\t\t\treturn maxLineWidth + layoutInfo.verticalScrollbarWidth;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn maxLineWidth;\n\t\t} else {\n\t\t\tconst extraHorizontalSpace = options.get(EditorOption.scrollBeyondLastColumn) * fontInfo.typicalHalfwidthCharacterWidth;\n\t\t\tconst whitespaceMinWidth = this._linesLayout.getWhitespaceMinWidth();\n\t\t\treturn Math.max(maxLineWidth + extraHorizontalSpace + layoutInfo.verticalScrollbarWidth, whitespaceMinWidth, this._overlayWidgetsMinWidth);\n\t\t}\n\t}\n\n\tpublic setMaxLineWidth(maxLineWidth: number): void {\n\t\tthis._maxLineWidth = maxLineWidth;\n\t\tthis._updateContentWidth();\n\t}\n\n\tpublic setOverlayWidgetsMinWidth(maxMinWidth: number): void {\n\t\tthis._overlayWidgetsMinWidth = maxMinWidth;\n\t\tthis._updateContentWidth();\n\t}\n\n\tprivate _updateContentWidth(): void {\n\t\tconst scrollDimensions = this._scrollable.getScrollDimensions();\n\t\tthis._scrollable.setScrollDimensions(new EditorScrollDimensions(\n\t\t\tscrollDimensions.width,\n\t\t\tthis._computeContentWidth(),\n\t\t\tscrollDimensions.height,\n\t\t\tscrollDimensions.contentHeight\n\t\t));\n\n\t\t// The height might depend on the fact that there is a horizontal scrollbar or not\n\t\tthis._updateHeight();\n\t}\n\n\t// ---- view state\n\n\tpublic saveState(): { scrollTop: number; scrollTopWithoutViewZones: number; scrollLeft: number } {\n\t\tconst currentScrollPosition = this._scrollable.getFutureScrollPosition();\n\t\tconst scrollTop = currentScrollPosition.scrollTop;\n\t\tconst firstLineNumberInViewport = this._linesLayout.getLineNumberAtOrAfterVerticalOffset(scrollTop);\n\t\tconst whitespaceAboveFirstLine = this._linesLayout.getWhitespaceAccumulatedHeightBeforeLineNumber(firstLineNumberInViewport);\n\t\treturn {\n\t\t\tscrollTop: scrollTop,\n\t\t\tscrollTopWithoutViewZones: scrollTop - whitespaceAboveFirstLine,\n\t\t\tscrollLeft: currentScrollPosition.scrollLeft\n\t\t};\n\t}\n\n\t// ----\n\tpublic changeWhitespace(callback: (accessor: IWhitespaceChangeAccessor) => void): boolean {\n\t\tconst hadAChange = this._linesLayout.changeWhitespace(callback);\n\t\tif (hadAChange) {\n\t\t\tthis.onHeightMaybeChanged();\n\t\t}\n\t\treturn hadAChange;\n\t}\n\tpublic getVerticalOffsetForLineNumber(lineNumber: number, includeViewZones: boolean = false): number {\n\t\treturn this._linesLayout.getVerticalOffsetForLineNumber(lineNumber, includeViewZones);\n\t}\n\tpublic getVerticalOffsetAfterLineNumber(lineNumber: number, includeViewZones: boolean = false): number {\n\t\treturn this._linesLayout.getVerticalOffsetAfterLineNumber(lineNumber, includeViewZones);\n\t}\n\tpublic isAfterLines(verticalOffset: number): boolean {\n\t\treturn this._linesLayout.isAfterLines(verticalOffset);\n\t}\n\tpublic isInTopPadding(verticalOffset: number): boolean {\n\t\treturn this._linesLayout.isInTopPadding(verticalOffset);\n\t}\n\tisInBottomPadding(verticalOffset: number): boolean {\n\t\treturn this._linesLayout.isInBottomPadding(verticalOffset);\n\t}\n\n\tpublic getLineNumberAtVerticalOffset(verticalOffset: number): number {\n\t\treturn this._linesLayout.getLineNumberAtOrAfterVerticalOffset(verticalOffset);\n\t}\n\n\tpublic getWhitespaceAtVerticalOffset(verticalOffset: number): IViewWhitespaceViewportData | null {\n\t\treturn this._linesLayout.getWhitespaceAtVerticalOffset(verticalOffset);\n\t}\n\tpublic getLinesViewportData(): IPartialViewLinesViewportData {\n\t\tconst visibleBox = this.getCurrentViewport();\n\t\treturn this._linesLayout.getLinesViewportData(visibleBox.top, visibleBox.top + visibleBox.height);\n\t}\n\tpublic getLinesViewportDataAtScrollTop(scrollTop: number): IPartialViewLinesViewportData {\n\t\t// do some minimal validations on scrollTop\n\t\tconst scrollDimensions = this._scrollable.getScrollDimensions();\n\t\tif (scrollTop + scrollDimensions.height > scrollDimensions.scrollHeight) {\n\t\t\tscrollTop = scrollDimensions.scrollHeight - scrollDimensions.height;\n\t\t}\n\t\tif (scrollTop < 0) {\n\t\t\tscrollTop = 0;\n\t\t}\n\t\treturn this._linesLayout.getLinesViewportData(scrollTop, scrollTop + scrollDimensions.height);\n\t}\n\tpublic getWhitespaceViewportData(): IViewWhitespaceViewportData[] {\n\t\tconst visibleBox = this.getCurrentViewport();\n\t\treturn this._linesLayout.getWhitespaceViewportData(visibleBox.top, visibleBox.top + visibleBox.height);\n\t}\n\tpublic getWhitespaces(): IEditorWhitespace[] {\n\t\treturn this._linesLayout.getWhitespaces();\n\t}\n\n\t// ----\n\n\tpublic getContentWidth(): number {\n\t\tconst scrollDimensions = this._scrollable.getScrollDimensions();\n\t\treturn scrollDimensions.contentWidth;\n\t}\n\tpublic getScrollWidth(): number {\n\t\tconst scrollDimensions = this._scrollable.getScrollDimensions();\n\t\treturn scrollDimensions.scrollWidth;\n\t}\n\tpublic getContentHeight(): number {\n\t\tconst scrollDimensions = this._scrollable.getScrollDimensions();\n\t\treturn scrollDimensions.contentHeight;\n\t}\n\tpublic getScrollHeight(): number {\n\t\tconst scrollDimensions = this._scrollable.getScrollDimensions();\n\t\treturn scrollDimensions.scrollHeight;\n\t}\n\n\tpublic getCurrentScrollLeft(): number {\n\t\tconst currentScrollPosition = this._scrollable.getCurrentScrollPosition();\n\t\treturn currentScrollPosition.scrollLeft;\n\t}\n\tpublic getCurrentScrollTop(): number {\n\t\tconst currentScrollPosition = this._scrollable.getCurrentScrollPosition();\n\t\treturn currentScrollPosition.scrollTop;\n\t}\n\n\tpublic validateScrollPosition(scrollPosition: INewScrollPosition): IScrollPosition {\n\t\treturn this._scrollable.validateScrollPosition(scrollPosition);\n\t}\n\n\tpublic setScrollPosition(position: INewScrollPosition, type: ScrollType): void {\n\t\tif (type === ScrollType.Immediate) {\n\t\t\tthis._scrollable.setScrollPositionNow(position);\n\t\t} else {\n\t\t\tthis._scrollable.setScrollPositionSmooth(position);\n\t\t}\n\t}\n\n\tpublic hasPendingScrollAnimation(): boolean {\n\t\treturn this._scrollable.hasPendingScrollAnimation();\n\t}\n\n\tpublic deltaScrollNow(deltaScrollLeft: number, deltaScrollTop: number): void {\n\t\tconst currentScrollPosition = this._scrollable.getCurrentScrollPosition();\n\t\tthis._scrollable.setScrollPositionNow({\n\t\t\tscrollLeft: currentScrollPosition.scrollLeft + deltaScrollLeft,\n\t\t\tscrollTop: currentScrollPosition.scrollTop + deltaScrollTop\n\t\t});\n\t}\n}\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\nimport { Range } from 'vs/editor/common/core/range';\nimport { Selection } from 'vs/editor/common/core/selection';\nimport { ICommand, ICursorStateComputerData, IEditOperationBuilder } from 'vs/editor/common/editorCommon';\nimport { ITextModel } from 'vs/editor/common/model';\n\nexport class MoveCaretCommand implements ICommand {\n\n\tprivate readonly _selection: Selection;\n\tprivate readonly _isMovingLeft: boolean;\n\n\tconstructor(selection: Selection, isMovingLeft: boolean) {\n\t\tthis._selection = selection;\n\t\tthis._isMovingLeft = isMovingLeft;\n\t}\n\n\tpublic getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {\n\t\tif (this._selection.startLineNumber !== this._selection.endLineNumber || this._selection.isEmpty()) {\n\t\t\treturn;\n\t\t}\n\t\tconst lineNumber = this._selection.startLineNumber;\n\t\tconst startColumn = this._selection.startColumn;\n\t\tconst endColumn = this._selection.endColumn;\n\t\tif (this._isMovingLeft && startColumn === 1) {\n\t\t\treturn;\n\t\t}\n\t\tif (!this._isMovingLeft && endColumn === model.getLineMaxColumn(lineNumber)) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (this._isMovingLeft) {\n\t\t\tconst rangeBefore = new Range(lineNumber, startColumn - 1, lineNumber, startColumn);\n\t\t\tconst charBefore = model.getValueInRange(rangeBefore);\n\t\t\tbuilder.addEditOperation(rangeBefore, null);\n\t\t\tbuilder.addEditOperation(new Range(lineNumber, endColumn, lineNumber, endColumn), charBefore);\n\t\t} else {\n\t\t\tconst rangeAfter = new Range(lineNumber, endColumn, lineNumber, endColumn + 1);\n\t\t\tconst charAfter = model.getValueInRange(rangeAfter);\n\t\t\tbuilder.addEditOperation(rangeAfter, null);\n\t\t\tbuilder.addEditOperation(new Range(lineNumber, startColumn, lineNumber, startColumn), charAfter);\n\t\t}\n\t}\n\n\tpublic computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {\n\t\tif (this._isMovingLeft) {\n\t\t\treturn new Selection(this._selection.startLineNumber, this._selection.startColumn - 1, this._selection.endLineNumber, this._selection.endColumn - 1);\n\t\t} else {\n\t\t\treturn new Selection(this._selection.startLineNumber, this._selection.startColumn + 1, this._selection.endLineNumber, this._selection.endColumn + 1);\n\t\t}\n\t}\n}\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\nimport { CancellationToken } from 'vs/base/common/cancellation';\nimport { onUnexpectedExternalError } from 'vs/base/common/errors';\nimport { HierarchicalKind } from 'vs/base/common/hierarchicalKind';\nimport { Position } from 'vs/editor/common/core/position';\nimport * as languages from 'vs/editor/common/languages';\nimport { ActionSet } from 'vs/platform/actionWidget/common/actionWidget';\n\nexport const CodeActionKind = new class {\n\tpublic readonly QuickFix = new HierarchicalKind('quickfix');\n\n\tpublic readonly Refactor = new HierarchicalKind('refactor');\n\tpublic readonly RefactorExtract = this.Refactor.append('extract');\n\tpublic readonly RefactorInline = this.Refactor.append('inline');\n\tpublic readonly RefactorMove = this.Refactor.append('move');\n\tpublic readonly RefactorRewrite = this.Refactor.append('rewrite');\n\n\tpublic readonly Notebook = new HierarchicalKind('notebook');\n\n\tpublic readonly Source = new HierarchicalKind('source');\n\tpublic readonly SourceOrganizeImports = this.Source.append('organizeImports');\n\tpublic readonly SourceFixAll = this.Source.append('fixAll');\n\tpublic readonly SurroundWith = this.Refactor.append('surround');\n};\n\nexport const enum CodeActionAutoApply {\n\tIfSingle = 'ifSingle',\n\tFirst = 'first',\n\tNever = 'never',\n}\n\nexport enum CodeActionTriggerSource {\n\tRefactor = 'refactor',\n\tRefactorPreview = 'refactor preview',\n\tLightbulb = 'lightbulb',\n\tDefault = 'other (default)',\n\tSourceAction = 'source action',\n\tQuickFix = 'quick fix action',\n\tFixAll = 'fix all',\n\tOrganizeImports = 'organize imports',\n\tAutoFix = 'auto fix',\n\tQuickFixHover = 'quick fix hover window',\n\tOnSave = 'save participants',\n\tProblemsView = 'problems view'\n}\n\nexport interface CodeActionFilter {\n\treadonly include?: HierarchicalKind;\n\treadonly excludes?: readonly HierarchicalKind[];\n\treadonly includeSourceActions?: boolean;\n\treadonly onlyIncludePreferredActions?: boolean;\n}\n\nexport function mayIncludeActionsOfKind(filter: CodeActionFilter, providedKind: HierarchicalKind): boolean {\n\t// A provided kind may be a subset or superset of our filtered kind.\n\tif (filter.include && !filter.include.intersects(providedKind)) {\n\t\treturn false;\n\t}\n\n\tif (filter.excludes) {\n\t\tif (filter.excludes.some(exclude => excludesAction(providedKind, exclude, filter.include))) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t// Don't return source actions unless they are explicitly requested\n\tif (!filter.includeSourceActions && CodeActionKind.Source.contains(providedKind)) {\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n\nexport function filtersAction(filter: CodeActionFilter, action: languages.CodeAction): boolean {\n\tconst actionKind = action.kind ? new HierarchicalKind(action.kind) : undefined;\n\n\t// Filter out actions by kind\n\tif (filter.include) {\n\t\tif (!actionKind || !filter.include.contains(actionKind)) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tif (filter.excludes) {\n\t\tif (actionKind && filter.excludes.some(exclude => excludesAction(actionKind, exclude, filter.include))) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\t// Don't return source actions unless they are explicitly requested\n\tif (!filter.includeSourceActions) {\n\t\tif (actionKind && CodeActionKind.Source.contains(actionKind)) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tif (filter.onlyIncludePreferredActions) {\n\t\tif (!action.isPreferred) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\treturn true;\n}\n\nfunction excludesAction(providedKind: HierarchicalKind, exclude: HierarchicalKind, include: HierarchicalKind | undefined): boolean {\n\tif (!exclude.contains(providedKind)) {\n\t\treturn false;\n\t}\n\tif (include && exclude.contains(include)) {\n\t\t// The include is more specific, don't filter out\n\t\treturn false;\n\t}\n\treturn true;\n}\n\nexport interface CodeActionTrigger {\n\treadonly type: languages.CodeActionTriggerType;\n\treadonly triggerAction: CodeActionTriggerSource;\n\treadonly filter?: CodeActionFilter;\n\treadonly autoApply?: CodeActionAutoApply;\n\treadonly context?: {\n\t\treadonly notAvailableMessage: string;\n\t\treadonly position: Position;\n\t};\n}\n\nexport class CodeActionCommandArgs {\n\tpublic static fromUser(arg: any, defaults: { kind: HierarchicalKind; apply: CodeActionAutoApply }): CodeActionCommandArgs {\n\t\tif (!arg || typeof arg !== 'object') {\n\t\t\treturn new CodeActionCommandArgs(defaults.kind, defaults.apply, false);\n\t\t}\n\t\treturn new CodeActionCommandArgs(\n\t\t\tCodeActionCommandArgs.getKindFromUser(arg, defaults.kind),\n\t\t\tCodeActionCommandArgs.getApplyFromUser(arg, defaults.apply),\n\t\t\tCodeActionCommandArgs.getPreferredUser(arg));\n\t}\n\n\tprivate static getApplyFromUser(arg: any, defaultAutoApply: CodeActionAutoApply) {\n\t\tswitch (typeof arg.apply === 'string' ? arg.apply.toLowerCase() : '') {\n\t\t\tcase 'first': return CodeActionAutoApply.First;\n\t\t\tcase 'never': return CodeActionAutoApply.Never;\n\t\t\tcase 'ifsingle': return CodeActionAutoApply.IfSingle;\n\t\t\tdefault: return defaultAutoApply;\n\t\t}\n\t}\n\n\tprivate static getKindFromUser(arg: any, defaultKind: HierarchicalKind) {\n\t\treturn typeof arg.kind === 'string'\n\t\t\t? new HierarchicalKind(arg.kind)\n\t\t\t: defaultKind;\n\t}\n\n\tprivate static getPreferredUser(arg: any): boolean {\n\t\treturn typeof arg.preferred === 'boolean'\n\t\t\t? arg.preferred\n\t\t\t: false;\n\t}\n\n\tprivate constructor(\n\t\tpublic readonly kind: HierarchicalKind,\n\t\tpublic readonly apply: CodeActionAutoApply,\n\t\tpublic readonly preferred: boolean,\n\t) { }\n}\n\nexport class CodeActionItem {\n\n\tconstructor(\n\t\tpublic readonly action: languages.CodeAction,\n\t\tpublic readonly provider: languages.CodeActionProvider | undefined,\n\t\tpublic highlightRange?: boolean,\n\t) { }\n\n\tasync resolve(token: CancellationToken): Promise {\n\t\tif (this.provider?.resolveCodeAction && !this.action.edit) {\n\t\t\tlet action: languages.CodeAction | undefined | null;\n\t\t\ttry {\n\t\t\t\taction = await this.provider.resolveCodeAction(this.action, token);\n\t\t\t} catch (err) {\n\t\t\t\tonUnexpectedExternalError(err);\n\t\t\t}\n\t\t\tif (action) {\n\t\t\t\tthis.action.edit = action.edit;\n\t\t\t}\n\t\t}\n\t\treturn this;\n\t}\n}\n\nexport interface CodeActionSet extends ActionSet {\n\treadonly validActions: readonly CodeActionItem[];\n\treadonly allActions: readonly CodeActionItem[];\n\n\treadonly documentation: readonly languages.Command[];\n}\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\nimport { Color } from 'vs/base/common/color';\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { IColorPresentation } from 'vs/editor/common/languages';\n\nexport class ColorPickerModel {\n\n\treadonly originalColor: Color;\n\tprivate _color: Color;\n\n\tget color(): Color {\n\t\treturn this._color;\n\t}\n\n\tset color(color: Color) {\n\t\tif (this._color.equals(color)) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._color = color;\n\t\tthis._onDidChangeColor.fire(color);\n\t}\n\n\tget presentation(): IColorPresentation { return this.colorPresentations[this.presentationIndex]; }\n\n\tprivate _colorPresentations: IColorPresentation[];\n\n\tget colorPresentations(): IColorPresentation[] {\n\t\treturn this._colorPresentations;\n\t}\n\n\tset colorPresentations(colorPresentations: IColorPresentation[]) {\n\t\tthis._colorPresentations = colorPresentations;\n\t\tif (this.presentationIndex > colorPresentations.length - 1) {\n\t\t\tthis.presentationIndex = 0;\n\t\t}\n\t\tthis._onDidChangePresentation.fire(this.presentation);\n\t}\n\n\tprivate readonly _onColorFlushed = new Emitter();\n\treadonly onColorFlushed: Event = this._onColorFlushed.event;\n\n\tprivate readonly _onDidChangeColor = new Emitter();\n\treadonly onDidChangeColor: Event = this._onDidChangeColor.event;\n\n\tprivate readonly _onDidChangePresentation = new Emitter();\n\treadonly onDidChangePresentation: Event = this._onDidChangePresentation.event;\n\n\tconstructor(color: Color, availableColorPresentations: IColorPresentation[], private presentationIndex: number) {\n\t\tthis.originalColor = color;\n\t\tthis._color = color;\n\t\tthis._colorPresentations = availableColorPresentations;\n\t}\n\n\tselectNextColorPresentation(): void {\n\t\tthis.presentationIndex = (this.presentationIndex + 1) % this.colorPresentations.length;\n\t\tthis.flushColor();\n\t\tthis._onDidChangePresentation.fire(this.presentation);\n\t}\n\n\tguessColorPresentation(color: Color, originalText: string): void {\n\t\tlet presentationIndex = -1;\n\t\tfor (let i = 0; i < this.colorPresentations.length; i++) {\n\t\t\tif (originalText.toLowerCase() === this.colorPresentations[i].label) {\n\t\t\t\tpresentationIndex = i;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (presentationIndex === -1) {\n\t\t\t// check which color presentation text has same prefix as original text's prefix\n\t\t\tconst originalTextPrefix = originalText.split('(')[0].toLowerCase();\n\t\t\tfor (let i = 0; i < this.colorPresentations.length; i++) {\n\t\t\t\tif (this.colorPresentations[i].label.toLowerCase().startsWith(originalTextPrefix)) {\n\t\t\t\t\tpresentationIndex = i;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (presentationIndex !== -1 && presentationIndex !== this.presentationIndex) {\n\t\t\tthis.presentationIndex = presentationIndex;\n\t\t\tthis._onDidChangePresentation.fire(this.presentation);\n\t\t}\n\t}\n\n\tflushColor(): void {\n\t\tthis._onColorFlushed.fire(this._color);\n\t}\n}\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\nimport { CharCode } from 'vs/base/common/charCode';\nimport { EditOperation, ISingleEditOperation } from 'vs/editor/common/core/editOperation';\nimport { Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\nimport { Selection } from 'vs/editor/common/core/selection';\nimport { ICommand, ICursorStateComputerData, IEditOperationBuilder } from 'vs/editor/common/editorCommon';\nimport { ITextModel } from 'vs/editor/common/model';\nimport { ILanguageConfigurationService } from 'vs/editor/common/languages/languageConfigurationRegistry';\n\nexport class BlockCommentCommand implements ICommand {\n\n\tprivate readonly _selection: Selection;\n\tprivate readonly _insertSpace: boolean;\n\tprivate _usedEndToken: string | null;\n\n\tconstructor(\n\t\tselection: Selection,\n\t\tinsertSpace: boolean,\n\t\tprivate readonly languageConfigurationService: ILanguageConfigurationService\n\t) {\n\t\tthis._selection = selection;\n\t\tthis._insertSpace = insertSpace;\n\t\tthis._usedEndToken = null;\n\t}\n\n\tpublic static _haystackHasNeedleAtOffset(haystack: string, needle: string, offset: number): boolean {\n\t\tif (offset < 0) {\n\t\t\treturn false;\n\t\t}\n\t\tconst needleLength = needle.length;\n\t\tconst haystackLength = haystack.length;\n\t\tif (offset + needleLength > haystackLength) {\n\t\t\treturn false;\n\t\t}\n\n\t\tfor (let i = 0; i < needleLength; i++) {\n\t\t\tconst codeA = haystack.charCodeAt(offset + i);\n\t\t\tconst codeB = needle.charCodeAt(i);\n\n\t\t\tif (codeA === codeB) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (codeA >= CharCode.A && codeA <= CharCode.Z && codeA + 32 === codeB) {\n\t\t\t\t// codeA is upper-case variant of codeB\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (codeB >= CharCode.A && codeB <= CharCode.Z && codeB + 32 === codeA) {\n\t\t\t\t// codeB is upper-case variant of codeA\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\tprivate _createOperationsForBlockComment(selection: Range, startToken: string, endToken: string, insertSpace: boolean, model: ITextModel, builder: IEditOperationBuilder): void {\n\t\tconst startLineNumber = selection.startLineNumber;\n\t\tconst startColumn = selection.startColumn;\n\t\tconst endLineNumber = selection.endLineNumber;\n\t\tconst endColumn = selection.endColumn;\n\n\t\tconst startLineText = model.getLineContent(startLineNumber);\n\t\tconst endLineText = model.getLineContent(endLineNumber);\n\n\t\tlet startTokenIndex = startLineText.lastIndexOf(startToken, startColumn - 1 + startToken.length);\n\t\tlet endTokenIndex = endLineText.indexOf(endToken, endColumn - 1 - endToken.length);\n\n\t\tif (startTokenIndex !== -1 && endTokenIndex !== -1) {\n\n\t\t\tif (startLineNumber === endLineNumber) {\n\t\t\t\tconst lineBetweenTokens = startLineText.substring(startTokenIndex + startToken.length, endTokenIndex);\n\n\t\t\t\tif (lineBetweenTokens.indexOf(endToken) >= 0) {\n\t\t\t\t\t// force to add a block comment\n\t\t\t\t\tstartTokenIndex = -1;\n\t\t\t\t\tendTokenIndex = -1;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst startLineAfterStartToken = startLineText.substring(startTokenIndex + startToken.length);\n\t\t\t\tconst endLineBeforeEndToken = endLineText.substring(0, endTokenIndex);\n\n\t\t\t\tif (startLineAfterStartToken.indexOf(endToken) >= 0 || endLineBeforeEndToken.indexOf(endToken) >= 0) {\n\t\t\t\t\t// force to add a block comment\n\t\t\t\t\tstartTokenIndex = -1;\n\t\t\t\t\tendTokenIndex = -1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tlet ops: ISingleEditOperation[];\n\n\t\tif (startTokenIndex !== -1 && endTokenIndex !== -1) {\n\t\t\t// Consider spaces as part of the comment tokens\n\t\t\tif (insertSpace && startTokenIndex + startToken.length < startLineText.length && startLineText.charCodeAt(startTokenIndex + startToken.length) === CharCode.Space) {\n\t\t\t\t// Pretend the start token contains a trailing space\n\t\t\t\tstartToken = startToken + ' ';\n\t\t\t}\n\n\t\t\tif (insertSpace && endTokenIndex > 0 && endLineText.charCodeAt(endTokenIndex - 1) === CharCode.Space) {\n\t\t\t\t// Pretend the end token contains a leading space\n\t\t\t\tendToken = ' ' + endToken;\n\t\t\t\tendTokenIndex -= 1;\n\t\t\t}\n\t\t\tops = BlockCommentCommand._createRemoveBlockCommentOperations(\n\t\t\t\tnew Range(startLineNumber, startTokenIndex + startToken.length + 1, endLineNumber, endTokenIndex + 1), startToken, endToken\n\t\t\t);\n\t\t} else {\n\t\t\tops = BlockCommentCommand._createAddBlockCommentOperations(selection, startToken, endToken, this._insertSpace);\n\t\t\tthis._usedEndToken = ops.length === 1 ? endToken : null;\n\t\t}\n\n\t\tfor (const op of ops) {\n\t\t\tbuilder.addTrackedEditOperation(op.range, op.text);\n\t\t}\n\t}\n\n\tpublic static _createRemoveBlockCommentOperations(r: Range, startToken: string, endToken: string): ISingleEditOperation[] {\n\t\tconst res: ISingleEditOperation[] = [];\n\n\t\tif (!Range.isEmpty(r)) {\n\t\t\t// Remove block comment start\n\t\t\tres.push(EditOperation.delete(new Range(\n\t\t\t\tr.startLineNumber, r.startColumn - startToken.length,\n\t\t\t\tr.startLineNumber, r.startColumn\n\t\t\t)));\n\n\t\t\t// Remove block comment end\n\t\t\tres.push(EditOperation.delete(new Range(\n\t\t\t\tr.endLineNumber, r.endColumn,\n\t\t\t\tr.endLineNumber, r.endColumn + endToken.length\n\t\t\t)));\n\t\t} else {\n\t\t\t// Remove both continuously\n\t\t\tres.push(EditOperation.delete(new Range(\n\t\t\t\tr.startLineNumber, r.startColumn - startToken.length,\n\t\t\t\tr.endLineNumber, r.endColumn + endToken.length\n\t\t\t)));\n\t\t}\n\n\t\treturn res;\n\t}\n\n\tpublic static _createAddBlockCommentOperations(r: Range, startToken: string, endToken: string, insertSpace: boolean): ISingleEditOperation[] {\n\t\tconst res: ISingleEditOperation[] = [];\n\n\t\tif (!Range.isEmpty(r)) {\n\t\t\t// Insert block comment start\n\t\t\tres.push(EditOperation.insert(new Position(r.startLineNumber, r.startColumn), startToken + (insertSpace ? ' ' : '')));\n\n\t\t\t// Insert block comment end\n\t\t\tres.push(EditOperation.insert(new Position(r.endLineNumber, r.endColumn), (insertSpace ? ' ' : '') + endToken));\n\t\t} else {\n\t\t\t// Insert both continuously\n\t\t\tres.push(EditOperation.replace(new Range(\n\t\t\t\tr.startLineNumber, r.startColumn,\n\t\t\t\tr.endLineNumber, r.endColumn\n\t\t\t), startToken + ' ' + endToken));\n\t\t}\n\n\t\treturn res;\n\t}\n\n\tpublic getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {\n\t\tconst startLineNumber = this._selection.startLineNumber;\n\t\tconst startColumn = this._selection.startColumn;\n\n\t\tmodel.tokenization.tokenizeIfCheap(startLineNumber);\n\t\tconst languageId = model.getLanguageIdAtPosition(startLineNumber, startColumn);\n\t\tconst config = this.languageConfigurationService.getLanguageConfiguration(languageId).comments;\n\t\tif (!config || !config.blockCommentStartToken || !config.blockCommentEndToken) {\n\t\t\t// Mode does not support block comments\n\t\t\treturn;\n\t\t}\n\n\t\tthis._createOperationsForBlockComment(this._selection, config.blockCommentStartToken, config.blockCommentEndToken, this._insertSpace, model, builder);\n\t}\n\n\tpublic computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {\n\t\tconst inverseEditOperations = helper.getInverseEditOperations();\n\t\tif (inverseEditOperations.length === 2) {\n\t\t\tconst startTokenEditOperation = inverseEditOperations[0];\n\t\t\tconst endTokenEditOperation = inverseEditOperations[1];\n\n\t\t\treturn new Selection(\n\t\t\t\tstartTokenEditOperation.range.endLineNumber,\n\t\t\t\tstartTokenEditOperation.range.endColumn,\n\t\t\t\tendTokenEditOperation.range.startLineNumber,\n\t\t\t\tendTokenEditOperation.range.startColumn\n\t\t\t);\n\t\t} else {\n\t\t\tconst srcRange = inverseEditOperations[0].range;\n\t\t\tconst deltaColumn = this._usedEndToken ? -this._usedEndToken.length - 1 : 0; // minus 1 space before endToken\n\t\t\treturn new Selection(\n\t\t\t\tsrcRange.endLineNumber,\n\t\t\t\tsrcRange.endColumn + deltaColumn,\n\t\t\t\tsrcRange.endLineNumber,\n\t\t\t\tsrcRange.endColumn + deltaColumn\n\t\t\t);\n\t\t}\n\t}\n}\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\nimport { CharCode } from 'vs/base/common/charCode';\nimport * as strings from 'vs/base/common/strings';\nimport { Constants } from 'vs/base/common/uint';\nimport { EditOperation, ISingleEditOperation } from 'vs/editor/common/core/editOperation';\nimport { Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\nimport { Selection } from 'vs/editor/common/core/selection';\nimport { ICommand, ICursorStateComputerData, IEditOperationBuilder } from 'vs/editor/common/editorCommon';\nimport { ITextModel } from 'vs/editor/common/model';\nimport { ILanguageConfigurationService } from 'vs/editor/common/languages/languageConfigurationRegistry';\nimport { BlockCommentCommand } from 'vs/editor/contrib/comment/browser/blockCommentCommand';\n\nexport interface IInsertionPoint {\n\tignore: boolean;\n\tcommentStrOffset: number;\n}\n\nexport interface ILinePreflightData {\n\tignore: boolean;\n\tcommentStr: string;\n\tcommentStrOffset: number;\n\tcommentStrLength: number;\n}\n\nexport interface IPreflightDataSupported {\n\tsupported: true;\n\tshouldRemoveComments: boolean;\n\tlines: ILinePreflightData[];\n}\nexport interface IPreflightDataUnsupported {\n\tsupported: false;\n}\nexport type IPreflightData = IPreflightDataSupported | IPreflightDataUnsupported;\n\nexport interface ISimpleModel {\n\tgetLineContent(lineNumber: number): string;\n}\n\nexport const enum Type {\n\tToggle = 0,\n\tForceAdd = 1,\n\tForceRemove = 2\n}\n\nexport class LineCommentCommand implements ICommand {\n\n\tprivate readonly _selection: Selection;\n\tprivate readonly _indentSize: number;\n\tprivate readonly _type: Type;\n\tprivate readonly _insertSpace: boolean;\n\tprivate readonly _ignoreEmptyLines: boolean;\n\tprivate _selectionId: string | null;\n\tprivate _deltaColumn: number;\n\tprivate _moveEndPositionDown: boolean;\n\tprivate _ignoreFirstLine: boolean;\n\n\tconstructor(\n\t\tprivate readonly languageConfigurationService: ILanguageConfigurationService,\n\t\tselection: Selection,\n\t\tindentSize: number,\n\t\ttype: Type,\n\t\tinsertSpace: boolean,\n\t\tignoreEmptyLines: boolean,\n\t\tignoreFirstLine?: boolean,\n\t) {\n\t\tthis._selection = selection;\n\t\tthis._indentSize = indentSize;\n\t\tthis._type = type;\n\t\tthis._insertSpace = insertSpace;\n\t\tthis._selectionId = null;\n\t\tthis._deltaColumn = 0;\n\t\tthis._moveEndPositionDown = false;\n\t\tthis._ignoreEmptyLines = ignoreEmptyLines;\n\t\tthis._ignoreFirstLine = ignoreFirstLine || false;\n\t}\n\n\t/**\n\t * Do an initial pass over the lines and gather info about the line comment string.\n\t * Returns null if any of the lines doesn't support a line comment string.\n\t */\n\tprivate static _gatherPreflightCommentStrings(model: ITextModel, startLineNumber: number, endLineNumber: number, languageConfigurationService: ILanguageConfigurationService): ILinePreflightData[] | null {\n\n\t\tmodel.tokenization.tokenizeIfCheap(startLineNumber);\n\t\tconst languageId = model.getLanguageIdAtPosition(startLineNumber, 1);\n\n\t\tconst config = languageConfigurationService.getLanguageConfiguration(languageId).comments;\n\t\tconst commentStr = (config ? config.lineCommentToken : null);\n\t\tif (!commentStr) {\n\t\t\t// Mode does not support line comments\n\t\t\treturn null;\n\t\t}\n\n\t\tconst lines: ILinePreflightData[] = [];\n\t\tfor (let i = 0, lineCount = endLineNumber - startLineNumber + 1; i < lineCount; i++) {\n\t\t\tlines[i] = {\n\t\t\t\tignore: false,\n\t\t\t\tcommentStr: commentStr,\n\t\t\t\tcommentStrOffset: 0,\n\t\t\t\tcommentStrLength: commentStr.length\n\t\t\t};\n\t\t}\n\n\t\treturn lines;\n\t}\n\n\t/**\n\t * Analyze lines and decide which lines are relevant and what the toggle should do.\n\t * Also, build up several offsets and lengths useful in the generation of editor operations.\n\t */\n\tpublic static _analyzeLines(type: Type, insertSpace: boolean, model: ISimpleModel, lines: ILinePreflightData[], startLineNumber: number, ignoreEmptyLines: boolean, ignoreFirstLine: boolean, languageConfigurationService: ILanguageConfigurationService): IPreflightData {\n\t\tlet onlyWhitespaceLines = true;\n\n\t\tlet shouldRemoveComments: boolean;\n\t\tif (type === Type.Toggle) {\n\t\t\tshouldRemoveComments = true;\n\t\t} else if (type === Type.ForceAdd) {\n\t\t\tshouldRemoveComments = false;\n\t\t} else {\n\t\t\tshouldRemoveComments = true;\n\t\t}\n\n\t\tfor (let i = 0, lineCount = lines.length; i < lineCount; i++) {\n\t\t\tconst lineData = lines[i];\n\t\t\tconst lineNumber = startLineNumber + i;\n\n\t\t\tif (lineNumber === startLineNumber && ignoreFirstLine) {\n\t\t\t\t// first line ignored\n\t\t\t\tlineData.ignore = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst lineContent = model.getLineContent(lineNumber);\n\t\t\tconst lineContentStartOffset = strings.firstNonWhitespaceIndex(lineContent);\n\n\t\t\tif (lineContentStartOffset === -1) {\n\t\t\t\t// Empty or whitespace only line\n\t\t\t\tlineData.ignore = ignoreEmptyLines;\n\t\t\t\tlineData.commentStrOffset = lineContent.length;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tonlyWhitespaceLines = false;\n\t\t\tlineData.ignore = false;\n\t\t\tlineData.commentStrOffset = lineContentStartOffset;\n\n\t\t\tif (shouldRemoveComments && !BlockCommentCommand._haystackHasNeedleAtOffset(lineContent, lineData.commentStr, lineContentStartOffset)) {\n\t\t\t\tif (type === Type.Toggle) {\n\t\t\t\t\t// Every line so far has been a line comment, but this one is not\n\t\t\t\t\tshouldRemoveComments = false;\n\t\t\t\t} else if (type === Type.ForceAdd) {\n\t\t\t\t\t// Will not happen\n\t\t\t\t} else {\n\t\t\t\t\tlineData.ignore = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (shouldRemoveComments && insertSpace) {\n\t\t\t\t// Remove a following space if present\n\t\t\t\tconst commentStrEndOffset = lineContentStartOffset + lineData.commentStrLength;\n\t\t\t\tif (commentStrEndOffset < lineContent.length && lineContent.charCodeAt(commentStrEndOffset) === CharCode.Space) {\n\t\t\t\t\tlineData.commentStrLength += 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (type === Type.Toggle && onlyWhitespaceLines) {\n\t\t\t// For only whitespace lines, we insert comments\n\t\t\tshouldRemoveComments = false;\n\n\t\t\t// Also, no longer ignore them\n\t\t\tfor (let i = 0, lineCount = lines.length; i < lineCount; i++) {\n\t\t\t\tlines[i].ignore = false;\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tsupported: true,\n\t\t\tshouldRemoveComments: shouldRemoveComments,\n\t\t\tlines: lines\n\t\t};\n\t}\n\n\t/**\n\t * Analyze all lines and decide exactly what to do => not supported | insert line comments | remove line comments\n\t */\n\tpublic static _gatherPreflightData(type: Type, insertSpace: boolean, model: ITextModel, startLineNumber: number, endLineNumber: number, ignoreEmptyLines: boolean, ignoreFirstLine: boolean, languageConfigurationService: ILanguageConfigurationService): IPreflightData {\n\t\tconst lines = LineCommentCommand._gatherPreflightCommentStrings(model, startLineNumber, endLineNumber, languageConfigurationService);\n\t\tif (lines === null) {\n\t\t\treturn {\n\t\t\t\tsupported: false\n\t\t\t};\n\t\t}\n\n\t\treturn LineCommentCommand._analyzeLines(type, insertSpace, model, lines, startLineNumber, ignoreEmptyLines, ignoreFirstLine, languageConfigurationService);\n\t}\n\n\t/**\n\t * Given a successful analysis, execute either insert line comments, either remove line comments\n\t */\n\tprivate _executeLineComments(model: ISimpleModel, builder: IEditOperationBuilder, data: IPreflightDataSupported, s: Selection): void {\n\n\t\tlet ops: ISingleEditOperation[];\n\n\t\tif (data.shouldRemoveComments) {\n\t\t\tops = LineCommentCommand._createRemoveLineCommentsOperations(data.lines, s.startLineNumber);\n\t\t} else {\n\t\t\tLineCommentCommand._normalizeInsertionPoint(model, data.lines, s.startLineNumber, this._indentSize);\n\t\t\tops = this._createAddLineCommentsOperations(data.lines, s.startLineNumber);\n\t\t}\n\n\t\tconst cursorPosition = new Position(s.positionLineNumber, s.positionColumn);\n\n\t\tfor (let i = 0, len = ops.length; i < len; i++) {\n\t\t\tbuilder.addEditOperation(ops[i].range, ops[i].text);\n\t\t\tif (Range.isEmpty(ops[i].range) && Range.getStartPosition(ops[i].range).equals(cursorPosition)) {\n\t\t\t\tconst lineContent = model.getLineContent(cursorPosition.lineNumber);\n\t\t\t\tif (lineContent.length + 1 === cursorPosition.column) {\n\t\t\t\t\tthis._deltaColumn = (ops[i].text || '').length;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthis._selectionId = builder.trackSelection(s);\n\t}\n\n\tprivate _attemptRemoveBlockComment(model: ITextModel, s: Selection, startToken: string, endToken: string): ISingleEditOperation[] | null {\n\t\tlet startLineNumber = s.startLineNumber;\n\t\tlet endLineNumber = s.endLineNumber;\n\n\t\tconst startTokenAllowedBeforeColumn = endToken.length + Math.max(\n\t\t\tmodel.getLineFirstNonWhitespaceColumn(s.startLineNumber),\n\t\t\ts.startColumn\n\t\t);\n\n\t\tlet startTokenIndex = model.getLineContent(startLineNumber).lastIndexOf(startToken, startTokenAllowedBeforeColumn - 1);\n\t\tlet endTokenIndex = model.getLineContent(endLineNumber).indexOf(endToken, s.endColumn - 1 - startToken.length);\n\n\t\tif (startTokenIndex !== -1 && endTokenIndex === -1) {\n\t\t\tendTokenIndex = model.getLineContent(startLineNumber).indexOf(endToken, startTokenIndex + startToken.length);\n\t\t\tendLineNumber = startLineNumber;\n\t\t}\n\n\t\tif (startTokenIndex === -1 && endTokenIndex !== -1) {\n\t\t\tstartTokenIndex = model.getLineContent(endLineNumber).lastIndexOf(startToken, endTokenIndex);\n\t\t\tstartLineNumber = endLineNumber;\n\t\t}\n\n\t\tif (s.isEmpty() && (startTokenIndex === -1 || endTokenIndex === -1)) {\n\t\t\tstartTokenIndex = model.getLineContent(startLineNumber).indexOf(startToken);\n\t\t\tif (startTokenIndex !== -1) {\n\t\t\t\tendTokenIndex = model.getLineContent(startLineNumber).indexOf(endToken, startTokenIndex + startToken.length);\n\t\t\t}\n\t\t}\n\n\t\t// We have to adjust to possible inner white space.\n\t\t// For Space after startToken, add Space to startToken - range math will work out.\n\t\tif (startTokenIndex !== -1 && model.getLineContent(startLineNumber).charCodeAt(startTokenIndex + startToken.length) === CharCode.Space) {\n\t\t\tstartToken += ' ';\n\t\t}\n\n\t\t// For Space before endToken, add Space before endToken and shift index one left.\n\t\tif (endTokenIndex !== -1 && model.getLineContent(endLineNumber).charCodeAt(endTokenIndex - 1) === CharCode.Space) {\n\t\t\tendToken = ' ' + endToken;\n\t\t\tendTokenIndex -= 1;\n\t\t}\n\n\t\tif (startTokenIndex !== -1 && endTokenIndex !== -1) {\n\t\t\treturn BlockCommentCommand._createRemoveBlockCommentOperations(\n\t\t\t\tnew Range(startLineNumber, startTokenIndex + startToken.length + 1, endLineNumber, endTokenIndex + 1), startToken, endToken\n\t\t\t);\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * Given an unsuccessful analysis, delegate to the block comment command\n\t */\n\tprivate _executeBlockComment(model: ITextModel, builder: IEditOperationBuilder, s: Selection): void {\n\t\tmodel.tokenization.tokenizeIfCheap(s.startLineNumber);\n\t\tconst languageId = model.getLanguageIdAtPosition(s.startLineNumber, 1);\n\t\tconst config = this.languageConfigurationService.getLanguageConfiguration(languageId).comments;\n\t\tif (!config || !config.blockCommentStartToken || !config.blockCommentEndToken) {\n\t\t\t// Mode does not support block comments\n\t\t\treturn;\n\t\t}\n\n\t\tconst startToken = config.blockCommentStartToken;\n\t\tconst endToken = config.blockCommentEndToken;\n\n\t\tlet ops = this._attemptRemoveBlockComment(model, s, startToken, endToken);\n\t\tif (!ops) {\n\t\t\tif (s.isEmpty()) {\n\t\t\t\tconst lineContent = model.getLineContent(s.startLineNumber);\n\t\t\t\tlet firstNonWhitespaceIndex = strings.firstNonWhitespaceIndex(lineContent);\n\t\t\t\tif (firstNonWhitespaceIndex === -1) {\n\t\t\t\t\t// Line is empty or contains only whitespace\n\t\t\t\t\tfirstNonWhitespaceIndex = lineContent.length;\n\t\t\t\t}\n\t\t\t\tops = BlockCommentCommand._createAddBlockCommentOperations(\n\t\t\t\t\tnew Range(s.startLineNumber, firstNonWhitespaceIndex + 1, s.startLineNumber, lineContent.length + 1),\n\t\t\t\t\tstartToken,\n\t\t\t\t\tendToken,\n\t\t\t\t\tthis._insertSpace\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tops = BlockCommentCommand._createAddBlockCommentOperations(\n\t\t\t\t\tnew Range(s.startLineNumber, model.getLineFirstNonWhitespaceColumn(s.startLineNumber), s.endLineNumber, model.getLineMaxColumn(s.endLineNumber)),\n\t\t\t\t\tstartToken,\n\t\t\t\t\tendToken,\n\t\t\t\t\tthis._insertSpace\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (ops.length === 1) {\n\t\t\t\t// Leave cursor after token and Space\n\t\t\t\tthis._deltaColumn = startToken.length + 1;\n\t\t\t}\n\t\t}\n\t\tthis._selectionId = builder.trackSelection(s);\n\t\tfor (const op of ops) {\n\t\t\tbuilder.addEditOperation(op.range, op.text);\n\t\t}\n\t}\n\n\tpublic getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {\n\n\t\tlet s = this._selection;\n\t\tthis._moveEndPositionDown = false;\n\n\t\tif (s.startLineNumber === s.endLineNumber && this._ignoreFirstLine) {\n\t\t\tbuilder.addEditOperation(new Range(s.startLineNumber, model.getLineMaxColumn(s.startLineNumber), s.startLineNumber + 1, 1), s.startLineNumber === model.getLineCount() ? '' : '\\n');\n\t\t\tthis._selectionId = builder.trackSelection(s);\n\t\t\treturn;\n\t\t}\n\n\t\tif (s.startLineNumber < s.endLineNumber && s.endColumn === 1) {\n\t\t\tthis._moveEndPositionDown = true;\n\t\t\ts = s.setEndPosition(s.endLineNumber - 1, model.getLineMaxColumn(s.endLineNumber - 1));\n\t\t}\n\n\t\tconst data = LineCommentCommand._gatherPreflightData(\n\t\t\tthis._type,\n\t\t\tthis._insertSpace,\n\t\t\tmodel,\n\t\t\ts.startLineNumber,\n\t\t\ts.endLineNumber,\n\t\t\tthis._ignoreEmptyLines,\n\t\t\tthis._ignoreFirstLine,\n\t\t\tthis.languageConfigurationService\n\t\t);\n\n\t\tif (data.supported) {\n\t\t\treturn this._executeLineComments(model, builder, data, s);\n\t\t}\n\n\t\treturn this._executeBlockComment(model, builder, s);\n\t}\n\n\tpublic computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {\n\t\tlet result = helper.getTrackedSelection(this._selectionId!);\n\n\t\tif (this._moveEndPositionDown) {\n\t\t\tresult = result.setEndPosition(result.endLineNumber + 1, 1);\n\t\t}\n\n\t\treturn new Selection(\n\t\t\tresult.selectionStartLineNumber,\n\t\t\tresult.selectionStartColumn + this._deltaColumn,\n\t\t\tresult.positionLineNumber,\n\t\t\tresult.positionColumn + this._deltaColumn\n\t\t);\n\t}\n\n\t/**\n\t * Generate edit operations in the remove line comment case\n\t */\n\tpublic static _createRemoveLineCommentsOperations(lines: ILinePreflightData[], startLineNumber: number): ISingleEditOperation[] {\n\t\tconst res: ISingleEditOperation[] = [];\n\n\t\tfor (let i = 0, len = lines.length; i < len; i++) {\n\t\t\tconst lineData = lines[i];\n\n\t\t\tif (lineData.ignore) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tres.push(EditOperation.delete(new Range(\n\t\t\t\tstartLineNumber + i, lineData.commentStrOffset + 1,\n\t\t\t\tstartLineNumber + i, lineData.commentStrOffset + lineData.commentStrLength + 1\n\t\t\t)));\n\t\t}\n\n\t\treturn res;\n\t}\n\n\t/**\n\t * Generate edit operations in the add line comment case\n\t */\n\tprivate _createAddLineCommentsOperations(lines: ILinePreflightData[], startLineNumber: number): ISingleEditOperation[] {\n\t\tconst res: ISingleEditOperation[] = [];\n\t\tconst afterCommentStr = this._insertSpace ? ' ' : '';\n\n\n\t\tfor (let i = 0, len = lines.length; i < len; i++) {\n\t\t\tconst lineData = lines[i];\n\n\t\t\tif (lineData.ignore) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tres.push(EditOperation.insert(new Position(startLineNumber + i, lineData.commentStrOffset + 1), lineData.commentStr + afterCommentStr));\n\t\t}\n\n\t\treturn res;\n\t}\n\n\tprivate static nextVisibleColumn(currentVisibleColumn: number, indentSize: number, isTab: boolean, columnSize: number): number {\n\t\tif (isTab) {\n\t\t\treturn currentVisibleColumn + (indentSize - (currentVisibleColumn % indentSize));\n\t\t}\n\t\treturn currentVisibleColumn + columnSize;\n\t}\n\n\t/**\n\t * Adjust insertion points to have them vertically aligned in the add line comment case\n\t */\n\tpublic static _normalizeInsertionPoint(model: ISimpleModel, lines: IInsertionPoint[], startLineNumber: number, indentSize: number): void {\n\t\tlet minVisibleColumn = Constants.MAX_SAFE_SMALL_INTEGER;\n\t\tlet j: number;\n\t\tlet lenJ: number;\n\n\t\tfor (let i = 0, len = lines.length; i < len; i++) {\n\t\t\tif (lines[i].ignore) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst lineContent = model.getLineContent(startLineNumber + i);\n\n\t\t\tlet currentVisibleColumn = 0;\n\t\t\tfor (let j = 0, lenJ = lines[i].commentStrOffset; currentVisibleColumn < minVisibleColumn && j < lenJ; j++) {\n\t\t\t\tcurrentVisibleColumn = LineCommentCommand.nextVisibleColumn(currentVisibleColumn, indentSize, lineContent.charCodeAt(j) === CharCode.Tab, 1);\n\t\t\t}\n\n\t\t\tif (currentVisibleColumn < minVisibleColumn) {\n\t\t\t\tminVisibleColumn = currentVisibleColumn;\n\t\t\t}\n\t\t}\n\n\t\tminVisibleColumn = Math.floor(minVisibleColumn / indentSize) * indentSize;\n\n\t\tfor (let i = 0, len = lines.length; i < len; i++) {\n\t\t\tif (lines[i].ignore) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst lineContent = model.getLineContent(startLineNumber + i);\n\n\t\t\tlet currentVisibleColumn = 0;\n\t\t\tfor (j = 0, lenJ = lines[i].commentStrOffset; currentVisibleColumn < minVisibleColumn && j < lenJ; j++) {\n\t\t\t\tcurrentVisibleColumn = LineCommentCommand.nextVisibleColumn(currentVisibleColumn, indentSize, lineContent.charCodeAt(j) === CharCode.Tab, 1);\n\t\t\t}\n\n\t\t\tif (currentVisibleColumn > minVisibleColumn) {\n\t\t\t\tlines[i].commentStrOffset = j - 1;\n\t\t\t} else {\n\t\t\t\tlines[i].commentStrOffset = j;\n\t\t\t}\n\t\t}\n\t}\n}\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\nimport { Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\nimport { Selection } from 'vs/editor/common/core/selection';\nimport { ICommand, ICursorStateComputerData, IEditOperationBuilder } from 'vs/editor/common/editorCommon';\nimport { ITextModel } from 'vs/editor/common/model';\n\n\nexport class DragAndDropCommand implements ICommand {\n\n\tprivate readonly selection: Selection;\n\tprivate readonly targetPosition: Position;\n\tprivate targetSelection: Selection | null;\n\tprivate readonly copy: boolean;\n\n\tconstructor(selection: Selection, targetPosition: Position, copy: boolean) {\n\t\tthis.selection = selection;\n\t\tthis.targetPosition = targetPosition;\n\t\tthis.copy = copy;\n\t\tthis.targetSelection = null;\n\t}\n\n\tpublic getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {\n\t\tconst text = model.getValueInRange(this.selection);\n\t\tif (!this.copy) {\n\t\t\tbuilder.addEditOperation(this.selection, null);\n\t\t}\n\t\tbuilder.addEditOperation(new Range(this.targetPosition.lineNumber, this.targetPosition.column, this.targetPosition.lineNumber, this.targetPosition.column), text);\n\n\t\tif (this.selection.containsPosition(this.targetPosition) && !(\n\t\t\tthis.copy && (\n\t\t\t\tthis.selection.getEndPosition().equals(this.targetPosition) || this.selection.getStartPosition().equals(this.targetPosition)\n\t\t\t) // we allow users to paste content beside the selection\n\t\t)) {\n\t\t\tthis.targetSelection = this.selection;\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.copy) {\n\t\t\tthis.targetSelection = new Selection(\n\t\t\t\tthis.targetPosition.lineNumber,\n\t\t\t\tthis.targetPosition.column,\n\t\t\t\tthis.selection.endLineNumber - this.selection.startLineNumber + this.targetPosition.lineNumber,\n\t\t\t\tthis.selection.startLineNumber === this.selection.endLineNumber ?\n\t\t\t\t\tthis.targetPosition.column + this.selection.endColumn - this.selection.startColumn :\n\t\t\t\t\tthis.selection.endColumn\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.targetPosition.lineNumber > this.selection.endLineNumber) {\n\t\t\t// Drag the selection downwards\n\t\t\tthis.targetSelection = new Selection(\n\t\t\t\tthis.targetPosition.lineNumber - this.selection.endLineNumber + this.selection.startLineNumber,\n\t\t\t\tthis.targetPosition.column,\n\t\t\t\tthis.targetPosition.lineNumber,\n\t\t\t\tthis.selection.startLineNumber === this.selection.endLineNumber ?\n\t\t\t\t\tthis.targetPosition.column + this.selection.endColumn - this.selection.startColumn :\n\t\t\t\t\tthis.selection.endColumn\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.targetPosition.lineNumber < this.selection.endLineNumber) {\n\t\t\t// Drag the selection upwards\n\t\t\tthis.targetSelection = new Selection(\n\t\t\t\tthis.targetPosition.lineNumber,\n\t\t\t\tthis.targetPosition.column,\n\t\t\t\tthis.targetPosition.lineNumber + this.selection.endLineNumber - this.selection.startLineNumber,\n\t\t\t\tthis.selection.startLineNumber === this.selection.endLineNumber ?\n\t\t\t\t\tthis.targetPosition.column + this.selection.endColumn - this.selection.startColumn :\n\t\t\t\t\tthis.selection.endColumn\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\t// The target position is at the same line as the selection's end position.\n\t\tif (this.selection.endColumn <= this.targetPosition.column) {\n\t\t\t// The target position is after the selection's end position\n\t\t\tthis.targetSelection = new Selection(\n\t\t\t\tthis.targetPosition.lineNumber - this.selection.endLineNumber + this.selection.startLineNumber,\n\t\t\t\tthis.selection.startLineNumber === this.selection.endLineNumber ?\n\t\t\t\t\tthis.targetPosition.column - this.selection.endColumn + this.selection.startColumn :\n\t\t\t\t\tthis.targetPosition.column - this.selection.endColumn + this.selection.startColumn,\n\t\t\t\tthis.targetPosition.lineNumber,\n\t\t\t\tthis.selection.startLineNumber === this.selection.endLineNumber ?\n\t\t\t\t\tthis.targetPosition.column :\n\t\t\t\t\tthis.selection.endColumn\n\t\t\t);\n\t\t} else {\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.\n\t\t\tthis.targetSelection = new Selection(\n\t\t\t\tthis.targetPosition.lineNumber - this.selection.endLineNumber + this.selection.startLineNumber,\n\t\t\t\tthis.targetPosition.column,\n\t\t\t\tthis.targetPosition.lineNumber,\n\t\t\t\tthis.targetPosition.column + this.selection.endColumn - this.selection.startColumn\n\t\t\t);\n\t\t}\n\t}\n\n\tpublic computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {\n\t\treturn this.targetSelection!;\n\t}\n}\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\nimport { Range } from 'vs/editor/common/core/range';\nimport { Selection } from 'vs/editor/common/core/selection';\nimport { ICommand, ICursorStateComputerData, IEditOperationBuilder } from 'vs/editor/common/editorCommon';\nimport { ITextModel } from 'vs/editor/common/model';\n\ninterface IEditOperation {\n\trange: Range;\n\ttext: string;\n}\n\nexport class ReplaceAllCommand implements ICommand {\n\n\tprivate readonly _editorSelection: Selection;\n\tprivate _trackedEditorSelectionId: string | null;\n\tprivate readonly _ranges: Range[];\n\tprivate readonly _replaceStrings: string[];\n\n\tconstructor(editorSelection: Selection, ranges: Range[], replaceStrings: string[]) {\n\t\tthis._editorSelection = editorSelection;\n\t\tthis._ranges = ranges;\n\t\tthis._replaceStrings = replaceStrings;\n\t\tthis._trackedEditorSelectionId = null;\n\t}\n\n\tpublic getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {\n\t\tif (this._ranges.length > 0) {\n\t\t\t// Collect all edit operations\n\t\t\tconst ops: IEditOperation[] = [];\n\t\t\tfor (let i = 0; i < this._ranges.length; i++) {\n\t\t\t\tops.push({\n\t\t\t\t\trange: this._ranges[i],\n\t\t\t\t\ttext: this._replaceStrings[i]\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Sort them in ascending order by range starts\n\t\t\tops.sort((o1, o2) => {\n\t\t\t\treturn Range.compareRangesUsingStarts(o1.range, o2.range);\n\t\t\t});\n\n\t\t\t// Merge operations that touch each other\n\t\t\tconst resultOps: IEditOperation[] = [];\n\t\t\tlet previousOp = ops[0];\n\t\t\tfor (let i = 1; i < ops.length; i++) {\n\t\t\t\tif (previousOp.range.endLineNumber === ops[i].range.startLineNumber && previousOp.range.endColumn === ops[i].range.startColumn) {\n\t\t\t\t\t// These operations are one after another and can be merged\n\t\t\t\t\tpreviousOp.range = previousOp.range.plusRange(ops[i].range);\n\t\t\t\t\tpreviousOp.text = previousOp.text + ops[i].text;\n\t\t\t\t} else {\n\t\t\t\t\tresultOps.push(previousOp);\n\t\t\t\t\tpreviousOp = ops[i];\n\t\t\t\t}\n\t\t\t}\n\t\t\tresultOps.push(previousOp);\n\n\t\t\tfor (const op of resultOps) {\n\t\t\t\tbuilder.addEditOperation(op.range, op.text);\n\t\t\t}\n\t\t}\n\n\t\tthis._trackedEditorSelectionId = builder.trackSelection(this._editorSelection);\n\t}\n\n\tpublic computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {\n\t\treturn helper.getTrackedSelection(this._trackedEditorSelectionId!);\n\t}\n}\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\nimport { CharCode } from 'vs/base/common/charCode';\nimport { buildReplaceStringWithCasePreserved } from 'vs/base/common/search';\n\nconst enum ReplacePatternKind {\n\tStaticValue = 0,\n\tDynamicPieces = 1\n}\n\n/**\n * Assigned when the replace pattern is entirely static.\n */\nclass StaticValueReplacePattern {\n\tpublic readonly kind = ReplacePatternKind.StaticValue;\n\tconstructor(public readonly staticValue: string) { }\n}\n\n/**\n * Assigned when the replace pattern has replacement patterns.\n */\nclass DynamicPiecesReplacePattern {\n\tpublic readonly kind = ReplacePatternKind.DynamicPieces;\n\tconstructor(public readonly pieces: ReplacePiece[]) { }\n}\n\nexport class ReplacePattern {\n\n\tpublic static fromStaticValue(value: string): ReplacePattern {\n\t\treturn new ReplacePattern([ReplacePiece.staticValue(value)]);\n\t}\n\n\tprivate readonly _state: StaticValueReplacePattern | DynamicPiecesReplacePattern;\n\n\tpublic get hasReplacementPatterns(): boolean {\n\t\treturn (this._state.kind === ReplacePatternKind.DynamicPieces);\n\t}\n\n\tconstructor(pieces: ReplacePiece[] | null) {\n\t\tif (!pieces || pieces.length === 0) {\n\t\t\tthis._state = new StaticValueReplacePattern('');\n\t\t} else if (pieces.length === 1 && pieces[0].staticValue !== null) {\n\t\t\tthis._state = new StaticValueReplacePattern(pieces[0].staticValue);\n\t\t} else {\n\t\t\tthis._state = new DynamicPiecesReplacePattern(pieces);\n\t\t}\n\t}\n\n\tpublic buildReplaceString(matches: string[] | null, preserveCase?: boolean): string {\n\t\tif (this._state.kind === ReplacePatternKind.StaticValue) {\n\t\t\tif (preserveCase) {\n\t\t\t\treturn buildReplaceStringWithCasePreserved(matches, this._state.staticValue);\n\t\t\t} else {\n\t\t\t\treturn this._state.staticValue;\n\t\t\t}\n\t\t}\n\n\t\tlet result = '';\n\t\tfor (let i = 0, len = this._state.pieces.length; i < len; i++) {\n\t\t\tconst piece = this._state.pieces[i];\n\t\t\tif (piece.staticValue !== null) {\n\t\t\t\t// static value ReplacePiece\n\t\t\t\tresult += piece.staticValue;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// match index ReplacePiece\n\t\t\tlet match: string = ReplacePattern._substitute(piece.matchIndex, matches);\n\t\t\tif (piece.caseOps !== null && piece.caseOps.length > 0) {\n\t\t\t\tconst repl: string[] = [];\n\t\t\t\tconst lenOps: number = piece.caseOps.length;\n\t\t\t\tlet opIdx: number = 0;\n\t\t\t\tfor (let idx: number = 0, len: number = match.length; idx < len; idx++) {\n\t\t\t\t\tif (opIdx >= lenOps) {\n\t\t\t\t\t\trepl.push(match.slice(idx));\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tswitch (piece.caseOps[opIdx]) {\n\t\t\t\t\t\tcase 'U':\n\t\t\t\t\t\t\trepl.push(match[idx].toUpperCase());\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'u':\n\t\t\t\t\t\t\trepl.push(match[idx].toUpperCase());\n\t\t\t\t\t\t\topIdx++;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'L':\n\t\t\t\t\t\t\trepl.push(match[idx].toLowerCase());\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 'l':\n\t\t\t\t\t\t\trepl.push(match[idx].toLowerCase());\n\t\t\t\t\t\t\topIdx++;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\trepl.push(match[idx]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tmatch = repl.join('');\n\t\t\t}\n\t\t\tresult += match;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tprivate static _substitute(matchIndex: number, matches: string[] | null): string {\n\t\tif (matches === null) {\n\t\t\treturn '';\n\t\t}\n\t\tif (matchIndex === 0) {\n\t\t\treturn matches[0];\n\t\t}\n\n\t\tlet remainder = '';\n\t\twhile (matchIndex > 0) {\n\t\t\tif (matchIndex < matches.length) {\n\t\t\t\t// A match can be undefined\n\t\t\t\tconst match = (matches[matchIndex] || '');\n\t\t\t\treturn match + remainder;\n\t\t\t}\n\t\t\tremainder = String(matchIndex % 10) + remainder;\n\t\t\tmatchIndex = Math.floor(matchIndex / 10);\n\t\t}\n\t\treturn '$' + remainder;\n\t}\n}\n\n/**\n * A replace piece can either be a static string or an index to a specific match.\n */\nexport class ReplacePiece {\n\n\tpublic static staticValue(value: string): ReplacePiece {\n\t\treturn new ReplacePiece(value, -1, null);\n\t}\n\n\tpublic static caseOps(index: number, caseOps: string[]): ReplacePiece {\n\t\treturn new ReplacePiece(null, index, caseOps);\n\t}\n\n\tpublic readonly staticValue: string | null;\n\tpublic readonly matchIndex: number;\n\tpublic readonly caseOps: string[] | null;\n\n\tprivate constructor(staticValue: string | null, matchIndex: number, caseOps: string[] | null) {\n\t\tthis.staticValue = staticValue;\n\t\tthis.matchIndex = matchIndex;\n\t\tif (!caseOps || caseOps.length === 0) {\n\t\t\tthis.caseOps = null;\n\t\t} else {\n\t\t\tthis.caseOps = caseOps.slice(0);\n\t\t}\n\t}\n}\n\nclass ReplacePieceBuilder {\n\n\tprivate readonly _source: string;\n\tprivate _lastCharIndex: number;\n\tprivate readonly _result: ReplacePiece[];\n\tprivate _resultLen: number;\n\tprivate _currentStaticPiece: string;\n\n\tconstructor(source: string) {\n\t\tthis._source = source;\n\t\tthis._lastCharIndex = 0;\n\t\tthis._result = [];\n\t\tthis._resultLen = 0;\n\t\tthis._currentStaticPiece = '';\n\t}\n\n\tpublic emitUnchanged(toCharIndex: number): void {\n\t\tthis._emitStatic(this._source.substring(this._lastCharIndex, toCharIndex));\n\t\tthis._lastCharIndex = toCharIndex;\n\t}\n\n\tpublic emitStatic(value: string, toCharIndex: number): void {\n\t\tthis._emitStatic(value);\n\t\tthis._lastCharIndex = toCharIndex;\n\t}\n\n\tprivate _emitStatic(value: string): void {\n\t\tif (value.length === 0) {\n\t\t\treturn;\n\t\t}\n\t\tthis._currentStaticPiece += value;\n\t}\n\n\tpublic emitMatchIndex(index: number, toCharIndex: number, caseOps: string[]): void {\n\t\tif (this._currentStaticPiece.length !== 0) {\n\t\t\tthis._result[this._resultLen++] = ReplacePiece.staticValue(this._currentStaticPiece);\n\t\t\tthis._currentStaticPiece = '';\n\t\t}\n\t\tthis._result[this._resultLen++] = ReplacePiece.caseOps(index, caseOps);\n\t\tthis._lastCharIndex = toCharIndex;\n\t}\n\n\n\tpublic finalize(): ReplacePattern {\n\t\tthis.emitUnchanged(this._source.length);\n\t\tif (this._currentStaticPiece.length !== 0) {\n\t\t\tthis._result[this._resultLen++] = ReplacePiece.staticValue(this._currentStaticPiece);\n\t\t\tthis._currentStaticPiece = '';\n\t\t}\n\t\treturn new ReplacePattern(this._result);\n\t}\n}\n\n/**\n * \\n\t\t\t=> inserts a LF\n * \\t\t\t\t=> inserts a TAB\n * \\\\\t\t\t=> inserts a \"\\\".\n * \\u\t\t\t=> upper-cases one character in a match.\n * \\U\t\t\t=> upper-cases ALL remaining characters in a match.\n * \\l\t\t\t=> lower-cases one character in a match.\n * \\L\t\t\t=> lower-cases ALL remaining characters in a match.\n * $$\t\t\t=> inserts a \"$\".\n * $& and $0\t=> inserts the matched substring.\n * $n\t\t\t=> Where n is a non-negative integer lesser than 100, inserts the nth parenthesized submatch string\n * everything else stays untouched\n *\n * Also see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace#Specifying_a_string_as_a_parameter\n */\nexport function parseReplaceString(replaceString: string): ReplacePattern {\n\tif (!replaceString || replaceString.length === 0) {\n\t\treturn new ReplacePattern(null);\n\t}\n\n\tconst caseOps: string[] = [];\n\tconst result = new ReplacePieceBuilder(replaceString);\n\n\tfor (let i = 0, len = replaceString.length; i < len; i++) {\n\t\tconst chCode = replaceString.charCodeAt(i);\n\n\t\tif (chCode === CharCode.Backslash) {\n\n\t\t\t// move to next char\n\t\t\ti++;\n\n\t\t\tif (i >= len) {\n\t\t\t\t// string ends with a \\\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tconst nextChCode = replaceString.charCodeAt(i);\n\t\t\t// let replaceWithCharacter: string | null = null;\n\n\t\t\tswitch (nextChCode) {\n\t\t\t\tcase CharCode.Backslash:\n\t\t\t\t\t// \\\\ => inserts a \"\\\"\n\t\t\t\t\tresult.emitUnchanged(i - 1);\n\t\t\t\t\tresult.emitStatic('\\\\', i + 1);\n\t\t\t\t\tbreak;\n\t\t\t\tcase CharCode.n:\n\t\t\t\t\t// \\n => inserts a LF\n\t\t\t\t\tresult.emitUnchanged(i - 1);\n\t\t\t\t\tresult.emitStatic('\\n', i + 1);\n\t\t\t\t\tbreak;\n\t\t\t\tcase CharCode.t:\n\t\t\t\t\t// \\t => inserts a TAB\n\t\t\t\t\tresult.emitUnchanged(i - 1);\n\t\t\t\t\tresult.emitStatic('\\t', i + 1);\n\t\t\t\t\tbreak;\n\t\t\t\t// Case modification of string replacements, patterned after Boost, but only applied\n\t\t\t\t// to the replacement text, not subsequent content.\n\t\t\t\tcase CharCode.u:\n\t\t\t\t// \\u => upper-cases one character.\n\t\t\t\tcase CharCode.U:\n\t\t\t\t// \\U => upper-cases ALL following characters.\n\t\t\t\tcase CharCode.l:\n\t\t\t\t// \\l => lower-cases one character.\n\t\t\t\tcase CharCode.L:\n\t\t\t\t\t// \\L => lower-cases ALL following characters.\n\t\t\t\t\tresult.emitUnchanged(i - 1);\n\t\t\t\t\tresult.emitStatic('', i + 1);\n\t\t\t\t\tcaseOps.push(String.fromCharCode(nextChCode));\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (chCode === CharCode.DollarSign) {\n\n\t\t\t// move to next char\n\t\t\ti++;\n\n\t\t\tif (i >= len) {\n\t\t\t\t// string ends with a $\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tconst nextChCode = replaceString.charCodeAt(i);\n\n\t\t\tif (nextChCode === CharCode.DollarSign) {\n\t\t\t\t// $$ => inserts a \"$\"\n\t\t\t\tresult.emitUnchanged(i - 1);\n\t\t\t\tresult.emitStatic('$', i + 1);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (nextChCode === CharCode.Digit0 || nextChCode === CharCode.Ampersand) {\n\t\t\t\t// $& and $0 => inserts the matched substring.\n\t\t\t\tresult.emitUnchanged(i - 1);\n\t\t\t\tresult.emitMatchIndex(0, i + 1, caseOps);\n\t\t\t\tcaseOps.length = 0;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (CharCode.Digit1 <= nextChCode && nextChCode <= CharCode.Digit9) {\n\t\t\t\t// $n\n\n\t\t\t\tlet matchIndex = nextChCode - CharCode.Digit0;\n\n\t\t\t\t// peek next char to probe for $nn\n\t\t\t\tif (i + 1 < len) {\n\t\t\t\t\tconst nextNextChCode = replaceString.charCodeAt(i + 1);\n\t\t\t\t\tif (CharCode.Digit0 <= nextNextChCode && nextNextChCode <= CharCode.Digit9) {\n\t\t\t\t\t\t// $nn\n\n\t\t\t\t\t\t// move to next char\n\t\t\t\t\t\ti++;\n\t\t\t\t\t\tmatchIndex = matchIndex * 10 + (nextNextChCode - CharCode.Digit0);\n\n\t\t\t\t\t\tresult.emitUnchanged(i - 2);\n\t\t\t\t\t\tresult.emitMatchIndex(matchIndex, i + 1, caseOps);\n\t\t\t\t\t\tcaseOps.length = 0;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tresult.emitUnchanged(i - 1);\n\t\t\t\tresult.emitMatchIndex(matchIndex, i + 1, caseOps);\n\t\t\t\tcaseOps.length = 0;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn result.finalize();\n}\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\nexport interface ILineRange {\n\tstartLineNumber: number;\n\tendLineNumber: number;\n}\n\nexport const enum FoldSource {\n\tprovider = 0,\n\tuserDefined = 1,\n\trecovered = 2\n}\n\nexport const foldSourceAbbr = {\n\t[FoldSource.provider]: ' ',\n\t[FoldSource.userDefined]: 'u',\n\t[FoldSource.recovered]: 'r',\n};\n\nexport interface FoldRange {\n\tstartLineNumber: number;\n\tendLineNumber: number;\n\ttype: string | undefined;\n\tisCollapsed: boolean;\n\tsource: FoldSource;\n}\n\nexport const MAX_FOLDING_REGIONS = 0xFFFF;\nexport const MAX_LINE_NUMBER = 0xFFFFFF;\n\nconst MASK_INDENT = 0xFF000000;\n\nclass BitField {\n\tprivate readonly _states: Uint32Array;\n\tconstructor(size: number) {\n\t\tconst numWords = Math.ceil(size / 32);\n\t\tthis._states = new Uint32Array(numWords);\n\t}\n\n\tpublic get(index: number): boolean {\n\t\tconst arrayIndex = (index / 32) | 0;\n\t\tconst bit = index % 32;\n\t\treturn (this._states[arrayIndex] & (1 << bit)) !== 0;\n\t}\n\n\tpublic set(index: number, newState: boolean) {\n\t\tconst arrayIndex = (index / 32) | 0;\n\t\tconst bit = index % 32;\n\t\tconst value = this._states[arrayIndex];\n\t\tif (newState) {\n\t\t\tthis._states[arrayIndex] = value | (1 << bit);\n\t\t} else {\n\t\t\tthis._states[arrayIndex] = value & ~(1 << bit);\n\t\t}\n\t}\n}\n\nexport class FoldingRegions {\n\tprivate readonly _startIndexes: Uint32Array;\n\tprivate readonly _endIndexes: Uint32Array;\n\tprivate readonly _collapseStates: BitField;\n\tprivate readonly _userDefinedStates: BitField;\n\tprivate readonly _recoveredStates: BitField;\n\n\tprivate _parentsComputed: boolean;\n\tprivate readonly _types: Array | undefined;\n\n\tconstructor(startIndexes: Uint32Array, endIndexes: Uint32Array, types?: Array) {\n\t\tif (startIndexes.length !== endIndexes.length || startIndexes.length > MAX_FOLDING_REGIONS) {\n\t\t\tthrow new Error('invalid startIndexes or endIndexes size');\n\t\t}\n\t\tthis._startIndexes = startIndexes;\n\t\tthis._endIndexes = endIndexes;\n\t\tthis._collapseStates = new BitField(startIndexes.length);\n\t\tthis._userDefinedStates = new BitField(startIndexes.length);\n\t\tthis._recoveredStates = new BitField(startIndexes.length);\n\t\tthis._types = types;\n\t\tthis._parentsComputed = false;\n\t}\n\n\tprivate ensureParentIndices() {\n\t\tif (!this._parentsComputed) {\n\t\t\tthis._parentsComputed = true;\n\t\t\tconst parentIndexes: number[] = [];\n\t\t\tconst isInsideLast = (startLineNumber: number, endLineNumber: number) => {\n\t\t\t\tconst index = parentIndexes[parentIndexes.length - 1];\n\t\t\t\treturn this.getStartLineNumber(index) <= startLineNumber && this.getEndLineNumber(index) >= endLineNumber;\n\t\t\t};\n\t\t\tfor (let i = 0, len = this._startIndexes.length; i < len; i++) {\n\t\t\t\tconst startLineNumber = this._startIndexes[i];\n\t\t\t\tconst endLineNumber = this._endIndexes[i];\n\t\t\t\tif (startLineNumber > MAX_LINE_NUMBER || endLineNumber > MAX_LINE_NUMBER) {\n\t\t\t\t\tthrow new Error('startLineNumber or endLineNumber must not exceed ' + MAX_LINE_NUMBER);\n\t\t\t\t}\n\t\t\t\twhile (parentIndexes.length > 0 && !isInsideLast(startLineNumber, endLineNumber)) {\n\t\t\t\t\tparentIndexes.pop();\n\t\t\t\t}\n\t\t\t\tconst parentIndex = parentIndexes.length > 0 ? parentIndexes[parentIndexes.length - 1] : -1;\n\t\t\t\tparentIndexes.push(i);\n\t\t\t\tthis._startIndexes[i] = startLineNumber + ((parentIndex & 0xFF) << 24);\n\t\t\t\tthis._endIndexes[i] = endLineNumber + ((parentIndex & 0xFF00) << 16);\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic get length(): number {\n\t\treturn this._startIndexes.length;\n\t}\n\n\tpublic getStartLineNumber(index: number): number {\n\t\treturn this._startIndexes[index] & MAX_LINE_NUMBER;\n\t}\n\n\tpublic getEndLineNumber(index: number): number {\n\t\treturn this._endIndexes[index] & MAX_LINE_NUMBER;\n\t}\n\n\tpublic getType(index: number): string | undefined {\n\t\treturn this._types ? this._types[index] : undefined;\n\t}\n\n\tpublic hasTypes() {\n\t\treturn !!this._types;\n\t}\n\n\tpublic isCollapsed(index: number): boolean {\n\t\treturn this._collapseStates.get(index);\n\t}\n\n\tpublic setCollapsed(index: number, newState: boolean) {\n\t\tthis._collapseStates.set(index, newState);\n\t}\n\n\tprivate isUserDefined(index: number): boolean {\n\t\treturn this._userDefinedStates.get(index);\n\t}\n\n\tprivate setUserDefined(index: number, newState: boolean) {\n\t\treturn this._userDefinedStates.set(index, newState);\n\t}\n\n\tprivate isRecovered(index: number): boolean {\n\t\treturn this._recoveredStates.get(index);\n\t}\n\n\tprivate setRecovered(index: number, newState: boolean) {\n\t\treturn this._recoveredStates.set(index, newState);\n\t}\n\n\tpublic getSource(index: number): FoldSource {\n\t\tif (this.isUserDefined(index)) {\n\t\t\treturn FoldSource.userDefined;\n\t\t} else if (this.isRecovered(index)) {\n\t\t\treturn FoldSource.recovered;\n\t\t}\n\t\treturn FoldSource.provider;\n\t}\n\n\tpublic setSource(index: number, source: FoldSource): void {\n\t\tif (source === FoldSource.userDefined) {\n\t\t\tthis.setUserDefined(index, true);\n\t\t\tthis.setRecovered(index, false);\n\t\t} else if (source === FoldSource.recovered) {\n\t\t\tthis.setUserDefined(index, false);\n\t\t\tthis.setRecovered(index, true);\n\t\t} else {\n\t\t\tthis.setUserDefined(index, false);\n\t\t\tthis.setRecovered(index, false);\n\t\t}\n\t}\n\n\tpublic setCollapsedAllOfType(type: string, newState: boolean) {\n\t\tlet hasChanged = false;\n\t\tif (this._types) {\n\t\t\tfor (let i = 0; i < this._types.length; i++) {\n\t\t\t\tif (this._types[i] === type) {\n\t\t\t\t\tthis.setCollapsed(i, newState);\n\t\t\t\t\thasChanged = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn hasChanged;\n\t}\n\n\tpublic toRegion(index: number): FoldingRegion {\n\t\treturn new FoldingRegion(this, index);\n\t}\n\n\tpublic getParentIndex(index: number) {\n\t\tthis.ensureParentIndices();\n\t\tconst parent = ((this._startIndexes[index] & MASK_INDENT) >>> 24) + ((this._endIndexes[index] & MASK_INDENT) >>> 16);\n\t\tif (parent === MAX_FOLDING_REGIONS) {\n\t\t\treturn -1;\n\t\t}\n\t\treturn parent;\n\t}\n\n\tpublic contains(index: number, line: number) {\n\t\treturn this.getStartLineNumber(index) <= line && this.getEndLineNumber(index) >= line;\n\t}\n\n\tprivate findIndex(line: number) {\n\t\tlet low = 0, high = this._startIndexes.length;\n\t\tif (high === 0) {\n\t\t\treturn -1; // no children\n\t\t}\n\t\twhile (low < high) {\n\t\t\tconst mid = Math.floor((low + high) / 2);\n\t\t\tif (line < this.getStartLineNumber(mid)) {\n\t\t\t\thigh = mid;\n\t\t\t} else {\n\t\t\t\tlow = mid + 1;\n\t\t\t}\n\t\t}\n\t\treturn low - 1;\n\t}\n\n\tpublic findRange(line: number): number {\n\t\tlet index = this.findIndex(line);\n\t\tif (index >= 0) {\n\t\t\tconst endLineNumber = this.getEndLineNumber(index);\n\t\t\tif (endLineNumber >= line) {\n\t\t\t\treturn index;\n\t\t\t}\n\t\t\tindex = this.getParentIndex(index);\n\t\t\twhile (index !== -1) {\n\t\t\t\tif (this.contains(index, line)) {\n\t\t\t\t\treturn index;\n\t\t\t\t}\n\t\t\t\tindex = this.getParentIndex(index);\n\t\t\t}\n\t\t}\n\t\treturn -1;\n\t}\n\n\n\tpublic toString() {\n\t\tconst res: string[] = [];\n\t\tfor (let i = 0; i < this.length; i++) {\n\t\t\tres[i] = `[${foldSourceAbbr[this.getSource(i)]}${this.isCollapsed(i) ? '+' : '-'}] ${this.getStartLineNumber(i)}/${this.getEndLineNumber(i)}`;\n\t\t}\n\t\treturn res.join(', ');\n\t}\n\n\tpublic toFoldRange(index: number): FoldRange {\n\t\treturn {\n\t\t\tstartLineNumber: this._startIndexes[index] & MAX_LINE_NUMBER,\n\t\t\tendLineNumber: this._endIndexes[index] & MAX_LINE_NUMBER,\n\t\t\ttype: this._types ? this._types[index] : undefined,\n\t\t\tisCollapsed: this.isCollapsed(index),\n\t\t\tsource: this.getSource(index)\n\t\t};\n\t}\n\n\tpublic static fromFoldRanges(ranges: FoldRange[]): FoldingRegions {\n\t\tconst rangesLength = ranges.length;\n\t\tconst startIndexes = new Uint32Array(rangesLength);\n\t\tconst endIndexes = new Uint32Array(rangesLength);\n\t\tlet types: Array | undefined = [];\n\t\tlet gotTypes = false;\n\t\tfor (let i = 0; i < rangesLength; i++) {\n\t\t\tconst range = ranges[i];\n\t\t\tstartIndexes[i] = range.startLineNumber;\n\t\t\tendIndexes[i] = range.endLineNumber;\n\t\t\ttypes.push(range.type);\n\t\t\tif (range.type) {\n\t\t\t\tgotTypes = true;\n\t\t\t}\n\t\t}\n\t\tif (!gotTypes) {\n\t\t\ttypes = undefined;\n\t\t}\n\t\tconst regions = new FoldingRegions(startIndexes, endIndexes, types);\n\t\tfor (let i = 0; i < rangesLength; i++) {\n\t\t\tif (ranges[i].isCollapsed) {\n\t\t\t\tregions.setCollapsed(i, true);\n\t\t\t}\n\t\t\tregions.setSource(i, ranges[i].source);\n\t\t}\n\t\treturn regions;\n\t}\n\n\t/**\n\t * Two inputs, each a FoldingRegions or a FoldRange[], are merged.\n\t * Each input must be pre-sorted on startLineNumber.\n\t * The first list is assumed to always include all regions currently defined by range providers.\n\t * The second list only contains the previously collapsed and all manual ranges.\n\t * If the line position matches, the range of the new range is taken, and the range is no longer manual\n\t * When an entry in one list overlaps an entry in the other, the second list's entry \"wins\" and\n\t * overlapping entries in the first list are discarded.\n\t * Invalid entries are discarded. An entry is invalid if:\n\t * \t\tthe start and end line numbers aren't a valid range of line numbers,\n\t * \t\tit is out of sequence or has the same start line as a preceding entry,\n\t * \t\tit overlaps a preceding entry and is not fully contained by that entry.\n\t */\n\tpublic static sanitizeAndMerge(\n\t\trangesA: FoldingRegions | FoldRange[],\n\t\trangesB: FoldingRegions | FoldRange[],\n\t\tmaxLineNumber: number | undefined): FoldRange[] {\n\t\tmaxLineNumber = maxLineNumber ?? Number.MAX_VALUE;\n\n\t\tconst getIndexedFunction = (r: FoldingRegions | FoldRange[], limit: number) => {\n\t\t\treturn Array.isArray(r)\n\t\t\t\t? ((i: number) => { return (i < limit) ? r[i] : undefined; })\n\t\t\t\t: ((i: number) => { return (i < limit) ? r.toFoldRange(i) : undefined; });\n\t\t};\n\t\tconst getA = getIndexedFunction(rangesA, rangesA.length);\n\t\tconst getB = getIndexedFunction(rangesB, rangesB.length);\n\t\tlet indexA = 0;\n\t\tlet indexB = 0;\n\t\tlet nextA = getA(0);\n\t\tlet nextB = getB(0);\n\n\t\tconst stackedRanges: FoldRange[] = [];\n\t\tlet topStackedRange: FoldRange | undefined;\n\t\tlet prevLineNumber = 0;\n\t\tconst resultRanges: FoldRange[] = [];\n\n\t\twhile (nextA || nextB) {\n\n\t\t\tlet useRange: FoldRange | undefined = undefined;\n\t\t\tif (nextB && (!nextA || nextA.startLineNumber >= nextB.startLineNumber)) {\n\t\t\t\tif (nextA && nextA.startLineNumber === nextB.startLineNumber) {\n\t\t\t\t\tif (nextB.source === FoldSource.userDefined) {\n\t\t\t\t\t\t// a user defined range (possibly unfolded)\n\t\t\t\t\t\tuseRange = nextB;\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// a previously folded range or a (possibly unfolded) recovered range\n\t\t\t\t\t\tuseRange = nextA;\n\t\t\t\t\t\tuseRange.isCollapsed = nextB.isCollapsed && nextA.endLineNumber === nextB.endLineNumber;\n\t\t\t\t\t\tuseRange.source = FoldSource.provider;\n\t\t\t\t\t}\n\t\t\t\t\tnextA = getA(++indexA); // not necessary, just for speed\n\t\t\t\t} else {\n\t\t\t\t\tuseRange = nextB;\n\t\t\t\t\tif (nextB.isCollapsed && nextB.source === FoldSource.provider) {\n\t\t\t\t\t\t// a previously collapsed range\n\t\t\t\t\t\tuseRange.source = FoldSource.recovered;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tnextB = getB(++indexB);\n\t\t\t} else {\n\t\t\t\t// nextA is next. The user folded B set takes precedence and we sometimes need to look\n\t\t\t\t// ahead in it to check for an upcoming conflict.\n\t\t\t\tlet scanIndex = indexB;\n\t\t\t\tlet prescanB = nextB;\n\t\t\t\twhile (true) {\n\t\t\t\t\tif (!prescanB || prescanB.startLineNumber > nextA!.endLineNumber) {\n\t\t\t\t\t\tuseRange = nextA;\n\t\t\t\t\t\tbreak; // no conflict, use this nextA\n\t\t\t\t\t}\n\t\t\t\t\tif (prescanB.source === FoldSource.userDefined && prescanB.endLineNumber > nextA!.endLineNumber) {\n\t\t\t\t\t\t// we found a user folded range, it wins\n\t\t\t\t\t\tbreak; // without setting nextResult, so this nextA gets skipped\n\t\t\t\t\t}\n\t\t\t\t\tprescanB = getB(++scanIndex);\n\t\t\t\t}\n\t\t\t\tnextA = getA(++indexA);\n\t\t\t}\n\n\t\t\tif (useRange) {\n\t\t\t\twhile (topStackedRange\n\t\t\t\t\t&& topStackedRange.endLineNumber < useRange.startLineNumber) {\n\t\t\t\t\ttopStackedRange = stackedRanges.pop();\n\t\t\t\t}\n\t\t\t\tif (useRange.endLineNumber > useRange.startLineNumber\n\t\t\t\t\t&& useRange.startLineNumber > prevLineNumber\n\t\t\t\t\t&& useRange.endLineNumber <= maxLineNumber\n\t\t\t\t\t&& (!topStackedRange\n\t\t\t\t\t\t|| topStackedRange.endLineNumber >= useRange.endLineNumber)) {\n\t\t\t\t\tresultRanges.push(useRange);\n\t\t\t\t\tprevLineNumber = useRange.startLineNumber;\n\t\t\t\t\tif (topStackedRange) {\n\t\t\t\t\t\tstackedRanges.push(topStackedRange);\n\t\t\t\t\t}\n\t\t\t\t\ttopStackedRange = useRange;\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\t\treturn resultRanges;\n\t}\n\n}\n\nexport class FoldingRegion {\n\n\tconstructor(private readonly ranges: FoldingRegions, private index: number) {\n\t}\n\n\tpublic get startLineNumber() {\n\t\treturn this.ranges.getStartLineNumber(this.index);\n\t}\n\n\tpublic get endLineNumber() {\n\t\treturn this.ranges.getEndLineNumber(this.index);\n\t}\n\n\tpublic get regionIndex() {\n\t\treturn this.index;\n\t}\n\n\tpublic get parentIndex() {\n\t\treturn this.ranges.getParentIndex(this.index);\n\t}\n\n\tpublic get isCollapsed() {\n\t\treturn this.ranges.isCollapsed(this.index);\n\t}\n\n\tcontainedBy(range: ILineRange): boolean {\n\t\treturn range.startLineNumber <= this.startLineNumber && range.endLineNumber >= this.endLineNumber;\n\t}\n\tcontainsLine(lineNumber: number) {\n\t\treturn this.startLineNumber <= lineNumber && lineNumber <= this.endLineNumber;\n\t}\n}\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\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { IModelDecorationOptions, IModelDecorationsChangeAccessor, IModelDeltaDecoration, ITextModel } from 'vs/editor/common/model';\nimport { FoldingRegion, FoldingRegions, ILineRange, FoldRange, FoldSource } from './foldingRanges';\nimport { hash } from 'vs/base/common/hash';\n\nexport interface IDecorationProvider {\n\tgetDecorationOption(isCollapsed: boolean, isHidden: boolean, isManual: boolean): IModelDecorationOptions;\n\tchangeDecorations(callback: (changeAccessor: IModelDecorationsChangeAccessor) => T): T | null;\n\tremoveDecorations(decorationIds: string[]): void;\n}\n\nexport interface FoldingModelChangeEvent {\n\tmodel: FoldingModel;\n\tcollapseStateChanged?: FoldingRegion[];\n}\n\ninterface ILineMemento extends ILineRange {\n\tchecksum?: number;\n\tisCollapsed?: boolean;\n\tsource?: FoldSource;\n}\n\nexport type CollapseMemento = ILineMemento[];\n\nexport class FoldingModel {\n\tprivate readonly _textModel: ITextModel;\n\tprivate readonly _decorationProvider: IDecorationProvider;\n\n\tprivate _regions: FoldingRegions;\n\tprivate _editorDecorationIds: string[];\n\n\tprivate readonly _updateEventEmitter = new Emitter();\n\tpublic readonly onDidChange: Event = this._updateEventEmitter.event;\n\n\tpublic get regions(): FoldingRegions { return this._regions; }\n\tpublic get textModel() { return this._textModel; }\n\n\tconstructor(textModel: ITextModel, decorationProvider: IDecorationProvider) {\n\t\tthis._textModel = textModel;\n\t\tthis._decorationProvider = decorationProvider;\n\t\tthis._regions = new FoldingRegions(new Uint32Array(0), new Uint32Array(0));\n\t\tthis._editorDecorationIds = [];\n\t}\n\n\tpublic toggleCollapseState(toggledRegions: FoldingRegion[]) {\n\t\tif (!toggledRegions.length) {\n\t\t\treturn;\n\t\t}\n\t\ttoggledRegions = toggledRegions.sort((r1, r2) => r1.regionIndex - r2.regionIndex);\n\n\t\tconst processed: { [key: string]: boolean | undefined } = {};\n\t\tthis._decorationProvider.changeDecorations(accessor => {\n\t\t\tlet k = 0; // index from [0 ... this.regions.length]\n\t\t\tlet dirtyRegionEndLine = -1; // end of the range where decorations need to be updated\n\t\t\tlet lastHiddenLine = -1; // the end of the last hidden lines\n\t\t\tconst updateDecorationsUntil = (index: number) => {\n\t\t\t\twhile (k < index) {\n\t\t\t\t\tconst endLineNumber = this._regions.getEndLineNumber(k);\n\t\t\t\t\tconst isCollapsed = this._regions.isCollapsed(k);\n\t\t\t\t\tif (endLineNumber <= dirtyRegionEndLine) {\n\t\t\t\t\t\tconst isManual = this.regions.getSource(k) !== FoldSource.provider;\n\t\t\t\t\t\taccessor.changeDecorationOptions(this._editorDecorationIds[k], this._decorationProvider.getDecorationOption(isCollapsed, endLineNumber <= lastHiddenLine, isManual));\n\t\t\t\t\t}\n\t\t\t\t\tif (isCollapsed && endLineNumber > lastHiddenLine) {\n\t\t\t\t\t\tlastHiddenLine = endLineNumber;\n\t\t\t\t\t}\n\t\t\t\t\tk++;\n\t\t\t\t}\n\t\t\t};\n\t\t\tfor (const region of toggledRegions) {\n\t\t\t\tconst index = region.regionIndex;\n\t\t\t\tconst editorDecorationId = this._editorDecorationIds[index];\n\t\t\t\tif (editorDecorationId && !processed[editorDecorationId]) {\n\t\t\t\t\tprocessed[editorDecorationId] = true;\n\n\t\t\t\t\tupdateDecorationsUntil(index); // update all decorations up to current index using the old dirtyRegionEndLine\n\n\t\t\t\t\tconst newCollapseState = !this._regions.isCollapsed(index);\n\t\t\t\t\tthis._regions.setCollapsed(index, newCollapseState);\n\n\t\t\t\t\tdirtyRegionEndLine = Math.max(dirtyRegionEndLine, this._regions.getEndLineNumber(index));\n\t\t\t\t}\n\t\t\t}\n\t\t\tupdateDecorationsUntil(this._regions.length);\n\t\t});\n\t\tthis._updateEventEmitter.fire({ model: this, collapseStateChanged: toggledRegions });\n\t}\n\n\tpublic removeManualRanges(ranges: ILineRange[]) {\n\t\tconst newFoldingRanges: FoldRange[] = new Array();\n\t\tconst intersects = (foldRange: FoldRange) => {\n\t\t\tfor (const range of ranges) {\n\t\t\t\tif (!(range.startLineNumber > foldRange.endLineNumber || foldRange.startLineNumber > range.endLineNumber)) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t};\n\t\tfor (let i = 0; i < this._regions.length; i++) {\n\t\t\tconst foldRange = this._regions.toFoldRange(i);\n\t\t\tif (foldRange.source === FoldSource.provider || !intersects(foldRange)) {\n\t\t\t\tnewFoldingRanges.push(foldRange);\n\t\t\t}\n\t\t}\n\t\tthis.updatePost(FoldingRegions.fromFoldRanges(newFoldingRanges));\n\t}\n\n\tpublic update(newRegions: FoldingRegions, blockedLineNumers: number[] = []): void {\n\t\tconst foldedOrManualRanges = this._currentFoldedOrManualRanges(blockedLineNumers);\n\t\tconst newRanges = FoldingRegions.sanitizeAndMerge(newRegions, foldedOrManualRanges, this._textModel.getLineCount());\n\t\tthis.updatePost(FoldingRegions.fromFoldRanges(newRanges));\n\t}\n\n\tpublic updatePost(newRegions: FoldingRegions) {\n\t\tconst newEditorDecorations: IModelDeltaDecoration[] = [];\n\t\tlet lastHiddenLine = -1;\n\t\tfor (let index = 0, limit = newRegions.length; index < limit; index++) {\n\t\t\tconst startLineNumber = newRegions.getStartLineNumber(index);\n\t\t\tconst endLineNumber = newRegions.getEndLineNumber(index);\n\t\t\tconst isCollapsed = newRegions.isCollapsed(index);\n\t\t\tconst isManual = newRegions.getSource(index) !== FoldSource.provider;\n\t\t\tconst decorationRange = {\n\t\t\t\tstartLineNumber: startLineNumber,\n\t\t\t\tstartColumn: this._textModel.getLineMaxColumn(startLineNumber),\n\t\t\t\tendLineNumber: endLineNumber,\n\t\t\t\tendColumn: this._textModel.getLineMaxColumn(endLineNumber) + 1\n\t\t\t};\n\t\t\tnewEditorDecorations.push({ range: decorationRange, options: this._decorationProvider.getDecorationOption(isCollapsed, endLineNumber <= lastHiddenLine, isManual) });\n\t\t\tif (isCollapsed && endLineNumber > lastHiddenLine) {\n\t\t\t\tlastHiddenLine = endLineNumber;\n\t\t\t}\n\t\t}\n\t\tthis._decorationProvider.changeDecorations(accessor => this._editorDecorationIds = accessor.deltaDecorations(this._editorDecorationIds, newEditorDecorations));\n\t\tthis._regions = newRegions;\n\t\tthis._updateEventEmitter.fire({ model: this });\n\t}\n\n\tprivate _currentFoldedOrManualRanges(blockedLineNumers: number[] = []): FoldRange[] {\n\n\t\tconst isBlocked = (startLineNumber: number, endLineNumber: number) => {\n\t\t\tfor (const blockedLineNumber of blockedLineNumers) {\n\t\t\t\tif (startLineNumber < blockedLineNumber && blockedLineNumber <= endLineNumber) { // first line is visible\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t};\n\n\t\tconst foldedRanges: FoldRange[] = [];\n\t\tfor (let i = 0, limit = this._regions.length; i < limit; i++) {\n\t\t\tlet isCollapsed = this.regions.isCollapsed(i);\n\t\t\tconst source = this.regions.getSource(i);\n\t\t\tif (isCollapsed || source !== FoldSource.provider) {\n\t\t\t\tconst foldRange = this._regions.toFoldRange(i);\n\t\t\t\tconst decRange = this._textModel.getDecorationRange(this._editorDecorationIds[i]);\n\t\t\t\tif (decRange) {\n\t\t\t\t\tif (isCollapsed && isBlocked(decRange.startLineNumber, decRange.endLineNumber)) {\n\t\t\t\t\t\tisCollapsed = false; // uncollapse is the range is blocked\n\t\t\t\t\t}\n\t\t\t\t\tfoldedRanges.push({\n\t\t\t\t\t\tstartLineNumber: decRange.startLineNumber,\n\t\t\t\t\t\tendLineNumber: decRange.endLineNumber,\n\t\t\t\t\t\ttype: foldRange.type,\n\t\t\t\t\t\tisCollapsed,\n\t\t\t\t\t\tsource\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn foldedRanges;\n\t}\n\n\t/**\n\t * Collapse state memento, for persistence only\n\t */\n\tpublic getMemento(): CollapseMemento | undefined {\n\t\tconst foldedOrManualRanges = this._currentFoldedOrManualRanges();\n\t\tconst result: ILineMemento[] = [];\n\t\tconst maxLineNumber = this._textModel.getLineCount();\n\t\tfor (let i = 0, limit = foldedOrManualRanges.length; i < limit; i++) {\n\t\t\tconst range = foldedOrManualRanges[i];\n\t\t\tif (range.startLineNumber >= range.endLineNumber || range.startLineNumber < 1 || range.endLineNumber > maxLineNumber) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst checksum = this._getLinesChecksum(range.startLineNumber + 1, range.endLineNumber);\n\t\t\tresult.push({\n\t\t\t\tstartLineNumber: range.startLineNumber,\n\t\t\t\tendLineNumber: range.endLineNumber,\n\t\t\t\tisCollapsed: range.isCollapsed,\n\t\t\t\tsource: range.source,\n\t\t\t\tchecksum: checksum\n\t\t\t});\n\t\t}\n\t\treturn (result.length > 0) ? result : undefined;\n\t}\n\n\t/**\n\t * Apply persisted state, for persistence only\n\t */\n\tpublic applyMemento(state: CollapseMemento) {\n\t\tif (!Array.isArray(state)) {\n\t\t\treturn;\n\t\t}\n\t\tconst rangesToRestore: FoldRange[] = [];\n\t\tconst maxLineNumber = this._textModel.getLineCount();\n\t\tfor (const range of state) {\n\t\t\tif (range.startLineNumber >= range.endLineNumber || range.startLineNumber < 1 || range.endLineNumber > maxLineNumber) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst checksum = this._getLinesChecksum(range.startLineNumber + 1, range.endLineNumber);\n\t\t\tif (!range.checksum || checksum === range.checksum) {\n\t\t\t\trangesToRestore.push({\n\t\t\t\t\tstartLineNumber: range.startLineNumber,\n\t\t\t\t\tendLineNumber: range.endLineNumber,\n\t\t\t\t\ttype: undefined,\n\t\t\t\t\tisCollapsed: range.isCollapsed ?? true,\n\t\t\t\t\tsource: range.source ?? FoldSource.provider\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tconst newRanges = FoldingRegions.sanitizeAndMerge(this._regions, rangesToRestore, maxLineNumber);\n\t\tthis.updatePost(FoldingRegions.fromFoldRanges(newRanges));\n\t}\n\n\tprivate _getLinesChecksum(lineNumber1: number, lineNumber2: number): number {\n\t\tconst h = hash(this._textModel.getLineContent(lineNumber1)\n\t\t\t+ this._textModel.getLineContent(lineNumber2));\n\t\treturn h % 1000000; // 6 digits is plenty\n\t}\n\n\tpublic dispose() {\n\t\tthis._decorationProvider.removeDecorations(this._editorDecorationIds);\n\t}\n\n\tgetAllRegionsAtLine(lineNumber: number, filter?: (r: FoldingRegion, level: number) => boolean): FoldingRegion[] {\n\t\tconst result: FoldingRegion[] = [];\n\t\tif (this._regions) {\n\t\t\tlet index = this._regions.findRange(lineNumber);\n\t\t\tlet level = 1;\n\t\t\twhile (index >= 0) {\n\t\t\t\tconst current = this._regions.toRegion(index);\n\t\t\t\tif (!filter || filter(current, level)) {\n\t\t\t\t\tresult.push(current);\n\t\t\t\t}\n\t\t\t\tlevel++;\n\t\t\t\tindex = current.parentIndex;\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tgetRegionAtLine(lineNumber: number): FoldingRegion | null {\n\t\tif (this._regions) {\n\t\t\tconst index = this._regions.findRange(lineNumber);\n\t\t\tif (index >= 0) {\n\t\t\t\treturn this._regions.toRegion(index);\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tgetRegionsInside(region: FoldingRegion | null, filter?: RegionFilter | RegionFilterWithLevel): FoldingRegion[] {\n\t\tconst result: FoldingRegion[] = [];\n\t\tconst index = region ? region.regionIndex + 1 : 0;\n\t\tconst endLineNumber = region ? region.endLineNumber : Number.MAX_VALUE;\n\n\t\tif (filter && filter.length === 2) {\n\t\t\tconst levelStack: FoldingRegion[] = [];\n\t\t\tfor (let i = index, len = this._regions.length; i < len; i++) {\n\t\t\t\tconst current = this._regions.toRegion(i);\n\t\t\t\tif (this._regions.getStartLineNumber(i) < endLineNumber) {\n\t\t\t\t\twhile (levelStack.length > 0 && !current.containedBy(levelStack[levelStack.length - 1])) {\n\t\t\t\t\t\tlevelStack.pop();\n\t\t\t\t\t}\n\t\t\t\t\tlevelStack.push(current);\n\t\t\t\t\tif (filter(current, levelStack.length)) {\n\t\t\t\t\t\tresult.push(current);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tfor (let i = index, len = this._regions.length; i < len; i++) {\n\t\t\t\tconst current = this._regions.toRegion(i);\n\t\t\t\tif (this._regions.getStartLineNumber(i) < endLineNumber) {\n\t\t\t\t\tif (!filter || (filter as RegionFilter)(current)) {\n\t\t\t\t\t\tresult.push(current);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n}\n\ntype RegionFilter = (r: FoldingRegion) => boolean;\ntype RegionFilterWithLevel = (r: FoldingRegion, level: number) => boolean;\n\n\n/**\n * Collapse or expand the regions at the given locations\n * @param levels The number of levels. Use 1 to only impact the regions at the location, use Number.MAX_VALUE for all levels.\n * @param lineNumbers the location of the regions to collapse or expand, or if not set, all regions in the model.\n */\nexport function toggleCollapseState(foldingModel: FoldingModel, levels: number, lineNumbers: number[]) {\n\tconst toToggle: FoldingRegion[] = [];\n\tfor (const lineNumber of lineNumbers) {\n\t\tconst region = foldingModel.getRegionAtLine(lineNumber);\n\t\tif (region) {\n\t\t\tconst doCollapse = !region.isCollapsed;\n\t\t\ttoToggle.push(region);\n\t\t\tif (levels > 1) {\n\t\t\t\tconst regionsInside = foldingModel.getRegionsInside(region, (r, level: number) => r.isCollapsed !== doCollapse && level < levels);\n\t\t\t\ttoToggle.push(...regionsInside);\n\t\t\t}\n\t\t}\n\t}\n\tfoldingModel.toggleCollapseState(toToggle);\n}\n\n\n/**\n * Collapse or expand the regions at the given locations including all children.\n * @param doCollapse Whether to collapse or expand\n * @param levels The number of levels. Use 1 to only impact the regions at the location, use Number.MAX_VALUE for all levels.\n * @param lineNumbers the location of the regions to collapse or expand, or if not set, all regions in the model.\n */\nexport function setCollapseStateLevelsDown(foldingModel: FoldingModel, doCollapse: boolean, levels = Number.MAX_VALUE, lineNumbers?: number[]): void {\n\tconst toToggle: FoldingRegion[] = [];\n\tif (lineNumbers && lineNumbers.length > 0) {\n\t\tfor (const lineNumber of lineNumbers) {\n\t\t\tconst region = foldingModel.getRegionAtLine(lineNumber);\n\t\t\tif (region) {\n\t\t\t\tif (region.isCollapsed !== doCollapse) {\n\t\t\t\t\ttoToggle.push(region);\n\t\t\t\t}\n\t\t\t\tif (levels > 1) {\n\t\t\t\t\tconst regionsInside = foldingModel.getRegionsInside(region, (r, level: number) => r.isCollapsed !== doCollapse && level < levels);\n\t\t\t\t\ttoToggle.push(...regionsInside);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} else {\n\t\tconst regionsInside = foldingModel.getRegionsInside(null, (r, level: number) => r.isCollapsed !== doCollapse && level < levels);\n\t\ttoToggle.push(...regionsInside);\n\t}\n\tfoldingModel.toggleCollapseState(toToggle);\n}\n\n/**\n * Collapse or expand the regions at the given locations including all parents.\n * @param doCollapse Whether to collapse or expand\n * @param levels The number of levels. Use 1 to only impact the regions at the location, use Number.MAX_VALUE for all levels.\n * @param lineNumbers the location of the regions to collapse or expand.\n */\nexport function setCollapseStateLevelsUp(foldingModel: FoldingModel, doCollapse: boolean, levels: number, lineNumbers: number[]): void {\n\tconst toToggle: FoldingRegion[] = [];\n\tfor (const lineNumber of lineNumbers) {\n\t\tconst regions = foldingModel.getAllRegionsAtLine(lineNumber, (region, level) => region.isCollapsed !== doCollapse && level <= levels);\n\t\ttoToggle.push(...regions);\n\t}\n\tfoldingModel.toggleCollapseState(toToggle);\n}\n\n/**\n * Collapse or expand a region at the given locations. If the inner most region is already collapsed/expanded, uses the first parent instead.\n * @param doCollapse Whether to collapse or expand\n * @param lineNumbers the location of the regions to collapse or expand.\n */\nexport function setCollapseStateUp(foldingModel: FoldingModel, doCollapse: boolean, lineNumbers: number[]): void {\n\tconst toToggle: FoldingRegion[] = [];\n\tfor (const lineNumber of lineNumbers) {\n\t\tconst regions = foldingModel.getAllRegionsAtLine(lineNumber, (region,) => region.isCollapsed !== doCollapse);\n\t\tif (regions.length > 0) {\n\t\t\ttoToggle.push(regions[0]);\n\t\t}\n\t}\n\tfoldingModel.toggleCollapseState(toToggle);\n}\n\n/**\n * Folds or unfolds all regions that have a given level, except if they contain one of the blocked lines.\n * @param foldLevel level. Level == 1 is the top level\n * @param doCollapse Whether to collapse or expand\n*/\nexport function setCollapseStateAtLevel(foldingModel: FoldingModel, foldLevel: number, doCollapse: boolean, blockedLineNumbers: number[]): void {\n\tconst filter = (region: FoldingRegion, level: number) => level === foldLevel && region.isCollapsed !== doCollapse && !blockedLineNumbers.some(line => region.containsLine(line));\n\tconst toToggle = foldingModel.getRegionsInside(null, filter);\n\tfoldingModel.toggleCollapseState(toToggle);\n}\n\n/**\n * Folds or unfolds all regions, except if they contain or are contained by a region of one of the blocked lines.\n * @param doCollapse Whether to collapse or expand\n * @param blockedLineNumbers the location of regions to not collapse or expand\n */\nexport function setCollapseStateForRest(foldingModel: FoldingModel, doCollapse: boolean, blockedLineNumbers: number[]): void {\n\tconst filteredRegions: FoldingRegion[] = [];\n\tfor (const lineNumber of blockedLineNumbers) {\n\t\tconst regions = foldingModel.getAllRegionsAtLine(lineNumber, undefined);\n\t\tif (regions.length > 0) {\n\t\t\tfilteredRegions.push(regions[0]);\n\t\t}\n\t}\n\tconst filter = (region: FoldingRegion) => filteredRegions.every((filteredRegion) => !filteredRegion.containedBy(region) && !region.containedBy(filteredRegion)) && region.isCollapsed !== doCollapse;\n\tconst toToggle = foldingModel.getRegionsInside(null, filter);\n\tfoldingModel.toggleCollapseState(toToggle);\n}\n\n/**\n * Folds all regions for which the lines start with a given regex\n * @param foldingModel the folding model\n */\nexport function setCollapseStateForMatchingLines(foldingModel: FoldingModel, regExp: RegExp, doCollapse: boolean): void {\n\tconst editorModel = foldingModel.textModel;\n\tconst regions = foldingModel.regions;\n\tconst toToggle: FoldingRegion[] = [];\n\tfor (let i = regions.length - 1; i >= 0; i--) {\n\t\tif (doCollapse !== regions.isCollapsed(i)) {\n\t\t\tconst startLineNumber = regions.getStartLineNumber(i);\n\t\t\tif (regExp.test(editorModel.getLineContent(startLineNumber))) {\n\t\t\t\ttoToggle.push(regions.toRegion(i));\n\t\t\t}\n\t\t}\n\t}\n\tfoldingModel.toggleCollapseState(toToggle);\n}\n\n/**\n * Folds all regions of the given type\n * @param foldingModel the folding model\n */\nexport function setCollapseStateForType(foldingModel: FoldingModel, type: string, doCollapse: boolean): void {\n\tconst regions = foldingModel.regions;\n\tconst toToggle: FoldingRegion[] = [];\n\tfor (let i = regions.length - 1; i >= 0; i--) {\n\t\tif (doCollapse !== regions.isCollapsed(i) && type === regions.getType(i)) {\n\t\t\ttoToggle.push(regions.toRegion(i));\n\t\t}\n\t}\n\tfoldingModel.toggleCollapseState(toToggle);\n}\n\n/**\n * Get line to go to for parent fold of current line\n * @param lineNumber the current line number\n * @param foldingModel the folding model\n *\n * @return Parent fold start line\n */\nexport function getParentFoldLine(lineNumber: number, foldingModel: FoldingModel): number | null {\n\tlet startLineNumber: number | null = null;\n\tconst foldingRegion = foldingModel.getRegionAtLine(lineNumber);\n\tif (foldingRegion !== null) {\n\t\tstartLineNumber = foldingRegion.startLineNumber;\n\t\t// If current line is not the start of the current fold, go to top line of current fold. If not, go to parent fold\n\t\tif (lineNumber === startLineNumber) {\n\t\t\tconst parentFoldingIdx = foldingRegion.parentIndex;\n\t\t\tif (parentFoldingIdx !== -1) {\n\t\t\t\tstartLineNumber = foldingModel.regions.getStartLineNumber(parentFoldingIdx);\n\t\t\t} else {\n\t\t\t\tstartLineNumber = null;\n\t\t\t}\n\t\t}\n\t}\n\treturn startLineNumber;\n}\n\n/**\n * Get line to go to for previous fold at the same level of current line\n * @param lineNumber the current line number\n * @param foldingModel the folding model\n *\n * @return Previous fold start line\n */\nexport function getPreviousFoldLine(lineNumber: number, foldingModel: FoldingModel): number | null {\n\tlet foldingRegion = foldingModel.getRegionAtLine(lineNumber);\n\t// If on the folding range start line, go to previous sibling.\n\tif (foldingRegion !== null && foldingRegion.startLineNumber === lineNumber) {\n\t\t// If current line is not the start of the current fold, go to top line of current fold. If not, go to previous fold.\n\t\tif (lineNumber !== foldingRegion.startLineNumber) {\n\t\t\treturn foldingRegion.startLineNumber;\n\t\t} else {\n\t\t\t// Find min line number to stay within parent.\n\t\t\tconst expectedParentIndex = foldingRegion.parentIndex;\n\t\t\tlet minLineNumber = 0;\n\t\t\tif (expectedParentIndex !== -1) {\n\t\t\t\tminLineNumber = foldingModel.regions.getStartLineNumber(foldingRegion.parentIndex);\n\t\t\t}\n\n\t\t\t// Find fold at same level.\n\t\t\twhile (foldingRegion !== null) {\n\t\t\t\tif (foldingRegion.regionIndex > 0) {\n\t\t\t\t\tfoldingRegion = foldingModel.regions.toRegion(foldingRegion.regionIndex - 1);\n\n\t\t\t\t\t// Keep at same level.\n\t\t\t\t\tif (foldingRegion.startLineNumber <= minLineNumber) {\n\t\t\t\t\t\treturn null;\n\t\t\t\t\t} else if (foldingRegion.parentIndex === expectedParentIndex) {\n\t\t\t\t\t\treturn foldingRegion.startLineNumber;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} else {\n\t\t// Go to last fold that's before the current line.\n\t\tif (foldingModel.regions.length > 0) {\n\t\t\tfoldingRegion = foldingModel.regions.toRegion(foldingModel.regions.length - 1);\n\t\t\twhile (foldingRegion !== null) {\n\t\t\t\t// Found fold before current line.\n\t\t\t\tif (foldingRegion.startLineNumber < lineNumber) {\n\t\t\t\t\treturn foldingRegion.startLineNumber;\n\t\t\t\t}\n\t\t\t\tif (foldingRegion.regionIndex > 0) {\n\t\t\t\t\tfoldingRegion = foldingModel.regions.toRegion(foldingRegion.regionIndex - 1);\n\t\t\t\t} else {\n\t\t\t\t\tfoldingRegion = null;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn null;\n}\n\n/**\n * Get line to go to next fold at the same level of current line\n * @param lineNumber the current line number\n * @param foldingModel the folding model\n *\n * @return Next fold start line\n */\nexport function getNextFoldLine(lineNumber: number, foldingModel: FoldingModel): number | null {\n\tlet foldingRegion = foldingModel.getRegionAtLine(lineNumber);\n\t// If on the folding range start line, go to next sibling.\n\tif (foldingRegion !== null && foldingRegion.startLineNumber === lineNumber) {\n\t\t// Find max line number to stay within parent.\n\t\tconst expectedParentIndex = foldingRegion.parentIndex;\n\t\tlet maxLineNumber = 0;\n\t\tif (expectedParentIndex !== -1) {\n\t\t\tmaxLineNumber = foldingModel.regions.getEndLineNumber(foldingRegion.parentIndex);\n\t\t} else if (foldingModel.regions.length === 0) {\n\t\t\treturn null;\n\t\t} else {\n\t\t\tmaxLineNumber = foldingModel.regions.getEndLineNumber(foldingModel.regions.length - 1);\n\t\t}\n\n\t\t// Find fold at same level.\n\t\twhile (foldingRegion !== null) {\n\t\t\tif (foldingRegion.regionIndex < foldingModel.regions.length) {\n\t\t\t\tfoldingRegion = foldingModel.regions.toRegion(foldingRegion.regionIndex + 1);\n\n\t\t\t\t// Keep at same level.\n\t\t\t\tif (foldingRegion.startLineNumber >= maxLineNumber) {\n\t\t\t\t\treturn null;\n\t\t\t\t} else if (foldingRegion.parentIndex === expectedParentIndex) {\n\t\t\t\t\treturn foldingRegion.startLineNumber;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\t} else {\n\t\t// Go to first fold that's after the current line.\n\t\tif (foldingModel.regions.length > 0) {\n\t\t\tfoldingRegion = foldingModel.regions.toRegion(0);\n\t\t\twhile (foldingRegion !== null) {\n\t\t\t\t// Found fold after current line.\n\t\t\t\tif (foldingRegion.startLineNumber > lineNumber) {\n\t\t\t\t\treturn foldingRegion.startLineNumber;\n\t\t\t\t}\n\t\t\t\tif (foldingRegion.regionIndex < foldingModel.regions.length) {\n\t\t\t\t\tfoldingRegion = foldingModel.regions.toRegion(foldingRegion.regionIndex + 1);\n\t\t\t\t} else {\n\t\t\t\t\tfoldingRegion = null;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn null;\n}\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\nimport { findFirstIdxMonotonousOrArrLen } from 'vs/base/common/arraysFind';\n\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { IDisposable } from 'vs/base/common/lifecycle';\nimport { IRange, Range } from 'vs/editor/common/core/range';\nimport { Selection } from 'vs/editor/common/core/selection';\nimport { IModelContentChangedEvent } from 'vs/editor/common/textModelEvents';\nimport { countEOL } from 'vs/editor/common/core/eolCounter';\nimport { FoldingModel } from 'vs/editor/contrib/folding/browser/foldingModel';\n\nexport class HiddenRangeModel {\n\n\tprivate readonly _foldingModel: FoldingModel;\n\tprivate _hiddenRanges: IRange[];\n\tprivate _foldingModelListener: IDisposable | null;\n\tprivate readonly _updateEventEmitter = new Emitter();\n\tprivate _hasLineChanges: boolean = false;\n\n\tpublic get onDidChange(): Event { return this._updateEventEmitter.event; }\n\tpublic get hiddenRanges() { return this._hiddenRanges; }\n\n\tpublic constructor(model: FoldingModel) {\n\t\tthis._foldingModel = model;\n\t\tthis._foldingModelListener = model.onDidChange(_ => this.updateHiddenRanges());\n\t\tthis._hiddenRanges = [];\n\t\tif (model.regions.length) {\n\t\t\tthis.updateHiddenRanges();\n\t\t}\n\t}\n\n\tpublic notifyChangeModelContent(e: IModelContentChangedEvent) {\n\t\tif (this._hiddenRanges.length && !this._hasLineChanges) {\n\t\t\tthis._hasLineChanges = e.changes.some(change => {\n\t\t\t\treturn change.range.endLineNumber !== change.range.startLineNumber || countEOL(change.text)[0] !== 0;\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate updateHiddenRanges(): void {\n\t\tlet updateHiddenAreas = false;\n\t\tconst newHiddenAreas: IRange[] = [];\n\t\tlet i = 0; // index into hidden\n\t\tlet k = 0;\n\n\t\tlet lastCollapsedStart = Number.MAX_VALUE;\n\t\tlet lastCollapsedEnd = -1;\n\n\t\tconst ranges = this._foldingModel.regions;\n\t\tfor (; i < ranges.length; i++) {\n\t\t\tif (!ranges.isCollapsed(i)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst startLineNumber = ranges.getStartLineNumber(i) + 1; // the first line is not hidden\n\t\t\tconst endLineNumber = ranges.getEndLineNumber(i);\n\t\t\tif (lastCollapsedStart <= startLineNumber && endLineNumber <= lastCollapsedEnd) {\n\t\t\t\t// ignore ranges contained in collapsed regions\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (!updateHiddenAreas && k < this._hiddenRanges.length && this._hiddenRanges[k].startLineNumber === startLineNumber && this._hiddenRanges[k].endLineNumber === endLineNumber) {\n\t\t\t\t// reuse the old ranges\n\t\t\t\tnewHiddenAreas.push(this._hiddenRanges[k]);\n\t\t\t\tk++;\n\t\t\t} else {\n\t\t\t\tupdateHiddenAreas = true;\n\t\t\t\tnewHiddenAreas.push(new Range(startLineNumber, 1, endLineNumber, 1));\n\t\t\t}\n\t\t\tlastCollapsedStart = startLineNumber;\n\t\t\tlastCollapsedEnd = endLineNumber;\n\t\t}\n\t\tif (this._hasLineChanges || updateHiddenAreas || k < this._hiddenRanges.length) {\n\t\t\tthis.applyHiddenRanges(newHiddenAreas);\n\t\t}\n\t}\n\n\tprivate applyHiddenRanges(newHiddenAreas: IRange[]) {\n\t\tthis._hiddenRanges = newHiddenAreas;\n\t\tthis._hasLineChanges = false;\n\t\tthis._updateEventEmitter.fire(newHiddenAreas);\n\t}\n\n\tpublic hasRanges() {\n\t\treturn this._hiddenRanges.length > 0;\n\t}\n\n\tpublic isHidden(line: number): boolean {\n\t\treturn findRange(this._hiddenRanges, line) !== null;\n\t}\n\n\tpublic adjustSelections(selections: Selection[]): boolean {\n\t\tlet hasChanges = false;\n\t\tconst editorModel = this._foldingModel.textModel;\n\t\tlet lastRange: IRange | null = null;\n\n\t\tconst adjustLine = (line: number) => {\n\t\t\tif (!lastRange || !isInside(line, lastRange)) {\n\t\t\t\tlastRange = findRange(this._hiddenRanges, line);\n\t\t\t}\n\t\t\tif (lastRange) {\n\t\t\t\treturn lastRange.startLineNumber - 1;\n\t\t\t}\n\t\t\treturn null;\n\t\t};\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\n\t\t\tlet selection = selections[i];\n\t\t\tconst adjustedStartLine = adjustLine(selection.startLineNumber);\n\t\t\tif (adjustedStartLine) {\n\t\t\t\tselection = selection.setStartPosition(adjustedStartLine, editorModel.getLineMaxColumn(adjustedStartLine));\n\t\t\t\thasChanges = true;\n\t\t\t}\n\t\t\tconst adjustedEndLine = adjustLine(selection.endLineNumber);\n\t\t\tif (adjustedEndLine) {\n\t\t\t\tselection = selection.setEndPosition(adjustedEndLine, editorModel.getLineMaxColumn(adjustedEndLine));\n\t\t\t\thasChanges = true;\n\t\t\t}\n\t\t\tselections[i] = selection;\n\t\t}\n\t\treturn hasChanges;\n\t}\n\n\n\tpublic dispose() {\n\t\tif (this.hiddenRanges.length > 0) {\n\t\t\tthis._hiddenRanges = [];\n\t\t\tthis._updateEventEmitter.fire(this._hiddenRanges);\n\t\t}\n\t\tif (this._foldingModelListener) {\n\t\t\tthis._foldingModelListener.dispose();\n\t\t\tthis._foldingModelListener = null;\n\t\t}\n\t}\n}\n\nfunction isInside(line: number, range: IRange) {\n\treturn line >= range.startLineNumber && line <= range.endLineNumber;\n}\nfunction findRange(ranges: IRange[], line: number): IRange | null {\n\tconst i = findFirstIdxMonotonousOrArrLen(ranges, r => line < r.startLineNumber) - 1;\n\tif (i >= 0 && ranges[i].endLineNumber >= line) {\n\t\treturn ranges[i];\n\t}\n\treturn null;\n}\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\nimport { CancellationToken } from 'vs/base/common/cancellation';\nimport { ITextModel } from 'vs/editor/common/model';\nimport { computeIndentLevel } from 'vs/editor/common/model/utils';\nimport { FoldingMarkers } from 'vs/editor/common/languages/languageConfiguration';\nimport { ILanguageConfigurationService } from 'vs/editor/common/languages/languageConfigurationRegistry';\nimport { FoldingRegions, MAX_LINE_NUMBER } from 'vs/editor/contrib/folding/browser/foldingRanges';\nimport { FoldingLimitReporter, RangeProvider } from './folding';\n\nconst MAX_FOLDING_REGIONS_FOR_INDENT_DEFAULT = 5000;\n\nconst ID_INDENT_PROVIDER = 'indent';\n\nexport class IndentRangeProvider implements RangeProvider {\n\treadonly id = ID_INDENT_PROVIDER;\n\n\tconstructor(\n\t\tprivate readonly editorModel: ITextModel,\n\t\tprivate readonly languageConfigurationService: ILanguageConfigurationService,\n\t\tprivate readonly foldingRangesLimit: FoldingLimitReporter\n\t) { }\n\n\tdispose() { }\n\n\tcompute(cancelationToken: CancellationToken,): Promise {\n\t\tconst foldingRules = this.languageConfigurationService.getLanguageConfiguration(this.editorModel.getLanguageId()).foldingRules;\n\t\tconst offSide = foldingRules && !!foldingRules.offSide;\n\t\tconst markers = foldingRules && foldingRules.markers;\n\t\treturn Promise.resolve(computeRanges(this.editorModel, offSide, markers, this.foldingRangesLimit));\n\t}\n}\n\n// public only for testing\nexport class RangesCollector {\n\tprivate readonly _startIndexes: number[];\n\tprivate readonly _endIndexes: number[];\n\tprivate readonly _indentOccurrences: number[];\n\tprivate _length: number;\n\tprivate readonly _foldingRangesLimit: FoldingLimitReporter;\n\n\tconstructor(foldingRangesLimit: FoldingLimitReporter) {\n\t\tthis._startIndexes = [];\n\t\tthis._endIndexes = [];\n\t\tthis._indentOccurrences = [];\n\t\tthis._length = 0;\n\t\tthis._foldingRangesLimit = foldingRangesLimit;\n\t}\n\n\tpublic insertFirst(startLineNumber: number, endLineNumber: number, indent: number) {\n\t\tif (startLineNumber > MAX_LINE_NUMBER || endLineNumber > MAX_LINE_NUMBER) {\n\t\t\treturn;\n\t\t}\n\t\tconst index = this._length;\n\t\tthis._startIndexes[index] = startLineNumber;\n\t\tthis._endIndexes[index] = endLineNumber;\n\t\tthis._length++;\n\t\tif (indent < 1000) {\n\t\t\tthis._indentOccurrences[indent] = (this._indentOccurrences[indent] || 0) + 1;\n\t\t}\n\t}\n\n\tpublic toIndentRanges(model: ITextModel) {\n\t\tconst limit = this._foldingRangesLimit.limit;\n\t\tif (this._length <= limit) {\n\t\t\tthis._foldingRangesLimit.update(this._length, false);\n\n\t\t\t// reverse and create arrays of the exact length\n\t\t\tconst startIndexes = new Uint32Array(this._length);\n\t\t\tconst endIndexes = new Uint32Array(this._length);\n\t\t\tfor (let i = this._length - 1, k = 0; i >= 0; i--, k++) {\n\t\t\t\tstartIndexes[k] = this._startIndexes[i];\n\t\t\t\tendIndexes[k] = this._endIndexes[i];\n\t\t\t}\n\t\t\treturn new FoldingRegions(startIndexes, endIndexes);\n\t\t} else {\n\t\t\tthis._foldingRangesLimit.update(this._length, limit);\n\n\t\t\tlet entries = 0;\n\t\t\tlet maxIndent = this._indentOccurrences.length;\n\t\t\tfor (let i = 0; i < this._indentOccurrences.length; i++) {\n\t\t\t\tconst n = this._indentOccurrences[i];\n\t\t\t\tif (n) {\n\t\t\t\t\tif (n + entries > limit) {\n\t\t\t\t\t\tmaxIndent = i;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tentries += n;\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst tabSize = model.getOptions().tabSize;\n\t\t\t// reverse and create arrays of the exact length\n\t\t\tconst startIndexes = new Uint32Array(limit);\n\t\t\tconst endIndexes = new Uint32Array(limit);\n\t\t\tfor (let i = this._length - 1, k = 0; i >= 0; i--) {\n\t\t\t\tconst startIndex = this._startIndexes[i];\n\t\t\t\tconst lineContent = model.getLineContent(startIndex);\n\t\t\t\tconst indent = computeIndentLevel(lineContent, tabSize);\n\t\t\t\tif (indent < maxIndent || (indent === maxIndent && entries++ < limit)) {\n\t\t\t\t\tstartIndexes[k] = startIndex;\n\t\t\t\t\tendIndexes[k] = this._endIndexes[i];\n\t\t\t\t\tk++;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn new FoldingRegions(startIndexes, endIndexes);\n\t\t}\n\n\t}\n}\n\n\ninterface PreviousRegion {\n\tindent: number; // indent or -2 if a marker\n\tendAbove: number; // end line number for the region above\n\tline: number; // start line of the region. Only used for marker regions.\n}\n\nconst foldingRangesLimitDefault: FoldingLimitReporter = {\n\tlimit: MAX_FOLDING_REGIONS_FOR_INDENT_DEFAULT,\n\tupdate: () => { }\n};\n\nexport function computeRanges(model: ITextModel, offSide: boolean, markers?: FoldingMarkers, foldingRangesLimit: FoldingLimitReporter = foldingRangesLimitDefault): FoldingRegions {\n\tconst tabSize = model.getOptions().tabSize;\n\tconst result = new RangesCollector(foldingRangesLimit);\n\n\tlet pattern: RegExp | undefined = undefined;\n\tif (markers) {\n\t\tpattern = new RegExp(`(${markers.start.source})|(?:${markers.end.source})`);\n\t}\n\n\tconst previousRegions: PreviousRegion[] = [];\n\tconst line = model.getLineCount() + 1;\n\tpreviousRegions.push({ indent: -1, endAbove: line, line }); // sentinel, to make sure there's at least one entry\n\n\tfor (let line = model.getLineCount(); line > 0; line--) {\n\t\tconst lineContent = model.getLineContent(line);\n\t\tconst indent = computeIndentLevel(lineContent, tabSize);\n\t\tlet previous = previousRegions[previousRegions.length - 1];\n\t\tif (indent === -1) {\n\t\t\tif (offSide) {\n\t\t\t\t// for offSide languages, empty lines are associated to the previous block\n\t\t\t\t// note: the next block is already written to the results, so this only\n\t\t\t\t// impacts the end position of the block before\n\t\t\t\tprevious.endAbove = line;\n\t\t\t}\n\t\t\tcontinue; // only whitespace\n\t\t}\n\t\tlet m;\n\t\tif (pattern && (m = lineContent.match(pattern))) {\n\t\t\t// folding pattern match\n\t\t\tif (m[1]) { // start pattern match\n\t\t\t\t// discard all regions until the folding pattern\n\t\t\t\tlet i = previousRegions.length - 1;\n\t\t\t\twhile (i > 0 && previousRegions[i].indent !== -2) {\n\t\t\t\t\ti--;\n\t\t\t\t}\n\t\t\t\tif (i > 0) {\n\t\t\t\t\tpreviousRegions.length = i + 1;\n\t\t\t\t\tprevious = previousRegions[i];\n\n\t\t\t\t\t// new folding range from pattern, includes the end line\n\t\t\t\t\tresult.insertFirst(line, previous.line, indent);\n\t\t\t\t\tprevious.line = line;\n\t\t\t\t\tprevious.indent = indent;\n\t\t\t\t\tprevious.endAbove = line;\n\t\t\t\t\tcontinue;\n\t\t\t\t} else {\n\t\t\t\t\t// no end marker found, treat line as a regular line\n\t\t\t\t}\n\t\t\t} else { // end pattern match\n\t\t\t\tpreviousRegions.push({ indent: -2, endAbove: line, line });\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t\tif (previous.indent > indent) {\n\t\t\t// discard all regions with larger indent\n\t\t\tdo {\n\t\t\t\tpreviousRegions.pop();\n\t\t\t\tprevious = previousRegions[previousRegions.length - 1];\n\t\t\t} while (previous.indent > indent);\n\n\t\t\t// new folding range\n\t\t\tconst endLineNumber = previous.endAbove - 1;\n\t\t\tif (endLineNumber - line >= 1) { // needs at east size 1\n\t\t\t\tresult.insertFirst(line, endLineNumber, indent);\n\t\t\t}\n\t\t}\n\t\tif (previous.indent === indent) {\n\t\t\tprevious.endAbove = line;\n\t\t} else { // previous.indent < indent\n\t\t\t// new region with a bigger indent\n\t\t\tpreviousRegions.push({ indent, endAbove: line, line });\n\t\t}\n\t}\n\treturn result.toIndentRanges(model);\n}\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\nimport { CancellationToken } from 'vs/base/common/cancellation';\nimport { onUnexpectedExternalError } from 'vs/base/common/errors';\nimport { DisposableStore } from 'vs/base/common/lifecycle';\nimport { ITextModel } from 'vs/editor/common/model';\nimport { FoldingContext, FoldingRange, FoldingRangeProvider } from 'vs/editor/common/languages';\nimport { FoldingLimitReporter, RangeProvider } from './folding';\nimport { FoldingRegions, MAX_LINE_NUMBER } from './foldingRanges';\n\nexport interface IFoldingRangeData extends FoldingRange {\n\trank: number;\n}\n\nconst foldingContext: FoldingContext = {\n};\n\nconst ID_SYNTAX_PROVIDER = 'syntax';\n\nexport class SyntaxRangeProvider implements RangeProvider {\n\n\treadonly id = ID_SYNTAX_PROVIDER;\n\n\treadonly disposables: DisposableStore;\n\n\tconstructor(\n\t\tprivate readonly editorModel: ITextModel,\n\t\tprivate readonly providers: FoldingRangeProvider[],\n\t\treadonly handleFoldingRangesChange: () => void,\n\t\tprivate readonly foldingRangesLimit: FoldingLimitReporter,\n\t\tprivate readonly fallbackRangeProvider: RangeProvider | undefined // used when all providers return null\n\t) {\n\t\tthis.disposables = new DisposableStore();\n\t\tif (fallbackRangeProvider) {\n\t\t\tthis.disposables.add(fallbackRangeProvider);\n\t\t}\n\n\t\tfor (const provider of providers) {\n\t\t\tif (typeof provider.onDidChange === 'function') {\n\t\t\t\tthis.disposables.add(provider.onDidChange(handleFoldingRangesChange));\n\t\t\t}\n\t\t}\n\t}\n\n\tcompute(cancellationToken: CancellationToken): Promise {\n\t\treturn collectSyntaxRanges(this.providers, this.editorModel, cancellationToken).then(ranges => {\n\t\t\tif (ranges) {\n\t\t\t\tconst res = sanitizeRanges(ranges, this.foldingRangesLimit);\n\t\t\t\treturn res;\n\t\t\t}\n\t\t\treturn this.fallbackRangeProvider?.compute(cancellationToken) ?? null;\n\t\t});\n\t}\n\n\tdispose() {\n\t\tthis.disposables.dispose();\n\t}\n}\n\nfunction collectSyntaxRanges(providers: FoldingRangeProvider[], model: ITextModel, cancellationToken: CancellationToken): Promise {\n\tlet rangeData: IFoldingRangeData[] | null = null;\n\tconst promises = providers.map((provider, i) => {\n\t\treturn Promise.resolve(provider.provideFoldingRanges(model, foldingContext, cancellationToken)).then(ranges => {\n\t\t\tif (cancellationToken.isCancellationRequested) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (Array.isArray(ranges)) {\n\t\t\t\tif (!Array.isArray(rangeData)) {\n\t\t\t\t\trangeData = [];\n\t\t\t\t}\n\t\t\t\tconst nLines = model.getLineCount();\n\t\t\t\tfor (const r of ranges) {\n\t\t\t\t\tif (r.start > 0 && r.end > r.start && r.end <= nLines) {\n\t\t\t\t\t\trangeData.push({ start: r.start, end: r.end, rank: i, kind: r.kind });\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}, onUnexpectedExternalError);\n\t});\n\treturn Promise.all(promises).then(_ => {\n\t\treturn rangeData;\n\t});\n}\n\nclass RangesCollector {\n\tprivate readonly _startIndexes: number[];\n\tprivate readonly _endIndexes: number[];\n\tprivate readonly _nestingLevels: number[];\n\tprivate readonly _nestingLevelCounts: number[];\n\tprivate readonly _types: Array;\n\tprivate _length: number;\n\tprivate readonly _foldingRangesLimit: FoldingLimitReporter;\n\n\tconstructor(foldingRangesLimit: FoldingLimitReporter) {\n\t\tthis._startIndexes = [];\n\t\tthis._endIndexes = [];\n\t\tthis._nestingLevels = [];\n\t\tthis._nestingLevelCounts = [];\n\t\tthis._types = [];\n\t\tthis._length = 0;\n\t\tthis._foldingRangesLimit = foldingRangesLimit;\n\t}\n\n\tpublic add(startLineNumber: number, endLineNumber: number, type: string | undefined, nestingLevel: number) {\n\t\tif (startLineNumber > MAX_LINE_NUMBER || endLineNumber > MAX_LINE_NUMBER) {\n\t\t\treturn;\n\t\t}\n\t\tconst index = this._length;\n\t\tthis._startIndexes[index] = startLineNumber;\n\t\tthis._endIndexes[index] = endLineNumber;\n\t\tthis._nestingLevels[index] = nestingLevel;\n\t\tthis._types[index] = type;\n\t\tthis._length++;\n\t\tif (nestingLevel < 30) {\n\t\t\tthis._nestingLevelCounts[nestingLevel] = (this._nestingLevelCounts[nestingLevel] || 0) + 1;\n\t\t}\n\t}\n\n\tpublic toIndentRanges() {\n\t\tconst limit = this._foldingRangesLimit.limit;\n\t\tif (this._length <= limit) {\n\t\t\tthis._foldingRangesLimit.update(this._length, false);\n\n\t\t\tconst startIndexes = new Uint32Array(this._length);\n\t\t\tconst endIndexes = new Uint32Array(this._length);\n\t\t\tfor (let i = 0; i < this._length; i++) {\n\t\t\t\tstartIndexes[i] = this._startIndexes[i];\n\t\t\t\tendIndexes[i] = this._endIndexes[i];\n\t\t\t}\n\t\t\treturn new FoldingRegions(startIndexes, endIndexes, this._types);\n\t\t} else {\n\t\t\tthis._foldingRangesLimit.update(this._length, limit);\n\n\t\t\tlet entries = 0;\n\t\t\tlet maxLevel = this._nestingLevelCounts.length;\n\t\t\tfor (let i = 0; i < this._nestingLevelCounts.length; i++) {\n\t\t\t\tconst n = this._nestingLevelCounts[i];\n\t\t\t\tif (n) {\n\t\t\t\t\tif (n + entries > limit) {\n\t\t\t\t\t\tmaxLevel = i;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tentries += n;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst startIndexes = new Uint32Array(limit);\n\t\t\tconst endIndexes = new Uint32Array(limit);\n\t\t\tconst types: Array = [];\n\t\t\tfor (let i = 0, k = 0; i < this._length; i++) {\n\t\t\t\tconst level = this._nestingLevels[i];\n\t\t\t\tif (level < maxLevel || (level === maxLevel && entries++ < limit)) {\n\t\t\t\t\tstartIndexes[k] = this._startIndexes[i];\n\t\t\t\t\tendIndexes[k] = this._endIndexes[i];\n\t\t\t\t\ttypes[k] = this._types[i];\n\t\t\t\t\tk++;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn new FoldingRegions(startIndexes, endIndexes, types);\n\t\t}\n\n\t}\n\n}\n\nexport function sanitizeRanges(rangeData: IFoldingRangeData[], foldingRangesLimit: FoldingLimitReporter): FoldingRegions {\n\tconst sorted = rangeData.sort((d1, d2) => {\n\t\tlet diff = d1.start - d2.start;\n\t\tif (diff === 0) {\n\t\t\tdiff = d1.rank - d2.rank;\n\t\t}\n\t\treturn diff;\n\t});\n\tconst collector = new RangesCollector(foldingRangesLimit);\n\n\tlet top: IFoldingRangeData | undefined = undefined;\n\tconst previous: IFoldingRangeData[] = [];\n\tfor (const entry of sorted) {\n\t\tif (!top) {\n\t\t\ttop = entry;\n\t\t\tcollector.add(entry.start, entry.end, entry.kind && entry.kind.value, previous.length);\n\t\t} else {\n\t\t\tif (entry.start > top.start) {\n\t\t\t\tif (entry.end <= top.end) {\n\t\t\t\t\tprevious.push(top);\n\t\t\t\t\ttop = entry;\n\t\t\t\t\tcollector.add(entry.start, entry.end, entry.kind && entry.kind.value, previous.length);\n\t\t\t\t} else {\n\t\t\t\t\tif (entry.start > top.end) {\n\t\t\t\t\t\tdo {\n\t\t\t\t\t\t\ttop = previous.pop();\n\t\t\t\t\t\t} while (top && entry.start > top.end);\n\t\t\t\t\t\tif (top) {\n\t\t\t\t\t\t\tprevious.push(top);\n\t\t\t\t\t\t}\n\t\t\t\t\t\ttop = entry;\n\t\t\t\t\t}\n\t\t\t\t\tcollector.add(entry.start, entry.end, entry.kind && entry.kind.value, previous.length);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn collector.toIndentRanges();\n}\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\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\nimport { EditOperation, ISingleEditOperation } from 'vs/editor/common/core/editOperation';\nimport { Range } from 'vs/editor/common/core/range';\nimport { EndOfLineSequence } from 'vs/editor/common/model';\nimport { TextEdit } from 'vs/editor/common/languages';\nimport { StableEditorScrollState } from 'vs/editor/browser/stableEditorScroll';\n\nexport class FormattingEdit {\n\n\tprivate static _handleEolEdits(editor: ICodeEditor, edits: TextEdit[]): ISingleEditOperation[] {\n\t\tlet newEol: EndOfLineSequence | undefined = undefined;\n\t\tconst singleEdits: ISingleEditOperation[] = [];\n\n\t\tfor (const edit of edits) {\n\t\t\tif (typeof edit.eol === 'number') {\n\t\t\t\tnewEol = edit.eol;\n\t\t\t}\n\t\t\tif (edit.range && typeof edit.text === 'string') {\n\t\t\t\tsingleEdits.push(edit);\n\t\t\t}\n\t\t}\n\n\t\tif (typeof newEol === 'number') {\n\t\t\tif (editor.hasModel()) {\n\t\t\t\teditor.getModel().pushEOL(newEol);\n\t\t\t}\n\t\t}\n\n\t\treturn singleEdits;\n\t}\n\n\tprivate static _isFullModelReplaceEdit(editor: ICodeEditor, edit: ISingleEditOperation): boolean {\n\t\tif (!editor.hasModel()) {\n\t\t\treturn false;\n\t\t}\n\t\tconst model = editor.getModel();\n\t\tconst editRange = model.validateRange(edit.range);\n\t\tconst fullModelRange = model.getFullModelRange();\n\t\treturn fullModelRange.equalsRange(editRange);\n\t}\n\n\tstatic execute(editor: ICodeEditor, _edits: TextEdit[], addUndoStops: boolean) {\n\t\tif (addUndoStops) {\n\t\t\teditor.pushUndoStop();\n\t\t}\n\t\tconst scrollState = StableEditorScrollState.capture(editor);\n\t\tconst edits = FormattingEdit._handleEolEdits(editor, _edits);\n\t\tif (edits.length === 1 && FormattingEdit._isFullModelReplaceEdit(editor, edits[0])) {\n\t\t\t// We use replace semantics and hope that markers stay put...\n\t\t\teditor.executeEdits('formatEditsCommand', edits.map(edit => EditOperation.replace(Range.lift(edit.range), edit.text)));\n\t\t} else {\n\t\t\teditor.executeEdits('formatEditsCommand', edits.map(edit => EditOperation.replaceMove(Range.lift(edit.range), edit.text)));\n\t\t}\n\t\tif (addUndoStops) {\n\t\t\teditor.pushUndoStop();\n\t\t}\n\t\tscrollState.restoreRelativeVerticalPositionOfCursor(editor);\n\t}\n}\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\nimport { DisposableStore } from 'vs/base/common/lifecycle';\nimport { Position } from 'vs/editor/common/core/position';\nimport { HoverStartSource } from 'vs/editor/contrib/hover/browser/hoverOperation';\nimport { HoverAnchor, IEditorHoverColorPickerWidget, IHoverPart } from 'vs/editor/contrib/hover/browser/hoverTypes';\n\nexport class HoverResult {\n\n\tconstructor(\n\t\tpublic readonly anchor: HoverAnchor,\n\t\tpublic readonly messages: IHoverPart[],\n\t\tpublic readonly isComplete: boolean\n\t) { }\n\n\tpublic filter(anchor: HoverAnchor): HoverResult {\n\t\tconst filteredMessages = this.messages.filter((m) => m.isValidForHoverAnchor(anchor));\n\t\tif (filteredMessages.length === this.messages.length) {\n\t\t\treturn this;\n\t\t}\n\t\treturn new FilteredHoverResult(this, this.anchor, filteredMessages, this.isComplete);\n\t}\n}\n\nexport class FilteredHoverResult extends HoverResult {\n\n\tconstructor(\n\t\tprivate readonly original: HoverResult,\n\t\tanchor: HoverAnchor,\n\t\tmessages: IHoverPart[],\n\t\tisComplete: boolean\n\t) {\n\t\tsuper(anchor, messages, isComplete);\n\t}\n\n\tpublic override filter(anchor: HoverAnchor): HoverResult {\n\t\treturn this.original.filter(anchor);\n\t}\n}\n\nexport class ContentHoverVisibleData {\n\n\tpublic closestMouseDistance: number | undefined = undefined;\n\n\tconstructor(\n\t\tpublic initialMousePosX: number | undefined,\n\t\tpublic initialMousePosY: number | undefined,\n\t\tpublic readonly colorPicker: IEditorHoverColorPickerWidget | null,\n\t\tpublic readonly showAtPosition: Position,\n\t\tpublic readonly showAtSecondaryPosition: Position,\n\t\tpublic readonly preferAbove: boolean,\n\t\tpublic readonly stoleFocus: boolean,\n\t\tpublic readonly source: HoverStartSource,\n\t\tpublic readonly isBeforeContent: boolean,\n\t\tpublic readonly disposables: DisposableStore\n\t) { }\n}\n","\nimport { IAccessibleViewImplentation } from 'vs/platform/accessibility/browser/accessibleViewRegistry';\n\nexport class HoverAccessibleView implements IAccessibleViewImplentation {\n}\n\nexport class ExtHoverAccessibleView implements IAccessibleViewImplentation {\n}\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\nexport const SHOW_OR_FOCUS_HOVER_ACTION_ID = 'editor.action.showHover';\nexport const SHOW_DEFINITION_PREVIEW_HOVER_ACTION_ID = 'editor.action.showDefinitionPreviewHover';\nexport const SCROLL_UP_HOVER_ACTION_ID = 'editor.action.scrollUpHover';\nexport const SCROLL_DOWN_HOVER_ACTION_ID = 'editor.action.scrollDownHover';\nexport const SCROLL_LEFT_HOVER_ACTION_ID = 'editor.action.scrollLeftHover';\nexport const SCROLL_RIGHT_HOVER_ACTION_ID = 'editor.action.scrollRightHover';\nexport const PAGE_UP_HOVER_ACTION_ID = 'editor.action.pageUpHover';\nexport const PAGE_DOWN_HOVER_ACTION_ID = 'editor.action.pageDownHover';\nexport const GO_TO_TOP_HOVER_ACTION_ID = 'editor.action.goToTopHover';\nexport const GO_TO_BOTTOM_HOVER_ACTION_ID = 'editor.action.goToBottomHover';\nexport const INCREASE_HOVER_VERBOSITY_ACTION_ID = 'editor.action.increaseHoverVerbosityLevel';\nexport const DECREASE_HOVER_VERBOSITY_ACTION_ID = 'editor.action.decreaseHoverVerbosityLevel';\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\nimport { Dimension } from 'vs/base/browser/dom';\nimport { AsyncIterableObject } from 'vs/base/common/async';\nimport { CancellationToken } from 'vs/base/common/cancellation';\nimport { IDisposable } from 'vs/base/common/lifecycle';\nimport { ICodeEditor, IEditorMouseEvent } from 'vs/editor/browser/editorBrowser';\nimport { Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\nimport { IModelDecoration } from 'vs/editor/common/model';\nimport { BrandedService, IConstructorSignature } from 'vs/platform/instantiation/common/instantiation';\n\nexport interface IHoverPart {\n\t/**\n\t * The creator of this hover part.\n\t */\n\treadonly owner: IEditorHoverParticipant;\n\t/**\n\t * The range where this hover part applies.\n\t */\n\treadonly range: Range;\n\t/**\n\t * Force the hover to always be rendered at this specific range,\n\t * even in the case of multiple hover parts.\n\t */\n\treadonly forceShowAtRange?: boolean;\n\n\t/**\n\t * If true, the hover item should appear before content\n\t */\n\treadonly isBeforeContent?: boolean;\n\t/**\n\t * Is this hover part still valid for this new anchor?\n\t */\n\tisValidForHoverAnchor(anchor: HoverAnchor): boolean;\n}\n\nexport const enum HoverAnchorType {\n\tRange = 1,\n\tForeignElement = 2\n}\n\nexport class HoverRangeAnchor {\n\tpublic readonly type = HoverAnchorType.Range;\n\tconstructor(\n\t\tpublic readonly priority: number,\n\t\tpublic readonly range: Range,\n\t\tpublic readonly initialMousePosX: number | undefined,\n\t\tpublic readonly initialMousePosY: number | undefined,\n\t) {\n\t}\n\tpublic equals(other: HoverAnchor) {\n\t\treturn (other.type === HoverAnchorType.Range && this.range.equalsRange(other.range));\n\t}\n\tpublic canAdoptVisibleHover(lastAnchor: HoverAnchor, showAtPosition: Position): boolean {\n\t\treturn (lastAnchor.type === HoverAnchorType.Range && showAtPosition.lineNumber === this.range.startLineNumber);\n\t}\n}\n\nexport class HoverForeignElementAnchor {\n\tpublic readonly type = HoverAnchorType.ForeignElement;\n\tconstructor(\n\t\tpublic readonly priority: number,\n\t\tpublic readonly owner: IEditorHoverParticipant,\n\t\tpublic readonly range: Range,\n\t\tpublic readonly initialMousePosX: number | undefined,\n\t\tpublic readonly initialMousePosY: number | undefined,\n\t\tpublic readonly supportsMarkerHover: boolean | undefined\n\t) {\n\t}\n\tpublic equals(other: HoverAnchor) {\n\t\treturn (other.type === HoverAnchorType.ForeignElement && this.owner === other.owner);\n\t}\n\tpublic canAdoptVisibleHover(lastAnchor: HoverAnchor, showAtPosition: Position): boolean {\n\t\treturn (lastAnchor.type === HoverAnchorType.ForeignElement && this.owner === lastAnchor.owner);\n\t}\n}\n\nexport type HoverAnchor = HoverRangeAnchor | HoverForeignElementAnchor;\n\nexport interface IEditorHoverStatusBar {\n\taddAction(actionOptions: { label: string; iconClass?: string; run: (target: HTMLElement) => void; commandId: string }): IEditorHoverAction;\n\tappend(element: HTMLElement): HTMLElement;\n}\n\nexport interface IEditorHoverAction {\n}\n\nexport interface IEditorHoverColorPickerWidget {\n\tlayout(): void;\n}\n\nexport interface IEditorHoverRenderContext {\n\t/**\n\t * The fragment where dom elements should be attached.\n\t */\n\treadonly fragment: DocumentFragment;\n\t/**\n\t * The status bar for actions for this hover.\n\t */\n\treadonly statusBar: IEditorHoverStatusBar;\n\t/**\n\t * Set if the hover will render a color picker widget.\n\t */\n\tsetColorPicker(widget: IEditorHoverColorPickerWidget): void;\n\t/**\n\t * The contents rendered inside the fragment have been changed, which means that the hover should relayout.\n\t */\n\tonContentsChanged(): void;\n\t/**\n\t * Set the minimum dimensions of the resizable hover\n\t */\n\tsetMinimumDimensions?(dimensions: Dimension): void;\n\t/**\n\t * Hide the hover.\n\t */\n\thide(): void;\n}\n\nexport interface IEditorHoverParticipant {\n\treadonly hoverOrdinal: number;\n\tsuggestHoverAnchor?(mouseEvent: IEditorMouseEvent): HoverAnchor | null;\n\tcomputeSync(anchor: HoverAnchor, lineDecorations: IModelDecoration[]): T[];\n\tcomputeAsync?(anchor: HoverAnchor, lineDecorations: IModelDecoration[], token: CancellationToken): AsyncIterableObject;\n\tcreateLoadingMessage?(anchor: HoverAnchor): T | null;\n\trenderHoverParts(context: IEditorHoverRenderContext, hoverParts: T[]): IDisposable;\n}\n\nexport type IEditorHoverParticipantCtor = IConstructorSignature;\n\nexport const HoverParticipantRegistry = (new class HoverParticipantRegistry {\n\n\t_participants: IEditorHoverParticipantCtor[] = [];\n\n\tpublic register(ctor: { new(editor: ICodeEditor, ...services: Services): IEditorHoverParticipant }): void {\n\t\tthis._participants.push(ctor as IEditorHoverParticipantCtor);\n\t}\n\n\tpublic getAll(): IEditorHoverParticipantCtor[] {\n\t\treturn this._participants;\n\t}\n\n}());\n\nexport interface IHoverWidget {\n\t/**\n\t * Returns whether the hover widget is shown or should show in the future.\n\t * If the widget should show, this triggers the display.\n\t * @param mouseEvent editor mouse event\n\t */\n\tshowsOrWillShow(mouseEvent: IEditorMouseEvent): boolean;\n\n\t/**\n\t * Hides the hover.\n\t */\n\thide(): void;\n}\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\nimport { Range } from 'vs/editor/common/core/range';\nimport { Selection } from 'vs/editor/common/core/selection';\nimport { ICommand, ICursorStateComputerData, IEditOperationBuilder } from 'vs/editor/common/editorCommon';\nimport { ITextModel } from 'vs/editor/common/model';\n\nexport class InPlaceReplaceCommand implements ICommand {\n\n\tprivate readonly _editRange: Range;\n\tprivate readonly _originalSelection: Selection;\n\tprivate readonly _text: string;\n\n\tconstructor(editRange: Range, originalSelection: Selection, text: string) {\n\t\tthis._editRange = editRange;\n\t\tthis._originalSelection = originalSelection;\n\t\tthis._text = text;\n\t}\n\n\tpublic getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {\n\t\tbuilder.addTrackedEditOperation(this._editRange, this._text);\n\t}\n\n\tpublic computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {\n\t\tconst inverseEditOperations = helper.getInverseEditOperations();\n\t\tconst srcRange = inverseEditOperations[0].range;\n\n\t\tif (!this._originalSelection.isEmpty()) {\n\t\t\t// Preserve selection and extends to typed text\n\t\t\treturn new Selection(\n\t\t\t\tsrcRange.endLineNumber,\n\t\t\t\tsrcRange.endColumn - this._text.length,\n\t\t\t\tsrcRange.endLineNumber,\n\t\t\t\tsrcRange.endColumn\n\t\t\t);\n\t\t}\n\n\t\treturn new Selection(\n\t\t\tsrcRange.endLineNumber,\n\t\t\tMath.min(this._originalSelection.positionColumn, srcRange.endColumn),\n\t\t\tsrcRange.endLineNumber,\n\t\t\tMath.min(this._originalSelection.positionColumn, srcRange.endColumn)\n\t\t);\n\t}\n}\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\nexport function getSpaceCnt(str: string, tabSize: number) {\n\tlet spacesCnt = 0;\n\n\tfor (let i = 0; i < str.length; i++) {\n\t\tif (str.charAt(i) === '\\t') {\n\t\t\tspacesCnt += tabSize;\n\t\t} else {\n\t\t\tspacesCnt++;\n\t\t}\n\t}\n\n\treturn spacesCnt;\n}\n\nexport function generateIndent(spacesCnt: number, tabSize: number, insertSpaces: boolean) {\n\tspacesCnt = spacesCnt < 0 ? 0 : spacesCnt;\n\n\tlet result = '';\n\tif (!insertSpaces) {\n\t\tconst tabsCnt = Math.floor(spacesCnt / tabSize);\n\t\tspacesCnt = spacesCnt % tabSize;\n\t\tfor (let i = 0; i < tabsCnt; i++) {\n\t\t\tresult += '\\t';\n\t\t}\n\t}\n\n\tfor (let i = 0; i < spacesCnt; i++) {\n\t\tresult += ' ';\n\t}\n\n\treturn result;\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\nexport const inlineSuggestCommitId = 'editor.action.inlineSuggest.commit';\n\nexport const showPreviousInlineSuggestionActionId = 'editor.action.inlineSuggest.showPrevious';\n\nexport const showNextInlineSuggestionActionId = 'editor.action.inlineSuggest.showNext';\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\nimport { equals } from 'vs/base/common/arrays';\nimport { splitLines } from 'vs/base/common/strings';\nimport { Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\nimport { SingleTextEdit, TextEdit } from 'vs/editor/common/core/textEdit';\nimport { ColumnRange } from 'vs/editor/contrib/inlineCompletions/browser/utils';\n\nexport class GhostText {\n\tconstructor(\n\t\tpublic readonly lineNumber: number,\n\t\tpublic readonly parts: GhostTextPart[],\n\t) {\n\t}\n\n\tequals(other: GhostText): boolean {\n\t\treturn this.lineNumber === other.lineNumber &&\n\t\t\tthis.parts.length === other.parts.length &&\n\t\t\tthis.parts.every((part, index) => part.equals(other.parts[index]));\n\t}\n\n\trenderForScreenReader(lineText: string): string {\n\t\tif (this.parts.length === 0) {\n\t\t\treturn '';\n\t\t}\n\t\tconst lastPart = this.parts[this.parts.length - 1];\n\n\t\tconst cappedLineText = lineText.substr(0, lastPart.column - 1);\n\t\tconst text = new TextEdit([\n\t\t\t...this.parts.map(p => new SingleTextEdit(\n\t\t\t\tRange.fromPositions(new Position(1, p.column)),\n\t\t\t\tp.lines.join('\\n')\n\t\t\t)),\n\t\t]).applyToString(cappedLineText);\n\n\t\treturn text.substring(this.parts[0].column - 1);\n\t}\n\n\tisEmpty(): boolean {\n\t\treturn this.parts.every(p => p.lines.length === 0);\n\t}\n\n\tget lineCount(): number {\n\t\treturn 1 + this.parts.reduce((r, p) => r + p.lines.length - 1, 0);\n\t}\n}\n\nexport class GhostTextPart {\n\tconstructor(\n\t\treadonly column: number,\n\t\treadonly text: string,\n\t\t/**\n\t\t * Indicates if this part is a preview of an inline suggestion when a suggestion is previewed.\n\t\t*/\n\t\treadonly preview: boolean,\n\t) {\n\t}\n\n\treadonly lines = splitLines(this.text);\n\n\tequals(other: GhostTextPart): boolean {\n\t\treturn this.column === other.column &&\n\t\t\tthis.lines.length === other.lines.length &&\n\t\t\tthis.lines.every((line, index) => line === other.lines[index]);\n\t}\n}\n\nexport class GhostTextReplacement {\n\tpublic readonly parts: ReadonlyArray = [\n\t\tnew GhostTextPart(\n\t\t\tthis.columnRange.endColumnExclusive,\n\t\t\tthis.text,\n\t\t\tfalse\n\t\t),\n\t];\n\n\tconstructor(\n\t\treadonly lineNumber: number,\n\t\treadonly columnRange: ColumnRange,\n\t\treadonly text: string,\n\t\tpublic readonly additionalReservedLineCount: number = 0,\n\t) { }\n\n\treadonly newLines = splitLines(this.text);\n\n\trenderForScreenReader(_lineText: string): string {\n\t\treturn this.newLines.join('\\n');\n\t}\n\n\tget lineCount(): number {\n\t\treturn this.newLines.length;\n\t}\n\n\tisEmpty(): boolean {\n\t\treturn this.parts.every(p => p.lines.length === 0);\n\t}\n\n\tequals(other: GhostTextReplacement): boolean {\n\t\treturn this.lineNumber === other.lineNumber &&\n\t\t\tthis.columnRange.equals(other.columnRange) &&\n\t\t\tthis.newLines.length === other.newLines.length &&\n\t\t\tthis.newLines.every((line, index) => line === other.newLines[index]) &&\n\t\t\tthis.additionalReservedLineCount === other.additionalReservedLineCount;\n\t}\n}\n\nexport type GhostTextOrReplacement = GhostText | GhostTextReplacement;\n\nexport function ghostTextsOrReplacementsEqual(a: readonly GhostTextOrReplacement[] | undefined, b: readonly GhostTextOrReplacement[] | undefined): boolean {\n\treturn equals(a, b, ghostTextOrReplacementEquals);\n}\n\nexport function ghostTextOrReplacementEquals(a: GhostTextOrReplacement | undefined, b: GhostTextOrReplacement | undefined): boolean {\n\tif (a === b) {\n\t\treturn true;\n\t}\n\tif (!a || !b) {\n\t\treturn false;\n\t}\n\tif (a instanceof GhostText && b instanceof GhostText) {\n\t\treturn a.equals(b);\n\t}\n\tif (a instanceof GhostTextReplacement && b instanceof GhostTextReplacement) {\n\t\treturn a.equals(b);\n\t}\n\treturn false;\n}\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\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport { IAccessibleViewImplentation } from 'vs/platform/accessibility/browser/accessibleViewRegistry';\n\nexport class InlineCompletionsAccessibleView extends Disposable implements IAccessibleViewImplentation {\n\tconstructor() {\n\t\tsuper();\n\t}\n}\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\nimport { IDiffChange, LcsDiff } from 'vs/base/common/diff/diff';\nimport { commonPrefixLength, getLeadingWhitespace } from 'vs/base/common/strings';\nimport { Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\nimport { TextLength } from 'vs/editor/common/core/textLength';\nimport { SingleTextEdit } from 'vs/editor/common/core/textEdit';\nimport { EndOfLinePreference, ITextModel } from 'vs/editor/common/model';\nimport { GhostText, GhostTextPart } from 'vs/editor/contrib/inlineCompletions/browser/ghostText';\n\nexport function singleTextRemoveCommonPrefix(edit: SingleTextEdit, model: ITextModel, validModelRange?: Range): SingleTextEdit {\n\tconst modelRange = validModelRange ? edit.range.intersectRanges(validModelRange) : edit.range;\n\tif (!modelRange) {\n\t\treturn edit;\n\t}\n\tconst valueToReplace = model.getValueInRange(modelRange, EndOfLinePreference.LF);\n\tconst commonPrefixLen = commonPrefixLength(valueToReplace, edit.text);\n\tconst start = TextLength.ofText(valueToReplace.substring(0, commonPrefixLen)).addToPosition(edit.range.getStartPosition());\n\tconst text = edit.text.substring(commonPrefixLen);\n\tconst range = Range.fromPositions(start, edit.range.getEndPosition());\n\treturn new SingleTextEdit(range, text);\n}\n\nexport function singleTextEditAugments(edit: SingleTextEdit, base: SingleTextEdit): boolean {\n\t// The augmented completion must replace the base range, but can replace even more\n\treturn edit.text.startsWith(base.text) && rangeExtends(edit.range, base.range);\n}\n\n/**\n * @param previewSuffixLength Sets where to split `inlineCompletion.text`.\n * \tIf the text is `hello` and the suffix length is 2, the non-preview part is `hel` and the preview-part is `lo`.\n*/\nexport function computeGhostText(\n\tedit: SingleTextEdit,\n\tmodel: ITextModel,\n\tmode: 'prefix' | 'subword' | 'subwordSmart',\n\tcursorPosition?: Position,\n\tpreviewSuffixLength = 0\n): GhostText | undefined {\n\tlet e = singleTextRemoveCommonPrefix(edit, model);\n\n\tif (e.range.endLineNumber !== e.range.startLineNumber) {\n\t\t// This edit might span multiple lines, but the first lines must be a common prefix.\n\t\treturn undefined;\n\t}\n\n\tconst sourceLine = model.getLineContent(e.range.startLineNumber);\n\tconst sourceIndentationLength = getLeadingWhitespace(sourceLine).length;\n\n\tconst suggestionTouchesIndentation = e.range.startColumn - 1 <= sourceIndentationLength;\n\tif (suggestionTouchesIndentation) {\n\t\t// source: ··········[······abc]\n\t\t// ^^^^^^^^^ inlineCompletion.range\n\t\t// ^^^^^^^^^^ ^^^^^^ sourceIndentationLength\n\t\t// ^^^^^^ replacedIndentation.length\n\t\t// ^^^ rangeThatDoesNotReplaceIndentation\n\n\t\t// inlineCompletion.text: '··foo'\n\t\t// ^^ suggestionAddedIndentationLength\n\n\t\tconst suggestionAddedIndentationLength = getLeadingWhitespace(e.text).length;\n\n\t\tconst replacedIndentation = sourceLine.substring(e.range.startColumn - 1, sourceIndentationLength);\n\n\t\tconst [startPosition, endPosition] = [e.range.getStartPosition(), e.range.getEndPosition()];\n\t\tconst newStartPosition =\n\t\t\tstartPosition.column + replacedIndentation.length <= endPosition.column\n\t\t\t\t? startPosition.delta(0, replacedIndentation.length)\n\t\t\t\t: endPosition;\n\t\tconst rangeThatDoesNotReplaceIndentation = Range.fromPositions(newStartPosition, endPosition);\n\n\t\tconst suggestionWithoutIndentationChange =\n\t\t\te.text.startsWith(replacedIndentation)\n\t\t\t\t// Adds more indentation without changing existing indentation: We can add ghost text for this\n\t\t\t\t? e.text.substring(replacedIndentation.length)\n\t\t\t\t// Changes or removes existing indentation. Only add ghost text for the non-indentation part.\n\t\t\t\t: e.text.substring(suggestionAddedIndentationLength);\n\n\t\te = new SingleTextEdit(rangeThatDoesNotReplaceIndentation, suggestionWithoutIndentationChange);\n\t}\n\n\t// This is a single line string\n\tconst valueToBeReplaced = model.getValueInRange(e.range);\n\n\tconst changes = cachingDiff(valueToBeReplaced, e.text);\n\n\tif (!changes) {\n\t\t// No ghost text in case the diff would be too slow to compute\n\t\treturn undefined;\n\t}\n\n\tconst lineNumber = e.range.startLineNumber;\n\n\tconst parts = new Array();\n\n\tif (mode === 'prefix') {\n\t\tconst filteredChanges = changes.filter(c => c.originalLength === 0);\n\t\tif (filteredChanges.length > 1 || filteredChanges.length === 1 && filteredChanges[0].originalStart !== valueToBeReplaced.length) {\n\t\t\t// Prefixes only have a single change.\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\tconst previewStartInCompletionText = e.text.length - previewSuffixLength;\n\n\tfor (const c of changes) {\n\t\tconst insertColumn = e.range.startColumn + c.originalStart + c.originalLength;\n\n\t\tif (mode === 'subwordSmart' && cursorPosition && cursorPosition.lineNumber === e.range.startLineNumber && insertColumn < cursorPosition.column) {\n\t\t\t// No ghost text before cursor\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (c.originalLength > 0) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (c.modifiedLength === 0) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst modifiedEnd = c.modifiedStart + c.modifiedLength;\n\t\tconst nonPreviewTextEnd = Math.max(c.modifiedStart, Math.min(modifiedEnd, previewStartInCompletionText));\n\t\tconst nonPreviewText = e.text.substring(c.modifiedStart, nonPreviewTextEnd);\n\t\tconst italicText = e.text.substring(nonPreviewTextEnd, Math.max(c.modifiedStart, modifiedEnd));\n\n\t\tif (nonPreviewText.length > 0) {\n\t\t\tparts.push(new GhostTextPart(insertColumn, nonPreviewText, false));\n\t\t}\n\t\tif (italicText.length > 0) {\n\t\t\tparts.push(new GhostTextPart(insertColumn, italicText, true));\n\t\t}\n\t}\n\n\treturn new GhostText(lineNumber, parts);\n}\n\nfunction rangeExtends(extendingRange: Range, rangeToExtend: Range): boolean {\n\treturn rangeToExtend.getStartPosition().equals(extendingRange.getStartPosition())\n\t\t&& rangeToExtend.getEndPosition().isBeforeOrEqual(extendingRange.getEndPosition());\n}\n\nlet lastRequest: { originalValue: string; newValue: string; changes: readonly IDiffChange[] | undefined } | undefined = undefined;\nfunction cachingDiff(originalValue: string, newValue: string): readonly IDiffChange[] | undefined {\n\tif (lastRequest?.originalValue === originalValue && lastRequest?.newValue === newValue) {\n\t\treturn lastRequest?.changes;\n\t} else {\n\t\tlet changes = smartDiff(originalValue, newValue, true);\n\t\tif (changes) {\n\t\t\tconst deletedChars = deletedCharacters(changes);\n\t\t\tif (deletedChars > 0) {\n\t\t\t\t// For performance reasons, don't compute diff if there is nothing to improve\n\t\t\t\tconst newChanges = smartDiff(originalValue, newValue, false);\n\t\t\t\tif (newChanges && deletedCharacters(newChanges) < deletedChars) {\n\t\t\t\t\t// Disabling smartness seems to be better here\n\t\t\t\t\tchanges = newChanges;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tlastRequest = {\n\t\t\toriginalValue,\n\t\t\tnewValue,\n\t\t\tchanges\n\t\t};\n\t\treturn changes;\n\t}\n}\n\nfunction deletedCharacters(changes: readonly IDiffChange[]): number {\n\tlet sum = 0;\n\tfor (const c of changes) {\n\t\tsum += c.originalLength;\n\t}\n\treturn sum;\n}\n\n/**\n * When matching `if ()` with `if (f() = 1) { g(); }`,\n * align it like this: `if ( )`\n * Not like this:\t\t\t `if ( )`\n * Also not like this:\t\t `if ( )`.\n *\n * The parenthesis are preprocessed to ensure that they match correctly.\n */\nfunction smartDiff(originalValue: string, newValue: string, smartBracketMatching: boolean): (readonly IDiffChange[]) | undefined {\n\tif (originalValue.length > 5000 || newValue.length > 5000) {\n\t\t// We don't want to work on strings that are too big\n\t\treturn undefined;\n\t}\n\n\tfunction getMaxCharCode(val: string): number {\n\t\tlet maxCharCode = 0;\n\t\tfor (let i = 0, len = val.length; i < len; i++) {\n\t\t\tconst charCode = val.charCodeAt(i);\n\t\t\tif (charCode > maxCharCode) {\n\t\t\t\tmaxCharCode = charCode;\n\t\t\t}\n\t\t}\n\t\treturn maxCharCode;\n\t}\n\n\tconst maxCharCode = Math.max(getMaxCharCode(originalValue), getMaxCharCode(newValue));\n\tfunction getUniqueCharCode(id: number): number {\n\t\tif (id < 0) {\n\t\t\tthrow new Error('unexpected');\n\t\t}\n\t\treturn maxCharCode + id + 1;\n\t}\n\n\tfunction getElements(source: string): Int32Array {\n\t\tlet level = 0;\n\t\tlet group = 0;\n\t\tconst characters = new Int32Array(source.length);\n\t\tfor (let i = 0, len = source.length; i < len; i++) {\n\t\t\t// TODO support more brackets\n\t\t\tif (smartBracketMatching && source[i] === '(') {\n\t\t\t\tconst id = group * 100 + level;\n\t\t\t\tcharacters[i] = getUniqueCharCode(2 * id);\n\t\t\t\tlevel++;\n\t\t\t} else if (smartBracketMatching && source[i] === ')') {\n\t\t\t\tlevel = Math.max(level - 1, 0);\n\t\t\t\tconst id = group * 100 + level;\n\t\t\t\tcharacters[i] = getUniqueCharCode(2 * id + 1);\n\t\t\t\tif (level === 0) {\n\t\t\t\t\tgroup++;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tcharacters[i] = source.charCodeAt(i);\n\t\t\t}\n\t\t}\n\t\treturn characters;\n\t}\n\n\tconst elements1 = getElements(originalValue);\n\tconst elements2 = getElements(newValue);\n\n\treturn new LcsDiff({ getElements: () => elements1 }, { getElements: () => elements2 }).ComputeDiff(false).changes;\n}\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\nimport { BugIndicatingError } from 'vs/base/common/errors';\nimport { DisposableStore, IDisposable } from 'vs/base/common/lifecycle';\nimport { IObservable, autorunOpts } from 'vs/base/common/observable';\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\nimport { Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\nimport { IModelDeltaDecoration } from 'vs/editor/common/model';\n\nconst array: ReadonlyArray = [];\nexport function getReadonlyEmptyArray(): readonly T[] {\n\treturn array;\n}\n\nexport class ColumnRange {\n\tconstructor(\n\t\tpublic readonly startColumn: number,\n\t\tpublic readonly endColumnExclusive: number,\n\t) {\n\t\tif (startColumn > endColumnExclusive) {\n\t\t\tthrow new BugIndicatingError(`startColumn ${startColumn} cannot be after endColumnExclusive ${endColumnExclusive}`);\n\t\t}\n\t}\n\n\ttoRange(lineNumber: number): Range {\n\t\treturn new Range(lineNumber, this.startColumn, lineNumber, this.endColumnExclusive);\n\t}\n\n\tequals(other: ColumnRange): boolean {\n\t\treturn this.startColumn === other.startColumn\n\t\t\t&& this.endColumnExclusive === other.endColumnExclusive;\n\t}\n}\n\nexport function applyObservableDecorations(editor: ICodeEditor, decorations: IObservable): IDisposable {\n\tconst d = new DisposableStore();\n\tconst decorationsCollection = editor.createDecorationsCollection();\n\td.add(autorunOpts({ debugName: () => `Apply decorations from ${decorations.debugName}` }, reader => {\n\t\tconst d = decorations.read(reader);\n\t\tdecorationsCollection.set(d);\n\t}));\n\td.add({\n\t\tdispose: () => {\n\t\t\tdecorationsCollection.clear();\n\t\t}\n\t});\n\treturn d;\n}\n\nexport function addPositions(pos1: Position, pos2: Position): Position {\n\treturn new Position(pos1.lineNumber + pos2.lineNumber - 1, pos2.lineNumber === 1 ? pos1.column + pos2.column - 1 : pos2.column);\n}\n\nexport function subtractPositions(pos1: Position, pos2: Position): Position {\n\treturn new Position(pos1.lineNumber - pos2.lineNumber + 1, pos1.lineNumber - pos2.lineNumber === 0 ? pos1.column - pos2.column + 1 : pos1.column);\n}\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\nexport const inlineEditAcceptId = 'editor.action.inlineEdit.accept';\nexport const inlineEditRejectId = 'editor.action.inlineEdit.reject';\nexport const inlineEditJumpToId = 'editor.action.inlineEdit.jumpTo';\nexport const inlineEditJumpBackId = 'editor.action.inlineEdit.jumpBack';\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\nimport { Range } from 'vs/editor/common/core/range';\nimport { Selection, SelectionDirection } from 'vs/editor/common/core/selection';\nimport { ICommand, ICursorStateComputerData, IEditOperationBuilder } from 'vs/editor/common/editorCommon';\nimport { ITextModel } from 'vs/editor/common/model';\n\nexport class CopyLinesCommand implements ICommand {\n\n\tprivate readonly _selection: Selection;\n\tprivate readonly _isCopyingDown: boolean;\n\tprivate readonly _noop: boolean;\n\n\tprivate _selectionDirection: SelectionDirection;\n\tprivate _selectionId: string | null;\n\tprivate _startLineNumberDelta: number;\n\tprivate _endLineNumberDelta: number;\n\n\tconstructor(selection: Selection, isCopyingDown: boolean, noop?: boolean) {\n\t\tthis._selection = selection;\n\t\tthis._isCopyingDown = isCopyingDown;\n\t\tthis._noop = noop || false;\n\t\tthis._selectionDirection = SelectionDirection.LTR;\n\t\tthis._selectionId = null;\n\t\tthis._startLineNumberDelta = 0;\n\t\tthis._endLineNumberDelta = 0;\n\t}\n\n\tpublic getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {\n\t\tlet s = this._selection;\n\n\t\tthis._startLineNumberDelta = 0;\n\t\tthis._endLineNumberDelta = 0;\n\t\tif (s.startLineNumber < s.endLineNumber && s.endColumn === 1) {\n\t\t\tthis._endLineNumberDelta = 1;\n\t\t\ts = s.setEndPosition(s.endLineNumber - 1, model.getLineMaxColumn(s.endLineNumber - 1));\n\t\t}\n\n\t\tconst sourceLines: string[] = [];\n\t\tfor (let i = s.startLineNumber; i <= s.endLineNumber; i++) {\n\t\t\tsourceLines.push(model.getLineContent(i));\n\t\t}\n\t\tconst sourceText = sourceLines.join('\\n');\n\n\t\tif (sourceText === '') {\n\t\t\t// Duplicating empty line\n\t\t\tif (this._isCopyingDown) {\n\t\t\t\tthis._startLineNumberDelta++;\n\t\t\t\tthis._endLineNumberDelta++;\n\t\t\t}\n\t\t}\n\n\t\tif (this._noop) {\n\t\t\tbuilder.addEditOperation(new Range(s.endLineNumber, model.getLineMaxColumn(s.endLineNumber), s.endLineNumber + 1, 1), s.endLineNumber === model.getLineCount() ? '' : '\\n');\n\t\t} else {\n\t\t\tif (!this._isCopyingDown) {\n\t\t\t\tbuilder.addEditOperation(new Range(s.endLineNumber, model.getLineMaxColumn(s.endLineNumber), s.endLineNumber, model.getLineMaxColumn(s.endLineNumber)), '\\n' + sourceText);\n\t\t\t} else {\n\t\t\t\tbuilder.addEditOperation(new Range(s.startLineNumber, 1, s.startLineNumber, 1), sourceText + '\\n');\n\t\t\t}\n\t\t}\n\n\t\tthis._selectionId = builder.trackSelection(s);\n\t\tthis._selectionDirection = this._selection.getDirection();\n\t}\n\n\tpublic computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {\n\t\tlet result = helper.getTrackedSelection(this._selectionId!);\n\n\t\tif (this._startLineNumberDelta !== 0 || this._endLineNumberDelta !== 0) {\n\t\t\tlet startLineNumber = result.startLineNumber;\n\t\t\tlet startColumn = result.startColumn;\n\t\t\tlet endLineNumber = result.endLineNumber;\n\t\t\tlet endColumn = result.endColumn;\n\n\t\t\tif (this._startLineNumberDelta !== 0) {\n\t\t\t\tstartLineNumber = startLineNumber + this._startLineNumberDelta;\n\t\t\t\tstartColumn = 1;\n\t\t\t}\n\n\t\t\tif (this._endLineNumberDelta !== 0) {\n\t\t\t\tendLineNumber = endLineNumber + this._endLineNumberDelta;\n\t\t\t\tendColumn = 1;\n\t\t\t}\n\n\t\t\tresult = Selection.createWithDirection(startLineNumber, startColumn, endLineNumber, endColumn, this._selectionDirection);\n\t\t}\n\n\t\treturn result;\n\t}\n}\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\nimport { EditOperation, ISingleEditOperation } from 'vs/editor/common/core/editOperation';\nimport { Range } from 'vs/editor/common/core/range';\nimport { Selection } from 'vs/editor/common/core/selection';\nimport { ICommand, ICursorStateComputerData, IEditOperationBuilder } from 'vs/editor/common/editorCommon';\nimport { ITextModel } from 'vs/editor/common/model';\n\nexport class SortLinesCommand implements ICommand {\n\n\tprivate static _COLLATOR: Intl.Collator | null = null;\n\tpublic static getCollator(): Intl.Collator {\n\t\tif (!SortLinesCommand._COLLATOR) {\n\t\t\tSortLinesCommand._COLLATOR = new Intl.Collator();\n\t\t}\n\t\treturn SortLinesCommand._COLLATOR;\n\t}\n\n\tprivate readonly selection: Selection;\n\tprivate readonly descending: boolean;\n\tprivate selectionId: string | null;\n\n\tconstructor(selection: Selection, descending: boolean) {\n\t\tthis.selection = selection;\n\t\tthis.descending = descending;\n\t\tthis.selectionId = null;\n\t}\n\n\tpublic getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {\n\t\tconst op = sortLines(model, this.selection, this.descending);\n\t\tif (op) {\n\t\t\tbuilder.addEditOperation(op.range, op.text);\n\t\t}\n\n\t\tthis.selectionId = builder.trackSelection(this.selection);\n\t}\n\n\tpublic computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {\n\t\treturn helper.getTrackedSelection(this.selectionId!);\n\t}\n\n\tpublic static canRun(model: ITextModel | null, selection: Selection, descending: boolean): boolean {\n\t\tif (model === null) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst data = getSortData(model, selection, descending);\n\n\t\tif (!data) {\n\t\t\treturn false;\n\t\t}\n\n\t\tfor (let i = 0, len = data.before.length; i < len; i++) {\n\t\t\tif (data.before[i] !== data.after[i]) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n}\n\nfunction getSortData(model: ITextModel, selection: Selection, descending: boolean) {\n\tconst startLineNumber = selection.startLineNumber;\n\tlet endLineNumber = selection.endLineNumber;\n\n\tif (selection.endColumn === 1) {\n\t\tendLineNumber--;\n\t}\n\n\t// Nothing to sort if user didn't select anything.\n\tif (startLineNumber >= endLineNumber) {\n\t\treturn null;\n\t}\n\n\tconst linesToSort: string[] = [];\n\n\t// Get the contents of the selection to be sorted.\n\tfor (let lineNumber = startLineNumber; lineNumber <= endLineNumber; lineNumber++) {\n\t\tlinesToSort.push(model.getLineContent(lineNumber));\n\t}\n\n\tlet sorted = linesToSort.slice(0);\n\tsorted.sort(SortLinesCommand.getCollator().compare);\n\n\t// If descending, reverse the order.\n\tif (descending === true) {\n\t\tsorted = sorted.reverse();\n\t}\n\n\treturn {\n\t\tstartLineNumber: startLineNumber,\n\t\tendLineNumber: endLineNumber,\n\t\tbefore: linesToSort,\n\t\tafter: sorted\n\t};\n}\n\n/**\n * Generate commands for sorting lines on a model.\n */\nfunction sortLines(model: ITextModel, selection: Selection, descending: boolean): ISingleEditOperation | null {\n\tconst data = getSortData(model, selection, descending);\n\n\tif (!data) {\n\t\treturn null;\n\t}\n\n\treturn EditOperation.replace(\n\t\tnew Range(data.startLineNumber, 1, data.endLineNumber, model.getLineMaxColumn(data.endLineNumber)),\n\t\tdata.after.join('\\n')\n\t);\n}\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\nimport { ITextModel } from 'vs/editor/common/model';\nimport { IConfigurationService } from 'vs/platform/configuration/common/configuration';\nimport { IThemeService } from 'vs/platform/theme/common/themeService';\n\nexport const SEMANTIC_HIGHLIGHTING_SETTING_ID = 'editor.semanticHighlighting';\n\nexport interface IEditorSemanticHighlightingOptions {\n\tenabled: true | false | 'configuredByTheme';\n}\n\nexport function isSemanticColoringEnabled(model: ITextModel, themeService: IThemeService, configurationService: IConfigurationService): boolean {\n\tconst setting = configurationService.getValue(SEMANTIC_HIGHLIGHTING_SETTING_ID, { overrideIdentifier: model.getLanguageId(), resource: model.uri })?.enabled;\n\tif (typeof setting === 'boolean') {\n\t\treturn setting;\n\t}\n\treturn themeService.getColorTheme().semanticHighlighting;\n}\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\nimport { LinkedList } from 'vs/base/common/linkedList';\nimport { Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\nimport { ITextModel } from 'vs/editor/common/model';\nimport { SelectionRange, SelectionRangeProvider } from 'vs/editor/common/languages';\n\nexport class BracketSelectionRangeProvider implements SelectionRangeProvider {\n\n\tasync provideSelectionRanges(model: ITextModel, positions: Position[]): Promise {\n\t\tconst result: SelectionRange[][] = [];\n\n\t\tfor (const position of positions) {\n\t\t\tconst bucket: SelectionRange[] = [];\n\t\t\tresult.push(bucket);\n\n\t\t\tconst ranges = new Map>();\n\t\t\tawait new Promise(resolve => BracketSelectionRangeProvider._bracketsRightYield(resolve, 0, model, position, ranges));\n\t\t\tawait new Promise(resolve => BracketSelectionRangeProvider._bracketsLeftYield(resolve, 0, model, position, ranges, bucket));\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic static _maxDuration = 30;\n\tprivate static readonly _maxRounds = 2;\n\n\tprivate static _bracketsRightYield(resolve: () => void, round: number, model: ITextModel, pos: Position, ranges: Map>): void {\n\t\tconst counts = new Map();\n\t\tconst t1 = Date.now();\n\t\twhile (true) {\n\t\t\tif (round >= BracketSelectionRangeProvider._maxRounds) {\n\t\t\t\tresolve();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (!pos) {\n\t\t\t\tresolve();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tconst bracket = model.bracketPairs.findNextBracket(pos);\n\t\t\tif (!bracket) {\n\t\t\t\tresolve();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tconst d = Date.now() - t1;\n\t\t\tif (d > BracketSelectionRangeProvider._maxDuration) {\n\t\t\t\tsetTimeout(() => BracketSelectionRangeProvider._bracketsRightYield(resolve, round + 1, model, pos, ranges));\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (bracket.bracketInfo.isOpeningBracket) {\n\t\t\t\tconst key = bracket.bracketInfo.bracketText;\n\t\t\t\t// wait for closing\n\t\t\t\tconst val = counts.has(key) ? counts.get(key)! : 0;\n\t\t\t\tcounts.set(key, val + 1);\n\t\t\t} else {\n\t\t\t\tconst key = bracket.bracketInfo.getOpeningBrackets()[0].bracketText;\n\t\t\t\t// process closing\n\t\t\t\tlet val = counts.has(key) ? counts.get(key)! : 0;\n\t\t\t\tval -= 1;\n\t\t\t\tcounts.set(key, Math.max(0, val));\n\t\t\t\tif (val < 0) {\n\t\t\t\t\tlet list = ranges.get(key);\n\t\t\t\t\tif (!list) {\n\t\t\t\t\t\tlist = new LinkedList();\n\t\t\t\t\t\tranges.set(key, list);\n\t\t\t\t\t}\n\t\t\t\t\tlist.push(bracket.range);\n\t\t\t\t}\n\t\t\t}\n\t\t\tpos = bracket.range.getEndPosition();\n\t\t}\n\t}\n\n\tprivate static _bracketsLeftYield(resolve: () => void, round: number, model: ITextModel, pos: Position, ranges: Map>, bucket: SelectionRange[]): void {\n\t\tconst counts = new Map();\n\t\tconst t1 = Date.now();\n\t\twhile (true) {\n\t\t\tif (round >= BracketSelectionRangeProvider._maxRounds && ranges.size === 0) {\n\t\t\t\tresolve();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (!pos) {\n\t\t\t\tresolve();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tconst bracket = model.bracketPairs.findPrevBracket(pos);\n\t\t\tif (!bracket) {\n\t\t\t\tresolve();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tconst d = Date.now() - t1;\n\t\t\tif (d > BracketSelectionRangeProvider._maxDuration) {\n\t\t\t\tsetTimeout(() => BracketSelectionRangeProvider._bracketsLeftYield(resolve, round + 1, model, pos, ranges, bucket));\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (!bracket.bracketInfo.isOpeningBracket) {\n\t\t\t\tconst key = bracket.bracketInfo.getOpeningBrackets()[0].bracketText;\n\t\t\t\t// wait for opening\n\t\t\t\tconst val = counts.has(key) ? counts.get(key)! : 0;\n\t\t\t\tcounts.set(key, val + 1);\n\t\t\t} else {\n\t\t\t\tconst key = bracket.bracketInfo.bracketText;\n\t\t\t\t// opening\n\t\t\t\tlet val = counts.has(key) ? counts.get(key)! : 0;\n\t\t\t\tval -= 1;\n\t\t\t\tcounts.set(key, Math.max(0, val));\n\t\t\t\tif (val < 0) {\n\t\t\t\t\tconst list = ranges.get(key);\n\t\t\t\t\tif (list) {\n\t\t\t\t\t\tconst closing = list.shift();\n\t\t\t\t\t\tif (list.size === 0) {\n\t\t\t\t\t\t\tranges.delete(key);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst innerBracket = Range.fromPositions(bracket.range.getEndPosition(), closing!.getStartPosition());\n\t\t\t\t\t\tconst outerBracket = Range.fromPositions(bracket.range.getStartPosition(), closing!.getEndPosition());\n\t\t\t\t\t\tbucket.push({ range: innerBracket });\n\t\t\t\t\t\tbucket.push({ range: outerBracket });\n\t\t\t\t\t\tBracketSelectionRangeProvider._addBracketLeading(model, outerBracket, bucket);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tpos = bracket.range.getStartPosition();\n\t\t}\n\t}\n\n\tprivate static _addBracketLeading(model: ITextModel, bracket: Range, bucket: SelectionRange[]): void {\n\t\tif (bracket.startLineNumber === bracket.endLineNumber) {\n\t\t\treturn;\n\t\t}\n\t\t// xxxxxxxx {\n\t\t//\n\t\t// }\n\t\tconst startLine = bracket.startLineNumber;\n\t\tconst column = model.getLineFirstNonWhitespaceColumn(startLine);\n\t\tif (column !== 0 && column !== bracket.startColumn) {\n\t\t\tbucket.push({ range: Range.fromPositions(new Position(startLine, column), bracket.getEndPosition()) });\n\t\t\tbucket.push({ range: Range.fromPositions(new Position(startLine, 1), bracket.getEndPosition()) });\n\t\t}\n\n\t\t// xxxxxxxx\n\t\t// {\n\t\t//\n\t\t// }\n\t\tconst aboveLine = startLine - 1;\n\t\tif (aboveLine > 0) {\n\t\t\tconst column = model.getLineFirstNonWhitespaceColumn(aboveLine);\n\t\t\tif (column === bracket.startColumn && column !== model.getLineLastNonWhitespaceColumn(aboveLine)) {\n\t\t\t\tbucket.push({ range: Range.fromPositions(new Position(aboveLine, column), bracket.getEndPosition()) });\n\t\t\t\tbucket.push({ range: Range.fromPositions(new Position(aboveLine, 1), bracket.getEndPosition()) });\n\t\t\t}\n\t\t}\n\t}\n}\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\nimport { CharCode } from 'vs/base/common/charCode';\nimport { isLowerAsciiLetter, isUpperAsciiLetter } from 'vs/base/common/strings';\nimport { Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\nimport { ITextModel } from 'vs/editor/common/model';\nimport { SelectionRange, SelectionRangeProvider } from 'vs/editor/common/languages';\n\nexport class WordSelectionRangeProvider implements SelectionRangeProvider {\n\n\tconstructor(private readonly selectSubwords = true) { }\n\n\tprovideSelectionRanges(model: ITextModel, positions: Position[]): SelectionRange[][] {\n\t\tconst result: SelectionRange[][] = [];\n\t\tfor (const position of positions) {\n\t\t\tconst bucket: SelectionRange[] = [];\n\t\t\tresult.push(bucket);\n\t\t\tif (this.selectSubwords) {\n\t\t\t\tthis._addInWordRanges(bucket, model, position);\n\t\t\t}\n\t\t\tthis._addWordRanges(bucket, model, position);\n\t\t\tthis._addWhitespaceLine(bucket, model, position);\n\t\t\tbucket.push({ range: model.getFullModelRange() });\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate _addInWordRanges(bucket: SelectionRange[], model: ITextModel, pos: Position): void {\n\t\tconst obj = model.getWordAtPosition(pos);\n\t\tif (!obj) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst { word, startColumn } = obj;\n\t\tconst offset = pos.column - startColumn;\n\t\tlet start = offset;\n\t\tlet end = offset;\n\t\tlet lastCh: number = 0;\n\n\t\t// LEFT anchor (start)\n\t\tfor (; start >= 0; start--) {\n\t\t\tconst ch = word.charCodeAt(start);\n\t\t\tif ((start !== offset) && (ch === CharCode.Underline || ch === CharCode.Dash)) {\n\t\t\t\t// foo-bar OR foo_bar\n\t\t\t\tbreak;\n\t\t\t} else if (isLowerAsciiLetter(ch) && isUpperAsciiLetter(lastCh)) {\n\t\t\t\t// fooBar\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tlastCh = ch;\n\t\t}\n\t\tstart += 1;\n\n\t\t// RIGHT anchor (end)\n\t\tfor (; end < word.length; end++) {\n\t\t\tconst ch = word.charCodeAt(end);\n\t\t\tif (isUpperAsciiLetter(ch) && isLowerAsciiLetter(lastCh)) {\n\t\t\t\t// fooBar\n\t\t\t\tbreak;\n\t\t\t} else if (ch === CharCode.Underline || ch === CharCode.Dash) {\n\t\t\t\t// foo-bar OR foo_bar\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tlastCh = ch;\n\t\t}\n\n\t\tif (start < end) {\n\t\t\tbucket.push({ range: new Range(pos.lineNumber, startColumn + start, pos.lineNumber, startColumn + end) });\n\t\t}\n\t}\n\n\tprivate _addWordRanges(bucket: SelectionRange[], model: ITextModel, pos: Position): void {\n\t\tconst word = model.getWordAtPosition(pos);\n\t\tif (word) {\n\t\t\tbucket.push({ range: new Range(pos.lineNumber, word.startColumn, pos.lineNumber, word.endColumn) });\n\t\t}\n\t}\n\n\tprivate _addWhitespaceLine(bucket: SelectionRange[], model: ITextModel, pos: Position): void {\n\t\tif (model.getLineLength(pos.lineNumber) > 0\n\t\t\t&& model.getLineFirstNonWhitespaceColumn(pos.lineNumber) === 0\n\t\t\t&& model.getLineLastNonWhitespaceColumn(pos.lineNumber) === 0\n\t\t) {\n\t\t\tbucket.push({ range: new Range(pos.lineNumber, 1, pos.lineNumber, model.getLineMaxColumn(pos.lineNumber)) });\n\t\t}\n\t}\n}\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\nimport { CharCode } from 'vs/base/common/charCode';\n\nexport const enum TokenType {\n\tDollar,\n\tColon,\n\tComma,\n\tCurlyOpen,\n\tCurlyClose,\n\tBackslash,\n\tForwardslash,\n\tPipe,\n\tInt,\n\tVariableName,\n\tFormat,\n\tPlus,\n\tDash,\n\tQuestionMark,\n\tEOF\n}\n\nexport interface Token {\n\ttype: TokenType;\n\tpos: number;\n\tlen: number;\n}\n\n\nexport class Scanner {\n\n\tprivate static _table: { [ch: number]: TokenType } = {\n\t\t[CharCode.DollarSign]: TokenType.Dollar,\n\t\t[CharCode.Colon]: TokenType.Colon,\n\t\t[CharCode.Comma]: TokenType.Comma,\n\t\t[CharCode.OpenCurlyBrace]: TokenType.CurlyOpen,\n\t\t[CharCode.CloseCurlyBrace]: TokenType.CurlyClose,\n\t\t[CharCode.Backslash]: TokenType.Backslash,\n\t\t[CharCode.Slash]: TokenType.Forwardslash,\n\t\t[CharCode.Pipe]: TokenType.Pipe,\n\t\t[CharCode.Plus]: TokenType.Plus,\n\t\t[CharCode.Dash]: TokenType.Dash,\n\t\t[CharCode.QuestionMark]: TokenType.QuestionMark,\n\t};\n\n\tstatic isDigitCharacter(ch: number): boolean {\n\t\treturn ch >= CharCode.Digit0 && ch <= CharCode.Digit9;\n\t}\n\n\tstatic isVariableCharacter(ch: number): boolean {\n\t\treturn ch === CharCode.Underline\n\t\t\t|| (ch >= CharCode.a && ch <= CharCode.z)\n\t\t\t|| (ch >= CharCode.A && ch <= CharCode.Z);\n\t}\n\n\tvalue: string = '';\n\tpos: number = 0;\n\n\ttext(value: string) {\n\t\tthis.value = value;\n\t\tthis.pos = 0;\n\t}\n\n\ttokenText(token: Token): string {\n\t\treturn this.value.substr(token.pos, token.len);\n\t}\n\n\tnext(): Token {\n\n\t\tif (this.pos >= this.value.length) {\n\t\t\treturn { type: TokenType.EOF, pos: this.pos, len: 0 };\n\t\t}\n\n\t\tconst pos = this.pos;\n\t\tlet len = 0;\n\t\tlet ch = this.value.charCodeAt(pos);\n\t\tlet type: TokenType;\n\n\t\t// static types\n\t\ttype = Scanner._table[ch];\n\t\tif (typeof type === 'number') {\n\t\t\tthis.pos += 1;\n\t\t\treturn { type, pos, len: 1 };\n\t\t}\n\n\t\t// number\n\t\tif (Scanner.isDigitCharacter(ch)) {\n\t\t\ttype = TokenType.Int;\n\t\t\tdo {\n\t\t\t\tlen += 1;\n\t\t\t\tch = this.value.charCodeAt(pos + len);\n\t\t\t} while (Scanner.isDigitCharacter(ch));\n\n\t\t\tthis.pos += len;\n\t\t\treturn { type, pos, len };\n\t\t}\n\n\t\t// variable name\n\t\tif (Scanner.isVariableCharacter(ch)) {\n\t\t\ttype = TokenType.VariableName;\n\t\t\tdo {\n\t\t\t\tch = this.value.charCodeAt(pos + (++len));\n\t\t\t} while (Scanner.isVariableCharacter(ch) || Scanner.isDigitCharacter(ch));\n\n\t\t\tthis.pos += len;\n\t\t\treturn { type, pos, len };\n\t\t}\n\n\n\t\t// format\n\t\ttype = TokenType.Format;\n\t\tdo {\n\t\t\tlen += 1;\n\t\t\tch = this.value.charCodeAt(pos + len);\n\t\t} while (\n\t\t\t!isNaN(ch)\n\t\t\t&& typeof Scanner._table[ch] === 'undefined' // not static token\n\t\t\t&& !Scanner.isDigitCharacter(ch) // not number\n\t\t\t&& !Scanner.isVariableCharacter(ch) // not variable\n\t\t);\n\n\t\tthis.pos += len;\n\t\treturn { type, pos, len };\n\t}\n}\n\nexport abstract class Marker {\n\n\treadonly _markerBrand: any;\n\n\tpublic parent!: Marker;\n\tprotected _children: Marker[] = [];\n\n\tappendChild(child: Marker): this {\n\t\tif (child instanceof Text && this._children[this._children.length - 1] instanceof Text) {\n\t\t\t// this and previous child are text -> merge them\n\t\t\t(this._children[this._children.length - 1]).value += child.value;\n\t\t} else {\n\t\t\t// normal adoption of child\n\t\t\tchild.parent = this;\n\t\t\tthis._children.push(child);\n\t\t}\n\t\treturn this;\n\t}\n\n\treplace(child: Marker, others: Marker[]): void {\n\t\tconst { parent } = child;\n\t\tconst idx = parent.children.indexOf(child);\n\t\tconst newChildren = parent.children.slice(0);\n\t\tnewChildren.splice(idx, 1, ...others);\n\t\tparent._children = newChildren;\n\n\t\t(function _fixParent(children: Marker[], parent: Marker) {\n\t\t\tfor (const child of children) {\n\t\t\t\tchild.parent = parent;\n\t\t\t\t_fixParent(child.children, child);\n\t\t\t}\n\t\t})(others, parent);\n\t}\n\n\tget children(): Marker[] {\n\t\treturn this._children;\n\t}\n\n\tget rightMostDescendant(): Marker {\n\t\tif (this._children.length > 0) {\n\t\t\treturn this._children[this._children.length - 1].rightMostDescendant;\n\t\t}\n\t\treturn this;\n\t}\n\n\tget snippet(): TextmateSnippet | undefined {\n\t\tlet candidate: Marker = this;\n\t\twhile (true) {\n\t\t\tif (!candidate) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tif (candidate instanceof TextmateSnippet) {\n\t\t\t\treturn candidate;\n\t\t\t}\n\t\t\tcandidate = candidate.parent;\n\t\t}\n\t}\n\n\ttoString(): string {\n\t\treturn this.children.reduce((prev, cur) => prev + cur.toString(), '');\n\t}\n\n\tlen(): number {\n\t\treturn 0;\n\t}\n\n\tabstract clone(): Marker;\n}\n\nexport class Text extends Marker {\n\n\tconstructor(public value: string) {\n\t\tsuper();\n\t}\n\toverride toString() {\n\t\treturn this.value;\n\t}\n\toverride len(): number {\n\t\treturn this.value.length;\n\t}\n\tclone(): Text {\n\t\treturn new Text(this.value);\n\t}\n}\n\nexport abstract class TransformableMarker extends Marker {\n\tpublic transform?: Transform;\n}\n\nexport class Placeholder extends TransformableMarker {\n\tstatic compareByIndex(a: Placeholder, b: Placeholder): number {\n\t\tif (a.index === b.index) {\n\t\t\treturn 0;\n\t\t} else if (a.isFinalTabstop) {\n\t\t\treturn 1;\n\t\t} else if (b.isFinalTabstop) {\n\t\t\treturn -1;\n\t\t} else if (a.index < b.index) {\n\t\t\treturn -1;\n\t\t} else if (a.index > b.index) {\n\t\t\treturn 1;\n\t\t} else {\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\tconstructor(public index: number) {\n\t\tsuper();\n\t}\n\n\tget isFinalTabstop() {\n\t\treturn this.index === 0;\n\t}\n\n\tget choice(): Choice | undefined {\n\t\treturn this._children.length === 1 && this._children[0] instanceof Choice\n\t\t\t? this._children[0] as Choice\n\t\t\t: undefined;\n\t}\n\n\tclone(): Placeholder {\n\t\tconst ret = new Placeholder(this.index);\n\t\tif (this.transform) {\n\t\t\tret.transform = this.transform.clone();\n\t\t}\n\t\tret._children = this.children.map(child => child.clone());\n\t\treturn ret;\n\t}\n}\n\nexport class Choice extends Marker {\n\n\treadonly options: Text[] = [];\n\n\toverride appendChild(marker: Marker): this {\n\t\tif (marker instanceof Text) {\n\t\t\tmarker.parent = this;\n\t\t\tthis.options.push(marker);\n\t\t}\n\t\treturn this;\n\t}\n\n\toverride toString() {\n\t\treturn this.options[0].value;\n\t}\n\n\toverride len(): number {\n\t\treturn this.options[0].len();\n\t}\n\n\tclone(): Choice {\n\t\tconst ret = new Choice();\n\t\tthis.options.forEach(ret.appendChild, ret);\n\t\treturn ret;\n\t}\n}\n\nexport class Transform extends Marker {\n\n\tregexp: RegExp = new RegExp('');\n\n\tresolve(value: string): string {\n\t\tconst _this = this;\n\t\tlet didMatch = false;\n\t\tlet ret = value.replace(this.regexp, function () {\n\t\t\tdidMatch = true;\n\t\t\treturn _this._replace(Array.prototype.slice.call(arguments, 0, -2));\n\t\t});\n\t\t// when the regex didn't match and when the transform has\n\t\t// else branches, then run those\n\t\tif (!didMatch && this._children.some(child => child instanceof FormatString && Boolean(child.elseValue))) {\n\t\t\tret = this._replace([]);\n\t\t}\n\t\treturn ret;\n\t}\n\n\tprivate _replace(groups: string[]): string {\n\t\tlet ret = '';\n\t\tfor (const marker of this._children) {\n\t\t\tif (marker instanceof FormatString) {\n\t\t\t\tlet value = groups[marker.index] || '';\n\t\t\t\tvalue = marker.resolve(value);\n\t\t\t\tret += value;\n\t\t\t} else {\n\t\t\t\tret += marker.toString();\n\t\t\t}\n\t\t}\n\t\treturn ret;\n\t}\n\n\toverride toString(): string {\n\t\treturn '';\n\t}\n\n\tclone(): Transform {\n\t\tconst ret = new Transform();\n\t\tret.regexp = new RegExp(this.regexp.source, '' + (this.regexp.ignoreCase ? 'i' : '') + (this.regexp.global ? 'g' : ''));\n\t\tret._children = this.children.map(child => child.clone());\n\t\treturn ret;\n\t}\n\n}\n\nexport class FormatString extends Marker {\n\n\tconstructor(\n\t\treadonly index: number,\n\t\treadonly shorthandName?: string,\n\t\treadonly ifValue?: string,\n\t\treadonly elseValue?: string,\n\t) {\n\t\tsuper();\n\t}\n\n\tresolve(value?: string): string {\n\t\tif (this.shorthandName === 'upcase') {\n\t\t\treturn !value ? '' : value.toLocaleUpperCase();\n\t\t} else if (this.shorthandName === 'downcase') {\n\t\t\treturn !value ? '' : value.toLocaleLowerCase();\n\t\t} else if (this.shorthandName === 'capitalize') {\n\t\t\treturn !value ? '' : (value[0].toLocaleUpperCase() + value.substr(1));\n\t\t} else if (this.shorthandName === 'pascalcase') {\n\t\t\treturn !value ? '' : this._toPascalCase(value);\n\t\t} else if (this.shorthandName === 'camelcase') {\n\t\t\treturn !value ? '' : this._toCamelCase(value);\n\t\t} else if (Boolean(value) && typeof this.ifValue === 'string') {\n\t\t\treturn this.ifValue;\n\t\t} else if (!Boolean(value) && typeof this.elseValue === 'string') {\n\t\t\treturn this.elseValue;\n\t\t} else {\n\t\t\treturn value || '';\n\t\t}\n\t}\n\n\tprivate _toPascalCase(value: string): string {\n\t\tconst match = value.match(/[a-z0-9]+/gi);\n\t\tif (!match) {\n\t\t\treturn value;\n\t\t}\n\t\treturn match.map(word => {\n\t\t\treturn word.charAt(0).toUpperCase() + word.substr(1);\n\t\t})\n\t\t\t.join('');\n\t}\n\n\tprivate _toCamelCase(value: string): string {\n\t\tconst match = value.match(/[a-z0-9]+/gi);\n\t\tif (!match) {\n\t\t\treturn value;\n\t\t}\n\t\treturn match.map((word, index) => {\n\t\t\tif (index === 0) {\n\t\t\t\treturn word.charAt(0).toLowerCase() + word.substr(1);\n\t\t\t}\n\t\t\treturn word.charAt(0).toUpperCase() + word.substr(1);\n\t\t})\n\t\t\t.join('');\n\t}\n\n\tclone(): FormatString {\n\t\tconst ret = new FormatString(this.index, this.shorthandName, this.ifValue, this.elseValue);\n\t\treturn ret;\n\t}\n}\n\nexport class Variable extends TransformableMarker {\n\n\tconstructor(public name: string) {\n\t\tsuper();\n\t}\n\n\tresolve(resolver: VariableResolver): boolean {\n\t\tlet value = resolver.resolve(this);\n\t\tif (this.transform) {\n\t\t\tvalue = this.transform.resolve(value || '');\n\t\t}\n\t\tif (value !== undefined) {\n\t\t\tthis._children = [new Text(value)];\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tclone(): Variable {\n\t\tconst ret = new Variable(this.name);\n\t\tif (this.transform) {\n\t\t\tret.transform = this.transform.clone();\n\t\t}\n\t\tret._children = this.children.map(child => child.clone());\n\t\treturn ret;\n\t}\n}\n\nexport interface VariableResolver {\n\tresolve(variable: Variable): string | undefined;\n}\n\nfunction walk(marker: Marker[], visitor: (marker: Marker) => boolean): void {\n\tconst stack = [...marker];\n\twhile (stack.length > 0) {\n\t\tconst marker = stack.shift()!;\n\t\tconst recurse = visitor(marker);\n\t\tif (!recurse) {\n\t\t\tbreak;\n\t\t}\n\t\tstack.unshift(...marker.children);\n\t}\n}\n\nexport class TextmateSnippet extends Marker {\n\n\tprivate _placeholders?: { all: Placeholder[]; last?: Placeholder };\n\n\tget placeholderInfo() {\n\t\tif (!this._placeholders) {\n\t\t\t// fill in placeholders\n\t\t\tconst all: Placeholder[] = [];\n\t\t\tlet last: Placeholder | undefined;\n\t\t\tthis.walk(function (candidate) {\n\t\t\t\tif (candidate instanceof Placeholder) {\n\t\t\t\t\tall.push(candidate);\n\t\t\t\t\tlast = !last || last.index < candidate.index ? candidate : last;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t});\n\t\t\tthis._placeholders = { all, last };\n\t\t}\n\t\treturn this._placeholders;\n\t}\n\n\tget placeholders(): Placeholder[] {\n\t\tconst { all } = this.placeholderInfo;\n\t\treturn all;\n\t}\n\n\toffset(marker: Marker): number {\n\t\tlet pos = 0;\n\t\tlet found = false;\n\t\tthis.walk(candidate => {\n\t\t\tif (candidate === marker) {\n\t\t\t\tfound = true;\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tpos += candidate.len();\n\t\t\treturn true;\n\t\t});\n\n\t\tif (!found) {\n\t\t\treturn -1;\n\t\t}\n\t\treturn pos;\n\t}\n\n\tfullLen(marker: Marker): number {\n\t\tlet ret = 0;\n\t\twalk([marker], marker => {\n\t\t\tret += marker.len();\n\t\t\treturn true;\n\t\t});\n\t\treturn ret;\n\t}\n\n\tenclosingPlaceholders(placeholder: Placeholder): Placeholder[] {\n\t\tconst ret: Placeholder[] = [];\n\t\tlet { parent } = placeholder;\n\t\twhile (parent) {\n\t\t\tif (parent instanceof Placeholder) {\n\t\t\t\tret.push(parent);\n\t\t\t}\n\t\t\tparent = parent.parent;\n\t\t}\n\t\treturn ret;\n\t}\n\n\tresolveVariables(resolver: VariableResolver): this {\n\t\tthis.walk(candidate => {\n\t\t\tif (candidate instanceof Variable) {\n\t\t\t\tif (candidate.resolve(resolver)) {\n\t\t\t\t\tthis._placeholders = undefined;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t});\n\t\treturn this;\n\t}\n\n\toverride appendChild(child: Marker) {\n\t\tthis._placeholders = undefined;\n\t\treturn super.appendChild(child);\n\t}\n\n\toverride replace(child: Marker, others: Marker[]): void {\n\t\tthis._placeholders = undefined;\n\t\treturn super.replace(child, others);\n\t}\n\n\tclone(): TextmateSnippet {\n\t\tconst ret = new TextmateSnippet();\n\t\tthis._children = this.children.map(child => child.clone());\n\t\treturn ret;\n\t}\n\n\twalk(visitor: (marker: Marker) => boolean): void {\n\t\twalk(this.children, visitor);\n\t}\n}\n\nexport class SnippetParser {\n\n\tstatic escape(value: string): string {\n\t\treturn value.replace(/\\$|}|\\\\/g, '\\\\$&');\n\t}\n\n\tstatic guessNeedsClipboard(template: string): boolean {\n\t\treturn /\\${?CLIPBOARD/.test(template);\n\t}\n\n\tprivate _scanner: Scanner = new Scanner();\n\tprivate _token: Token = { type: TokenType.EOF, pos: 0, len: 0 };\n\n\tparse(value: string, insertFinalTabstop?: boolean, enforceFinalTabstop?: boolean): TextmateSnippet {\n\t\tconst snippet = new TextmateSnippet();\n\t\tthis.parseFragment(value, snippet);\n\t\tthis.ensureFinalTabstop(snippet, enforceFinalTabstop ?? false, insertFinalTabstop ?? false);\n\t\treturn snippet;\n\t}\n\n\tparseFragment(value: string, snippet: TextmateSnippet): readonly Marker[] {\n\n\t\tconst offset = snippet.children.length;\n\t\tthis._scanner.text(value);\n\t\tthis._token = this._scanner.next();\n\t\twhile (this._parse(snippet)) {\n\t\t\t// nothing\n\t\t}\n\n\t\t// fill in values for placeholders. the first placeholder of an index\n\t\t// that has a value defines the value for all placeholders with that index\n\t\tconst placeholderDefaultValues = new Map();\n\t\tconst incompletePlaceholders: Placeholder[] = [];\n\t\tsnippet.walk(marker => {\n\t\t\tif (marker instanceof Placeholder) {\n\t\t\t\tif (marker.isFinalTabstop) {\n\t\t\t\t\tplaceholderDefaultValues.set(0, undefined);\n\t\t\t\t} else if (!placeholderDefaultValues.has(marker.index) && marker.children.length > 0) {\n\t\t\t\t\tplaceholderDefaultValues.set(marker.index, marker.children);\n\t\t\t\t} else {\n\t\t\t\t\tincompletePlaceholders.push(marker);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t});\n\n\t\tconst fillInIncompletePlaceholder = (placeholder: Placeholder, stack: Set) => {\n\t\t\tconst defaultValues = placeholderDefaultValues.get(placeholder.index);\n\t\t\tif (!defaultValues) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst clone = new Placeholder(placeholder.index);\n\t\t\tclone.transform = placeholder.transform;\n\t\t\tfor (const child of defaultValues) {\n\t\t\t\tconst newChild = child.clone();\n\t\t\t\tclone.appendChild(newChild);\n\n\t\t\t\t// \"recurse\" on children that are again placeholders\n\t\t\t\tif (newChild instanceof Placeholder && placeholderDefaultValues.has(newChild.index) && !stack.has(newChild.index)) {\n\t\t\t\t\tstack.add(newChild.index);\n\t\t\t\t\tfillInIncompletePlaceholder(newChild, stack);\n\t\t\t\t\tstack.delete(newChild.index);\n\t\t\t\t}\n\t\t\t}\n\t\t\tsnippet.replace(placeholder, [clone]);\n\t\t};\n\n\t\tconst stack = new Set();\n\t\tfor (const placeholder of incompletePlaceholders) {\n\t\t\tfillInIncompletePlaceholder(placeholder, stack);\n\t\t}\n\n\t\treturn snippet.children.slice(offset);\n\t}\n\n\tensureFinalTabstop(snippet: TextmateSnippet, enforceFinalTabstop: boolean, insertFinalTabstop: boolean) {\n\n\t\tif (enforceFinalTabstop || insertFinalTabstop && snippet.placeholders.length > 0) {\n\t\t\tconst finalTabstop = snippet.placeholders.find(p => p.index === 0);\n\t\t\tif (!finalTabstop) {\n\t\t\t\t// the snippet uses placeholders but has no\n\t\t\t\t// final tabstop defined -> insert at the end\n\t\t\t\tsnippet.appendChild(new Placeholder(0));\n\t\t\t}\n\t\t}\n\n\t}\n\n\tprivate _accept(type?: TokenType): boolean;\n\tprivate _accept(type: TokenType | undefined, value: true): string;\n\tprivate _accept(type: TokenType, value?: boolean): boolean | string {\n\t\tif (type === undefined || this._token.type === type) {\n\t\t\tconst ret = !value ? true : this._scanner.tokenText(this._token);\n\t\t\tthis._token = this._scanner.next();\n\t\t\treturn ret;\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate _backTo(token: Token): false {\n\t\tthis._scanner.pos = token.pos + token.len;\n\t\tthis._token = token;\n\t\treturn false;\n\t}\n\n\tprivate _until(type: TokenType): false | string {\n\t\tconst start = this._token;\n\t\twhile (this._token.type !== type) {\n\t\t\tif (this._token.type === TokenType.EOF) {\n\t\t\t\treturn false;\n\t\t\t} else if (this._token.type === TokenType.Backslash) {\n\t\t\t\tconst nextToken = this._scanner.next();\n\t\t\t\tif (nextToken.type !== TokenType.Dollar\n\t\t\t\t\t&& nextToken.type !== TokenType.CurlyClose\n\t\t\t\t\t&& nextToken.type !== TokenType.Backslash) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis._token = this._scanner.next();\n\t\t}\n\t\tconst value = this._scanner.value.substring(start.pos, this._token.pos).replace(/\\\\(\\$|}|\\\\)/g, '$1');\n\t\tthis._token = this._scanner.next();\n\t\treturn value;\n\t}\n\n\tprivate _parse(marker: Marker): boolean {\n\t\treturn this._parseEscaped(marker)\n\t\t\t|| this._parseTabstopOrVariableName(marker)\n\t\t\t|| this._parseComplexPlaceholder(marker)\n\t\t\t|| this._parseComplexVariable(marker)\n\t\t\t|| this._parseAnything(marker);\n\t}\n\n\t// \\$, \\\\, \\} -> just text\n\tprivate _parseEscaped(marker: Marker): boolean {\n\t\tlet value: string;\n\t\tif (value = this._accept(TokenType.Backslash, true)) {\n\t\t\t// saw a backslash, append escaped token or that backslash\n\t\t\tvalue = this._accept(TokenType.Dollar, true)\n\t\t\t\t|| this._accept(TokenType.CurlyClose, true)\n\t\t\t\t|| this._accept(TokenType.Backslash, true)\n\t\t\t\t|| value;\n\n\t\t\tmarker.appendChild(new Text(value));\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\t// $foo -> variable, $1 -> tabstop\n\tprivate _parseTabstopOrVariableName(parent: Marker): boolean {\n\t\tlet value: string;\n\t\tconst token = this._token;\n\t\tconst match = this._accept(TokenType.Dollar)\n\t\t\t&& (value = this._accept(TokenType.VariableName, true) || this._accept(TokenType.Int, true));\n\n\t\tif (!match) {\n\t\t\treturn this._backTo(token);\n\t\t}\n\n\t\tparent.appendChild(/^\\d+$/.test(value!)\n\t\t\t? new Placeholder(Number(value!))\n\t\t\t: new Variable(value!)\n\t\t);\n\t\treturn true;\n\t}\n\n\t// ${1:}, ${1} -> placeholder\n\tprivate _parseComplexPlaceholder(parent: Marker): boolean {\n\t\tlet index: string;\n\t\tconst token = this._token;\n\t\tconst match = this._accept(TokenType.Dollar)\n\t\t\t&& this._accept(TokenType.CurlyOpen)\n\t\t\t&& (index = this._accept(TokenType.Int, true));\n\n\t\tif (!match) {\n\t\t\treturn this._backTo(token);\n\t\t}\n\n\t\tconst placeholder = new Placeholder(Number(index!));\n\n\t\tif (this._accept(TokenType.Colon)) {\n\t\t\t// ${1:}\n\t\t\twhile (true) {\n\n\t\t\t\t// ...} -> done\n\t\t\t\tif (this._accept(TokenType.CurlyClose)) {\n\t\t\t\t\tparent.appendChild(placeholder);\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tif (this._parse(placeholder)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// fallback\n\t\t\t\tparent.appendChild(new Text('${' + index! + ':'));\n\t\t\t\tplaceholder.children.forEach(parent.appendChild, parent);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t} else if (placeholder.index > 0 && this._accept(TokenType.Pipe)) {\n\t\t\t// ${1|one,two,three|}\n\t\t\tconst choice = new Choice();\n\n\t\t\twhile (true) {\n\t\t\t\tif (this._parseChoiceElement(choice)) {\n\n\t\t\t\t\tif (this._accept(TokenType.Comma)) {\n\t\t\t\t\t\t// opt, -> more\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (this._accept(TokenType.Pipe)) {\n\t\t\t\t\t\tplaceholder.appendChild(choice);\n\t\t\t\t\t\tif (this._accept(TokenType.CurlyClose)) {\n\t\t\t\t\t\t\t// ..|} -> done\n\t\t\t\t\t\t\tparent.appendChild(placeholder);\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tthis._backTo(token);\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t} else if (this._accept(TokenType.Forwardslash)) {\n\t\t\t// ${1///}\n\t\t\tif (this._parseTransform(placeholder)) {\n\t\t\t\tparent.appendChild(placeholder);\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tthis._backTo(token);\n\t\t\treturn false;\n\n\t\t} else if (this._accept(TokenType.CurlyClose)) {\n\t\t\t// ${1}\n\t\t\tparent.appendChild(placeholder);\n\t\t\treturn true;\n\n\t\t} else {\n\t\t\t// ${1 <- missing curly or colon\n\t\t\treturn this._backTo(token);\n\t\t}\n\t}\n\n\tprivate _parseChoiceElement(parent: Choice): boolean {\n\t\tconst token = this._token;\n\t\tconst values: string[] = [];\n\n\t\twhile (true) {\n\t\t\tif (this._token.type === TokenType.Comma || this._token.type === TokenType.Pipe) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tlet value: string;\n\t\t\tif (value = this._accept(TokenType.Backslash, true)) {\n\t\t\t\t// \\, \\|, or \\\\\n\t\t\t\tvalue = this._accept(TokenType.Comma, true)\n\t\t\t\t\t|| this._accept(TokenType.Pipe, true)\n\t\t\t\t\t|| this._accept(TokenType.Backslash, true)\n\t\t\t\t\t|| value;\n\t\t\t} else {\n\t\t\t\tvalue = this._accept(undefined, true);\n\t\t\t}\n\t\t\tif (!value) {\n\t\t\t\t// EOF\n\t\t\t\tthis._backTo(token);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tvalues.push(value);\n\t\t}\n\n\t\tif (values.length === 0) {\n\t\t\tthis._backTo(token);\n\t\t\treturn false;\n\t\t}\n\n\t\tparent.appendChild(new Text(values.join('')));\n\t\treturn true;\n\t}\n\n\t// ${foo:}, ${foo} -> variable\n\tprivate _parseComplexVariable(parent: Marker): boolean {\n\t\tlet name: string;\n\t\tconst token = this._token;\n\t\tconst match = this._accept(TokenType.Dollar)\n\t\t\t&& this._accept(TokenType.CurlyOpen)\n\t\t\t&& (name = this._accept(TokenType.VariableName, true));\n\n\t\tif (!match) {\n\t\t\treturn this._backTo(token);\n\t\t}\n\n\t\tconst variable = new Variable(name!);\n\n\t\tif (this._accept(TokenType.Colon)) {\n\t\t\t// ${foo:}\n\t\t\twhile (true) {\n\n\t\t\t\t// ...} -> done\n\t\t\t\tif (this._accept(TokenType.CurlyClose)) {\n\t\t\t\t\tparent.appendChild(variable);\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tif (this._parse(variable)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// fallback\n\t\t\t\tparent.appendChild(new Text('${' + name! + ':'));\n\t\t\t\tvariable.children.forEach(parent.appendChild, parent);\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t} else if (this._accept(TokenType.Forwardslash)) {\n\t\t\t// ${foo///}\n\t\t\tif (this._parseTransform(variable)) {\n\t\t\t\tparent.appendChild(variable);\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tthis._backTo(token);\n\t\t\treturn false;\n\n\t\t} else if (this._accept(TokenType.CurlyClose)) {\n\t\t\t// ${foo}\n\t\t\tparent.appendChild(variable);\n\t\t\treturn true;\n\n\t\t} else {\n\t\t\t// ${foo <- missing curly or colon\n\t\t\treturn this._backTo(token);\n\t\t}\n\t}\n\n\tprivate _parseTransform(parent: TransformableMarker): boolean {\n\t\t// ...//}\n\n\t\tconst transform = new Transform();\n\t\tlet regexValue = '';\n\t\tlet regexOptions = '';\n\n\t\t// (1) /regex\n\t\twhile (true) {\n\t\t\tif (this._accept(TokenType.Forwardslash)) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tlet escaped: string;\n\t\t\tif (escaped = this._accept(TokenType.Backslash, true)) {\n\t\t\t\tescaped = this._accept(TokenType.Forwardslash, true) || escaped;\n\t\t\t\tregexValue += escaped;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (this._token.type !== TokenType.EOF) {\n\t\t\t\tregexValue += this._accept(undefined, true);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t\t// (2) /format\n\t\twhile (true) {\n\t\t\tif (this._accept(TokenType.Forwardslash)) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tlet escaped: string;\n\t\t\tif (escaped = this._accept(TokenType.Backslash, true)) {\n\t\t\t\tescaped = this._accept(TokenType.Backslash, true) || this._accept(TokenType.Forwardslash, true) || escaped;\n\t\t\t\ttransform.appendChild(new Text(escaped));\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (this._parseFormatString(transform) || this._parseAnything(transform)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t\t// (3) /option\n\t\twhile (true) {\n\t\t\tif (this._accept(TokenType.CurlyClose)) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (this._token.type !== TokenType.EOF) {\n\t\t\t\tregexOptions += this._accept(undefined, true);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\n\t\ttry {\n\t\t\ttransform.regexp = new RegExp(regexValue, regexOptions);\n\t\t} catch (e) {\n\t\t\t// invalid regexp\n\t\t\treturn false;\n\t\t}\n\n\t\tparent.transform = transform;\n\t\treturn true;\n\t}\n\n\tprivate _parseFormatString(parent: Transform): boolean {\n\n\t\tconst token = this._token;\n\t\tif (!this._accept(TokenType.Dollar)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tlet complex = false;\n\t\tif (this._accept(TokenType.CurlyOpen)) {\n\t\t\tcomplex = true;\n\t\t}\n\n\t\tconst index = this._accept(TokenType.Int, true);\n\n\t\tif (!index) {\n\t\t\tthis._backTo(token);\n\t\t\treturn false;\n\n\t\t} else if (!complex) {\n\t\t\t// $1\n\t\t\tparent.appendChild(new FormatString(Number(index)));\n\t\t\treturn true;\n\n\t\t} else if (this._accept(TokenType.CurlyClose)) {\n\t\t\t// ${1}\n\t\t\tparent.appendChild(new FormatString(Number(index)));\n\t\t\treturn true;\n\n\t\t} else if (!this._accept(TokenType.Colon)) {\n\t\t\tthis._backTo(token);\n\t\t\treturn false;\n\t\t}\n\n\t\tif (this._accept(TokenType.Forwardslash)) {\n\t\t\t// ${1:/upcase}\n\t\t\tconst shorthand = this._accept(TokenType.VariableName, true);\n\t\t\tif (!shorthand || !this._accept(TokenType.CurlyClose)) {\n\t\t\t\tthis._backTo(token);\n\t\t\t\treturn false;\n\t\t\t} else {\n\t\t\t\tparent.appendChild(new FormatString(Number(index), shorthand));\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t} else if (this._accept(TokenType.Plus)) {\n\t\t\t// ${1:+}\n\t\t\tconst ifValue = this._until(TokenType.CurlyClose);\n\t\t\tif (ifValue) {\n\t\t\t\tparent.appendChild(new FormatString(Number(index), undefined, ifValue, undefined));\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t} else if (this._accept(TokenType.Dash)) {\n\t\t\t// ${2:-}\n\t\t\tconst elseValue = this._until(TokenType.CurlyClose);\n\t\t\tif (elseValue) {\n\t\t\t\tparent.appendChild(new FormatString(Number(index), undefined, undefined, elseValue));\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t} else if (this._accept(TokenType.QuestionMark)) {\n\t\t\t// ${2:?:}\n\t\t\tconst ifValue = this._until(TokenType.Colon);\n\t\t\tif (ifValue) {\n\t\t\t\tconst elseValue = this._until(TokenType.CurlyClose);\n\t\t\t\tif (elseValue) {\n\t\t\t\t\tparent.appendChild(new FormatString(Number(index), undefined, ifValue, elseValue));\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t} else {\n\t\t\t// ${1:}\n\t\t\tconst elseValue = this._until(TokenType.CurlyClose);\n\t\t\tif (elseValue) {\n\t\t\t\tparent.appendChild(new FormatString(Number(index), undefined, undefined, elseValue));\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\tthis._backTo(token);\n\t\treturn false;\n\t}\n\n\tprivate _parseAnything(marker: Marker): boolean {\n\t\tif (this._token.type !== TokenType.EOF) {\n\t\t\tmarker.appendChild(new Text(this._scanner.tokenText(this._token)));\n\t\t\tthis._accept(undefined);\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n}\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\nimport { URI } from 'vs/base/common/uri';\n\nexport class StickyRange {\n\tconstructor(\n\t\tpublic readonly startLineNumber: number,\n\t\tpublic readonly endLineNumber: number\n\t) { }\n}\n\nexport class StickyElement {\n\n\tconstructor(\n\t\t/**\n\t\t * Range of line numbers spanned by the current scope\n\t\t */\n\t\tpublic readonly range: StickyRange | undefined,\n\t\t/**\n\t\t * Must be sorted by start line number\n\t\t*/\n\t\tpublic readonly children: StickyElement[],\n\t\t/**\n\t\t * Parent sticky outline element\n\t\t */\n\t\tpublic readonly parent: StickyElement | undefined\n\t) {\n\t}\n}\n\nexport class StickyModel {\n\tconstructor(\n\t\treadonly uri: URI,\n\t\treadonly version: number,\n\t\treadonly element: StickyElement | undefined,\n\t\treadonly outlineProviderId: string | undefined\n\t) { }\n}\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\nimport { quickSelect } from 'vs/base/common/arrays';\nimport { CharCode } from 'vs/base/common/charCode';\nimport { anyScore, fuzzyScore, FuzzyScore, fuzzyScoreGracefulAggressive, FuzzyScoreOptions, FuzzyScorer } from 'vs/base/common/filters';\nimport { compareIgnoreCase } from 'vs/base/common/strings';\nimport { InternalSuggestOptions } from 'vs/editor/common/config/editorOptions';\nimport { CompletionItemKind, CompletionItemProvider } from 'vs/editor/common/languages';\nimport { WordDistance } from 'vs/editor/contrib/suggest/browser/wordDistance';\nimport { CompletionItem } from './suggest';\n\ntype StrictCompletionItem = Required;\n\nexport interface ICompletionStats {\n\tpLabelLen: number;\n}\n\nexport class LineContext {\n\tconstructor(\n\t\treadonly leadingLineContent: string,\n\t\treadonly characterCountDelta: number,\n\t) { }\n}\n\nconst enum Refilter {\n\tNothing = 0,\n\tAll = 1,\n\tIncr = 2\n}\n\n/**\n * Sorted, filtered completion view model\n * */\nexport class CompletionModel {\n\n\tprivate readonly _items: CompletionItem[];\n\tprivate readonly _column: number;\n\tprivate readonly _wordDistance: WordDistance;\n\tprivate readonly _options: InternalSuggestOptions;\n\tprivate readonly _snippetCompareFn = CompletionModel._compareCompletionItems;\n\tprivate readonly _fuzzyScoreOptions: FuzzyScoreOptions;\n\n\tprivate _lineContext: LineContext;\n\tprivate _refilterKind: Refilter;\n\tprivate _filteredItems?: StrictCompletionItem[];\n\n\tprivate _itemsByProvider?: Map;\n\tprivate _stats?: ICompletionStats;\n\n\tconstructor(\n\t\titems: CompletionItem[],\n\t\tcolumn: number,\n\t\tlineContext: LineContext,\n\t\twordDistance: WordDistance,\n\t\toptions: InternalSuggestOptions,\n\t\tsnippetSuggestions: 'top' | 'bottom' | 'inline' | 'none',\n\t\tfuzzyScoreOptions: FuzzyScoreOptions | undefined = FuzzyScoreOptions.default,\n\t\treadonly clipboardText: string | undefined = undefined\n\t) {\n\t\tthis._items = items;\n\t\tthis._column = column;\n\t\tthis._wordDistance = wordDistance;\n\t\tthis._options = options;\n\t\tthis._refilterKind = Refilter.All;\n\t\tthis._lineContext = lineContext;\n\t\tthis._fuzzyScoreOptions = fuzzyScoreOptions;\n\n\t\tif (snippetSuggestions === 'top') {\n\t\t\tthis._snippetCompareFn = CompletionModel._compareCompletionItemsSnippetsUp;\n\t\t} else if (snippetSuggestions === 'bottom') {\n\t\t\tthis._snippetCompareFn = CompletionModel._compareCompletionItemsSnippetsDown;\n\t\t}\n\t}\n\n\tget lineContext(): LineContext {\n\t\treturn this._lineContext;\n\t}\n\n\tset lineContext(value: LineContext) {\n\t\tif (this._lineContext.leadingLineContent !== value.leadingLineContent\n\t\t\t|| this._lineContext.characterCountDelta !== value.characterCountDelta\n\t\t) {\n\t\t\tthis._refilterKind = this._lineContext.characterCountDelta < value.characterCountDelta && this._filteredItems ? Refilter.Incr : Refilter.All;\n\t\t\tthis._lineContext = value;\n\t\t}\n\t}\n\n\tget items(): CompletionItem[] {\n\t\tthis._ensureCachedState();\n\t\treturn this._filteredItems!;\n\t}\n\n\tgetItemsByProvider(): ReadonlyMap {\n\t\tthis._ensureCachedState();\n\t\treturn this._itemsByProvider!;\n\t}\n\n\tgetIncompleteProvider(): Set {\n\t\tthis._ensureCachedState();\n\t\tconst result = new Set();\n\t\tfor (const [provider, items] of this.getItemsByProvider()) {\n\t\t\tif (items.length > 0 && items[0].container.incomplete) {\n\t\t\t\tresult.add(provider);\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tget stats(): ICompletionStats {\n\t\tthis._ensureCachedState();\n\t\treturn this._stats!;\n\t}\n\n\tprivate _ensureCachedState(): void {\n\t\tif (this._refilterKind !== Refilter.Nothing) {\n\t\t\tthis._createCachedState();\n\t\t}\n\t}\n\n\tprivate _createCachedState(): void {\n\n\t\tthis._itemsByProvider = new Map();\n\n\t\tconst labelLengths: number[] = [];\n\n\t\tconst { leadingLineContent, characterCountDelta } = this._lineContext;\n\t\tlet word = '';\n\t\tlet wordLow = '';\n\n\t\t// incrementally filter less\n\t\tconst source = this._refilterKind === Refilter.All ? this._items : this._filteredItems!;\n\t\tconst target: StrictCompletionItem[] = [];\n\n\t\t// picks a score function based on the number of\n\t\t// items that we have to score/filter and based on the\n\t\t// user-configuration\n\t\tconst scoreFn: FuzzyScorer = (!this._options.filterGraceful || source.length > 2000) ? fuzzyScore : fuzzyScoreGracefulAggressive;\n\n\t\tfor (let i = 0; i < source.length; i++) {\n\n\t\t\tconst item = source[i];\n\n\t\t\tif (item.isInvalid) {\n\t\t\t\tcontinue; // SKIP invalid items\n\t\t\t}\n\n\t\t\t// keep all items by their provider\n\t\t\tconst arr = this._itemsByProvider.get(item.provider);\n\t\t\tif (arr) {\n\t\t\t\tarr.push(item);\n\t\t\t} else {\n\t\t\t\tthis._itemsByProvider.set(item.provider, [item]);\n\t\t\t}\n\n\t\t\t// 'word' is that remainder of the current line that we\n\t\t\t// filter and score against. In theory each suggestion uses a\n\t\t\t// different word, but in practice not - that's why we cache\n\t\t\tconst overwriteBefore = item.position.column - item.editStart.column;\n\t\t\tconst wordLen = overwriteBefore + characterCountDelta - (item.position.column - this._column);\n\t\t\tif (word.length !== wordLen) {\n\t\t\t\tword = wordLen === 0 ? '' : leadingLineContent.slice(-wordLen);\n\t\t\t\twordLow = word.toLowerCase();\n\t\t\t}\n\n\t\t\t// remember the word against which this item was\n\t\t\t// scored\n\t\t\titem.word = word;\n\n\t\t\tif (wordLen === 0) {\n\t\t\t\t// when there is nothing to score against, don't\n\t\t\t\t// event try to do. Use a const rank and rely on\n\t\t\t\t// the fallback-sort using the initial sort order.\n\t\t\t\t// use a score of `-100` because that is out of the\n\t\t\t\t// bound of values `fuzzyScore` will return\n\t\t\t\titem.score = FuzzyScore.Default;\n\n\t\t\t} else {\n\t\t\t\t// skip word characters that are whitespace until\n\t\t\t\t// we have hit the replace range (overwriteBefore)\n\t\t\t\tlet wordPos = 0;\n\t\t\t\twhile (wordPos < overwriteBefore) {\n\t\t\t\t\tconst ch = word.charCodeAt(wordPos);\n\t\t\t\t\tif (ch === CharCode.Space || ch === CharCode.Tab) {\n\t\t\t\t\t\twordPos += 1;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (wordPos >= wordLen) {\n\t\t\t\t\t// the wordPos at which scoring starts is the whole word\n\t\t\t\t\t// and therefore the same rules as not having a word apply\n\t\t\t\t\titem.score = FuzzyScore.Default;\n\n\t\t\t\t} else if (typeof item.completion.filterText === 'string') {\n\t\t\t\t\t// when there is a `filterText` it must match the `word`.\n\t\t\t\t\t// if it matches we check with the label to compute highlights\n\t\t\t\t\t// and if that doesn't yield a result we have no highlights,\n\t\t\t\t\t// despite having the match\n\t\t\t\t\tconst match = scoreFn(word, wordLow, wordPos, item.completion.filterText, item.filterTextLow!, 0, this._fuzzyScoreOptions);\n\t\t\t\t\tif (!match) {\n\t\t\t\t\t\tcontinue; // NO match\n\t\t\t\t\t}\n\t\t\t\t\tif (compareIgnoreCase(item.completion.filterText, item.textLabel) === 0) {\n\t\t\t\t\t\t// filterText and label are actually the same -> use good highlights\n\t\t\t\t\t\titem.score = match;\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// re-run the scorer on the label in the hope of a result BUT use the rank\n\t\t\t\t\t\t// of the filterText-match\n\t\t\t\t\t\titem.score = anyScore(word, wordLow, wordPos, item.textLabel, item.labelLow, 0);\n\t\t\t\t\t\titem.score[0] = match[0]; // use score from filterText\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\t\t\t\t\t// by default match `word` against the `label`\n\t\t\t\t\tconst match = scoreFn(word, wordLow, wordPos, item.textLabel, item.labelLow, 0, this._fuzzyScoreOptions);\n\t\t\t\t\tif (!match) {\n\t\t\t\t\t\tcontinue; // NO match\n\t\t\t\t\t}\n\t\t\t\t\titem.score = match;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\titem.idx = i;\n\t\t\titem.distance = this._wordDistance.distance(item.position, item.completion);\n\t\t\ttarget.push(item as StrictCompletionItem);\n\n\t\t\t// update stats\n\t\t\tlabelLengths.push(item.textLabel.length);\n\t\t}\n\n\t\tthis._filteredItems = target.sort(this._snippetCompareFn);\n\t\tthis._refilterKind = Refilter.Nothing;\n\t\tthis._stats = {\n\t\t\tpLabelLen: labelLengths.length ?\n\t\t\t\tquickSelect(labelLengths.length - .85, labelLengths, (a, b) => a - b)\n\t\t\t\t: 0\n\t\t};\n\t}\n\n\tprivate static _compareCompletionItems(a: StrictCompletionItem, b: StrictCompletionItem): number {\n\t\tif (a.score[0] > b.score[0]) {\n\t\t\treturn -1;\n\t\t} else if (a.score[0] < b.score[0]) {\n\t\t\treturn 1;\n\t\t} else if (a.distance < b.distance) {\n\t\t\treturn -1;\n\t\t} else if (a.distance > b.distance) {\n\t\t\treturn 1;\n\t\t} else if (a.idx < b.idx) {\n\t\t\treturn -1;\n\t\t} else if (a.idx > b.idx) {\n\t\t\treturn 1;\n\t\t} else {\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\tprivate static _compareCompletionItemsSnippetsDown(a: StrictCompletionItem, b: StrictCompletionItem): number {\n\t\tif (a.completion.kind !== b.completion.kind) {\n\t\t\tif (a.completion.kind === CompletionItemKind.Snippet) {\n\t\t\t\treturn 1;\n\t\t\t} else if (b.completion.kind === CompletionItemKind.Snippet) {\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t}\n\t\treturn CompletionModel._compareCompletionItems(a, b);\n\t}\n\n\tprivate static _compareCompletionItemsSnippetsUp(a: StrictCompletionItem, b: StrictCompletionItem): number {\n\t\tif (a.completion.kind !== b.completion.kind) {\n\t\t\tif (a.completion.kind === CompletionItemKind.Snippet) {\n\t\t\t\treturn -1;\n\t\t\t} else if (b.completion.kind === CompletionItemKind.Snippet) {\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t}\n\t\treturn CompletionModel._compareCompletionItems(a, b);\n\t}\n}\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\nimport { isNonEmptyArray } from 'vs/base/common/arrays';\nimport { DisposableStore } from 'vs/base/common/lifecycle';\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\nimport { CharacterSet } from 'vs/editor/common/core/characterClassifier';\nimport { State, SuggestModel } from 'vs/editor/contrib/suggest/browser/suggestModel';\nimport { ISelectedSuggestion, SuggestWidget } from './suggestWidget';\n\nexport class CommitCharacterController {\n\n\tprivate readonly _disposables = new DisposableStore();\n\n\tprivate _active?: {\n\t\treadonly acceptCharacters: CharacterSet;\n\t\treadonly item: ISelectedSuggestion;\n\t};\n\n\tconstructor(editor: ICodeEditor, widget: SuggestWidget, model: SuggestModel, accept: (selected: ISelectedSuggestion) => any) {\n\n\t\tthis._disposables.add(model.onDidSuggest(e => {\n\t\t\tif (e.completionModel.items.length === 0) {\n\t\t\t\tthis.reset();\n\t\t\t}\n\t\t}));\n\t\tthis._disposables.add(model.onDidCancel(e => {\n\t\t\tthis.reset();\n\t\t}));\n\n\t\tthis._disposables.add(widget.onDidShow(() => this._onItem(widget.getFocusedItem())));\n\t\tthis._disposables.add(widget.onDidFocus(this._onItem, this));\n\t\tthis._disposables.add(widget.onDidHide(this.reset, this));\n\n\t\tthis._disposables.add(editor.onWillType(text => {\n\t\t\tif (this._active && !widget.isFrozen() && model.state !== State.Idle) {\n\t\t\t\tconst ch = text.charCodeAt(text.length - 1);\n\t\t\t\tif (this._active.acceptCharacters.has(ch) && editor.getOption(EditorOption.acceptSuggestionOnCommitCharacter)) {\n\t\t\t\t\taccept(this._active.item);\n\t\t\t\t}\n\t\t\t}\n\t\t}));\n\t}\n\n\tprivate _onItem(selected: ISelectedSuggestion | undefined): void {\n\t\tif (!selected || !isNonEmptyArray(selected.item.completion.commitCharacters)) {\n\t\t\t// no item or no commit characters\n\t\t\tthis.reset();\n\t\t\treturn;\n\t\t}\n\n\t\tif (this._active && this._active.item.item === selected.item) {\n\t\t\t// still the same item\n\t\t\treturn;\n\t\t}\n\n\t\t// keep item and its commit characters\n\t\tconst acceptCharacters = new CharacterSet();\n\t\tfor (const ch of selected.item.completion.commitCharacters) {\n\t\t\tif (ch.length > 0) {\n\t\t\t\tacceptCharacters.add(ch.charCodeAt(0));\n\t\t\t}\n\t\t}\n\t\tthis._active = { acceptCharacters, item: selected };\n\t}\n\n\treset(): void {\n\t\tthis._active = undefined;\n\t}\n\n\tdispose() {\n\t\tthis._disposables.dispose();\n\t}\n}\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\nimport { DisposableStore, IDisposable } from 'vs/base/common/lifecycle';\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\nimport { SuggestModel } from 'vs/editor/contrib/suggest/browser/suggestModel';\n\nexport class OvertypingCapturer implements IDisposable {\n\n\tprivate static readonly _maxSelectionLength = 51200;\n\tprivate readonly _disposables = new DisposableStore();\n\n\tprivate _lastOvertyped: { value: string; multiline: boolean }[] = [];\n\tprivate _locked: boolean = false;\n\n\tconstructor(editor: ICodeEditor, suggestModel: SuggestModel) {\n\n\t\tthis._disposables.add(editor.onWillType(() => {\n\t\t\tif (this._locked || !editor.hasModel()) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst selections = editor.getSelections();\n\t\t\tconst selectionsLength = selections.length;\n\n\t\t\t// Check if it will overtype any selections\n\t\t\tlet willOvertype = false;\n\t\t\tfor (let i = 0; i < selectionsLength; i++) {\n\t\t\t\tif (!selections[i].isEmpty()) {\n\t\t\t\t\twillOvertype = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!willOvertype) {\n\t\t\t\tif (this._lastOvertyped.length !== 0) {\n\t\t\t\t\tthis._lastOvertyped.length = 0;\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis._lastOvertyped = [];\n\t\t\tconst model = editor.getModel();\n\t\t\tfor (let i = 0; i < selectionsLength; i++) {\n\t\t\t\tconst selection = selections[i];\n\t\t\t\t// Check for overtyping capturer restrictions\n\t\t\t\tif (model.getValueLengthInRange(selection) > OvertypingCapturer._maxSelectionLength) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tthis._lastOvertyped[i] = { value: model.getValueInRange(selection), multiline: selection.startLineNumber !== selection.endLineNumber };\n\t\t\t}\n\t\t}));\n\n\t\tthis._disposables.add(suggestModel.onDidTrigger(e => {\n\t\t\tthis._locked = true;\n\t\t}));\n\n\t\tthis._disposables.add(suggestModel.onDidCancel(e => {\n\t\t\tthis._locked = false;\n\t\t}));\n\t}\n\n\tgetLastOvertypedInfo(idx: number): { value: string; multiline: boolean } | undefined {\n\t\tif (idx >= 0 && idx < this._lastOvertyped.length) {\n\t\t\treturn this._lastOvertyped[idx];\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tdispose() {\n\t\tthis._disposables.dispose();\n\t}\n}\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\nimport { binarySearch, isFalsyOrEmpty } from 'vs/base/common/arrays';\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\nimport { IPosition } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\nimport { CompletionItem, CompletionItemKind } from 'vs/editor/common/languages';\nimport { IEditorWorkerService } from 'vs/editor/common/services/editorWorker';\nimport { BracketSelectionRangeProvider } from 'vs/editor/contrib/smartSelect/browser/bracketSelections';\n\nexport abstract class WordDistance {\n\n\tstatic readonly None = new class extends WordDistance {\n\t\tdistance() { return 0; }\n\t};\n\n\tstatic async create(service: IEditorWorkerService, editor: ICodeEditor): Promise {\n\n\t\tif (!editor.getOption(EditorOption.suggest).localityBonus) {\n\t\t\treturn WordDistance.None;\n\t\t}\n\n\t\tif (!editor.hasModel()) {\n\t\t\treturn WordDistance.None;\n\t\t}\n\n\t\tconst model = editor.getModel();\n\t\tconst position = editor.getPosition();\n\n\t\tif (!service.canComputeWordRanges(model.uri)) {\n\t\t\treturn WordDistance.None;\n\t\t}\n\n\t\tconst [ranges] = await new BracketSelectionRangeProvider().provideSelectionRanges(model, [position]);\n\t\tif (ranges.length === 0) {\n\t\t\treturn WordDistance.None;\n\t\t}\n\n\t\tconst wordRanges = await service.computeWordRanges(model.uri, ranges[0].range);\n\t\tif (!wordRanges) {\n\t\t\treturn WordDistance.None;\n\t\t}\n\n\t\t// remove current word\n\t\tconst wordUntilPos = model.getWordUntilPosition(position);\n\t\tdelete wordRanges[wordUntilPos.word];\n\n\t\treturn new class extends WordDistance {\n\t\t\tdistance(anchor: IPosition, item: CompletionItem) {\n\t\t\t\tif (!position.equals(editor.getPosition())) {\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t\tif (item.kind === CompletionItemKind.Keyword) {\n\t\t\t\t\treturn 2 << 20;\n\t\t\t\t}\n\t\t\t\tconst word = typeof item.label === 'string' ? item.label : item.label.label;\n\t\t\t\tconst wordLines = wordRanges[word];\n\t\t\t\tif (isFalsyOrEmpty(wordLines)) {\n\t\t\t\t\treturn 2 << 20;\n\t\t\t\t}\n\t\t\t\tconst idx = binarySearch(wordLines, Range.fromPositions(anchor), Range.compareRangesUsingStarts);\n\t\t\t\tconst bestWordRange = idx >= 0 ? wordLines[idx] : wordLines[Math.max(0, ~idx - 1)];\n\t\t\t\tlet blockDistance = ranges.length;\n\t\t\t\tfor (const range of ranges) {\n\t\t\t\t\tif (!Range.containsRange(range.range, bestWordRange)) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tblockDistance -= 1;\n\t\t\t\t}\n\t\t\t\treturn blockDistance;\n\t\t\t}\n\t\t};\n\t}\n\n\tabstract distance(anchor: IPosition, suggestion: CompletionItem): number;\n}\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 * This module exports common types and functionality shared between\n * the Monarch compiler that compiles JSON to ILexer, and the Monarch\n * Tokenizer (that highlights at runtime)\n */\n\n/*\n * Type definitions to be used internally to Monarch.\n * Inside monarch we use fully typed definitions and compiled versions of the more abstract JSON descriptions.\n */\n\nexport const enum MonarchBracket {\n\tNone = 0,\n\tOpen = 1,\n\tClose = -1\n}\n\nexport interface ILexerMin {\n\tlanguageId: string;\n\tincludeLF: boolean;\n\tnoThrow: boolean;\n\tignoreCase: boolean;\n\tunicode: boolean;\n\tusesEmbedded: boolean;\n\tdefaultToken: string;\n\tstateNames: { [stateName: string]: any };\n\t[attr: string]: any;\n}\n\nexport interface ILexer extends ILexerMin {\n\tmaxStack: number;\n\tstart: string | null;\n\tignoreCase: boolean;\n\tunicode: boolean;\n\ttokenPostfix: string;\n\n\ttokenizer: { [stateName: string]: IRule[] };\n\tbrackets: IBracket[];\n}\n\nexport interface IBracket {\n\ttoken: string;\n\topen: string;\n\tclose: string;\n}\n\nexport type FuzzyAction = IAction | string;\n\nexport function isFuzzyActionArr(what: FuzzyAction | FuzzyAction[]): what is FuzzyAction[] {\n\treturn (Array.isArray(what));\n}\n\nexport function isFuzzyAction(what: FuzzyAction | FuzzyAction[]): what is FuzzyAction {\n\treturn !isFuzzyActionArr(what);\n}\n\nexport function isString(what: FuzzyAction): what is string {\n\treturn (typeof what === 'string');\n}\n\nexport function isIAction(what: FuzzyAction): what is IAction {\n\treturn !isString(what);\n}\n\nexport interface IRule {\n\taction: FuzzyAction;\n\tmatchOnlyAtLineStart: boolean;\n\tname: string;\n\tresolveRegex(state: string): RegExp;\n}\n\nexport interface IAction {\n\t// an action is either a group of actions\n\tgroup?: FuzzyAction[];\n\n\t// or a function that returns a fresh action\n\ttest?: (id: string, matches: string[], state: string, eos: boolean) => FuzzyAction;\n\n\t// or it is a declarative action with a token value and various other attributes\n\ttoken?: string;\n\ttokenSubst?: boolean;\n\tnext?: string;\n\tnextEmbedded?: string;\n\tbracket?: MonarchBracket;\n\tlog?: string;\n\tswitchTo?: string;\n\tgoBack?: number;\n\ttransform?: (states: string[]) => string[];\n}\n\nexport interface IBranch {\n\tname: string;\n\tvalue: FuzzyAction;\n\ttest?: (id: string, matches: string[], state: string, eos: boolean) => boolean;\n}\n\n// Small helper functions\n\n/**\n * Is a string null, undefined, or empty?\n */\nexport function empty(s: string): boolean {\n\treturn (s ? false : true);\n}\n\n/**\n * Puts a string to lower case if 'ignoreCase' is set.\n */\nexport function fixCase(lexer: ILexerMin, str: string): string {\n\treturn (lexer.ignoreCase && str ? str.toLowerCase() : str);\n}\n\n/**\n * Ensures there are no bad characters in a CSS token class.\n */\nexport function sanitize(s: string) {\n\treturn s.replace(/[&<>'\"_]/g, '-'); // used on all output token CSS classes\n}\n\n// Logging\n\n/**\n * Logs a message.\n */\nexport function log(lexer: ILexerMin, msg: string) {\n\tconsole.log(`${lexer.languageId}: ${msg}`);\n}\n\n// Throwing errors\n\nexport function createError(lexer: ILexerMin, msg: string): Error {\n\treturn new Error(`${lexer.languageId}: ${msg}`);\n}\n\n// Helper functions for rule finding and substitution\n\n/**\n * substituteMatches is used on lexer strings and can substitutes predefined patterns:\n * \t\t$$ => $\n * \t\t$# => id\n * \t\t$n => matched entry n\n * \t\t@attr => contents of lexer[attr]\n *\n * See documentation for more info\n */\nexport function substituteMatches(lexer: ILexerMin, str: string, id: string, matches: string[], state: string): string {\n\tconst re = /\\$((\\$)|(#)|(\\d\\d?)|[sS](\\d\\d?)|@(\\w+))/g;\n\tlet stateMatches: string[] | null = null;\n\treturn str.replace(re, function (full, sub?, dollar?, hash?, n?, s?, attr?, ofs?, total?) {\n\t\tif (!empty(dollar)) {\n\t\t\treturn '$'; // $$\n\t\t}\n\t\tif (!empty(hash)) {\n\t\t\treturn fixCase(lexer, id); // default $#\n\t\t}\n\t\tif (!empty(n) && n < matches.length) {\n\t\t\treturn fixCase(lexer, matches[n]); // $n\n\t\t}\n\t\tif (!empty(attr) && lexer && typeof (lexer[attr]) === 'string') {\n\t\t\treturn lexer[attr]; //@attribute\n\t\t}\n\t\tif (stateMatches === null) { // split state on demand\n\t\t\tstateMatches = state.split('.');\n\t\t\tstateMatches.unshift(state);\n\t\t}\n\t\tif (!empty(s) && s < stateMatches.length) {\n\t\t\treturn fixCase(lexer, stateMatches[s]); //$Sn\n\t\t}\n\t\treturn '';\n\t});\n}\n\n/**\n * substituteMatchesRe is used on lexer regex rules and can substitutes predefined patterns:\n * \t\t$Sn => n'th part of state\n *\n */\nexport function substituteMatchesRe(lexer: ILexerMin, str: string, state: string): string {\n\tconst re = /\\$[sS](\\d\\d?)/g;\n\tlet stateMatches: string[] | null = null;\n\treturn str.replace(re, function (full, s) {\n\t\tif (stateMatches === null) { // split state on demand\n\t\t\tstateMatches = state.split('.');\n\t\t\tstateMatches.unshift(state);\n\t\t}\n\t\tif (!empty(s) && s < stateMatches.length) {\n\t\t\treturn fixCase(lexer, stateMatches[s]); //$Sn\n\t\t}\n\t\treturn '';\n\t});\n}\n\n/**\n * Find the tokenizer rules for a specific state (i.e. next action)\n */\nexport function findRules(lexer: ILexer, inState: string): IRule[] | null {\n\tlet state: string | null = inState;\n\twhile (state && state.length > 0) {\n\t\tconst rules = lexer.tokenizer[state];\n\t\tif (rules) {\n\t\t\treturn rules;\n\t\t}\n\n\t\tconst idx = state.lastIndexOf('.');\n\t\tif (idx < 0) {\n\t\t\tstate = null; // no further parent\n\t\t} else {\n\t\t\tstate = state.substr(0, idx);\n\t\t}\n\t}\n\treturn null;\n}\n\n/**\n * Is a certain state defined? In contrast to 'findRules' this works on a ILexerMin.\n * This is used during compilation where we may know the defined states\n * but not yet whether the corresponding rules are correct.\n */\nexport function stateExists(lexer: ILexerMin, inState: string): boolean {\n\tlet state: string | null = inState;\n\twhile (state && state.length > 0) {\n\t\tconst exist = lexer.stateNames[state];\n\t\tif (exist) {\n\t\t\treturn true;\n\t\t}\n\n\t\tconst idx = state.lastIndexOf('.');\n\t\tif (idx < 0) {\n\t\t\tstate = null; // no further parent\n\t\t} else {\n\t\t\tstate = state.substr(0, idx);\n\t\t}\n\t}\n\treturn false;\n}\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 * This module only exports 'compile' which compiles a JSON language definition\n * into a typed and checked ILexer definition.\n */\n\nimport * as monarchCommon from 'vs/editor/standalone/common/monarch/monarchCommon';\nimport { IMonarchLanguage, IMonarchLanguageBracket } from 'vs/editor/standalone/common/monarch/monarchTypes';\n\n/*\n * Type helpers\n *\n * Note: this is just for sanity checks on the JSON description which is\n * helpful for the programmer. No checks are done anymore once the lexer is\n * already 'compiled and checked'.\n *\n */\n\nfunction isArrayOf(elemType: (x: any) => boolean, obj: any): boolean {\n\tif (!obj) {\n\t\treturn false;\n\t}\n\tif (!(Array.isArray(obj))) {\n\t\treturn false;\n\t}\n\tfor (const el of obj) {\n\t\tif (!(elemType(el))) {\n\t\t\treturn false;\n\t\t}\n\t}\n\treturn true;\n}\n\nfunction bool(prop: any, defValue: boolean): boolean {\n\tif (typeof prop === 'boolean') {\n\t\treturn prop;\n\t}\n\treturn defValue;\n}\n\nfunction string(prop: any, defValue: string): string {\n\tif (typeof (prop) === 'string') {\n\t\treturn prop;\n\t}\n\treturn defValue;\n}\n\n\nfunction arrayToHash(array: string[]): { [name: string]: true } {\n\tconst result: any = {};\n\tfor (const e of array) {\n\t\tresult[e] = true;\n\t}\n\treturn result;\n}\n\n\nfunction createKeywordMatcher(arr: string[], caseInsensitive: boolean = false): (str: string) => boolean {\n\tif (caseInsensitive) {\n\t\tarr = arr.map(function (x) { return x.toLowerCase(); });\n\t}\n\tconst hash = arrayToHash(arr);\n\tif (caseInsensitive) {\n\t\treturn function (word) {\n\t\t\treturn hash[word.toLowerCase()] !== undefined && hash.hasOwnProperty(word.toLowerCase());\n\t\t};\n\t} else {\n\t\treturn function (word) {\n\t\t\treturn hash[word] !== undefined && hash.hasOwnProperty(word);\n\t\t};\n\t}\n}\n\n\n// Lexer helpers\n\n/**\n * Compiles a regular expression string, adding the 'i' flag if 'ignoreCase' is set, and the 'u' flag if 'unicode' is set.\n * Also replaces @\\w+ or sequences with the content of the specified attribute\n * @\\w+ replacement can be avoided by escaping `@` signs with another `@` sign.\n * @example /@attr/ will be replaced with the value of lexer[attr]\n * @example /@@text/ will not be replaced and will become /@text/.\n */\nfunction compileRegExp(lexer: monarchCommon.ILexerMin, str: string, handleSn: S): S extends true ? RegExp | DynamicRegExp : RegExp;\nfunction compileRegExp(lexer: monarchCommon.ILexerMin, str: string, handleSn: true | false): RegExp | DynamicRegExp {\n\t// @@ must be interpreted as a literal @, so we replace all occurences of @@ with a placeholder character\n\tstr = str.replace(/@@/g, `\\x01`);\n\n\tlet n = 0;\n\tlet hadExpansion: boolean;\n\tdo {\n\t\thadExpansion = false;\n\t\tstr = str.replace(/@(\\w+)/g, function (s, attr?) {\n\t\t\thadExpansion = true;\n\t\t\tlet sub = '';\n\t\t\tif (typeof (lexer[attr]) === 'string') {\n\t\t\t\tsub = lexer[attr];\n\t\t\t} else if (lexer[attr] && lexer[attr] instanceof RegExp) {\n\t\t\t\tsub = lexer[attr].source;\n\t\t\t} else {\n\t\t\t\tif (lexer[attr] === undefined) {\n\t\t\t\t\tthrow monarchCommon.createError(lexer, 'language definition does not contain attribute \\'' + attr + '\\', used at: ' + str);\n\t\t\t\t} else {\n\t\t\t\t\tthrow monarchCommon.createError(lexer, 'attribute reference \\'' + attr + '\\' must be a string, used at: ' + str);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn (monarchCommon.empty(sub) ? '' : '(?:' + sub + ')');\n\t\t});\n\t\tn++;\n\t} while (hadExpansion && n < 5);\n\n\t// handle escaped @@\n\tstr = str.replace(/\\x01/g, '@');\n\n\tconst flags = (lexer.ignoreCase ? 'i' : '') + (lexer.unicode ? 'u' : '');\n\n\t// handle $Sn\n\tif (handleSn) {\n\t\tconst match = str.match(/\\$[sS](\\d\\d?)/g);\n\t\tif (match) {\n\t\t\tlet lastState: string | null = null;\n\t\t\tlet lastRegEx: RegExp | null = null;\n\t\t\treturn (state: string) => {\n\t\t\t\tif (lastRegEx && lastState === state) {\n\t\t\t\t\treturn lastRegEx;\n\t\t\t\t}\n\t\t\t\tlastState = state;\n\t\t\t\tlastRegEx = new RegExp(monarchCommon.substituteMatchesRe(lexer, str, state), flags);\n\t\t\t\treturn lastRegEx;\n\t\t\t};\n\t\t}\n\t}\n\n\treturn new RegExp(str, flags);\n}\n\n/**\n * Compiles guard functions for case matches.\n * This compiles 'cases' attributes into efficient match functions.\n *\n */\nfunction selectScrutinee(id: string, matches: string[], state: string, num: number): string | null {\n\tif (num < 0) {\n\t\treturn id;\n\t}\n\tif (num < matches.length) {\n\t\treturn matches[num];\n\t}\n\tif (num >= 100) {\n\t\tnum = num - 100;\n\t\tconst parts = state.split('.');\n\t\tparts.unshift(state);\n\t\tif (num < parts.length) {\n\t\t\treturn parts[num];\n\t\t}\n\t}\n\treturn null;\n}\n\nfunction createGuard(lexer: monarchCommon.ILexerMin, ruleName: string, tkey: string, val: monarchCommon.FuzzyAction): monarchCommon.IBranch {\n\t// get the scrutinee and pattern\n\tlet scrut = -1; // -1: $!, 0-99: $n, 100+n: $Sn\n\tlet oppat = tkey;\n\tlet matches = tkey.match(/^\\$(([sS]?)(\\d\\d?)|#)(.*)$/);\n\tif (matches) {\n\t\tif (matches[3]) { // if digits\n\t\t\tscrut = parseInt(matches[3]);\n\t\t\tif (matches[2]) {\n\t\t\t\tscrut = scrut + 100; // if [sS] present\n\t\t\t}\n\t\t}\n\t\toppat = matches[4];\n\t}\n\t// get operator\n\tlet op = '~';\n\tlet pat = oppat;\n\tif (!oppat || oppat.length === 0) {\n\t\top = '!=';\n\t\tpat = '';\n\t}\n\telse if (/^\\w*$/.test(pat)) { // just a word\n\t\top = '==';\n\t}\n\telse {\n\t\tmatches = oppat.match(/^(@|!@|~|!~|==|!=)(.*)$/);\n\t\tif (matches) {\n\t\t\top = matches[1];\n\t\t\tpat = matches[2];\n\t\t}\n\t}\n\n\t// set the tester function\n\tlet tester: (s: string, id: string, matches: string[], state: string, eos: boolean) => boolean;\n\n\t// special case a regexp that matches just words\n\tif ((op === '~' || op === '!~') && /^(\\w|\\|)*$/.test(pat)) {\n\t\tconst inWords = createKeywordMatcher(pat.split('|'), lexer.ignoreCase);\n\t\ttester = function (s) { return (op === '~' ? inWords(s) : !inWords(s)); };\n\t}\n\telse if (op === '@' || op === '!@') {\n\t\tconst words = lexer[pat];\n\t\tif (!words) {\n\t\t\tthrow monarchCommon.createError(lexer, 'the @ match target \\'' + pat + '\\' is not defined, in rule: ' + ruleName);\n\t\t}\n\t\tif (!(isArrayOf(function (elem) { return (typeof (elem) === 'string'); }, words))) {\n\t\t\tthrow monarchCommon.createError(lexer, 'the @ match target \\'' + pat + '\\' must be an array of strings, in rule: ' + ruleName);\n\t\t}\n\t\tconst inWords = createKeywordMatcher(words, lexer.ignoreCase);\n\t\ttester = function (s) { return (op === '@' ? inWords(s) : !inWords(s)); };\n\t}\n\telse if (op === '~' || op === '!~') {\n\t\tif (pat.indexOf('$') < 0) {\n\t\t\t// precompile regular expression\n\t\t\tconst re = compileRegExp(lexer, '^' + pat + '$', false);\n\t\t\ttester = function (s) { return (op === '~' ? re.test(s) : !re.test(s)); };\n\t\t}\n\t\telse {\n\t\t\ttester = function (s, id, matches, state) {\n\t\t\t\tconst re = compileRegExp(lexer, '^' + monarchCommon.substituteMatches(lexer, pat, id, matches, state) + '$', false);\n\t\t\t\treturn re.test(s);\n\t\t\t};\n\t\t}\n\t}\n\telse { // if (op==='==' || op==='!=') {\n\t\tif (pat.indexOf('$') < 0) {\n\t\t\tconst patx = monarchCommon.fixCase(lexer, pat);\n\t\t\ttester = function (s) { return (op === '==' ? s === patx : s !== patx); };\n\t\t}\n\t\telse {\n\t\t\tconst patx = monarchCommon.fixCase(lexer, pat);\n\t\t\ttester = function (s, id, matches, state, eos) {\n\t\t\t\tconst patexp = monarchCommon.substituteMatches(lexer, patx, id, matches, state);\n\t\t\t\treturn (op === '==' ? s === patexp : s !== patexp);\n\t\t\t};\n\t\t}\n\t}\n\n\t// return the branch object\n\tif (scrut === -1) {\n\t\treturn {\n\t\t\tname: tkey, value: val, test: function (id, matches, state, eos) {\n\t\t\t\treturn tester(id, id, matches, state, eos);\n\t\t\t}\n\t\t};\n\t}\n\telse {\n\t\treturn {\n\t\t\tname: tkey, value: val, test: function (id, matches, state, eos) {\n\t\t\t\tconst scrutinee = selectScrutinee(id, matches, state, scrut);\n\t\t\t\treturn tester(!scrutinee ? '' : scrutinee, id, matches, state, eos);\n\t\t\t}\n\t\t};\n\t}\n}\n\n/**\n * Compiles an action: i.e. optimize regular expressions and case matches\n * and do many sanity checks.\n *\n * This is called only during compilation but if the lexer definition\n * contains user functions as actions (which is usually not allowed), then this\n * may be called during lexing. It is important therefore to compile common cases efficiently\n */\nfunction compileAction(lexer: monarchCommon.ILexerMin, ruleName: string, action: any): monarchCommon.FuzzyAction {\n\tif (!action) {\n\t\treturn { token: '' };\n\t}\n\telse if (typeof (action) === 'string') {\n\t\treturn action; // { token: action };\n\t}\n\telse if (action.token || action.token === '') {\n\t\tif (typeof (action.token) !== 'string') {\n\t\t\tthrow monarchCommon.createError(lexer, 'a \\'token\\' attribute must be of type string, in rule: ' + ruleName);\n\t\t}\n\t\telse {\n\t\t\t// only copy specific typed fields (only happens once during compile Lexer)\n\t\t\tconst newAction: monarchCommon.IAction = { token: action.token };\n\t\t\tif (action.token.indexOf('$') >= 0) {\n\t\t\t\tnewAction.tokenSubst = true;\n\t\t\t}\n\t\t\tif (typeof (action.bracket) === 'string') {\n\t\t\t\tif (action.bracket === '@open') {\n\t\t\t\t\tnewAction.bracket = monarchCommon.MonarchBracket.Open;\n\t\t\t\t} else if (action.bracket === '@close') {\n\t\t\t\t\tnewAction.bracket = monarchCommon.MonarchBracket.Close;\n\t\t\t\t} else {\n\t\t\t\t\tthrow monarchCommon.createError(lexer, 'a \\'bracket\\' attribute must be either \\'@open\\' or \\'@close\\', in rule: ' + ruleName);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (action.next) {\n\t\t\t\tif (typeof (action.next) !== 'string') {\n\t\t\t\t\tthrow monarchCommon.createError(lexer, 'the next state must be a string value in rule: ' + ruleName);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tlet next: string = action.next;\n\t\t\t\t\tif (!/^(@pop|@push|@popall)$/.test(next)) {\n\t\t\t\t\t\tif (next[0] === '@') {\n\t\t\t\t\t\t\tnext = next.substr(1); // peel off starting @ sign\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (next.indexOf('$') < 0) { // no dollar substitution, we can check if the state exists\n\t\t\t\t\t\t\tif (!monarchCommon.stateExists(lexer, monarchCommon.substituteMatches(lexer, next, '', [], ''))) {\n\t\t\t\t\t\t\t\tthrow monarchCommon.createError(lexer, 'the next state \\'' + action.next + '\\' is not defined in rule: ' + ruleName);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tnewAction.next = next;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (typeof (action.goBack) === 'number') {\n\t\t\t\tnewAction.goBack = action.goBack;\n\t\t\t}\n\t\t\tif (typeof (action.switchTo) === 'string') {\n\t\t\t\tnewAction.switchTo = action.switchTo;\n\t\t\t}\n\t\t\tif (typeof (action.log) === 'string') {\n\t\t\t\tnewAction.log = action.log;\n\t\t\t}\n\t\t\tif (typeof (action.nextEmbedded) === 'string') {\n\t\t\t\tnewAction.nextEmbedded = action.nextEmbedded;\n\t\t\t\tlexer.usesEmbedded = true;\n\t\t\t}\n\t\t\treturn newAction;\n\t\t}\n\t}\n\telse if (Array.isArray(action)) {\n\t\tconst results: monarchCommon.FuzzyAction[] = [];\n\t\tfor (let i = 0, len = action.length; i < len; i++) {\n\t\t\tresults[i] = compileAction(lexer, ruleName, action[i]);\n\t\t}\n\t\treturn { group: results };\n\t}\n\telse if (action.cases) {\n\t\t// build an array of test cases\n\t\tconst cases: monarchCommon.IBranch[] = [];\n\n\t\t// for each case, push a test function and result value\n\t\tfor (const tkey in action.cases) {\n\t\t\tif (action.cases.hasOwnProperty(tkey)) {\n\t\t\t\tconst val = compileAction(lexer, ruleName, action.cases[tkey]);\n\n\t\t\t\t// what kind of case\n\t\t\t\tif (tkey === '@default' || tkey === '@' || tkey === '') {\n\t\t\t\t\tcases.push({ test: undefined, value: val, name: tkey });\n\t\t\t\t}\n\t\t\t\telse if (tkey === '@eos') {\n\t\t\t\t\tcases.push({ test: function (id, matches, state, eos) { return eos; }, value: val, name: tkey });\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tcases.push(createGuard(lexer, ruleName, tkey, val)); // call separate function to avoid local variable capture\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// create a matching function\n\t\tconst def = lexer.defaultToken;\n\t\treturn {\n\t\t\ttest: function (id, matches, state, eos) {\n\t\t\t\tfor (const _case of cases) {\n\t\t\t\t\tconst didmatch = (!_case.test || _case.test(id, matches, state, eos));\n\t\t\t\t\tif (didmatch) {\n\t\t\t\t\t\treturn _case.value;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn def;\n\t\t\t}\n\t\t};\n\t}\n\telse {\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);\n\t}\n}\n\ntype DynamicRegExp = (state: string) => RegExp;\n\n/**\n * Helper class for creating matching rules\n */\nclass Rule implements monarchCommon.IRule {\n\tprivate regex: RegExp | DynamicRegExp = new RegExp('');\n\tpublic action: monarchCommon.FuzzyAction = { token: '' };\n\tpublic matchOnlyAtLineStart: boolean = false;\n\tpublic name: string = '';\n\n\tconstructor(name: string) {\n\t\tthis.name = name;\n\t}\n\n\tpublic setRegex(lexer: monarchCommon.ILexerMin, re: string | RegExp): void {\n\t\tlet sregex: string;\n\t\tif (typeof (re) === 'string') {\n\t\t\tsregex = re;\n\t\t}\n\t\telse if (re instanceof RegExp) {\n\t\t\tsregex = (re).source;\n\t\t}\n\t\telse {\n\t\t\tthrow monarchCommon.createError(lexer, 'rules must start with a match string or regular expression: ' + this.name);\n\t\t}\n\n\t\tthis.matchOnlyAtLineStart = (sregex.length > 0 && sregex[0] === '^');\n\t\tthis.name = this.name + ': ' + sregex;\n\t\tthis.regex = compileRegExp(lexer, '^(?:' + (this.matchOnlyAtLineStart ? sregex.substr(1) : sregex) + ')', true);\n\t}\n\n\tpublic setAction(lexer: monarchCommon.ILexerMin, act: monarchCommon.IAction) {\n\t\tthis.action = compileAction(lexer, this.name, act);\n\t}\n\n\tpublic resolveRegex(state: string): RegExp {\n\t\tif (this.regex instanceof RegExp) {\n\t\t\treturn this.regex;\n\t\t} else {\n\t\t\treturn this.regex(state);\n\t\t}\n\t}\n}\n\n/**\n * Compiles a json description function into json where all regular expressions,\n * case matches etc, are compiled and all include rules are expanded.\n * We also compile the bracket definitions, supply defaults, and do many sanity checks.\n * If the 'jsonStrict' parameter is 'false', we allow at certain locations\n * regular expression objects and functions that get called during lexing.\n * (Currently we have no samples that need this so perhaps we should always have\n * jsonStrict to true).\n */\nexport function compile(languageId: string, json: IMonarchLanguage): monarchCommon.ILexer {\n\tif (!json || typeof (json) !== 'object') {\n\t\tthrow new Error('Monarch: expecting a language definition object');\n\t}\n\n\t// Create our lexer\n\tconst lexer: monarchCommon.ILexer = {};\n\tlexer.languageId = languageId;\n\tlexer.includeLF = bool(json.includeLF, false);\n\tlexer.noThrow = false; // raise exceptions during compilation\n\tlexer.maxStack = 100;\n\n\t// Set standard fields: be defensive about types\n\tlexer.start = (typeof json.start === 'string' ? json.start : null);\n\tlexer.ignoreCase = bool(json.ignoreCase, false);\n\tlexer.unicode = bool(json.unicode, false);\n\n\tlexer.tokenPostfix = string(json.tokenPostfix, '.' + lexer.languageId);\n\tlexer.defaultToken = string(json.defaultToken, 'source');\n\n\tlexer.usesEmbedded = false; // becomes true if we find a nextEmbedded action\n\n\t// For calling compileAction later on\n\tconst lexerMin: monarchCommon.ILexerMin = json;\n\tlexerMin.languageId = languageId;\n\tlexerMin.includeLF = lexer.includeLF;\n\tlexerMin.ignoreCase = lexer.ignoreCase;\n\tlexerMin.unicode = lexer.unicode;\n\tlexerMin.noThrow = lexer.noThrow;\n\tlexerMin.usesEmbedded = lexer.usesEmbedded;\n\tlexerMin.stateNames = json.tokenizer;\n\tlexerMin.defaultToken = lexer.defaultToken;\n\n\n\t// Compile an array of rules into newrules where RegExp objects are created.\n\tfunction addRules(state: string, newrules: monarchCommon.IRule[], rules: any[]) {\n\t\tfor (const rule of rules) {\n\n\t\t\tlet include = rule.include;\n\t\t\tif (include) {\n\t\t\t\tif (typeof (include) !== 'string') {\n\t\t\t\t\tthrow monarchCommon.createError(lexer, 'an \\'include\\' attribute must be a string at: ' + state);\n\t\t\t\t}\n\t\t\t\tif (include[0] === '@') {\n\t\t\t\t\tinclude = include.substr(1); // peel off starting @\n\t\t\t\t}\n\t\t\t\tif (!json.tokenizer[include]) {\n\t\t\t\t\tthrow monarchCommon.createError(lexer, 'include target \\'' + include + '\\' is not defined at: ' + state);\n\t\t\t\t}\n\t\t\t\taddRules(state + '.' + include, newrules, json.tokenizer[include]);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tconst newrule = new Rule(state);\n\n\t\t\t\t// Set up new rule attributes\n\t\t\t\tif (Array.isArray(rule) && rule.length >= 1 && rule.length <= 3) {\n\t\t\t\t\tnewrule.setRegex(lexerMin, rule[0]);\n\t\t\t\t\tif (rule.length >= 3) {\n\t\t\t\t\t\tif (typeof (rule[1]) === 'string') {\n\t\t\t\t\t\t\tnewrule.setAction(lexerMin, { token: rule[1], next: rule[2] });\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (typeof (rule[1]) === 'object') {\n\t\t\t\t\t\t\tconst rule1 = rule[1];\n\t\t\t\t\t\t\trule1.next = rule[2];\n\t\t\t\t\t\t\tnewrule.setAction(lexerMin, rule1);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\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);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tnewrule.setAction(lexerMin, rule[1]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tif (!rule.regex) {\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);\n\t\t\t\t\t}\n\t\t\t\t\tif (rule.name) {\n\t\t\t\t\t\tif (typeof rule.name === 'string') {\n\t\t\t\t\t\t\tnewrule.name = rule.name;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (rule.matchOnlyAtStart) {\n\t\t\t\t\t\tnewrule.matchOnlyAtLineStart = bool(rule.matchOnlyAtLineStart, false);\n\t\t\t\t\t}\n\t\t\t\t\tnewrule.setRegex(lexerMin, rule.regex);\n\t\t\t\t\tnewrule.setAction(lexerMin, rule.action);\n\t\t\t\t}\n\n\t\t\t\tnewrules.push(newrule);\n\t\t\t}\n\t\t}\n\t}\n\n\t// compile the tokenizer rules\n\tif (!json.tokenizer || typeof (json.tokenizer) !== 'object') {\n\t\tthrow monarchCommon.createError(lexer, 'a language definition must define the \\'tokenizer\\' attribute as an object');\n\t}\n\n\tlexer.tokenizer = [];\n\tfor (const key in json.tokenizer) {\n\t\tif (json.tokenizer.hasOwnProperty(key)) {\n\t\t\tif (!lexer.start) {\n\t\t\t\tlexer.start = key;\n\t\t\t}\n\n\t\t\tconst rules = json.tokenizer[key];\n\t\t\tlexer.tokenizer[key] = new Array();\n\t\t\taddRules('tokenizer.' + key, lexer.tokenizer[key], rules);\n\t\t}\n\t}\n\tlexer.usesEmbedded = lexerMin.usesEmbedded; // can be set during compileAction\n\n\t// Set simple brackets\n\tif (json.brackets) {\n\t\tif (!(Array.isArray(json.brackets))) {\n\t\t\tthrow monarchCommon.createError(lexer, 'the \\'brackets\\' attribute must be defined as an array');\n\t\t}\n\t}\n\telse {\n\t\tjson.brackets = [\n\t\t\t{ open: '{', close: '}', token: 'delimiter.curly' },\n\t\t\t{ open: '[', close: ']', token: 'delimiter.square' },\n\t\t\t{ open: '(', close: ')', token: 'delimiter.parenthesis' },\n\t\t\t{ open: '<', close: '>', token: 'delimiter.angle' }];\n\t}\n\tconst brackets: IMonarchLanguageBracket[] = [];\n\tfor (const el of json.brackets) {\n\t\tlet desc: any = el;\n\t\tif (desc && Array.isArray(desc) && desc.length === 3) {\n\t\t\tdesc = { token: desc[2], open: desc[0], close: desc[1] };\n\t\t}\n\t\tif (desc.open === desc.close) {\n\t\t\tthrow monarchCommon.createError(lexer, 'open and close brackets in a \\'brackets\\' attribute must be different: ' + desc.open +\n\t\t\t\t'\\n hint: use the \\'bracket\\' attribute if matching on equal brackets is required.');\n\t\t}\n\t\tif (typeof desc.open === 'string' && typeof desc.token === 'string' && typeof desc.close === 'string') {\n\t\t\tbrackets.push({\n\t\t\t\ttoken: desc.token + lexer.tokenPostfix,\n\t\t\t\topen: monarchCommon.fixCase(lexer, desc.open),\n\t\t\t\tclose: monarchCommon.fixCase(lexer, desc.close)\n\t\t\t});\n\t\t}\n\t\telse {\n\t\t\tthrow monarchCommon.createError(lexer, 'every element in the \\'brackets\\' array must be a \\'{open,close,token}\\' object or array');\n\t\t}\n\t}\n\tlexer.brackets = brackets;\n\n\t// Disable throw so the syntax highlighter goes, no matter what\n\tlexer.noThrow = true;\n\treturn lexer;\n}\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\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { Disposable, IDisposable } from 'vs/base/common/lifecycle';\nimport * as nls from 'vs/nls';\n\nexport interface ITelemetryData {\n\t[key: string]: unknown;\n}\n\nexport type WorkbenchActionExecutedClassification = {\n\tid: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The identifier of the action that was run.' };\n\tfrom: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The name of the component the action was run from.' };\n\tdetail?: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Optional details about how the action was run, e.g which keybinding was used.' };\n\towner: 'bpasero';\n\tcomment: 'Provides insight into actions that are executed within the workbench.';\n};\n\nexport type WorkbenchActionExecutedEvent = {\n\tid: string;\n\tfrom: string;\n\tdetail?: string;\n};\n\nexport interface IAction {\n\treadonly id: string;\n\tlabel: string;\n\ttooltip: string;\n\tclass: string | undefined;\n\tenabled: boolean;\n\tchecked?: boolean;\n\trun(...args: unknown[]): unknown;\n}\n\nexport interface IActionRunner extends IDisposable {\n\treadonly onDidRun: Event;\n\treadonly onWillRun: Event;\n\n\trun(action: IAction, context?: unknown): unknown;\n}\n\nexport interface IActionChangeEvent {\n\treadonly label?: string;\n\treadonly tooltip?: string;\n\treadonly class?: string;\n\treadonly enabled?: boolean;\n\treadonly checked?: boolean;\n}\n\nexport class Action extends Disposable implements IAction {\n\n\tprotected _onDidChange = this._register(new Emitter());\n\treadonly onDidChange = this._onDidChange.event;\n\n\tprotected readonly _id: string;\n\tprotected _label: string;\n\tprotected _tooltip: string | undefined;\n\tprotected _cssClass: string | undefined;\n\tprotected _enabled: boolean = true;\n\tprotected _checked?: boolean;\n\tprotected readonly _actionCallback?: (event?: unknown) => unknown;\n\n\tconstructor(id: string, label: string = '', cssClass: string = '', enabled: boolean = true, actionCallback?: (event?: unknown) => unknown) {\n\t\tsuper();\n\t\tthis._id = id;\n\t\tthis._label = label;\n\t\tthis._cssClass = cssClass;\n\t\tthis._enabled = enabled;\n\t\tthis._actionCallback = actionCallback;\n\t}\n\n\tget id(): string {\n\t\treturn this._id;\n\t}\n\n\tget label(): string {\n\t\treturn this._label;\n\t}\n\n\tset label(value: string) {\n\t\tthis._setLabel(value);\n\t}\n\n\tprivate _setLabel(value: string): void {\n\t\tif (this._label !== value) {\n\t\t\tthis._label = value;\n\t\t\tthis._onDidChange.fire({ label: value });\n\t\t}\n\t}\n\n\tget tooltip(): string {\n\t\treturn this._tooltip || '';\n\t}\n\n\tset tooltip(value: string) {\n\t\tthis._setTooltip(value);\n\t}\n\n\tprotected _setTooltip(value: string): void {\n\t\tif (this._tooltip !== value) {\n\t\t\tthis._tooltip = value;\n\t\t\tthis._onDidChange.fire({ tooltip: value });\n\t\t}\n\t}\n\n\tget class(): string | undefined {\n\t\treturn this._cssClass;\n\t}\n\n\tset class(value: string | undefined) {\n\t\tthis._setClass(value);\n\t}\n\n\tprotected _setClass(value: string | undefined): void {\n\t\tif (this._cssClass !== value) {\n\t\t\tthis._cssClass = value;\n\t\t\tthis._onDidChange.fire({ class: value });\n\t\t}\n\t}\n\n\tget enabled(): boolean {\n\t\treturn this._enabled;\n\t}\n\n\tset enabled(value: boolean) {\n\t\tthis._setEnabled(value);\n\t}\n\n\tprotected _setEnabled(value: boolean): void {\n\t\tif (this._enabled !== value) {\n\t\t\tthis._enabled = value;\n\t\t\tthis._onDidChange.fire({ enabled: value });\n\t\t}\n\t}\n\n\tget checked(): boolean | undefined {\n\t\treturn this._checked;\n\t}\n\n\tset checked(value: boolean | undefined) {\n\t\tthis._setChecked(value);\n\t}\n\n\tprotected _setChecked(value: boolean | undefined): void {\n\t\tif (this._checked !== value) {\n\t\t\tthis._checked = value;\n\t\t\tthis._onDidChange.fire({ checked: value });\n\t\t}\n\t}\n\n\tasync run(event?: unknown, data?: ITelemetryData): Promise {\n\t\tif (this._actionCallback) {\n\t\t\tawait this._actionCallback(event);\n\t\t}\n\t}\n}\n\nexport interface IRunEvent {\n\treadonly action: IAction;\n\treadonly error?: Error;\n}\n\nexport class ActionRunner extends Disposable implements IActionRunner {\n\n\tprivate readonly _onWillRun = this._register(new Emitter());\n\treadonly onWillRun = this._onWillRun.event;\n\n\tprivate readonly _onDidRun = this._register(new Emitter());\n\treadonly onDidRun = this._onDidRun.event;\n\n\tasync run(action: IAction, context?: unknown): Promise {\n\t\tif (!action.enabled) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._onWillRun.fire({ action });\n\n\t\tlet error: Error | undefined = undefined;\n\t\ttry {\n\t\t\tawait this.runAction(action, context);\n\t\t} catch (e) {\n\t\t\terror = e;\n\t\t}\n\n\t\tthis._onDidRun.fire({ action, error });\n\t}\n\n\tprotected async runAction(action: IAction, context?: unknown): Promise {\n\t\tawait action.run(context);\n\t}\n}\n\nexport class Separator implements IAction {\n\n\t/**\n\t * Joins all non-empty lists of actions with separators.\n\t */\n\tpublic static join(...actionLists: readonly IAction[][]) {\n\t\tlet out: IAction[] = [];\n\t\tfor (const list of actionLists) {\n\t\t\tif (!list.length) {\n\t\t\t\t// skip\n\t\t\t} else if (out.length) {\n\t\t\t\tout = [...out, new Separator(), ...list];\n\t\t\t} else {\n\t\t\t\tout = list;\n\t\t\t}\n\t\t}\n\n\t\treturn out;\n\t}\n\n\tstatic readonly ID = 'vs.actions.separator';\n\n\treadonly id: string = Separator.ID;\n\n\treadonly label: string = '';\n\treadonly tooltip: string = '';\n\treadonly class: string = 'separator';\n\treadonly enabled: boolean = false;\n\treadonly checked: boolean = false;\n\tasync run() { }\n}\n\nexport class SubmenuAction implements IAction {\n\n\treadonly id: string;\n\treadonly label: string;\n\treadonly class: string | undefined;\n\treadonly tooltip: string = '';\n\treadonly enabled: boolean = true;\n\treadonly checked: undefined = undefined;\n\n\tprivate readonly _actions: readonly IAction[];\n\tget actions(): readonly IAction[] { return this._actions; }\n\n\tconstructor(id: string, label: string, actions: readonly IAction[], cssClass?: string) {\n\t\tthis.id = id;\n\t\tthis.label = label;\n\t\tthis.class = cssClass;\n\t\tthis._actions = actions;\n\t}\n\n\tasync run(): Promise { }\n}\n\nexport class EmptySubmenuAction extends Action {\n\n\tstatic readonly ID = 'vs.actions.empty';\n\n\tconstructor() {\n\t\tsuper(EmptySubmenuAction.ID, nls.localize('submenu.empty', '(empty)'), undefined, false);\n\t}\n}\n\nexport function toAction(props: { id: string; label: string; tooltip?: string; enabled?: boolean; checked?: boolean; class?: string; run: Function }): IAction {\n\treturn {\n\t\tid: props.id,\n\t\tlabel: props.label,\n\t\ttooltip: props.tooltip ?? props.label,\n\t\tclass: props.class,\n\t\tenabled: props.enabled ?? true,\n\t\tchecked: props.checked,\n\t\trun: async (...args: unknown[]) => props.run(...args),\n\t};\n}\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\nimport { ActionRunner, IAction } from 'vs/base/common/actions';\n\nexport class ActionRunnerWithContext extends ActionRunner {\n\tconstructor(private readonly _getContext: () => unknown) {\n\t\tsuper();\n\t}\n\n\tprotected override runAction(action: IAction, _context?: unknown): Promise {\n\t\tconst ctx = this._getContext();\n\t\treturn super.runAction(action, ctx);\n\t}\n}\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\nimport * as arrays from 'vs/base/common/arrays';\nimport * as types from 'vs/base/common/types';\nimport * as nls from 'vs/nls';\n\nfunction exceptionToErrorMessage(exception: any, verbose: boolean): string {\n\tif (verbose && (exception.stack || exception.stacktrace)) {\n\t\treturn nls.localize('stackTrace.format', \"{0}: {1}\", detectSystemErrorMessage(exception), stackToString(exception.stack) || stackToString(exception.stacktrace));\n\t}\n\n\treturn detectSystemErrorMessage(exception);\n}\n\nfunction stackToString(stack: string[] | string | undefined): string | undefined {\n\tif (Array.isArray(stack)) {\n\t\treturn stack.join('\\n');\n\t}\n\n\treturn stack;\n}\n\nfunction detectSystemErrorMessage(exception: any): string {\n\n\t// Custom node.js error from us\n\tif (exception.code === 'ERR_UNC_HOST_NOT_ALLOWED') {\n\t\treturn `${exception.message}. Please update the 'security.allowedUNCHosts' setting if you want to allow this host.`;\n\t}\n\n\t// See https://nodejs.org/api/errors.html#errors_class_system_error\n\tif (typeof exception.code === 'string' && typeof exception.errno === 'number' && typeof exception.syscall === 'string') {\n\t\treturn nls.localize('nodeExceptionMessage', \"A system error occurred ({0})\", exception.message);\n\t}\n\n\treturn exception.message || nls.localize('error.defaultMessage', \"An unknown error occurred. Please consult the log for more details.\");\n}\n\n/**\n * Tries to generate a human readable error message out of the error. If the verbose parameter\n * is set to true, the error message will include stacktrace details if provided.\n *\n * @returns A string containing the error message.\n */\nexport function toErrorMessage(error: any = null, verbose: boolean = false): string {\n\tif (!error) {\n\t\treturn nls.localize('error.defaultMessage', \"An unknown error occurred. Please consult the log for more details.\");\n\t}\n\n\tif (Array.isArray(error)) {\n\t\tconst errors: any[] = arrays.coalesce(error);\n\t\tconst msg = toErrorMessage(errors[0], verbose);\n\n\t\tif (errors.length > 1) {\n\t\t\treturn nls.localize('error.moreErrors', \"{0} ({1} errors in total)\", msg, errors.length);\n\t\t}\n\n\t\treturn msg;\n\t}\n\n\tif (types.isString(error)) {\n\t\treturn error;\n\t}\n\n\tif (error.detail) {\n\t\tconst detail = error.detail;\n\n\t\tif (detail.error) {\n\t\t\treturn exceptionToErrorMessage(detail.error, verbose);\n\t\t}\n\n\t\tif (detail.exception) {\n\t\t\treturn exceptionToErrorMessage(detail.exception, verbose);\n\t\t}\n\t}\n\n\tif (error.stack) {\n\t\treturn exceptionToErrorMessage(error, verbose);\n\t}\n\n\tif (error.message) {\n\t\treturn error.message;\n\t}\n\n\treturn nls.localize('error.defaultMessage', \"An unknown error occurred. Please consult the log for more details.\");\n}\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\nimport { Modifiers } from 'vs/base/common/keybindings';\nimport { OperatingSystem } from 'vs/base/common/platform';\nimport * as nls from 'vs/nls';\n\nexport interface ModifierLabels {\n\treadonly ctrlKey: string;\n\treadonly shiftKey: string;\n\treadonly altKey: string;\n\treadonly metaKey: string;\n\treadonly separator: string;\n}\n\nexport interface KeyLabelProvider {\n\t(keybinding: T): string | null;\n}\n\nexport class ModifierLabelProvider {\n\n\tpublic readonly modifierLabels: ModifierLabels[];\n\n\tconstructor(mac: ModifierLabels, windows: ModifierLabels, linux: ModifierLabels = windows) {\n\t\tthis.modifierLabels = [null!]; // index 0 will never me accessed.\n\t\tthis.modifierLabels[OperatingSystem.Macintosh] = mac;\n\t\tthis.modifierLabels[OperatingSystem.Windows] = windows;\n\t\tthis.modifierLabels[OperatingSystem.Linux] = linux;\n\t}\n\n\tpublic toLabel(OS: OperatingSystem, chords: readonly T[], keyLabelProvider: KeyLabelProvider): string | null {\n\t\tif (chords.length === 0) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst result: string[] = [];\n\t\tfor (let i = 0, len = chords.length; i < len; i++) {\n\t\t\tconst chord = chords[i];\n\t\t\tconst keyLabel = keyLabelProvider(chord);\n\t\t\tif (keyLabel === null) {\n\t\t\t\t// this keybinding cannot be expressed...\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tresult[i] = _simpleAsString(chord, keyLabel, this.modifierLabels[OS]);\n\t\t}\n\t\treturn result.join(' ');\n\t}\n}\n\n/**\n * A label provider that prints modifiers in a suitable format for displaying in the UI.\n */\nexport const UILabelProvider = new ModifierLabelProvider(\n\t{\n\t\tctrlKey: '\\u2303',\n\t\tshiftKey: '⇧',\n\t\taltKey: '⌥',\n\t\tmetaKey: '⌘',\n\t\tseparator: '',\n\t},\n\t{\n\t\tctrlKey: nls.localize({ key: 'ctrlKey', comment: ['This is the short form for the Control key on the keyboard'] }, \"Ctrl\"),\n\t\tshiftKey: nls.localize({ key: 'shiftKey', comment: ['This is the short form for the Shift key on the keyboard'] }, \"Shift\"),\n\t\taltKey: nls.localize({ key: 'altKey', comment: ['This is the short form for the Alt key on the keyboard'] }, \"Alt\"),\n\t\tmetaKey: nls.localize({ key: 'windowsKey', comment: ['This is the short form for the Windows key on the keyboard'] }, \"Windows\"),\n\t\tseparator: '+',\n\t},\n\t{\n\t\tctrlKey: nls.localize({ key: 'ctrlKey', comment: ['This is the short form for the Control key on the keyboard'] }, \"Ctrl\"),\n\t\tshiftKey: nls.localize({ key: 'shiftKey', comment: ['This is the short form for the Shift key on the keyboard'] }, \"Shift\"),\n\t\taltKey: nls.localize({ key: 'altKey', comment: ['This is the short form for the Alt key on the keyboard'] }, \"Alt\"),\n\t\tmetaKey: nls.localize({ key: 'superKey', comment: ['This is the short form for the Super key on the keyboard'] }, \"Super\"),\n\t\tseparator: '+',\n\t}\n);\n\n/**\n * A label provider that prints modifiers in a suitable format for ARIA.\n */\nexport const AriaLabelProvider = new ModifierLabelProvider(\n\t{\n\t\tctrlKey: nls.localize({ key: 'ctrlKey.long', comment: ['This is the long form for the Control key on the keyboard'] }, \"Control\"),\n\t\tshiftKey: nls.localize({ key: 'shiftKey.long', comment: ['This is the long form for the Shift key on the keyboard'] }, \"Shift\"),\n\t\taltKey: nls.localize({ key: 'optKey.long', comment: ['This is the long form for the Alt/Option key on the keyboard'] }, \"Option\"),\n\t\tmetaKey: nls.localize({ key: 'cmdKey.long', comment: ['This is the long form for the Command key on the keyboard'] }, \"Command\"),\n\t\tseparator: '+',\n\t},\n\t{\n\t\tctrlKey: nls.localize({ key: 'ctrlKey.long', comment: ['This is the long form for the Control key on the keyboard'] }, \"Control\"),\n\t\tshiftKey: nls.localize({ key: 'shiftKey.long', comment: ['This is the long form for the Shift key on the keyboard'] }, \"Shift\"),\n\t\taltKey: nls.localize({ key: 'altKey.long', comment: ['This is the long form for the Alt key on the keyboard'] }, \"Alt\"),\n\t\tmetaKey: nls.localize({ key: 'windowsKey.long', comment: ['This is the long form for the Windows key on the keyboard'] }, \"Windows\"),\n\t\tseparator: '+',\n\t},\n\t{\n\t\tctrlKey: nls.localize({ key: 'ctrlKey.long', comment: ['This is the long form for the Control key on the keyboard'] }, \"Control\"),\n\t\tshiftKey: nls.localize({ key: 'shiftKey.long', comment: ['This is the long form for the Shift key on the keyboard'] }, \"Shift\"),\n\t\taltKey: nls.localize({ key: 'altKey.long', comment: ['This is the long form for the Alt key on the keyboard'] }, \"Alt\"),\n\t\tmetaKey: nls.localize({ key: 'superKey.long', comment: ['This is the long form for the Super key on the keyboard'] }, \"Super\"),\n\t\tseparator: '+',\n\t}\n);\n\n/**\n * A label provider that prints modifiers in a suitable format for Electron Accelerators.\n * See https://github.com/electron/electron/blob/master/docs/api/accelerator.md\n */\nexport const ElectronAcceleratorLabelProvider = new ModifierLabelProvider(\n\t{\n\t\tctrlKey: 'Ctrl',\n\t\tshiftKey: 'Shift',\n\t\taltKey: 'Alt',\n\t\tmetaKey: 'Cmd',\n\t\tseparator: '+',\n\t},\n\t{\n\t\tctrlKey: 'Ctrl',\n\t\tshiftKey: 'Shift',\n\t\taltKey: 'Alt',\n\t\tmetaKey: 'Super',\n\t\tseparator: '+',\n\t}\n);\n\n/**\n * A label provider that prints modifiers in a suitable format for user settings.\n */\nexport const UserSettingsLabelProvider = new ModifierLabelProvider(\n\t{\n\t\tctrlKey: 'ctrl',\n\t\tshiftKey: 'shift',\n\t\taltKey: 'alt',\n\t\tmetaKey: 'cmd',\n\t\tseparator: '+',\n\t},\n\t{\n\t\tctrlKey: 'ctrl',\n\t\tshiftKey: 'shift',\n\t\taltKey: 'alt',\n\t\tmetaKey: 'win',\n\t\tseparator: '+',\n\t},\n\t{\n\t\tctrlKey: 'ctrl',\n\t\tshiftKey: 'shift',\n\t\taltKey: 'alt',\n\t\tmetaKey: 'meta',\n\t\tseparator: '+',\n\t}\n);\n\nfunction _simpleAsString(modifiers: Modifiers, key: string, labels: ModifierLabels): string {\n\tif (key === null) {\n\t\treturn '';\n\t}\n\n\tconst result: string[] = [];\n\n\t// translate modifier keys: Ctrl-Shift-Alt-Meta\n\tif (modifiers.ctrlKey) {\n\t\tresult.push(labels.ctrlKey);\n\t}\n\n\tif (modifiers.shiftKey) {\n\t\tresult.push(labels.shiftKey);\n\t}\n\n\tif (modifiers.altKey) {\n\t\tresult.push(labels.altKey);\n\t}\n\n\tif (modifiers.metaKey) {\n\t\tresult.push(labels.metaKey);\n\t}\n\n\t// the actual key\n\tif (key !== '') {\n\t\tresult.push(key);\n\t}\n\n\treturn result.join(labels.separator);\n}\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 *--------------------------------------------------------------------------------------------*/\nimport * as nls from 'vs/nls';\n\nexport const LANGUAGE_DEFAULT = 'en';\n\nlet _isWindows = false;\nlet _isMacintosh = false;\nlet _isLinux = false;\nlet _isLinuxSnap = false;\nlet _isNative = false;\nlet _isWeb = false;\nlet _isElectron = false;\nlet _isIOS = false;\nlet _isCI = false;\nlet _isMobile = false;\nlet _locale: string | undefined = undefined;\nlet _language: string = LANGUAGE_DEFAULT;\nlet _platformLocale: string = LANGUAGE_DEFAULT;\nlet _translationsConfigFile: string | undefined = undefined;\nlet _userAgent: string | undefined = undefined;\n\ninterface NLSConfig {\n\tlocale: string;\n\tosLocale: string;\n\tavailableLanguages: { [key: string]: string };\n\t_translationsConfigFile: string;\n}\n\nexport interface IProcessEnvironment {\n\t[key: string]: string | undefined;\n}\n\n/**\n * This interface is intentionally not identical to node.js\n * process because it also works in sandboxed environments\n * where the process object is implemented differently. We\n * define the properties here that we need for `platform`\n * to work and nothing else.\n */\nexport interface INodeProcess {\n\tplatform: string;\n\tarch: string;\n\tenv: IProcessEnvironment;\n\tversions?: {\n\t\tnode?: string;\n\t\telectron?: string;\n\t\tchrome?: string;\n\t};\n\ttype?: string;\n\tcwd: () => string;\n}\n\ndeclare const process: INodeProcess;\n\nconst $globalThis: any = globalThis;\n\nlet nodeProcess: INodeProcess | undefined = undefined;\nif (typeof $globalThis.vscode !== 'undefined' && typeof $globalThis.vscode.process !== 'undefined') {\n\t// Native environment (sandboxed)\n\tnodeProcess = $globalThis.vscode.process;\n} else if (typeof process !== 'undefined' && typeof process?.versions?.node === 'string') {\n\t// Native environment (non-sandboxed)\n\tnodeProcess = process;\n}\n\nconst isElectronProcess = typeof nodeProcess?.versions?.electron === 'string';\nconst isElectronRenderer = isElectronProcess && nodeProcess?.type === 'renderer';\n\ninterface INavigator {\n\tuserAgent: string;\n\tmaxTouchPoints?: number;\n\tlanguage: string;\n}\ndeclare const navigator: INavigator;\n\n// Native environment\nif (typeof nodeProcess === 'object') {\n\t_isWindows = (nodeProcess.platform === 'win32');\n\t_isMacintosh = (nodeProcess.platform === 'darwin');\n\t_isLinux = (nodeProcess.platform === 'linux');\n\t_isLinuxSnap = _isLinux && !!nodeProcess.env['SNAP'] && !!nodeProcess.env['SNAP_REVISION'];\n\t_isElectron = isElectronProcess;\n\t_isCI = !!nodeProcess.env['CI'] || !!nodeProcess.env['BUILD_ARTIFACTSTAGINGDIRECTORY'];\n\t_locale = LANGUAGE_DEFAULT;\n\t_language = LANGUAGE_DEFAULT;\n\tconst rawNlsConfig = nodeProcess.env['VSCODE_NLS_CONFIG'];\n\tif (rawNlsConfig) {\n\t\ttry {\n\t\t\tconst nlsConfig: NLSConfig = JSON.parse(rawNlsConfig);\n\t\t\tconst resolved = nlsConfig.availableLanguages['*'];\n\t\t\t_locale = nlsConfig.locale;\n\t\t\t_platformLocale = nlsConfig.osLocale;\n\t\t\t// VSCode's default language is 'en'\n\t\t\t_language = resolved ? resolved : LANGUAGE_DEFAULT;\n\t\t\t_translationsConfigFile = nlsConfig._translationsConfigFile;\n\t\t} catch (e) {\n\t\t}\n\t}\n\t_isNative = true;\n}\n\n// Web environment\nelse if (typeof navigator === 'object' && !isElectronRenderer) {\n\t_userAgent = navigator.userAgent;\n\t_isWindows = _userAgent.indexOf('Windows') >= 0;\n\t_isMacintosh = _userAgent.indexOf('Macintosh') >= 0;\n\t_isIOS = (_userAgent.indexOf('Macintosh') >= 0 || _userAgent.indexOf('iPad') >= 0 || _userAgent.indexOf('iPhone') >= 0) && !!navigator.maxTouchPoints && navigator.maxTouchPoints > 0;\n\t_isLinux = _userAgent.indexOf('Linux') >= 0;\n\t_isMobile = _userAgent?.indexOf('Mobi') >= 0;\n\t_isWeb = true;\n\n\tconst configuredLocale = nls.getConfiguredDefaultLocale(\n\t\t// This call _must_ be done in the file that calls `nls.getConfiguredDefaultLocale`\n\t\t// to ensure that the NLS AMD Loader plugin has been loaded and configured.\n\t\t// This is because the loader plugin decides what the default locale is based on\n\t\t// how it's able to resolve the strings.\n\t\tnls.localize({ key: 'ensureLoaderPluginIsLoaded', comment: ['{Locked}'] }, '_')\n\t);\n\n\t_locale = configuredLocale || LANGUAGE_DEFAULT;\n\t_language = _locale;\n\t_platformLocale = navigator.language;\n}\n\n// Unknown environment\nelse {\n\tconsole.error('Unable to resolve platform.');\n}\n\nexport const enum Platform {\n\tWeb,\n\tMac,\n\tLinux,\n\tWindows\n}\n\nlet _platform: Platform = Platform.Web;\nif (_isMacintosh) {\n\t_platform = Platform.Mac;\n} else if (_isWindows) {\n\t_platform = Platform.Windows;\n} else if (_isLinux) {\n\t_platform = Platform.Linux;\n}\n\nexport const isWindows = _isWindows;\nexport const isMacintosh = _isMacintosh;\nexport const isLinux = _isLinux;\nexport const isNative = _isNative;\nexport const isWeb = _isWeb;\nexport const isWebWorker = (_isWeb && typeof $globalThis.importScripts === 'function');\nexport const webWorkerOrigin = isWebWorker ? $globalThis.origin : undefined;\nexport const isIOS = _isIOS;\nexport const isMobile = _isMobile;\nexport const userAgent = _userAgent;\n\n/**\n * The language used for the user interface. The format of\n * the string is all lower case (e.g. zh-tw for Traditional\n * Chinese)\n */\nexport const language = _language;\n\nexport const setTimeout0IsFaster = (typeof $globalThis.postMessage === 'function' && !$globalThis.importScripts);\n\n/**\n * See https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#:~:text=than%204%2C%20then-,set%20timeout%20to%204,-.\n *\n * Works similarly to `setTimeout(0)` but doesn't suffer from the 4ms artificial delay\n * that browsers set when the nesting level is > 5.\n */\nexport const setTimeout0 = (() => {\n\tif (setTimeout0IsFaster) {\n\t\tinterface IQueueElement {\n\t\t\tid: number;\n\t\t\tcallback: () => void;\n\t\t}\n\t\tconst pending: IQueueElement[] = [];\n\n\t\t$globalThis.addEventListener('message', (e: any) => {\n\t\t\tif (e.data && e.data.vscodeScheduleAsyncWork) {\n\t\t\t\tfor (let i = 0, len = pending.length; i < len; i++) {\n\t\t\t\t\tconst candidate = pending[i];\n\t\t\t\t\tif (candidate.id === e.data.vscodeScheduleAsyncWork) {\n\t\t\t\t\t\tpending.splice(i, 1);\n\t\t\t\t\t\tcandidate.callback();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\tlet lastId = 0;\n\t\treturn (callback: () => void) => {\n\t\t\tconst myId = ++lastId;\n\t\t\tpending.push({\n\t\t\t\tid: myId,\n\t\t\t\tcallback: callback\n\t\t\t});\n\t\t\t$globalThis.postMessage({ vscodeScheduleAsyncWork: myId }, '*');\n\t\t};\n\t}\n\treturn (callback: () => void) => setTimeout(callback);\n})();\n\nexport const enum OperatingSystem {\n\tWindows = 1,\n\tMacintosh = 2,\n\tLinux = 3\n}\nexport const OS = (_isMacintosh || _isIOS ? OperatingSystem.Macintosh : (_isWindows ? OperatingSystem.Windows : OperatingSystem.Linux));\n\nlet _isLittleEndian = true;\nlet _isLittleEndianComputed = false;\nexport function isLittleEndian(): boolean {\n\tif (!_isLittleEndianComputed) {\n\t\t_isLittleEndianComputed = true;\n\t\tconst test = new Uint8Array(2);\n\t\ttest[0] = 1;\n\t\ttest[1] = 2;\n\t\tconst view = new Uint16Array(test.buffer);\n\t\t_isLittleEndian = (view[0] === (2 << 8) + 1);\n\t}\n\treturn _isLittleEndian;\n}\n\nexport const isChrome = !!(userAgent && userAgent.indexOf('Chrome') >= 0);\nexport const isFirefox = !!(userAgent && userAgent.indexOf('Firefox') >= 0);\nexport const isSafari = !!(!isChrome && (userAgent && userAgent.indexOf('Safari') >= 0));\nexport const isEdge = !!(userAgent && userAgent.indexOf('Edg/') >= 0);\nexport const isAndroid = !!(userAgent && userAgent.indexOf('Android') >= 0);\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\nimport * as browser from 'vs/base/browser/browser';\nimport { mainWindow } from 'vs/base/browser/window';\nimport * as platform from 'vs/base/common/platform';\n\nexport const enum KeyboardSupport {\n\tAlways,\n\tFullScreen,\n\tNone\n}\n\n/**\n * Browser feature we can support in current platform, browser and environment.\n */\nexport const BrowserFeatures = {\n\tclipboard: {\n\t\twriteText: (\n\t\t\tplatform.isNative\n\t\t\t|| (document.queryCommandSupported && document.queryCommandSupported('copy'))\n\t\t\t|| !!(navigator && navigator.clipboard && navigator.clipboard.writeText)\n\t\t),\n\t\treadText: (\n\t\t\tplatform.isNative\n\t\t\t|| !!(navigator && navigator.clipboard && navigator.clipboard.readText)\n\t\t)\n\t},\n\tkeyboard: (() => {\n\t\tif (platform.isNative || browser.isStandalone()) {\n\t\t\treturn KeyboardSupport.Always;\n\t\t}\n\n\t\tif ((navigator).keyboard || browser.isSafari) {\n\t\t\treturn KeyboardSupport.FullScreen;\n\t\t}\n\n\t\treturn KeyboardSupport.None;\n\t})(),\n\n\t// 'ontouchstart' in window always evaluates to true with typescript's modern typings. This causes `window` to be\n\t// `never` later in `window.navigator`. That's why we need the explicit `window as Window` cast\n\ttouch: 'ontouchstart' in mainWindow || navigator.maxTouchPoints > 0,\n\tpointerEvents: mainWindow.PointerEvent && ('ontouchstart' in mainWindow || navigator.maxTouchPoints > 0)\n};\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\nimport { isMacintosh, isWindows } from 'vs/base/common/platform';\n\n/**\n * The best font-family to be used in CSS based on the platform:\n * - Windows: Segoe preferred, fallback to sans-serif\n * - macOS: standard system font, fallback to sans-serif\n * - Linux: standard system font preferred, fallback to Ubuntu fonts\n *\n * Note: this currently does not adjust for different locales.\n */\nexport const DEFAULT_FONT_FAMILY = isWindows ? '\"Segoe WPC\", \"Segoe UI\", sans-serif' : isMacintosh ? '-apple-system, BlinkMacSystemFont, sans-serif' : 'system-ui, \"Ubuntu\", \"Droid Sans\", sans-serif';\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\nimport * as browser from 'vs/base/browser/browser';\nimport { EVENT_KEY_CODE_MAP, KeyCode, KeyCodeUtils, KeyMod } from 'vs/base/common/keyCodes';\nimport { KeyCodeChord } from 'vs/base/common/keybindings';\nimport * as platform from 'vs/base/common/platform';\n\n\n\nfunction extractKeyCode(e: KeyboardEvent): KeyCode {\n\tif (e.charCode) {\n\t\t// \"keypress\" events mostly\n\t\tconst char = String.fromCharCode(e.charCode).toUpperCase();\n\t\treturn KeyCodeUtils.fromString(char);\n\t}\n\n\tconst keyCode = e.keyCode;\n\n\t// browser quirks\n\tif (keyCode === 3) {\n\t\treturn KeyCode.PauseBreak;\n\t} else if (browser.isFirefox) {\n\t\tswitch (keyCode) {\n\t\t\tcase 59: return KeyCode.Semicolon;\n\t\t\tcase 60:\n\t\t\t\tif (platform.isLinux) { return KeyCode.IntlBackslash; }\n\t\t\t\tbreak;\n\t\t\tcase 61: return KeyCode.Equal;\n\t\t\t// based on: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode#numpad_keys\n\t\t\tcase 107: return KeyCode.NumpadAdd;\n\t\t\tcase 109: return KeyCode.NumpadSubtract;\n\t\t\tcase 173: return KeyCode.Minus;\n\t\t\tcase 224:\n\t\t\t\tif (platform.isMacintosh) { return KeyCode.Meta; }\n\t\t\t\tbreak;\n\t\t}\n\t} else if (browser.isWebKit) {\n\t\tif (platform.isMacintosh && keyCode === 93) {\n\t\t\t// the two meta keys in the Mac have different key codes (91 and 93)\n\t\t\treturn KeyCode.Meta;\n\t\t} else if (!platform.isMacintosh && keyCode === 92) {\n\t\t\treturn KeyCode.Meta;\n\t\t}\n\t}\n\n\t// cross browser keycodes:\n\treturn EVENT_KEY_CODE_MAP[keyCode] || KeyCode.Unknown;\n}\n\nexport interface IKeyboardEvent {\n\n\treadonly _standardKeyboardEventBrand: true;\n\n\treadonly browserEvent: KeyboardEvent;\n\treadonly target: HTMLElement;\n\n\treadonly ctrlKey: boolean;\n\treadonly shiftKey: boolean;\n\treadonly altKey: boolean;\n\treadonly metaKey: boolean;\n\treadonly altGraphKey: boolean;\n\treadonly keyCode: KeyCode;\n\treadonly code: string;\n\n\t/**\n\t * @internal\n\t */\n\ttoKeyCodeChord(): KeyCodeChord;\n\tequals(keybinding: number): boolean;\n\n\tpreventDefault(): void;\n\tstopPropagation(): void;\n}\n\nconst ctrlKeyMod = (platform.isMacintosh ? KeyMod.WinCtrl : KeyMod.CtrlCmd);\nconst altKeyMod = KeyMod.Alt;\nconst shiftKeyMod = KeyMod.Shift;\nconst metaKeyMod = (platform.isMacintosh ? KeyMod.CtrlCmd : KeyMod.WinCtrl);\n\nexport class StandardKeyboardEvent implements IKeyboardEvent {\n\n\treadonly _standardKeyboardEventBrand = true;\n\n\tpublic readonly browserEvent: KeyboardEvent;\n\tpublic readonly target: HTMLElement;\n\n\tpublic readonly ctrlKey: boolean;\n\tpublic readonly shiftKey: boolean;\n\tpublic readonly altKey: boolean;\n\tpublic readonly metaKey: boolean;\n\tpublic readonly altGraphKey: boolean;\n\tpublic readonly keyCode: KeyCode;\n\tpublic readonly code: string;\n\n\tprivate _asKeybinding: number;\n\tprivate _asKeyCodeChord: KeyCodeChord;\n\n\tconstructor(source: KeyboardEvent) {\n\t\tconst e = source;\n\n\t\tthis.browserEvent = e;\n\t\tthis.target = e.target;\n\n\t\tthis.ctrlKey = e.ctrlKey;\n\t\tthis.shiftKey = e.shiftKey;\n\t\tthis.altKey = e.altKey;\n\t\tthis.metaKey = e.metaKey;\n\t\tthis.altGraphKey = e.getModifierState?.('AltGraph');\n\t\tthis.keyCode = extractKeyCode(e);\n\t\tthis.code = e.code;\n\n\t\t// console.info(e.type + \": keyCode: \" + e.keyCode + \", which: \" + e.which + \", charCode: \" + e.charCode + \", detail: \" + e.detail + \" ====> \" + this.keyCode + ' -- ' + KeyCode[this.keyCode]);\n\n\t\tthis.ctrlKey = this.ctrlKey || this.keyCode === KeyCode.Ctrl;\n\t\tthis.altKey = this.altKey || this.keyCode === KeyCode.Alt;\n\t\tthis.shiftKey = this.shiftKey || this.keyCode === KeyCode.Shift;\n\t\tthis.metaKey = this.metaKey || this.keyCode === KeyCode.Meta;\n\n\t\tthis._asKeybinding = this._computeKeybinding();\n\t\tthis._asKeyCodeChord = this._computeKeyCodeChord();\n\n\t\t// console.log(`code: ${e.code}, keyCode: ${e.keyCode}, key: ${e.key}`);\n\t}\n\n\tpublic preventDefault(): void {\n\t\tif (this.browserEvent && this.browserEvent.preventDefault) {\n\t\t\tthis.browserEvent.preventDefault();\n\t\t}\n\t}\n\n\tpublic stopPropagation(): void {\n\t\tif (this.browserEvent && this.browserEvent.stopPropagation) {\n\t\t\tthis.browserEvent.stopPropagation();\n\t\t}\n\t}\n\n\tpublic toKeyCodeChord(): KeyCodeChord {\n\t\treturn this._asKeyCodeChord;\n\t}\n\n\tpublic equals(other: number): boolean {\n\t\treturn this._asKeybinding === other;\n\t}\n\n\tprivate _computeKeybinding(): number {\n\t\tlet key = KeyCode.Unknown;\n\t\tif (this.keyCode !== KeyCode.Ctrl && this.keyCode !== KeyCode.Shift && this.keyCode !== KeyCode.Alt && this.keyCode !== KeyCode.Meta) {\n\t\t\tkey = this.keyCode;\n\t\t}\n\n\t\tlet result = 0;\n\t\tif (this.ctrlKey) {\n\t\t\tresult |= ctrlKeyMod;\n\t\t}\n\t\tif (this.altKey) {\n\t\t\tresult |= altKeyMod;\n\t\t}\n\t\tif (this.shiftKey) {\n\t\t\tresult |= shiftKeyMod;\n\t\t}\n\t\tif (this.metaKey) {\n\t\t\tresult |= metaKeyMod;\n\t\t}\n\t\tresult |= key;\n\n\t\treturn result;\n\t}\n\n\tprivate _computeKeyCodeChord(): KeyCodeChord {\n\t\tlet key = KeyCode.Unknown;\n\t\tif (this.keyCode !== KeyCode.Ctrl && this.keyCode !== KeyCode.Shift && this.keyCode !== KeyCode.Alt && this.keyCode !== KeyCode.Meta) {\n\t\t\tkey = this.keyCode;\n\t\t}\n\t\treturn new KeyCodeChord(this.ctrlKey, this.shiftKey, this.altKey, this.metaKey, key);\n\t}\n}\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\nimport * as browser from 'vs/base/browser/browser';\nimport { IframeUtils } from 'vs/base/browser/iframe';\nimport * as platform from 'vs/base/common/platform';\n\nexport interface IMouseEvent {\n\treadonly browserEvent: MouseEvent;\n\treadonly leftButton: boolean;\n\treadonly middleButton: boolean;\n\treadonly rightButton: boolean;\n\treadonly buttons: number;\n\treadonly target: HTMLElement;\n\treadonly detail: number;\n\treadonly posx: number;\n\treadonly posy: number;\n\treadonly ctrlKey: boolean;\n\treadonly shiftKey: boolean;\n\treadonly altKey: boolean;\n\treadonly metaKey: boolean;\n\treadonly timestamp: number;\n\n\tpreventDefault(): void;\n\tstopPropagation(): void;\n}\n\nexport class StandardMouseEvent implements IMouseEvent {\n\n\tpublic readonly browserEvent: MouseEvent;\n\n\tpublic readonly leftButton: boolean;\n\tpublic readonly middleButton: boolean;\n\tpublic readonly rightButton: boolean;\n\tpublic readonly buttons: number;\n\tpublic readonly target: HTMLElement;\n\tpublic detail: number;\n\tpublic readonly posx: number;\n\tpublic readonly posy: number;\n\tpublic readonly ctrlKey: boolean;\n\tpublic readonly shiftKey: boolean;\n\tpublic readonly altKey: boolean;\n\tpublic readonly metaKey: boolean;\n\tpublic readonly timestamp: number;\n\n\tconstructor(targetWindow: Window, e: MouseEvent) {\n\t\tthis.timestamp = Date.now();\n\t\tthis.browserEvent = e;\n\t\tthis.leftButton = e.button === 0;\n\t\tthis.middleButton = e.button === 1;\n\t\tthis.rightButton = e.button === 2;\n\t\tthis.buttons = e.buttons;\n\n\t\tthis.target = e.target;\n\n\t\tthis.detail = e.detail || 1;\n\t\tif (e.type === 'dblclick') {\n\t\t\tthis.detail = 2;\n\t\t}\n\t\tthis.ctrlKey = e.ctrlKey;\n\t\tthis.shiftKey = e.shiftKey;\n\t\tthis.altKey = e.altKey;\n\t\tthis.metaKey = e.metaKey;\n\n\t\tif (typeof e.pageX === 'number') {\n\t\t\tthis.posx = e.pageX;\n\t\t\tthis.posy = e.pageY;\n\t\t} else {\n\t\t\t// Probably hit by MSGestureEvent\n\t\t\tthis.posx = e.clientX + this.target.ownerDocument.body.scrollLeft + this.target.ownerDocument.documentElement.scrollLeft;\n\t\t\tthis.posy = e.clientY + this.target.ownerDocument.body.scrollTop + this.target.ownerDocument.documentElement.scrollTop;\n\t\t}\n\n\t\t// Find the position of the iframe this code is executing in relative to the iframe where the event was captured.\n\t\tconst iframeOffsets = IframeUtils.getPositionOfChildWindowRelativeToAncestorWindow(targetWindow, e.view);\n\t\tthis.posx -= iframeOffsets.left;\n\t\tthis.posy -= iframeOffsets.top;\n\t}\n\n\tpublic preventDefault(): void {\n\t\tthis.browserEvent.preventDefault();\n\t}\n\n\tpublic stopPropagation(): void {\n\t\tthis.browserEvent.stopPropagation();\n\t}\n}\n\nexport interface IMouseWheelEvent extends MouseEvent {\n\treadonly wheelDelta: number;\n\treadonly wheelDeltaX: number;\n\treadonly wheelDeltaY: number;\n\n\treadonly deltaX: number;\n\treadonly deltaY: number;\n\treadonly deltaZ: number;\n\treadonly deltaMode: number;\n}\n\ninterface IWebKitMouseWheelEvent {\n\twheelDeltaY: number;\n\twheelDeltaX: number;\n}\n\ninterface IGeckoMouseWheelEvent {\n\tHORIZONTAL_AXIS: number;\n\tVERTICAL_AXIS: number;\n\taxis: number;\n\tdetail: number;\n}\n\nexport class StandardWheelEvent {\n\n\tpublic readonly browserEvent: IMouseWheelEvent | null;\n\tpublic readonly deltaY: number;\n\tpublic readonly deltaX: number;\n\tpublic readonly target: Node;\n\n\tconstructor(e: IMouseWheelEvent | null, deltaX: number = 0, deltaY: number = 0) {\n\n\t\tthis.browserEvent = e || null;\n\t\tthis.target = e ? (e.target || (e).targetNode || e.srcElement) : null;\n\n\t\tthis.deltaY = deltaY;\n\t\tthis.deltaX = deltaX;\n\n\t\tlet shouldFactorDPR: boolean = false;\n\t\tif (browser.isChrome) {\n\t\t\t// Chrome version >= 123 contains the fix to factor devicePixelRatio into the wheel event.\n\t\t\t// See https://chromium.googlesource.com/chromium/src.git/+/be51b448441ff0c9d1f17e0f25c4bf1ab3f11f61\n\t\t\tconst chromeVersionMatch = navigator.userAgent.match(/Chrome\\/(\\d+)/);\n\t\t\tconst chromeMajorVersion = chromeVersionMatch ? parseInt(chromeVersionMatch[1]) : 123;\n\t\t\tshouldFactorDPR = chromeMajorVersion <= 122;\n\t\t}\n\n\t\tif (e) {\n\t\t\t// Old (deprecated) wheel events\n\t\t\tconst e1 = e;\n\t\t\tconst e2 = e;\n\t\t\tconst devicePixelRatio = e.view?.devicePixelRatio || 1;\n\n\t\t\t// vertical delta scroll\n\t\t\tif (typeof e1.wheelDeltaY !== 'undefined') {\n\t\t\t\tif (shouldFactorDPR) {\n\t\t\t\t\t// Refs https://github.com/microsoft/vscode/issues/146403#issuecomment-1854538928\n\t\t\t\t\tthis.deltaY = e1.wheelDeltaY / (120 * devicePixelRatio);\n\t\t\t\t} else {\n\t\t\t\t\tthis.deltaY = e1.wheelDeltaY / 120;\n\t\t\t\t}\n\t\t\t} else if (typeof e2.VERTICAL_AXIS !== 'undefined' && e2.axis === e2.VERTICAL_AXIS) {\n\t\t\t\tthis.deltaY = -e2.detail / 3;\n\t\t\t} else if (e.type === 'wheel') {\n\t\t\t\t// Modern wheel event\n\t\t\t\t// https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent\n\t\t\t\tconst ev = e;\n\n\t\t\t\tif (ev.deltaMode === ev.DOM_DELTA_LINE) {\n\t\t\t\t\t// the deltas are expressed in lines\n\t\t\t\t\tif (browser.isFirefox && !platform.isMacintosh) {\n\t\t\t\t\t\tthis.deltaY = -e.deltaY / 3;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.deltaY = -e.deltaY;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tthis.deltaY = -e.deltaY / 40;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// horizontal delta scroll\n\t\t\tif (typeof e1.wheelDeltaX !== 'undefined') {\n\t\t\t\tif (browser.isSafari && platform.isWindows) {\n\t\t\t\t\tthis.deltaX = - (e1.wheelDeltaX / 120);\n\t\t\t\t} else if (shouldFactorDPR) {\n\t\t\t\t\t// Refs https://github.com/microsoft/vscode/issues/146403#issuecomment-1854538928\n\t\t\t\t\tthis.deltaX = e1.wheelDeltaX / (120 * devicePixelRatio);\n\t\t\t\t} else {\n\t\t\t\t\tthis.deltaX = e1.wheelDeltaX / 120;\n\t\t\t\t}\n\t\t\t} else if (typeof e2.HORIZONTAL_AXIS !== 'undefined' && e2.axis === e2.HORIZONTAL_AXIS) {\n\t\t\t\tthis.deltaX = -e.detail / 3;\n\t\t\t} else if (e.type === 'wheel') {\n\t\t\t\t// Modern wheel event\n\t\t\t\t// https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent\n\t\t\t\tconst ev = e;\n\n\t\t\t\tif (ev.deltaMode === ev.DOM_DELTA_LINE) {\n\t\t\t\t\t// the deltas are expressed in lines\n\t\t\t\t\tif (browser.isFirefox && !platform.isMacintosh) {\n\t\t\t\t\t\tthis.deltaX = -e.deltaX / 3;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.deltaX = -e.deltaX;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tthis.deltaX = -e.deltaX / 40;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Assume a vertical scroll if nothing else worked\n\t\t\tif (this.deltaY === 0 && this.deltaX === 0 && e.wheelDelta) {\n\t\t\t\tif (shouldFactorDPR) {\n\t\t\t\t\t// Refs https://github.com/microsoft/vscode/issues/146403#issuecomment-1854538928\n\t\t\t\t\tthis.deltaY = e.wheelDelta / (120 * devicePixelRatio);\n\t\t\t\t} else {\n\t\t\t\t\tthis.deltaY = e.wheelDelta / 120;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic preventDefault(): void {\n\t\tthis.browserEvent?.preventDefault();\n\t}\n\n\tpublic stopPropagation(): void {\n\t\tthis.browserEvent?.stopPropagation();\n\t}\n}\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\nimport { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';\nimport { BugIndicatingError, CancellationError } from 'vs/base/common/errors';\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle';\nimport { setTimeout0 } from 'vs/base/common/platform';\nimport { MicrotaskDelay } from './symbols';\n\nexport function isThenable(obj: unknown): obj is Promise {\n\treturn !!obj && typeof (obj as unknown as Promise).then === 'function';\n}\n\nexport interface CancelablePromise extends Promise {\n\tcancel(): void;\n}\n\nexport function createCancelablePromise(callback: (token: CancellationToken) => Promise): CancelablePromise {\n\tconst source = new CancellationTokenSource();\n\n\tconst thenable = callback(source.token);\n\tconst promise = new Promise((resolve, reject) => {\n\t\tconst subscription = source.token.onCancellationRequested(() => {\n\t\t\tsubscription.dispose();\n\t\t\treject(new CancellationError());\n\t\t});\n\t\tPromise.resolve(thenable).then(value => {\n\t\t\tsubscription.dispose();\n\t\t\tsource.dispose();\n\t\t\tresolve(value);\n\t\t}, err => {\n\t\t\tsubscription.dispose();\n\t\t\tsource.dispose();\n\t\t\treject(err);\n\t\t});\n\t});\n\n\treturn >new class {\n\t\tcancel() {\n\t\t\tsource.cancel();\n\t\t\tsource.dispose();\n\t\t}\n\t\tthen(resolve?: ((value: T) => TResult1 | Promise) | undefined | null, reject?: ((reason: any) => TResult2 | Promise) | undefined | null): Promise {\n\t\t\treturn promise.then(resolve, reject);\n\t\t}\n\t\tcatch(reject?: ((reason: any) => TResult | Promise) | undefined | null): Promise {\n\t\t\treturn this.then(undefined, reject);\n\t\t}\n\t\tfinally(onfinally?: (() => void) | undefined | null): Promise {\n\t\t\treturn promise.finally(onfinally);\n\t\t}\n\t};\n}\n\n/**\n * Returns a promise that resolves with `undefined` as soon as the passed token is cancelled.\n * @see {@link raceCancellationError}\n */\nexport function raceCancellation(promise: Promise, token: CancellationToken): Promise;\n\n/**\n * Returns a promise that resolves with `defaultValue` as soon as the passed token is cancelled.\n * @see {@link raceCancellationError}\n */\nexport function raceCancellation(promise: Promise, token: CancellationToken, defaultValue: T): Promise;\n\nexport function raceCancellation(promise: Promise, token: CancellationToken, defaultValue?: T): Promise {\n\treturn new Promise((resolve, reject) => {\n\t\tconst ref = token.onCancellationRequested(() => {\n\t\t\tref.dispose();\n\t\t\tresolve(defaultValue);\n\t\t});\n\t\tpromise.then(resolve, reject).finally(() => ref.dispose());\n\t});\n}\n\nexport interface ITask {\n\t(): T;\n}\n\n/**\n * A helper to prevent accumulation of sequential async tasks.\n *\n * Imagine a mail man with the sole task of delivering letters. As soon as\n * a letter submitted for delivery, he drives to the destination, delivers it\n * and returns to his base. Imagine that during the trip, N more letters were submitted.\n * When the mail man returns, he picks those N letters and delivers them all in a\n * single trip. Even though N+1 submissions occurred, only 2 deliveries were made.\n *\n * The throttler implements this via the queue() method, by providing it a task\n * factory. Following the example:\n *\n * \t\tconst throttler = new Throttler();\n * \t\tconst letters = [];\n *\n * \t\tfunction deliver() {\n * \t\t\tconst lettersToDeliver = letters;\n * \t\t\tletters = [];\n * \t\t\treturn makeTheTrip(lettersToDeliver);\n * \t\t}\n *\n * \t\tfunction onLetterReceived(l) {\n * \t\t\tletters.push(l);\n * \t\t\tthrottler.queue(deliver);\n * \t\t}\n */\nexport class Throttler implements IDisposable {\n\n\tprivate activePromise: Promise | null;\n\tprivate queuedPromise: Promise | null;\n\tprivate queuedPromiseFactory: ITask> | null;\n\n\tprivate isDisposed = false;\n\n\tconstructor() {\n\t\tthis.activePromise = null;\n\t\tthis.queuedPromise = null;\n\t\tthis.queuedPromiseFactory = null;\n\t}\n\n\tqueue(promiseFactory: ITask>): Promise {\n\t\tif (this.isDisposed) {\n\t\t\treturn Promise.reject(new Error('Throttler is disposed'));\n\t\t}\n\n\t\tif (this.activePromise) {\n\t\t\tthis.queuedPromiseFactory = promiseFactory;\n\n\t\t\tif (!this.queuedPromise) {\n\t\t\t\tconst onComplete = () => {\n\t\t\t\t\tthis.queuedPromise = null;\n\n\t\t\t\t\tif (this.isDisposed) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst result = this.queue(this.queuedPromiseFactory!);\n\t\t\t\t\tthis.queuedPromiseFactory = null;\n\n\t\t\t\t\treturn result;\n\t\t\t\t};\n\n\t\t\t\tthis.queuedPromise = new Promise(resolve => {\n\t\t\t\t\tthis.activePromise!.then(onComplete, onComplete).then(resolve);\n\t\t\t\t});\n\t\t\t}\n\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tthis.queuedPromise!.then(resolve, reject);\n\t\t\t});\n\t\t}\n\n\t\tthis.activePromise = promiseFactory();\n\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tthis.activePromise!.then((result: T) => {\n\t\t\t\tthis.activePromise = null;\n\t\t\t\tresolve(result);\n\t\t\t}, (err: unknown) => {\n\t\t\t\tthis.activePromise = null;\n\t\t\t\treject(err);\n\t\t\t});\n\t\t});\n\t}\n\n\tdispose(): void {\n\t\tthis.isDisposed = true;\n\t}\n}\n\ninterface IScheduledLater extends IDisposable {\n\tisTriggered(): boolean;\n}\n\nconst timeoutDeferred = (timeout: number, fn: () => void): IScheduledLater => {\n\tlet scheduled = true;\n\tconst handle = setTimeout(() => {\n\t\tscheduled = false;\n\t\tfn();\n\t}, timeout);\n\treturn {\n\t\tisTriggered: () => scheduled,\n\t\tdispose: () => {\n\t\t\tclearTimeout(handle);\n\t\t\tscheduled = false;\n\t\t},\n\t};\n};\n\nconst microtaskDeferred = (fn: () => void): IScheduledLater => {\n\tlet scheduled = true;\n\tqueueMicrotask(() => {\n\t\tif (scheduled) {\n\t\t\tscheduled = false;\n\t\t\tfn();\n\t\t}\n\t});\n\n\treturn {\n\t\tisTriggered: () => scheduled,\n\t\tdispose: () => { scheduled = false; },\n\t};\n};\n\n/**\n * A helper to delay (debounce) execution of a task that is being requested often.\n *\n * Following the throttler, now imagine the mail man wants to optimize the number of\n * trips proactively. The trip itself can be long, so he decides not to make the trip\n * as soon as a letter is submitted. Instead he waits a while, in case more\n * letters are submitted. After said waiting period, if no letters were submitted, he\n * decides to make the trip. Imagine that N more letters were submitted after the first\n * one, all within a short period of time between each other. Even though N+1\n * submissions occurred, only 1 delivery was made.\n *\n * The delayer offers this behavior via the trigger() method, into which both the task\n * to be executed and the waiting period (delay) must be passed in as arguments. Following\n * the example:\n *\n * \t\tconst delayer = new Delayer(WAITING_PERIOD);\n * \t\tconst letters = [];\n *\n * \t\tfunction letterReceived(l) {\n * \t\t\tletters.push(l);\n * \t\t\tdelayer.trigger(() => { return makeTheTrip(); });\n * \t\t}\n */\nexport class Delayer implements IDisposable {\n\n\tprivate deferred: IScheduledLater | null;\n\tprivate completionPromise: Promise | null;\n\tprivate doResolve: ((value?: any | Promise) => void) | null;\n\tprivate doReject: ((err: any) => void) | null;\n\tprivate task: ITask> | null;\n\n\tconstructor(public defaultDelay: number | typeof MicrotaskDelay) {\n\t\tthis.deferred = null;\n\t\tthis.completionPromise = null;\n\t\tthis.doResolve = null;\n\t\tthis.doReject = null;\n\t\tthis.task = null;\n\t}\n\n\ttrigger(task: ITask>, delay = this.defaultDelay): Promise {\n\t\tthis.task = task;\n\t\tthis.cancelTimeout();\n\n\t\tif (!this.completionPromise) {\n\t\t\tthis.completionPromise = new Promise((resolve, reject) => {\n\t\t\t\tthis.doResolve = resolve;\n\t\t\t\tthis.doReject = reject;\n\t\t\t}).then(() => {\n\t\t\t\tthis.completionPromise = null;\n\t\t\t\tthis.doResolve = null;\n\t\t\t\tif (this.task) {\n\t\t\t\t\tconst task = this.task;\n\t\t\t\t\tthis.task = null;\n\t\t\t\t\treturn task();\n\t\t\t\t}\n\t\t\t\treturn undefined;\n\t\t\t});\n\t\t}\n\n\t\tconst fn = () => {\n\t\t\tthis.deferred = null;\n\t\t\tthis.doResolve?.(null);\n\t\t};\n\n\t\tthis.deferred = delay === MicrotaskDelay ? microtaskDeferred(fn) : timeoutDeferred(delay, fn);\n\n\t\treturn this.completionPromise;\n\t}\n\n\tisTriggered(): boolean {\n\t\treturn !!this.deferred?.isTriggered();\n\t}\n\n\tcancel(): void {\n\t\tthis.cancelTimeout();\n\n\t\tif (this.completionPromise) {\n\t\t\tthis.doReject?.(new CancellationError());\n\t\t\tthis.completionPromise = null;\n\t\t}\n\t}\n\n\tprivate cancelTimeout(): void {\n\t\tthis.deferred?.dispose();\n\t\tthis.deferred = null;\n\t}\n\n\tdispose(): void {\n\t\tthis.cancel();\n\t}\n}\n\n/**\n * A helper to delay execution of a task that is being requested often, while\n * preventing accumulation of consecutive executions, while the task runs.\n *\n * The mail man is clever and waits for a certain amount of time, before going\n * out to deliver letters. While the mail man is going out, more letters arrive\n * and can only be delivered once he is back. Once he is back the mail man will\n * do one more trip to deliver the letters that have accumulated while he was out.\n */\nexport class ThrottledDelayer {\n\n\tprivate delayer: Delayer>;\n\tprivate throttler: Throttler;\n\n\tconstructor(defaultDelay: number) {\n\t\tthis.delayer = new Delayer(defaultDelay);\n\t\tthis.throttler = new Throttler();\n\t}\n\n\ttrigger(promiseFactory: ITask>, delay?: number): Promise {\n\t\treturn this.delayer.trigger(() => this.throttler.queue(promiseFactory), delay) as unknown as Promise;\n\t}\n\n\tcancel(): void {\n\t\tthis.delayer.cancel();\n\t}\n\n\tdispose(): void {\n\t\tthis.delayer.dispose();\n\t\tthis.throttler.dispose();\n\t}\n}\n\nexport function timeout(millis: number): CancelablePromise;\nexport function timeout(millis: number, token: CancellationToken): Promise;\nexport function timeout(millis: number, token?: CancellationToken): CancelablePromise | Promise {\n\tif (!token) {\n\t\treturn createCancelablePromise(token => timeout(millis, token));\n\t}\n\n\treturn new Promise((resolve, reject) => {\n\t\tconst handle = setTimeout(() => {\n\t\t\tdisposable.dispose();\n\t\t\tresolve();\n\t\t}, millis);\n\t\tconst disposable = token.onCancellationRequested(() => {\n\t\t\tclearTimeout(handle);\n\t\t\tdisposable.dispose();\n\t\t\treject(new CancellationError());\n\t\t});\n\t});\n}\n\n/**\n * Creates a timeout that can be disposed using its returned value.\n * @param handler The timeout handler.\n * @param timeout An optional timeout in milliseconds.\n * @param store An optional {@link DisposableStore} that will have the timeout disposable managed automatically.\n *\n * @example\n * const store = new DisposableStore;\n * // Call the timeout after 1000ms at which point it will be automatically\n * // evicted from the store.\n * const timeoutDisposable = disposableTimeout(() => {}, 1000, store);\n *\n * if (foo) {\n * // Cancel the timeout and evict it from store.\n * timeoutDisposable.dispose();\n * }\n */\nexport function disposableTimeout(handler: () => void, timeout = 0, store?: DisposableStore): IDisposable {\n\tconst timer = setTimeout(() => {\n\t\thandler();\n\t\tif (store) {\n\t\t\tdisposable.dispose();\n\t\t}\n\t}, timeout);\n\tconst disposable = toDisposable(() => {\n\t\tclearTimeout(timer);\n\t\tstore?.deleteAndLeak(disposable);\n\t});\n\tstore?.add(disposable);\n\treturn disposable;\n}\n\nexport function first(promiseFactories: ITask>[], shouldStop: (t: T) => boolean = t => !!t, defaultValue: T | null = null): Promise {\n\tlet index = 0;\n\tconst len = promiseFactories.length;\n\n\tconst loop: () => Promise = () => {\n\t\tif (index >= len) {\n\t\t\treturn Promise.resolve(defaultValue);\n\t\t}\n\n\t\tconst factory = promiseFactories[index++];\n\t\tconst promise = Promise.resolve(factory());\n\n\t\treturn promise.then(result => {\n\t\t\tif (shouldStop(result)) {\n\t\t\t\treturn Promise.resolve(result);\n\t\t\t}\n\n\t\t\treturn loop();\n\t\t});\n\t};\n\n\treturn loop();\n}\n\nexport class TimeoutTimer implements IDisposable {\n\tprivate _token: any;\n\tprivate _isDisposed = false;\n\n\tconstructor();\n\tconstructor(runner: () => void, timeout: number);\n\tconstructor(runner?: () => void, timeout?: number) {\n\t\tthis._token = -1;\n\n\t\tif (typeof runner === 'function' && typeof timeout === 'number') {\n\t\t\tthis.setIfNotSet(runner, timeout);\n\t\t}\n\t}\n\n\tdispose(): void {\n\t\tthis.cancel();\n\t\tthis._isDisposed = true;\n\t}\n\n\tcancel(): void {\n\t\tif (this._token !== -1) {\n\t\t\tclearTimeout(this._token);\n\t\t\tthis._token = -1;\n\t\t}\n\t}\n\n\tcancelAndSet(runner: () => void, timeout: number): void {\n\t\tif (this._isDisposed) {\n\t\t\tthrow new BugIndicatingError(`Calling 'cancelAndSet' on a disposed TimeoutTimer`);\n\t\t}\n\n\t\tthis.cancel();\n\t\tthis._token = setTimeout(() => {\n\t\t\tthis._token = -1;\n\t\t\trunner();\n\t\t}, timeout);\n\t}\n\n\tsetIfNotSet(runner: () => void, timeout: number): void {\n\t\tif (this._isDisposed) {\n\t\t\tthrow new BugIndicatingError(`Calling 'setIfNotSet' on a disposed TimeoutTimer`);\n\t\t}\n\n\t\tif (this._token !== -1) {\n\t\t\t// timer is already set\n\t\t\treturn;\n\t\t}\n\t\tthis._token = setTimeout(() => {\n\t\t\tthis._token = -1;\n\t\t\trunner();\n\t\t}, timeout);\n\t}\n}\n\nexport class IntervalTimer implements IDisposable {\n\n\tprivate disposable: IDisposable | undefined = undefined;\n\tprivate isDisposed = false;\n\n\tcancel(): void {\n\t\tthis.disposable?.dispose();\n\t\tthis.disposable = undefined;\n\t}\n\n\tcancelAndSet(runner: () => void, interval: number, context = globalThis): void {\n\t\tif (this.isDisposed) {\n\t\t\tthrow new BugIndicatingError(`Calling 'cancelAndSet' on a disposed IntervalTimer`);\n\t\t}\n\n\t\tthis.cancel();\n\t\tconst handle = context.setInterval(() => {\n\t\t\trunner();\n\t\t}, interval);\n\n\t\tthis.disposable = toDisposable(() => {\n\t\t\tcontext.clearInterval(handle);\n\t\t\tthis.disposable = undefined;\n\t\t});\n\t}\n\n\tdispose(): void {\n\t\tthis.cancel();\n\t\tthis.isDisposed = true;\n\t}\n}\n\nexport class RunOnceScheduler implements IDisposable {\n\n\tprotected runner: ((...args: unknown[]) => void) | null;\n\n\tprivate timeoutToken: any;\n\tprivate timeout: number;\n\tprivate timeoutHandler: () => void;\n\n\tconstructor(runner: (...args: any[]) => void, delay: number) {\n\t\tthis.timeoutToken = -1;\n\t\tthis.runner = runner;\n\t\tthis.timeout = delay;\n\t\tthis.timeoutHandler = this.onTimeout.bind(this);\n\t}\n\n\t/**\n\t * Dispose RunOnceScheduler\n\t */\n\tdispose(): void {\n\t\tthis.cancel();\n\t\tthis.runner = null;\n\t}\n\n\t/**\n\t * Cancel current scheduled runner (if any).\n\t */\n\tcancel(): void {\n\t\tif (this.isScheduled()) {\n\t\t\tclearTimeout(this.timeoutToken);\n\t\t\tthis.timeoutToken = -1;\n\t\t}\n\t}\n\n\t/**\n\t * Cancel previous runner (if any) & schedule a new runner.\n\t */\n\tschedule(delay = this.timeout): void {\n\t\tthis.cancel();\n\t\tthis.timeoutToken = setTimeout(this.timeoutHandler, delay);\n\t}\n\n\tget delay(): number {\n\t\treturn this.timeout;\n\t}\n\n\tset delay(value: number) {\n\t\tthis.timeout = value;\n\t}\n\n\t/**\n\t * Returns true if scheduled.\n\t */\n\tisScheduled(): boolean {\n\t\treturn this.timeoutToken !== -1;\n\t}\n\n\tprivate onTimeout() {\n\t\tthis.timeoutToken = -1;\n\t\tif (this.runner) {\n\t\t\tthis.doRun();\n\t\t}\n\t}\n\n\tprotected doRun(): void {\n\t\tthis.runner?.();\n\t}\n}\n\n//#region -- run on idle tricks ------------\n\nexport interface IdleDeadline {\n\treadonly didTimeout: boolean;\n\ttimeRemaining(): number;\n}\n\ntype IdleApi = Pick;\n\n\n/**\n * Execute the callback the next time the browser is idle, returning an\n * {@link IDisposable} that will cancel the callback when disposed. This wraps\n * [requestIdleCallback] so it will fallback to [setTimeout] if the environment\n * doesn't support it.\n *\n * @param callback The callback to run when idle, this includes an\n * [IdleDeadline] that provides the time alloted for the idle callback by the\n * browser. Not respecting this deadline will result in a degraded user\n * experience.\n * @param timeout A timeout at which point to queue no longer wait for an idle\n * callback but queue it on the regular event loop (like setTimeout). Typically\n * this should not be used.\n *\n * [IdleDeadline]: https://developer.mozilla.org/en-US/docs/Web/API/IdleDeadline\n * [requestIdleCallback]: https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback\n * [setTimeout]: https://developer.mozilla.org/en-US/docs/Web/API/Window/setTimeout\n *\n * **Note** that there is `dom.ts#runWhenWindowIdle` which is better suited when running inside a browser\n * context\n */\nexport let runWhenGlobalIdle: (callback: (idle: IdleDeadline) => void, timeout?: number) => IDisposable;\n\nexport let _runWhenIdle: (targetWindow: IdleApi, callback: (idle: IdleDeadline) => void, timeout?: number) => IDisposable;\n\n(function () {\n\tif (typeof globalThis.requestIdleCallback !== 'function' || typeof globalThis.cancelIdleCallback !== 'function') {\n\t\t_runWhenIdle = (_targetWindow, runner) => {\n\t\t\tsetTimeout0(() => {\n\t\t\t\tif (disposed) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst end = Date.now() + 15; // one frame at 64fps\n\t\t\t\tconst deadline: IdleDeadline = {\n\t\t\t\t\tdidTimeout: true,\n\t\t\t\t\ttimeRemaining() {\n\t\t\t\t\t\treturn Math.max(0, end - Date.now());\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\trunner(Object.freeze(deadline));\n\t\t\t});\n\t\t\tlet disposed = false;\n\t\t\treturn {\n\t\t\t\tdispose() {\n\t\t\t\t\tif (disposed) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tdisposed = true;\n\t\t\t\t}\n\t\t\t};\n\t\t};\n\t} else {\n\t\t_runWhenIdle = (targetWindow: IdleApi, runner, timeout?) => {\n\t\t\tconst handle: number = targetWindow.requestIdleCallback(runner, typeof timeout === 'number' ? { timeout } : undefined);\n\t\t\tlet disposed = false;\n\t\t\treturn {\n\t\t\t\tdispose() {\n\t\t\t\t\tif (disposed) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tdisposed = true;\n\t\t\t\t\ttargetWindow.cancelIdleCallback(handle);\n\t\t\t\t}\n\t\t\t};\n\t\t};\n\t}\n\trunWhenGlobalIdle = (runner) => _runWhenIdle(globalThis, runner);\n})();\n\nexport abstract class AbstractIdleValue {\n\n\tprivate readonly _executor: () => void;\n\tprivate readonly _handle: IDisposable;\n\n\tprivate _didRun: boolean = false;\n\tprivate _value?: T;\n\tprivate _error: unknown;\n\n\tconstructor(targetWindow: IdleApi, executor: () => T) {\n\t\tthis._executor = () => {\n\t\t\ttry {\n\t\t\t\tthis._value = executor();\n\t\t\t} catch (err) {\n\t\t\t\tthis._error = err;\n\t\t\t} finally {\n\t\t\t\tthis._didRun = true;\n\t\t\t}\n\t\t};\n\t\tthis._handle = _runWhenIdle(targetWindow, () => this._executor());\n\t}\n\n\tdispose(): void {\n\t\tthis._handle.dispose();\n\t}\n\n\tget value(): T {\n\t\tif (!this._didRun) {\n\t\t\tthis._handle.dispose();\n\t\t\tthis._executor();\n\t\t}\n\t\tif (this._error) {\n\t\t\tthrow this._error;\n\t\t}\n\t\treturn this._value!;\n\t}\n\n\tget isInitialized(): boolean {\n\t\treturn this._didRun;\n\t}\n}\n\n/**\n * An `IdleValue` that always uses the current window (which might be throttled or inactive)\n *\n * **Note** that there is `dom.ts#WindowIdleValue` which is better suited when running inside a browser\n * context\n */\nexport class GlobalIdleValue extends AbstractIdleValue {\n\n\tconstructor(executor: () => T) {\n\t\tsuper(globalThis, executor);\n\t}\n}\n\n//#endregion\n\n//#region\n\nexport type ValueCallback = (value: T | Promise) => void;\n\nconst enum DeferredOutcome {\n\tResolved,\n\tRejected\n}\n\n/**\n * Creates a promise whose resolution or rejection can be controlled imperatively.\n */\nexport class DeferredPromise {\n\n\tprivate completeCallback!: ValueCallback;\n\tprivate errorCallback!: (err: unknown) => void;\n\tprivate outcome?: { outcome: DeferredOutcome.Rejected; value: any } | { outcome: DeferredOutcome.Resolved; value: T };\n\n\tpublic get isRejected() {\n\t\treturn this.outcome?.outcome === DeferredOutcome.Rejected;\n\t}\n\n\tpublic get isSettled() {\n\t\treturn !!this.outcome;\n\t}\n\n\tpublic readonly p: Promise;\n\n\tconstructor() {\n\t\tthis.p = new Promise((c, e) => {\n\t\t\tthis.completeCallback = c;\n\t\t\tthis.errorCallback = e;\n\t\t});\n\t}\n\n\tpublic complete(value: T) {\n\t\treturn new Promise(resolve => {\n\t\t\tthis.completeCallback(value);\n\t\t\tthis.outcome = { outcome: DeferredOutcome.Resolved, value };\n\t\t\tresolve();\n\t\t});\n\t}\n\n\tpublic error(err: unknown) {\n\t\treturn new Promise(resolve => {\n\t\t\tthis.errorCallback(err);\n\t\t\tthis.outcome = { outcome: DeferredOutcome.Rejected, value: err };\n\t\t\tresolve();\n\t\t});\n\t}\n\n\tpublic cancel() {\n\t\treturn this.error(new CancellationError());\n\t}\n}\n\n//#endregion\n\n//#region Promises\n\nexport namespace Promises {\n\n\t/**\n\t * A drop-in replacement for `Promise.all` with the only difference\n\t * that the method awaits every promise to either fulfill or reject.\n\t *\n\t * Similar to `Promise.all`, only the first error will be returned\n\t * if any.\n\t */\n\texport async function settled(promises: Promise[]): Promise {\n\t\tlet firstError: Error | undefined = undefined;\n\n\t\tconst result = await Promise.all(promises.map(promise => promise.then(value => value, error => {\n\t\t\tif (!firstError) {\n\t\t\t\tfirstError = error;\n\t\t\t}\n\n\t\t\treturn undefined; // do not rethrow so that other promises can settle\n\t\t})));\n\n\t\tif (typeof firstError !== 'undefined') {\n\t\t\tthrow firstError;\n\t\t}\n\n\t\treturn result as unknown as T[]; // cast is needed and protected by the `throw` above\n\t}\n\n\t/**\n\t * A helper to create a new `Promise` with a body that is a promise\n\t * itself. By default, an error that raises from the async body will\n\t * end up as a unhandled rejection, so this utility properly awaits the\n\t * body and rejects the promise as a normal promise does without async\n\t * body.\n\t *\n\t * This method should only be used in rare cases where otherwise `async`\n\t * cannot be used (e.g. when callbacks are involved that require this).\n\t */\n\texport function withAsyncBody(bodyFn: (resolve: (value: T) => unknown, reject: (error: E) => unknown) => Promise): Promise {\n\t\t// eslint-disable-next-line no-async-promise-executor\n\t\treturn new Promise(async (resolve, reject) => {\n\t\t\ttry {\n\t\t\t\tawait bodyFn(resolve, reject);\n\t\t\t} catch (error) {\n\t\t\t\treject(error);\n\t\t\t}\n\t\t});\n\t}\n}\n\n//#endregion\n\n//#region\n\nconst enum AsyncIterableSourceState {\n\tInitial,\n\tDoneOK,\n\tDoneError,\n}\n\n/**\n * An object that allows to emit async values asynchronously or bring the iterable to an error state using `reject()`.\n * This emitter is valid only for the duration of the executor (until the promise returned by the executor settles).\n */\nexport interface AsyncIterableEmitter {\n\t/**\n\t * The value will be appended at the end.\n\t *\n\t * **NOTE** If `reject()` has already been called, this method has no effect.\n\t */\n\temitOne(value: T): void;\n\t/**\n\t * The values will be appended at the end.\n\t *\n\t * **NOTE** If `reject()` has already been called, this method has no effect.\n\t */\n\temitMany(values: T[]): void;\n\t/**\n\t * Writing an error will permanently invalidate this iterable.\n\t * The current users will receive an error thrown, as will all future users.\n\t *\n\t * **NOTE** If `reject()` have already been called, this method has no effect.\n\t */\n\treject(error: Error): void;\n}\n\n/**\n * An executor for the `AsyncIterableObject` that has access to an emitter.\n */\nexport interface AsyncIterableExecutor {\n\t/**\n\t * @param emitter An object that allows to emit async values valid only for the duration of the executor.\n\t */\n\t(emitter: AsyncIterableEmitter): void | Promise;\n}\n\n/**\n * A rich implementation for an `AsyncIterable`.\n */\nexport class AsyncIterableObject implements AsyncIterable {\n\n\tpublic static fromArray(items: T[]): AsyncIterableObject {\n\t\treturn new AsyncIterableObject((writer) => {\n\t\t\twriter.emitMany(items);\n\t\t});\n\t}\n\n\tpublic static fromPromise(promise: Promise): AsyncIterableObject {\n\t\treturn new AsyncIterableObject(async (emitter) => {\n\t\t\temitter.emitMany(await promise);\n\t\t});\n\t}\n\n\tpublic static fromPromises(promises: Promise[]): AsyncIterableObject {\n\t\treturn new AsyncIterableObject(async (emitter) => {\n\t\t\tawait Promise.all(promises.map(async (p) => emitter.emitOne(await p)));\n\t\t});\n\t}\n\n\tpublic static merge(iterables: AsyncIterable[]): AsyncIterableObject {\n\t\treturn new AsyncIterableObject(async (emitter) => {\n\t\t\tawait Promise.all(iterables.map(async (iterable) => {\n\t\t\t\tfor await (const item of iterable) {\n\t\t\t\t\temitter.emitOne(item);\n\t\t\t\t}\n\t\t\t}));\n\t\t});\n\t}\n\n\tpublic static EMPTY = AsyncIterableObject.fromArray([]);\n\n\tprivate _state: AsyncIterableSourceState;\n\tprivate _results: T[];\n\tprivate _error: Error | null;\n\tprivate readonly _onReturn?: () => void | Promise;\n\tprivate readonly _onStateChanged: Emitter;\n\n\tconstructor(executor: AsyncIterableExecutor, onReturn?: () => void | Promise) {\n\t\tthis._state = AsyncIterableSourceState.Initial;\n\t\tthis._results = [];\n\t\tthis._error = null;\n\t\tthis._onReturn = onReturn;\n\t\tthis._onStateChanged = new Emitter();\n\n\t\tqueueMicrotask(async () => {\n\t\t\tconst writer: AsyncIterableEmitter = {\n\t\t\t\temitOne: (item) => this.emitOne(item),\n\t\t\t\temitMany: (items) => this.emitMany(items),\n\t\t\t\treject: (error) => this.reject(error)\n\t\t\t};\n\t\t\ttry {\n\t\t\t\tawait Promise.resolve(executor(writer));\n\t\t\t\tthis.resolve();\n\t\t\t} catch (err) {\n\t\t\t\tthis.reject(err);\n\t\t\t} finally {\n\t\t\t\twriter.emitOne = undefined!;\n\t\t\t\twriter.emitMany = undefined!;\n\t\t\t\twriter.reject = undefined!;\n\t\t\t}\n\t\t});\n\t}\n\n\t[Symbol.asyncIterator](): AsyncIterator {\n\t\tlet i = 0;\n\t\treturn {\n\t\t\tnext: async () => {\n\t\t\t\tdo {\n\t\t\t\t\tif (this._state === AsyncIterableSourceState.DoneError) {\n\t\t\t\t\t\tthrow this._error;\n\t\t\t\t\t}\n\t\t\t\t\tif (i < this._results.length) {\n\t\t\t\t\t\treturn { done: false, value: this._results[i++] };\n\t\t\t\t\t}\n\t\t\t\t\tif (this._state === AsyncIterableSourceState.DoneOK) {\n\t\t\t\t\t\treturn { done: true, value: undefined };\n\t\t\t\t\t}\n\t\t\t\t\tawait Event.toPromise(this._onStateChanged.event);\n\t\t\t\t} while (true);\n\t\t\t},\n\t\t\treturn: async () => {\n\t\t\t\tthis._onReturn?.();\n\t\t\t\treturn { done: true, value: undefined };\n\t\t\t}\n\t\t};\n\t}\n\n\tpublic static map(iterable: AsyncIterable, mapFn: (item: T) => R): AsyncIterableObject {\n\t\treturn new AsyncIterableObject(async (emitter) => {\n\t\t\tfor await (const item of iterable) {\n\t\t\t\temitter.emitOne(mapFn(item));\n\t\t\t}\n\t\t});\n\t}\n\n\tpublic map(mapFn: (item: T) => R): AsyncIterableObject {\n\t\treturn AsyncIterableObject.map(this, mapFn);\n\t}\n\n\tpublic static filter(iterable: AsyncIterable, filterFn: (item: T) => boolean): AsyncIterableObject {\n\t\treturn new AsyncIterableObject(async (emitter) => {\n\t\t\tfor await (const item of iterable) {\n\t\t\t\tif (filterFn(item)) {\n\t\t\t\t\temitter.emitOne(item);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\tpublic filter(filterFn: (item: T) => boolean): AsyncIterableObject {\n\t\treturn AsyncIterableObject.filter(this, filterFn);\n\t}\n\n\tpublic static coalesce(iterable: AsyncIterable): AsyncIterableObject {\n\t\treturn >AsyncIterableObject.filter(iterable, item => !!item);\n\t}\n\n\tpublic coalesce(): AsyncIterableObject> {\n\t\treturn AsyncIterableObject.coalesce(this) as AsyncIterableObject>;\n\t}\n\n\tpublic static async toPromise(iterable: AsyncIterable): Promise {\n\t\tconst result: T[] = [];\n\t\tfor await (const item of iterable) {\n\t\t\tresult.push(item);\n\t\t}\n\t\treturn result;\n\t}\n\n\tpublic toPromise(): Promise {\n\t\treturn AsyncIterableObject.toPromise(this);\n\t}\n\n\t/**\n\t * The value will be appended at the end.\n\t *\n\t * **NOTE** If `resolve()` or `reject()` have already been called, this method has no effect.\n\t */\n\tprivate emitOne(value: T): void {\n\t\tif (this._state !== AsyncIterableSourceState.Initial) {\n\t\t\treturn;\n\t\t}\n\t\t// it is important to add new values at the end,\n\t\t// as we may have iterators already running on the array\n\t\tthis._results.push(value);\n\t\tthis._onStateChanged.fire();\n\t}\n\n\t/**\n\t * The values will be appended at the end.\n\t *\n\t * **NOTE** If `resolve()` or `reject()` have already been called, this method has no effect.\n\t */\n\tprivate emitMany(values: T[]): void {\n\t\tif (this._state !== AsyncIterableSourceState.Initial) {\n\t\t\treturn;\n\t\t}\n\t\t// it is important to add new values at the end,\n\t\t// as we may have iterators already running on the array\n\t\tthis._results = this._results.concat(values);\n\t\tthis._onStateChanged.fire();\n\t}\n\n\t/**\n\t * Calling `resolve()` will mark the result array as complete.\n\t *\n\t * **NOTE** `resolve()` must be called, otherwise all consumers of this iterable will hang indefinitely, similar to a non-resolved promise.\n\t * **NOTE** If `resolve()` or `reject()` have already been called, this method has no effect.\n\t */\n\tprivate resolve(): void {\n\t\tif (this._state !== AsyncIterableSourceState.Initial) {\n\t\t\treturn;\n\t\t}\n\t\tthis._state = AsyncIterableSourceState.DoneOK;\n\t\tthis._onStateChanged.fire();\n\t}\n\n\t/**\n\t * Writing an error will permanently invalidate this iterable.\n\t * The current users will receive an error thrown, as will all future users.\n\t *\n\t * **NOTE** If `resolve()` or `reject()` have already been called, this method has no effect.\n\t */\n\tprivate reject(error: Error) {\n\t\tif (this._state !== AsyncIterableSourceState.Initial) {\n\t\t\treturn;\n\t\t}\n\t\tthis._state = AsyncIterableSourceState.DoneError;\n\t\tthis._error = error;\n\t\tthis._onStateChanged.fire();\n\t}\n}\n\nexport class CancelableAsyncIterableObject extends AsyncIterableObject {\n\tconstructor(\n\t\tprivate readonly _source: CancellationTokenSource,\n\t\texecutor: AsyncIterableExecutor\n\t) {\n\t\tsuper(executor);\n\t}\n\n\tcancel(): void {\n\t\tthis._source.cancel();\n\t}\n}\n\nexport function createCancelableAsyncIterable(callback: (token: CancellationToken) => AsyncIterable): CancelableAsyncIterableObject {\n\tconst source = new CancellationTokenSource();\n\tconst innerIterable = callback(source.token);\n\n\treturn new CancelableAsyncIterableObject(source, async (emitter) => {\n\t\tconst subscription = source.token.onCancellationRequested(() => {\n\t\t\tsubscription.dispose();\n\t\t\tsource.dispose();\n\t\t\temitter.reject(new CancellationError());\n\t\t});\n\t\ttry {\n\t\t\tfor await (const item of innerIterable) {\n\t\t\t\tif (source.token.isCancellationRequested) {\n\t\t\t\t\t// canceled in the meantime\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\temitter.emitOne(item);\n\t\t\t}\n\t\t\tsubscription.dispose();\n\t\t\tsource.dispose();\n\t\t} catch (err) {\n\t\t\tsubscription.dispose();\n\t\t\tsource.dispose();\n\t\t\temitter.reject(err);\n\t\t}\n\t});\n}\n\n//#endregion\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\nimport { FastDomNode } from 'vs/base/browser/fastDomNode';\nimport { TimeoutTimer } from 'vs/base/common/async';\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport { ScrollbarVisibility } from 'vs/base/common/scrollable';\n\nexport class ScrollbarVisibilityController extends Disposable {\n\tprivate _visibility: ScrollbarVisibility;\n\tprivate _visibleClassName: string;\n\tprivate _invisibleClassName: string;\n\tprivate _domNode: FastDomNode | null;\n\tprivate _rawShouldBeVisible: boolean;\n\tprivate _shouldBeVisible: boolean;\n\tprivate _isNeeded: boolean;\n\tprivate _isVisible: boolean;\n\tprivate _revealTimer: TimeoutTimer;\n\n\tconstructor(visibility: ScrollbarVisibility, visibleClassName: string, invisibleClassName: string) {\n\t\tsuper();\n\t\tthis._visibility = visibility;\n\t\tthis._visibleClassName = visibleClassName;\n\t\tthis._invisibleClassName = invisibleClassName;\n\t\tthis._domNode = null;\n\t\tthis._isVisible = false;\n\t\tthis._isNeeded = false;\n\t\tthis._rawShouldBeVisible = false;\n\t\tthis._shouldBeVisible = false;\n\t\tthis._revealTimer = this._register(new TimeoutTimer());\n\t}\n\n\tpublic setVisibility(visibility: ScrollbarVisibility): void {\n\t\tif (this._visibility !== visibility) {\n\t\t\tthis._visibility = visibility;\n\t\t\tthis._updateShouldBeVisible();\n\t\t}\n\t}\n\n\t// ----------------- Hide / Reveal\n\n\tpublic setShouldBeVisible(rawShouldBeVisible: boolean): void {\n\t\tthis._rawShouldBeVisible = rawShouldBeVisible;\n\t\tthis._updateShouldBeVisible();\n\t}\n\n\tprivate _applyVisibilitySetting(): boolean {\n\t\tif (this._visibility === ScrollbarVisibility.Hidden) {\n\t\t\treturn false;\n\t\t}\n\t\tif (this._visibility === ScrollbarVisibility.Visible) {\n\t\t\treturn true;\n\t\t}\n\t\treturn this._rawShouldBeVisible;\n\t}\n\n\tprivate _updateShouldBeVisible(): void {\n\t\tconst shouldBeVisible = this._applyVisibilitySetting();\n\n\t\tif (this._shouldBeVisible !== shouldBeVisible) {\n\t\t\tthis._shouldBeVisible = shouldBeVisible;\n\t\t\tthis.ensureVisibility();\n\t\t}\n\t}\n\n\tpublic setIsNeeded(isNeeded: boolean): void {\n\t\tif (this._isNeeded !== isNeeded) {\n\t\t\tthis._isNeeded = isNeeded;\n\t\t\tthis.ensureVisibility();\n\t\t}\n\t}\n\n\tpublic setDomNode(domNode: FastDomNode): void {\n\t\tthis._domNode = domNode;\n\t\tthis._domNode.setClassName(this._invisibleClassName);\n\n\t\t// Now that the flags & the dom node are in a consistent state, ensure the Hidden/Visible configuration\n\t\tthis.setShouldBeVisible(false);\n\t}\n\n\tpublic ensureVisibility(): void {\n\n\t\tif (!this._isNeeded) {\n\t\t\t// Nothing to be rendered\n\t\t\tthis._hide(false);\n\t\t\treturn;\n\t\t}\n\n\t\tif (this._shouldBeVisible) {\n\t\t\tthis._reveal();\n\t\t} else {\n\t\t\tthis._hide(true);\n\t\t}\n\t}\n\n\tprivate _reveal(): void {\n\t\tif (this._isVisible) {\n\t\t\treturn;\n\t\t}\n\t\tthis._isVisible = true;\n\n\t\t// The CSS animation doesn't play otherwise\n\t\tthis._revealTimer.setIfNotSet(() => {\n\t\t\tthis._domNode?.setClassName(this._visibleClassName);\n\t\t}, 0);\n\t}\n\n\tprivate _hide(withFadeAway: boolean): void {\n\t\tthis._revealTimer.cancel();\n\t\tif (!this._isVisible) {\n\t\t\treturn;\n\t\t}\n\t\tthis._isVisible = false;\n\t\tthis._domNode?.setClassName(this._invisibleClassName + (withFadeAway ? ' fade' : ''));\n\t}\n}\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\nimport { IIdentityProvider } from 'vs/base/browser/ui/list/list';\nimport { ICollapseStateChangeEvent, ITreeElement, ITreeFilter, ITreeFilterDataResult, ITreeModel, ITreeModelSpliceEvent, ITreeNode, TreeError, TreeVisibility } from 'vs/base/browser/ui/tree/tree';\nimport { splice, tail2 } from 'vs/base/common/arrays';\nimport { Delayer } from 'vs/base/common/async';\nimport { MicrotaskDelay } from 'vs/base/common/symbols';\nimport { LcsDiff } from 'vs/base/common/diff/diff';\nimport { Emitter, Event, EventBufferer } from 'vs/base/common/event';\nimport { Iterable } from 'vs/base/common/iterator';\nimport { ISpliceable } from 'vs/base/common/sequence';\n\n// Exported for tests\nexport interface IIndexTreeNode extends ITreeNode {\n\treadonly parent: IIndexTreeNode | undefined;\n\treadonly children: IIndexTreeNode[];\n\tvisibleChildrenCount: number;\n\tvisibleChildIndex: number;\n\tcollapsible: boolean;\n\tcollapsed: boolean;\n\trenderNodeCount: number;\n\tvisibility: TreeVisibility;\n\tvisible: boolean;\n\tfilterData: TFilterData | undefined;\n\tlastDiffIds?: string[];\n}\n\nexport function isFilterResult(obj: any): obj is ITreeFilterDataResult {\n\treturn typeof obj === 'object' && 'visibility' in obj && 'data' in obj;\n}\n\nexport function getVisibleState(visibility: boolean | TreeVisibility): TreeVisibility {\n\tswitch (visibility) {\n\t\tcase true: return TreeVisibility.Visible;\n\t\tcase false: return TreeVisibility.Hidden;\n\t\tdefault: return visibility;\n\t}\n}\n\nexport interface IIndexTreeModelOptions {\n\treadonly collapseByDefault?: boolean; // defaults to false\n\treadonly allowNonCollapsibleParents?: boolean; // defaults to false\n\treadonly filter?: ITreeFilter;\n\treadonly autoExpandSingleChildren?: boolean;\n}\n\nexport interface IIndexTreeModelSpliceOptions {\n\t/**\n\t * If set, child updates will recurse the given number of levels even if\n\t * items in the splice operation are unchanged. `Infinity` is a valid value.\n\t */\n\treadonly diffDepth?: number;\n\n\t/**\n\t * Identity provider used to optimize splice() calls in the IndexTree. If\n\t * this is not present, optimized splicing is not enabled.\n\t *\n\t * Warning: if this is present, calls to `setChildren()` will not replace\n\t * or update nodes if their identity is the same, even if the elements are\n\t * different. For this, you should call `rerender()`.\n\t */\n\treadonly diffIdentityProvider?: IIdentityProvider;\n\n\t/**\n\t * Callback for when a node is created.\n\t */\n\tonDidCreateNode?: (node: ITreeNode) => void;\n\n\t/**\n\t * Callback for when a node is deleted.\n\t */\n\tonDidDeleteNode?: (node: ITreeNode) => void;\n}\n\ninterface CollapsibleStateUpdate {\n\treadonly collapsible: boolean;\n}\n\ninterface CollapsedStateUpdate {\n\treadonly collapsed: boolean;\n\treadonly recursive: boolean;\n}\n\ntype CollapseStateUpdate = CollapsibleStateUpdate | CollapsedStateUpdate;\n\nfunction isCollapsibleStateUpdate(update: CollapseStateUpdate): update is CollapsibleStateUpdate {\n\treturn typeof (update as any).collapsible === 'boolean';\n}\n\nexport interface IList extends ISpliceable {\n\tupdateElementHeight(index: number, height: number | undefined): void;\n}\n\nexport class IndexTreeModel, TFilterData = void> implements ITreeModel {\n\n\treadonly rootRef = [];\n\n\tprivate root: IIndexTreeNode;\n\tprivate eventBufferer = new EventBufferer();\n\n\tprivate readonly _onDidChangeCollapseState = new Emitter>();\n\treadonly onDidChangeCollapseState: Event> = this.eventBufferer.wrapEvent(this._onDidChangeCollapseState.event);\n\n\tprivate readonly _onDidChangeRenderNodeCount = new Emitter>();\n\treadonly onDidChangeRenderNodeCount: Event> = this.eventBufferer.wrapEvent(this._onDidChangeRenderNodeCount.event);\n\n\tprivate collapseByDefault: boolean;\n\tprivate allowNonCollapsibleParents: boolean;\n\tprivate filter?: ITreeFilter;\n\tprivate autoExpandSingleChildren: boolean;\n\n\tprivate readonly _onDidSplice = new Emitter>();\n\treadonly onDidSplice = this._onDidSplice.event;\n\n\tprivate readonly refilterDelayer = new Delayer(MicrotaskDelay);\n\n\tconstructor(\n\t\tprivate user: string,\n\t\tprivate list: IList>,\n\t\trootElement: T,\n\t\toptions: IIndexTreeModelOptions = {}\n\t) {\n\t\tthis.collapseByDefault = typeof options.collapseByDefault === 'undefined' ? false : options.collapseByDefault;\n\t\tthis.allowNonCollapsibleParents = options.allowNonCollapsibleParents ?? false;\n\t\tthis.filter = options.filter;\n\t\tthis.autoExpandSingleChildren = typeof options.autoExpandSingleChildren === 'undefined' ? false : options.autoExpandSingleChildren;\n\n\t\tthis.root = {\n\t\t\tparent: undefined,\n\t\t\telement: rootElement,\n\t\t\tchildren: [],\n\t\t\tdepth: 0,\n\t\t\tvisibleChildrenCount: 0,\n\t\t\tvisibleChildIndex: -1,\n\t\t\tcollapsible: false,\n\t\t\tcollapsed: false,\n\t\t\trenderNodeCount: 0,\n\t\t\tvisibility: TreeVisibility.Visible,\n\t\t\tvisible: true,\n\t\t\tfilterData: undefined\n\t\t};\n\t}\n\n\tsplice(\n\t\tlocation: number[],\n\t\tdeleteCount: number,\n\t\ttoInsert: Iterable> = Iterable.empty(),\n\t\toptions: IIndexTreeModelSpliceOptions = {},\n\t): void {\n\t\tif (location.length === 0) {\n\t\t\tthrow new TreeError(this.user, 'Invalid tree location');\n\t\t}\n\n\t\tif (options.diffIdentityProvider) {\n\t\t\tthis.spliceSmart(options.diffIdentityProvider, location, deleteCount, toInsert, options);\n\t\t} else {\n\t\t\tthis.spliceSimple(location, deleteCount, toInsert, options);\n\t\t}\n\t}\n\n\tprivate spliceSmart(\n\t\tidentity: IIdentityProvider,\n\t\tlocation: number[],\n\t\tdeleteCount: number,\n\t\ttoInsertIterable: Iterable> = Iterable.empty(),\n\t\toptions: IIndexTreeModelSpliceOptions,\n\t\trecurseLevels = options.diffDepth ?? 0,\n\t) {\n\t\tconst { parentNode } = this.getParentNodeWithListIndex(location);\n\t\tif (!parentNode.lastDiffIds) {\n\t\t\treturn this.spliceSimple(location, deleteCount, toInsertIterable, options);\n\t\t}\n\n\t\tconst toInsert = [...toInsertIterable];\n\t\tconst index = location[location.length - 1];\n\t\tconst diff = new LcsDiff(\n\t\t\t{ getElements: () => parentNode.lastDiffIds! },\n\t\t\t{\n\t\t\t\tgetElements: () => [\n\t\t\t\t\t...parentNode.children.slice(0, index),\n\t\t\t\t\t...toInsert,\n\t\t\t\t\t...parentNode.children.slice(index + deleteCount),\n\t\t\t\t].map(e => identity.getId(e.element).toString())\n\t\t\t},\n\t\t).ComputeDiff(false);\n\n\t\t// if we were given a 'best effort' diff, use default behavior\n\t\tif (diff.quitEarly) {\n\t\t\tparentNode.lastDiffIds = undefined;\n\t\t\treturn this.spliceSimple(location, deleteCount, toInsert, options);\n\t\t}\n\n\t\tconst locationPrefix = location.slice(0, -1);\n\t\tconst recurseSplice = (fromOriginal: number, fromModified: number, count: number) => {\n\t\t\tif (recurseLevels > 0) {\n\t\t\t\tfor (let i = 0; i < count; i++) {\n\t\t\t\t\tfromOriginal--;\n\t\t\t\t\tfromModified--;\n\t\t\t\t\tthis.spliceSmart(\n\t\t\t\t\t\tidentity,\n\t\t\t\t\t\t[...locationPrefix, fromOriginal, 0],\n\t\t\t\t\t\tNumber.MAX_SAFE_INTEGER,\n\t\t\t\t\t\ttoInsert[fromModified].children,\n\t\t\t\t\t\toptions,\n\t\t\t\t\t\trecurseLevels - 1,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tlet lastStartO = Math.min(parentNode.children.length, index + deleteCount);\n\t\tlet lastStartM = toInsert.length;\n\t\tfor (const change of diff.changes.sort((a, b) => b.originalStart - a.originalStart)) {\n\t\t\trecurseSplice(lastStartO, lastStartM, lastStartO - (change.originalStart + change.originalLength));\n\t\t\tlastStartO = change.originalStart;\n\t\t\tlastStartM = change.modifiedStart - index;\n\n\t\t\tthis.spliceSimple(\n\t\t\t\t[...locationPrefix, lastStartO],\n\t\t\t\tchange.originalLength,\n\t\t\t\tIterable.slice(toInsert, lastStartM, lastStartM + change.modifiedLength),\n\t\t\t\toptions,\n\t\t\t);\n\t\t}\n\n\t\t// at this point, startO === startM === count since any remaining prefix should match\n\t\trecurseSplice(lastStartO, lastStartM, lastStartO);\n\t}\n\n\tprivate spliceSimple(\n\t\tlocation: number[],\n\t\tdeleteCount: number,\n\t\ttoInsert: Iterable> = Iterable.empty(),\n\t\t{ onDidCreateNode, onDidDeleteNode, diffIdentityProvider }: IIndexTreeModelSpliceOptions,\n\t) {\n\t\tconst { parentNode, listIndex, revealed, visible } = this.getParentNodeWithListIndex(location);\n\t\tconst treeListElementsToInsert: ITreeNode[] = [];\n\t\tconst nodesToInsertIterator = Iterable.map(toInsert, el => this.createTreeNode(el, parentNode, parentNode.visible ? TreeVisibility.Visible : TreeVisibility.Hidden, revealed, treeListElementsToInsert, onDidCreateNode));\n\n\t\tconst lastIndex = location[location.length - 1];\n\n\t\t// figure out what's the visible child start index right before the\n\t\t// splice point\n\t\tlet visibleChildStartIndex = 0;\n\n\t\tfor (let i = lastIndex; i >= 0 && i < parentNode.children.length; i--) {\n\t\t\tconst child = parentNode.children[i];\n\n\t\t\tif (child.visible) {\n\t\t\t\tvisibleChildStartIndex = child.visibleChildIndex;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tconst nodesToInsert: IIndexTreeNode[] = [];\n\t\tlet insertedVisibleChildrenCount = 0;\n\t\tlet renderNodeCount = 0;\n\n\t\tfor (const child of nodesToInsertIterator) {\n\t\t\tnodesToInsert.push(child);\n\t\t\trenderNodeCount += child.renderNodeCount;\n\n\t\t\tif (child.visible) {\n\t\t\t\tchild.visibleChildIndex = visibleChildStartIndex + insertedVisibleChildrenCount++;\n\t\t\t}\n\t\t}\n\n\t\tconst deletedNodes = splice(parentNode.children, lastIndex, deleteCount, nodesToInsert);\n\n\t\tif (!diffIdentityProvider) {\n\t\t\tparentNode.lastDiffIds = undefined;\n\t\t} else if (parentNode.lastDiffIds) {\n\t\t\tsplice(parentNode.lastDiffIds, lastIndex, deleteCount, nodesToInsert.map(n => diffIdentityProvider.getId(n.element).toString()));\n\t\t} else {\n\t\t\tparentNode.lastDiffIds = parentNode.children.map(n => diffIdentityProvider.getId(n.element).toString());\n\t\t}\n\n\t\t// figure out what is the count of deleted visible children\n\t\tlet deletedVisibleChildrenCount = 0;\n\n\t\tfor (const child of deletedNodes) {\n\t\t\tif (child.visible) {\n\t\t\t\tdeletedVisibleChildrenCount++;\n\t\t\t}\n\t\t}\n\n\t\t// and adjust for all visible children after the splice point\n\t\tif (deletedVisibleChildrenCount !== 0) {\n\t\t\tfor (let i = lastIndex + nodesToInsert.length; i < parentNode.children.length; i++) {\n\t\t\t\tconst child = parentNode.children[i];\n\n\t\t\t\tif (child.visible) {\n\t\t\t\t\tchild.visibleChildIndex -= deletedVisibleChildrenCount;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// update parent's visible children count\n\t\tparentNode.visibleChildrenCount += insertedVisibleChildrenCount - deletedVisibleChildrenCount;\n\n\t\tif (revealed && visible) {\n\t\t\tconst visibleDeleteCount = deletedNodes.reduce((r, node) => r + (node.visible ? node.renderNodeCount : 0), 0);\n\n\t\t\tthis._updateAncestorsRenderNodeCount(parentNode, renderNodeCount - visibleDeleteCount);\n\t\t\tthis.list.splice(listIndex, visibleDeleteCount, treeListElementsToInsert);\n\t\t}\n\n\t\tif (deletedNodes.length > 0 && onDidDeleteNode) {\n\t\t\tconst visit = (node: ITreeNode) => {\n\t\t\t\tonDidDeleteNode(node);\n\t\t\t\tnode.children.forEach(visit);\n\t\t\t};\n\n\t\t\tdeletedNodes.forEach(visit);\n\t\t}\n\n\t\tthis._onDidSplice.fire({ insertedNodes: nodesToInsert, deletedNodes });\n\n\t\tlet node: IIndexTreeNode | undefined = parentNode;\n\n\t\twhile (node) {\n\t\t\tif (node.visibility === TreeVisibility.Recurse) {\n\t\t\t\t// delayed to avoid excessive refiltering, see #135941\n\t\t\t\tthis.refilterDelayer.trigger(() => this.refilter());\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tnode = node.parent;\n\t\t}\n\t}\n\n\trerender(location: number[]): void {\n\t\tif (location.length === 0) {\n\t\t\tthrow new TreeError(this.user, 'Invalid tree location');\n\t\t}\n\n\t\tconst { node, listIndex, revealed } = this.getTreeNodeWithListIndex(location);\n\n\t\tif (node.visible && revealed) {\n\t\t\tthis.list.splice(listIndex, 1, [node]);\n\t\t}\n\t}\n\n\thas(location: number[]): boolean {\n\t\treturn this.hasTreeNode(location);\n\t}\n\n\tgetListIndex(location: number[]): number {\n\t\tconst { listIndex, visible, revealed } = this.getTreeNodeWithListIndex(location);\n\t\treturn visible && revealed ? listIndex : -1;\n\t}\n\n\tgetListRenderCount(location: number[]): number {\n\t\treturn this.getTreeNode(location).renderNodeCount;\n\t}\n\n\tisCollapsible(location: number[]): boolean {\n\t\treturn this.getTreeNode(location).collapsible;\n\t}\n\n\tsetCollapsible(location: number[], collapsible?: boolean): boolean {\n\t\tconst node = this.getTreeNode(location);\n\n\t\tif (typeof collapsible === 'undefined') {\n\t\t\tcollapsible = !node.collapsible;\n\t\t}\n\n\t\tconst update: CollapsibleStateUpdate = { collapsible };\n\t\treturn this.eventBufferer.bufferEvents(() => this._setCollapseState(location, update));\n\t}\n\n\tisCollapsed(location: number[]): boolean {\n\t\treturn this.getTreeNode(location).collapsed;\n\t}\n\n\tsetCollapsed(location: number[], collapsed?: boolean, recursive?: boolean): boolean {\n\t\tconst node = this.getTreeNode(location);\n\n\t\tif (typeof collapsed === 'undefined') {\n\t\t\tcollapsed = !node.collapsed;\n\t\t}\n\n\t\tconst update: CollapsedStateUpdate = { collapsed, recursive: recursive || false };\n\t\treturn this.eventBufferer.bufferEvents(() => this._setCollapseState(location, update));\n\t}\n\n\tprivate _setCollapseState(location: number[], update: CollapseStateUpdate): boolean {\n\t\tconst { node, listIndex, revealed } = this.getTreeNodeWithListIndex(location);\n\n\t\tconst result = this._setListNodeCollapseState(node, listIndex, revealed, update);\n\n\t\tif (node !== this.root && this.autoExpandSingleChildren && result && !isCollapsibleStateUpdate(update) && node.collapsible && !node.collapsed && !update.recursive) {\n\t\t\tlet onlyVisibleChildIndex = -1;\n\n\t\t\tfor (let i = 0; i < node.children.length; i++) {\n\t\t\t\tconst child = node.children[i];\n\n\t\t\t\tif (child.visible) {\n\t\t\t\t\tif (onlyVisibleChildIndex > -1) {\n\t\t\t\t\t\tonlyVisibleChildIndex = -1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tonlyVisibleChildIndex = i;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (onlyVisibleChildIndex > -1) {\n\t\t\t\tthis._setCollapseState([...location, onlyVisibleChildIndex], update);\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tprivate _setListNodeCollapseState(node: IIndexTreeNode, listIndex: number, revealed: boolean, update: CollapseStateUpdate): boolean {\n\t\tconst result = this._setNodeCollapseState(node, update, false);\n\n\t\tif (!revealed || !node.visible || !result) {\n\t\t\treturn result;\n\t\t}\n\n\t\tconst previousRenderNodeCount = node.renderNodeCount;\n\t\tconst toInsert = this.updateNodeAfterCollapseChange(node);\n\t\tconst deleteCount = previousRenderNodeCount - (listIndex === -1 ? 0 : 1);\n\t\tthis.list.splice(listIndex + 1, deleteCount, toInsert.slice(1));\n\n\t\treturn result;\n\t}\n\n\tprivate _setNodeCollapseState(node: IIndexTreeNode, update: CollapseStateUpdate, deep: boolean): boolean {\n\t\tlet result: boolean;\n\n\t\tif (node === this.root) {\n\t\t\tresult = false;\n\t\t} else {\n\t\t\tif (isCollapsibleStateUpdate(update)) {\n\t\t\t\tresult = node.collapsible !== update.collapsible;\n\t\t\t\tnode.collapsible = update.collapsible;\n\t\t\t} else if (!node.collapsible) {\n\t\t\t\tresult = false;\n\t\t\t} else {\n\t\t\t\tresult = node.collapsed !== update.collapsed;\n\t\t\t\tnode.collapsed = update.collapsed;\n\t\t\t}\n\n\t\t\tif (result) {\n\t\t\t\tthis._onDidChangeCollapseState.fire({ node, deep });\n\t\t\t}\n\t\t}\n\n\t\tif (!isCollapsibleStateUpdate(update) && update.recursive) {\n\t\t\tfor (const child of node.children) {\n\t\t\t\tresult = this._setNodeCollapseState(child, update, true) || result;\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\texpandTo(location: number[]): void {\n\t\tthis.eventBufferer.bufferEvents(() => {\n\t\t\tlet node = this.getTreeNode(location);\n\n\t\t\twhile (node.parent) {\n\t\t\t\tnode = node.parent;\n\t\t\t\tlocation = location.slice(0, location.length - 1);\n\n\t\t\t\tif (node.collapsed) {\n\t\t\t\t\tthis._setCollapseState(location, { collapsed: false, recursive: false });\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\trefilter(): void {\n\t\tconst previousRenderNodeCount = this.root.renderNodeCount;\n\t\tconst toInsert = this.updateNodeAfterFilterChange(this.root);\n\t\tthis.list.splice(0, previousRenderNodeCount, toInsert);\n\t\tthis.refilterDelayer.cancel();\n\t}\n\n\tprivate createTreeNode(\n\t\ttreeElement: ITreeElement,\n\t\tparent: IIndexTreeNode,\n\t\tparentVisibility: TreeVisibility,\n\t\trevealed: boolean,\n\t\ttreeListElements: ITreeNode[],\n\t\tonDidCreateNode?: (node: ITreeNode) => void\n\t): IIndexTreeNode {\n\t\tconst node: IIndexTreeNode = {\n\t\t\tparent,\n\t\t\telement: treeElement.element,\n\t\t\tchildren: [],\n\t\t\tdepth: parent.depth + 1,\n\t\t\tvisibleChildrenCount: 0,\n\t\t\tvisibleChildIndex: -1,\n\t\t\tcollapsible: typeof treeElement.collapsible === 'boolean' ? treeElement.collapsible : (typeof treeElement.collapsed !== 'undefined'),\n\t\t\tcollapsed: typeof treeElement.collapsed === 'undefined' ? this.collapseByDefault : treeElement.collapsed,\n\t\t\trenderNodeCount: 1,\n\t\t\tvisibility: TreeVisibility.Visible,\n\t\t\tvisible: true,\n\t\t\tfilterData: undefined\n\t\t};\n\n\t\tconst visibility = this._filterNode(node, parentVisibility);\n\t\tnode.visibility = visibility;\n\n\t\tif (revealed) {\n\t\t\ttreeListElements.push(node);\n\t\t}\n\n\t\tconst childElements = treeElement.children || Iterable.empty();\n\t\tconst childRevealed = revealed && visibility !== TreeVisibility.Hidden && !node.collapsed;\n\n\t\tlet visibleChildrenCount = 0;\n\t\tlet renderNodeCount = 1;\n\n\t\tfor (const el of childElements) {\n\t\t\tconst child = this.createTreeNode(el, node, visibility, childRevealed, treeListElements, onDidCreateNode);\n\t\t\tnode.children.push(child);\n\t\t\trenderNodeCount += child.renderNodeCount;\n\n\t\t\tif (child.visible) {\n\t\t\t\tchild.visibleChildIndex = visibleChildrenCount++;\n\t\t\t}\n\t\t}\n\n\t\tif (!this.allowNonCollapsibleParents) {\n\t\t\tnode.collapsible = node.collapsible || node.children.length > 0;\n\t\t}\n\n\t\tnode.visibleChildrenCount = visibleChildrenCount;\n\t\tnode.visible = visibility === TreeVisibility.Recurse ? visibleChildrenCount > 0 : (visibility === TreeVisibility.Visible);\n\n\t\tif (!node.visible) {\n\t\t\tnode.renderNodeCount = 0;\n\n\t\t\tif (revealed) {\n\t\t\t\ttreeListElements.pop();\n\t\t\t}\n\t\t} else if (!node.collapsed) {\n\t\t\tnode.renderNodeCount = renderNodeCount;\n\t\t}\n\n\t\tonDidCreateNode?.(node);\n\n\t\treturn node;\n\t}\n\n\tprivate updateNodeAfterCollapseChange(node: IIndexTreeNode): ITreeNode[] {\n\t\tconst previousRenderNodeCount = node.renderNodeCount;\n\t\tconst result: ITreeNode[] = [];\n\n\t\tthis._updateNodeAfterCollapseChange(node, result);\n\t\tthis._updateAncestorsRenderNodeCount(node.parent, result.length - previousRenderNodeCount);\n\n\t\treturn result;\n\t}\n\n\tprivate _updateNodeAfterCollapseChange(node: IIndexTreeNode, result: ITreeNode[]): number {\n\t\tif (node.visible === false) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tresult.push(node);\n\t\tnode.renderNodeCount = 1;\n\n\t\tif (!node.collapsed) {\n\t\t\tfor (const child of node.children) {\n\t\t\t\tnode.renderNodeCount += this._updateNodeAfterCollapseChange(child, result);\n\t\t\t}\n\t\t}\n\n\t\tthis._onDidChangeRenderNodeCount.fire(node);\n\t\treturn node.renderNodeCount;\n\t}\n\n\tprivate updateNodeAfterFilterChange(node: IIndexTreeNode): ITreeNode[] {\n\t\tconst previousRenderNodeCount = node.renderNodeCount;\n\t\tconst result: ITreeNode[] = [];\n\n\t\tthis._updateNodeAfterFilterChange(node, node.visible ? TreeVisibility.Visible : TreeVisibility.Hidden, result);\n\t\tthis._updateAncestorsRenderNodeCount(node.parent, result.length - previousRenderNodeCount);\n\n\t\treturn result;\n\t}\n\n\tprivate _updateNodeAfterFilterChange(node: IIndexTreeNode, parentVisibility: TreeVisibility, result: ITreeNode[], revealed = true): boolean {\n\t\tlet visibility: TreeVisibility;\n\n\t\tif (node !== this.root) {\n\t\t\tvisibility = this._filterNode(node, parentVisibility);\n\n\t\t\tif (visibility === TreeVisibility.Hidden) {\n\t\t\t\tnode.visible = false;\n\t\t\t\tnode.renderNodeCount = 0;\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (revealed) {\n\t\t\t\tresult.push(node);\n\t\t\t}\n\t\t}\n\n\t\tconst resultStartLength = result.length;\n\t\tnode.renderNodeCount = node === this.root ? 0 : 1;\n\n\t\tlet hasVisibleDescendants = false;\n\t\tif (!node.collapsed || visibility! !== TreeVisibility.Hidden) {\n\t\t\tlet visibleChildIndex = 0;\n\n\t\t\tfor (const child of node.children) {\n\t\t\t\thasVisibleDescendants = this._updateNodeAfterFilterChange(child, visibility!, result, revealed && !node.collapsed) || hasVisibleDescendants;\n\n\t\t\t\tif (child.visible) {\n\t\t\t\t\tchild.visibleChildIndex = visibleChildIndex++;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tnode.visibleChildrenCount = visibleChildIndex;\n\t\t} else {\n\t\t\tnode.visibleChildrenCount = 0;\n\t\t}\n\n\t\tif (node !== this.root) {\n\t\t\tnode.visible = visibility! === TreeVisibility.Recurse ? hasVisibleDescendants : (visibility! === TreeVisibility.Visible);\n\t\t\tnode.visibility = visibility!;\n\t\t}\n\n\t\tif (!node.visible) {\n\t\t\tnode.renderNodeCount = 0;\n\n\t\t\tif (revealed) {\n\t\t\t\tresult.pop();\n\t\t\t}\n\t\t} else if (!node.collapsed) {\n\t\t\tnode.renderNodeCount += result.length - resultStartLength;\n\t\t}\n\n\t\tthis._onDidChangeRenderNodeCount.fire(node);\n\t\treturn node.visible;\n\t}\n\n\tprivate _updateAncestorsRenderNodeCount(node: IIndexTreeNode | undefined, diff: number): void {\n\t\tif (diff === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\twhile (node) {\n\t\t\tnode.renderNodeCount += diff;\n\t\t\tthis._onDidChangeRenderNodeCount.fire(node);\n\t\t\tnode = node.parent;\n\t\t}\n\t}\n\n\tprivate _filterNode(node: IIndexTreeNode, parentVisibility: TreeVisibility): TreeVisibility {\n\t\tconst result = this.filter ? this.filter.filter(node.element, parentVisibility) : TreeVisibility.Visible;\n\n\t\tif (typeof result === 'boolean') {\n\t\t\tnode.filterData = undefined;\n\t\t\treturn result ? TreeVisibility.Visible : TreeVisibility.Hidden;\n\t\t} else if (isFilterResult(result)) {\n\t\t\tnode.filterData = result.data;\n\t\t\treturn getVisibleState(result.visibility);\n\t\t} else {\n\t\t\tnode.filterData = undefined;\n\t\t\treturn getVisibleState(result);\n\t\t}\n\t}\n\n\t// cheap\n\tprivate hasTreeNode(location: number[], node: IIndexTreeNode = this.root): boolean {\n\t\tif (!location || location.length === 0) {\n\t\t\treturn true;\n\t\t}\n\n\t\tconst [index, ...rest] = location;\n\n\t\tif (index < 0 || index > node.children.length) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn this.hasTreeNode(rest, node.children[index]);\n\t}\n\n\t// cheap\n\tprivate getTreeNode(location: number[], node: IIndexTreeNode = this.root): IIndexTreeNode {\n\t\tif (!location || location.length === 0) {\n\t\t\treturn node;\n\t\t}\n\n\t\tconst [index, ...rest] = location;\n\n\t\tif (index < 0 || index > node.children.length) {\n\t\t\tthrow new TreeError(this.user, 'Invalid tree location');\n\t\t}\n\n\t\treturn this.getTreeNode(rest, node.children[index]);\n\t}\n\n\t// expensive\n\tprivate getTreeNodeWithListIndex(location: number[]): { node: IIndexTreeNode; listIndex: number; revealed: boolean; visible: boolean } {\n\t\tif (location.length === 0) {\n\t\t\treturn { node: this.root, listIndex: -1, revealed: true, visible: false };\n\t\t}\n\n\t\tconst { parentNode, listIndex, revealed, visible } = this.getParentNodeWithListIndex(location);\n\t\tconst index = location[location.length - 1];\n\n\t\tif (index < 0 || index > parentNode.children.length) {\n\t\t\tthrow new TreeError(this.user, 'Invalid tree location');\n\t\t}\n\n\t\tconst node = parentNode.children[index];\n\n\t\treturn { node, listIndex, revealed, visible: visible && node.visible };\n\t}\n\n\tprivate getParentNodeWithListIndex(location: number[], node: IIndexTreeNode = this.root, listIndex: number = 0, revealed = true, visible = true): { parentNode: IIndexTreeNode; listIndex: number; revealed: boolean; visible: boolean } {\n\t\tconst [index, ...rest] = location;\n\n\t\tif (index < 0 || index > node.children.length) {\n\t\t\tthrow new TreeError(this.user, 'Invalid tree location');\n\t\t}\n\n\t\t// TODO@joao perf!\n\t\tfor (let i = 0; i < index; i++) {\n\t\t\tlistIndex += node.children[i].renderNodeCount;\n\t\t}\n\n\t\trevealed = revealed && !node.collapsed;\n\t\tvisible = visible && node.visible;\n\n\t\tif (rest.length === 0) {\n\t\t\treturn { parentNode: node, listIndex, revealed, visible };\n\t\t}\n\n\t\treturn this.getParentNodeWithListIndex(rest, node.children[index], listIndex + 1, revealed, visible);\n\t}\n\n\tgetNode(location: number[] = []): ITreeNode {\n\t\treturn this.getTreeNode(location);\n\t}\n\n\t// TODO@joao perf!\n\tgetNodeLocation(node: ITreeNode): number[] {\n\t\tconst location: number[] = [];\n\t\tlet indexTreeNode = node as IIndexTreeNode; // typing woes\n\n\t\twhile (indexTreeNode.parent) {\n\t\t\tlocation.push(indexTreeNode.parent.children.indexOf(indexTreeNode));\n\t\t\tindexTreeNode = indexTreeNode.parent;\n\t\t}\n\n\t\treturn location.reverse();\n\t}\n\n\tgetParentNodeLocation(location: number[]): number[] | undefined {\n\t\tif (location.length === 0) {\n\t\t\treturn undefined;\n\t\t} else if (location.length === 1) {\n\t\t\treturn [];\n\t\t} else {\n\t\t\treturn tail2(location)[0];\n\t\t}\n\t}\n\n\tgetFirstElementChild(location: number[]): T | undefined {\n\t\tconst node = this.getTreeNode(location);\n\n\t\tif (node.children.length === 0) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\treturn node.children[0].element;\n\t}\n}\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\nimport { IIdentityProvider } from 'vs/base/browser/ui/list/list';\nimport { IIndexTreeModelOptions, IIndexTreeModelSpliceOptions, IList, IndexTreeModel } from 'vs/base/browser/ui/tree/indexTreeModel';\nimport { ICollapseStateChangeEvent, IObjectTreeElement, ITreeElement, ITreeModel, ITreeModelSpliceEvent, ITreeNode, ITreeSorter, ObjectTreeElementCollapseState, TreeError } from 'vs/base/browser/ui/tree/tree';\nimport { Event } from 'vs/base/common/event';\nimport { Iterable } from 'vs/base/common/iterator';\n\nexport interface IObjectTreeModel, TFilterData extends NonNullable = void> extends ITreeModel {\n\tsetChildren(element: T | null, children: Iterable> | undefined, options?: IObjectTreeModelSetChildrenOptions): void;\n}\n\nexport interface IObjectTreeModelSetChildrenOptions extends IIndexTreeModelSpliceOptions {\n}\n\nexport interface IObjectTreeModelOptions extends IIndexTreeModelOptions {\n\treadonly sorter?: ITreeSorter;\n\treadonly identityProvider?: IIdentityProvider;\n}\n\nexport class ObjectTreeModel, TFilterData extends NonNullable = void> implements IObjectTreeModel {\n\n\treadonly rootRef = null;\n\n\tprivate model: IndexTreeModel;\n\tprivate nodes = new Map>();\n\tprivate readonly nodesByIdentity = new Map>();\n\tprivate readonly identityProvider?: IIdentityProvider;\n\tprivate sorter?: ITreeSorter<{ element: T }>;\n\n\treadonly onDidSplice: Event>;\n\treadonly onDidChangeCollapseState: Event>;\n\treadonly onDidChangeRenderNodeCount: Event>;\n\n\tconstructor(\n\t\tprivate user: string,\n\t\tlist: IList>,\n\t\toptions: IObjectTreeModelOptions = {}\n\t) {\n\t\tthis.model = new IndexTreeModel(user, list, null, options);\n\t\tthis.onDidSplice = this.model.onDidSplice;\n\t\tthis.onDidChangeCollapseState = this.model.onDidChangeCollapseState as Event>;\n\t\tthis.onDidChangeRenderNodeCount = this.model.onDidChangeRenderNodeCount as Event>;\n\n\t\tif (options.sorter) {\n\t\t\tthis.sorter = {\n\t\t\t\tcompare(a, b) {\n\t\t\t\t\treturn options.sorter!.compare(a.element, b.element);\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t\tthis.identityProvider = options.identityProvider;\n\t}\n\n\tsetChildren(\n\t\telement: T | null,\n\t\tchildren: Iterable> = Iterable.empty(),\n\t\toptions: IObjectTreeModelSetChildrenOptions = {},\n\t): void {\n\t\tconst location = this.getElementLocation(element);\n\t\tthis._setChildren(location, this.preserveCollapseState(children), options);\n\t}\n\n\tprivate _setChildren(\n\t\tlocation: number[],\n\t\tchildren: Iterable> = Iterable.empty(),\n\t\toptions: IObjectTreeModelSetChildrenOptions,\n\t): void {\n\t\tconst insertedElements = new Set();\n\t\tconst insertedElementIds = new Set();\n\n\t\tconst onDidCreateNode = (node: ITreeNode) => {\n\t\t\tif (node.element === null) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst tnode = node as ITreeNode;\n\n\t\t\tinsertedElements.add(tnode.element);\n\t\t\tthis.nodes.set(tnode.element, tnode);\n\n\t\t\tif (this.identityProvider) {\n\t\t\t\tconst id = this.identityProvider.getId(tnode.element).toString();\n\t\t\t\tinsertedElementIds.add(id);\n\t\t\t\tthis.nodesByIdentity.set(id, tnode);\n\t\t\t}\n\n\t\t\toptions.onDidCreateNode?.(tnode);\n\t\t};\n\n\t\tconst onDidDeleteNode = (node: ITreeNode) => {\n\t\t\tif (node.element === null) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst tnode = node as ITreeNode;\n\n\t\t\tif (!insertedElements.has(tnode.element)) {\n\t\t\t\tthis.nodes.delete(tnode.element);\n\t\t\t}\n\n\t\t\tif (this.identityProvider) {\n\t\t\t\tconst id = this.identityProvider.getId(tnode.element).toString();\n\t\t\t\tif (!insertedElementIds.has(id)) {\n\t\t\t\t\tthis.nodesByIdentity.delete(id);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\toptions.onDidDeleteNode?.(tnode);\n\t\t};\n\n\t\tthis.model.splice(\n\t\t\t[...location, 0],\n\t\t\tNumber.MAX_VALUE,\n\t\t\tchildren,\n\t\t\t{ ...options, onDidCreateNode, onDidDeleteNode }\n\t\t);\n\t}\n\n\tprivate preserveCollapseState(elements: Iterable> = Iterable.empty()): Iterable> {\n\t\tif (this.sorter) {\n\t\t\telements = [...elements].sort(this.sorter.compare.bind(this.sorter));\n\t\t}\n\n\t\treturn Iterable.map(elements, treeElement => {\n\t\t\tlet node = this.nodes.get(treeElement.element);\n\n\t\t\tif (!node && this.identityProvider) {\n\t\t\t\tconst id = this.identityProvider.getId(treeElement.element).toString();\n\t\t\t\tnode = this.nodesByIdentity.get(id);\n\t\t\t}\n\n\t\t\tif (!node) {\n\t\t\t\tlet collapsed: boolean | undefined;\n\n\t\t\t\tif (typeof treeElement.collapsed === 'undefined') {\n\t\t\t\t\tcollapsed = undefined;\n\t\t\t\t} else if (treeElement.collapsed === ObjectTreeElementCollapseState.Collapsed || treeElement.collapsed === ObjectTreeElementCollapseState.PreserveOrCollapsed) {\n\t\t\t\t\tcollapsed = true;\n\t\t\t\t} else if (treeElement.collapsed === ObjectTreeElementCollapseState.Expanded || treeElement.collapsed === ObjectTreeElementCollapseState.PreserveOrExpanded) {\n\t\t\t\t\tcollapsed = false;\n\t\t\t\t} else {\n\t\t\t\t\tcollapsed = Boolean(treeElement.collapsed);\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\t...treeElement,\n\t\t\t\t\tchildren: this.preserveCollapseState(treeElement.children),\n\t\t\t\t\tcollapsed\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst collapsible = typeof treeElement.collapsible === 'boolean' ? treeElement.collapsible : node.collapsible;\n\t\t\tlet collapsed: boolean | undefined;\n\n\t\t\tif (typeof treeElement.collapsed === 'undefined' || treeElement.collapsed === ObjectTreeElementCollapseState.PreserveOrCollapsed || treeElement.collapsed === ObjectTreeElementCollapseState.PreserveOrExpanded) {\n\t\t\t\tcollapsed = node.collapsed;\n\t\t\t} else if (treeElement.collapsed === ObjectTreeElementCollapseState.Collapsed) {\n\t\t\t\tcollapsed = true;\n\t\t\t} else if (treeElement.collapsed === ObjectTreeElementCollapseState.Expanded) {\n\t\t\t\tcollapsed = false;\n\t\t\t} else {\n\t\t\t\tcollapsed = Boolean(treeElement.collapsed);\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\t...treeElement,\n\t\t\t\tcollapsible,\n\t\t\t\tcollapsed,\n\t\t\t\tchildren: this.preserveCollapseState(treeElement.children)\n\t\t\t};\n\t\t});\n\t}\n\n\trerender(element: T | null): void {\n\t\tconst location = this.getElementLocation(element);\n\t\tthis.model.rerender(location);\n\t}\n\n\tgetFirstElementChild(ref: T | null = null): T | null | undefined {\n\t\tconst location = this.getElementLocation(ref);\n\t\treturn this.model.getFirstElementChild(location);\n\t}\n\n\thas(element: T | null): boolean {\n\t\treturn this.nodes.has(element);\n\t}\n\n\tgetListIndex(element: T | null): number {\n\t\tconst location = this.getElementLocation(element);\n\t\treturn this.model.getListIndex(location);\n\t}\n\n\tgetListRenderCount(element: T | null): number {\n\t\tconst location = this.getElementLocation(element);\n\t\treturn this.model.getListRenderCount(location);\n\t}\n\n\tisCollapsible(element: T | null): boolean {\n\t\tconst location = this.getElementLocation(element);\n\t\treturn this.model.isCollapsible(location);\n\t}\n\n\tsetCollapsible(element: T | null, collapsible?: boolean): boolean {\n\t\tconst location = this.getElementLocation(element);\n\t\treturn this.model.setCollapsible(location, collapsible);\n\t}\n\n\tisCollapsed(element: T | null): boolean {\n\t\tconst location = this.getElementLocation(element);\n\t\treturn this.model.isCollapsed(location);\n\t}\n\n\tsetCollapsed(element: T | null, collapsed?: boolean, recursive?: boolean): boolean {\n\t\tconst location = this.getElementLocation(element);\n\t\treturn this.model.setCollapsed(location, collapsed, recursive);\n\t}\n\n\texpandTo(element: T | null): void {\n\t\tconst location = this.getElementLocation(element);\n\t\tthis.model.expandTo(location);\n\t}\n\n\trefilter(): void {\n\t\tthis.model.refilter();\n\t}\n\n\tgetNode(element: T | null = null): ITreeNode {\n\t\tif (element === null) {\n\t\t\treturn this.model.getNode(this.model.rootRef);\n\t\t}\n\n\t\tconst node = this.nodes.get(element);\n\n\t\tif (!node) {\n\t\t\tthrow new TreeError(this.user, `Tree element not found: ${element}`);\n\t\t}\n\n\t\treturn node;\n\t}\n\n\tgetNodeLocation(node: ITreeNode): T | null {\n\t\treturn node.element;\n\t}\n\n\tgetParentNodeLocation(element: T | null): T | null {\n\t\tif (element === null) {\n\t\t\tthrow new TreeError(this.user, `Invalid getParentNodeLocation call`);\n\t\t}\n\n\t\tconst node = this.nodes.get(element);\n\n\t\tif (!node) {\n\t\t\tthrow new TreeError(this.user, `Tree element not found: ${element}`);\n\t\t}\n\n\t\tconst location = this.model.getNodeLocation(node);\n\t\tconst parentLocation = this.model.getParentNodeLocation(location);\n\t\tconst parent = this.model.getNode(parentLocation);\n\n\t\treturn parent.element;\n\t}\n\n\tprivate getElementLocation(element: T | null): number[] {\n\t\tif (element === null) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst node = this.nodes.get(element);\n\n\t\tif (!node) {\n\t\t\tthrow new TreeError(this.user, `Tree element not found: ${element}`);\n\t\t}\n\n\t\treturn this.model.getNodeLocation(node);\n\t}\n}\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\nimport { IIdentityProvider } from 'vs/base/browser/ui/list/list';\nimport { IIndexTreeModelSpliceOptions, IList } from 'vs/base/browser/ui/tree/indexTreeModel';\nimport { IObjectTreeModel, IObjectTreeModelOptions, IObjectTreeModelSetChildrenOptions, ObjectTreeModel } from 'vs/base/browser/ui/tree/objectTreeModel';\nimport { ICollapseStateChangeEvent, IObjectTreeElement, ITreeModel, ITreeModelSpliceEvent, ITreeNode, TreeError, TreeFilterResult, TreeVisibility, WeakMapper } from 'vs/base/browser/ui/tree/tree';\nimport { equals } from 'vs/base/common/arrays';\nimport { Event } from 'vs/base/common/event';\nimport { Iterable } from 'vs/base/common/iterator';\n\n// Exported only for test reasons, do not use directly\nexport interface ICompressedTreeElement extends IObjectTreeElement {\n\treadonly children?: Iterable>;\n\treadonly incompressible?: boolean;\n}\n\n// Exported only for test reasons, do not use directly\nexport interface ICompressedTreeNode {\n\treadonly elements: T[];\n\treadonly incompressible: boolean;\n}\n\nfunction noCompress(element: ICompressedTreeElement): ICompressedTreeElement> {\n\tconst elements = [element.element];\n\tconst incompressible = element.incompressible || false;\n\n\treturn {\n\t\telement: { elements, incompressible },\n\t\tchildren: Iterable.map(Iterable.from(element.children), noCompress),\n\t\tcollapsible: element.collapsible,\n\t\tcollapsed: element.collapsed\n\t};\n}\n\n// Exported only for test reasons, do not use directly\nexport function compress(element: ICompressedTreeElement): ICompressedTreeElement> {\n\tconst elements = [element.element];\n\tconst incompressible = element.incompressible || false;\n\n\tlet childrenIterator: Iterable>;\n\tlet children: ICompressedTreeElement[];\n\n\twhile (true) {\n\t\t[children, childrenIterator] = Iterable.consume(Iterable.from(element.children), 2);\n\n\t\tif (children.length !== 1) {\n\t\t\tbreak;\n\t\t}\n\n\t\tif (children[0].incompressible) {\n\t\t\tbreak;\n\t\t}\n\n\t\telement = children[0];\n\t\telements.push(element.element);\n\t}\n\n\treturn {\n\t\telement: { elements, incompressible },\n\t\tchildren: Iterable.map(Iterable.concat(children, childrenIterator), compress),\n\t\tcollapsible: element.collapsible,\n\t\tcollapsed: element.collapsed\n\t};\n}\n\nfunction _decompress(element: ICompressedTreeElement>, index = 0): ICompressedTreeElement {\n\tlet children: Iterable>;\n\n\tif (index < element.element.elements.length - 1) {\n\t\tchildren = [_decompress(element, index + 1)];\n\t} else {\n\t\tchildren = Iterable.map(Iterable.from(element.children), el => _decompress(el, 0));\n\t}\n\n\tif (index === 0 && element.element.incompressible) {\n\t\treturn {\n\t\t\telement: element.element.elements[index],\n\t\t\tchildren,\n\t\t\tincompressible: true,\n\t\t\tcollapsible: element.collapsible,\n\t\t\tcollapsed: element.collapsed\n\t\t};\n\t}\n\n\treturn {\n\t\telement: element.element.elements[index],\n\t\tchildren,\n\t\tcollapsible: element.collapsible,\n\t\tcollapsed: element.collapsed\n\t};\n}\n\n// Exported only for test reasons, do not use directly\nexport function decompress(element: ICompressedTreeElement>): ICompressedTreeElement {\n\treturn _decompress(element, 0);\n}\n\nfunction splice(treeElement: ICompressedTreeElement, element: T, children: Iterable>): ICompressedTreeElement {\n\tif (treeElement.element === element) {\n\t\treturn { ...treeElement, children };\n\t}\n\n\treturn { ...treeElement, children: Iterable.map(Iterable.from(treeElement.children), e => splice(e, element, children)) };\n}\n\ninterface ICompressedObjectTreeModelOptions extends IObjectTreeModelOptions, TFilterData> {\n\treadonly compressionEnabled?: boolean;\n}\n\nconst wrapIdentityProvider = (base: IIdentityProvider): IIdentityProvider> => ({\n\tgetId(node) {\n\t\treturn node.elements.map(e => base.getId(e).toString()).join('\\0');\n\t}\n});\n\n// Exported only for test reasons, do not use directly\nexport class CompressedObjectTreeModel, TFilterData extends NonNullable = void> implements ITreeModel | null, TFilterData, T | null> {\n\n\treadonly rootRef = null;\n\n\tget onDidSplice(): Event | null, TFilterData>> { return this.model.onDidSplice; }\n\tget onDidChangeCollapseState(): Event, TFilterData>> { return this.model.onDidChangeCollapseState; }\n\tget onDidChangeRenderNodeCount(): Event, TFilterData>> { return this.model.onDidChangeRenderNodeCount; }\n\n\tprivate model: ObjectTreeModel, TFilterData>;\n\tprivate nodes = new Map>();\n\tprivate enabled: boolean;\n\tprivate readonly identityProvider?: IIdentityProvider>;\n\n\tconstructor(\n\t\tprivate user: string,\n\t\tlist: IList, TFilterData>>,\n\t\toptions: ICompressedObjectTreeModelOptions = {}\n\t) {\n\t\tthis.model = new ObjectTreeModel(user, list, options);\n\t\tthis.enabled = typeof options.compressionEnabled === 'undefined' ? true : options.compressionEnabled;\n\t\tthis.identityProvider = options.identityProvider;\n\t}\n\n\tsetChildren(\n\t\telement: T | null,\n\t\tchildren: Iterable> = Iterable.empty(),\n\t\toptions: IObjectTreeModelSetChildrenOptions,\n\t): void {\n\t\t// Diffs must be deep, since the compression can affect nested elements.\n\t\t// @see https://github.com/microsoft/vscode/pull/114237#issuecomment-759425034\n\n\t\tconst diffIdentityProvider = options.diffIdentityProvider && wrapIdentityProvider(options.diffIdentityProvider);\n\t\tif (element === null) {\n\t\t\tconst compressedChildren = Iterable.map(children, this.enabled ? compress : noCompress);\n\t\t\tthis._setChildren(null, compressedChildren, { diffIdentityProvider, diffDepth: Infinity });\n\t\t\treturn;\n\t\t}\n\n\t\tconst compressedNode = this.nodes.get(element);\n\n\t\tif (!compressedNode) {\n\t\t\tthrow new TreeError(this.user, 'Unknown compressed tree node');\n\t\t}\n\n\t\tconst node = this.model.getNode(compressedNode) as ITreeNode, TFilterData>;\n\t\tconst compressedParentNode = this.model.getParentNodeLocation(compressedNode);\n\t\tconst parent = this.model.getNode(compressedParentNode) as ITreeNode, TFilterData>;\n\n\t\tconst decompressedElement = decompress(node);\n\t\tconst splicedElement = splice(decompressedElement, element, children);\n\t\tconst recompressedElement = (this.enabled ? compress : noCompress)(splicedElement);\n\n\t\t// If the recompressed node is identical to the original, just set its children.\n\t\t// Saves work and churn diffing the parent element.\n\t\tconst elementComparator = options.diffIdentityProvider\n\t\t\t? ((a: T, b: T) => options.diffIdentityProvider!.getId(a) === options.diffIdentityProvider!.getId(b))\n\t\t\t: undefined;\n\t\tif (equals(recompressedElement.element.elements, node.element.elements, elementComparator)) {\n\t\t\tthis._setChildren(compressedNode, recompressedElement.children || Iterable.empty(), { diffIdentityProvider, diffDepth: 1 });\n\t\t\treturn;\n\t\t}\n\n\t\tconst parentChildren = parent.children\n\t\t\t.map(child => child === node ? recompressedElement : child);\n\n\t\tthis._setChildren(parent.element, parentChildren, {\n\t\t\tdiffIdentityProvider,\n\t\t\tdiffDepth: node.depth - parent.depth,\n\t\t});\n\t}\n\n\tisCompressionEnabled(): boolean {\n\t\treturn this.enabled;\n\t}\n\n\tsetCompressionEnabled(enabled: boolean): void {\n\t\tif (enabled === this.enabled) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.enabled = enabled;\n\n\t\tconst root = this.model.getNode();\n\t\tconst rootChildren = root.children as ITreeNode>[];\n\t\tconst decompressedRootChildren = Iterable.map(rootChildren, decompress);\n\t\tconst recompressedRootChildren = Iterable.map(decompressedRootChildren, enabled ? compress : noCompress);\n\n\t\t// it should be safe to always use deep diff mode here if an identity\n\t\t// provider is available, since we know the raw nodes are unchanged.\n\t\tthis._setChildren(null, recompressedRootChildren, {\n\t\t\tdiffIdentityProvider: this.identityProvider,\n\t\t\tdiffDepth: Infinity,\n\t\t});\n\t}\n\n\tprivate _setChildren(\n\t\tnode: ICompressedTreeNode | null,\n\t\tchildren: Iterable>>,\n\t\toptions: IIndexTreeModelSpliceOptions, TFilterData>,\n\t): void {\n\t\tconst insertedElements = new Set();\n\t\tconst onDidCreateNode = (node: ITreeNode, TFilterData>) => {\n\t\t\tfor (const element of node.element.elements) {\n\t\t\t\tinsertedElements.add(element);\n\t\t\t\tthis.nodes.set(element, node.element);\n\t\t\t}\n\t\t};\n\n\t\tconst onDidDeleteNode = (node: ITreeNode, TFilterData>) => {\n\t\t\tfor (const element of node.element.elements) {\n\t\t\t\tif (!insertedElements.has(element)) {\n\t\t\t\t\tthis.nodes.delete(element);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tthis.model.setChildren(node, children, { ...options, onDidCreateNode, onDidDeleteNode });\n\t}\n\n\thas(element: T | null): boolean {\n\t\treturn this.nodes.has(element);\n\t}\n\n\tgetListIndex(location: T | null): number {\n\t\tconst node = this.getCompressedNode(location);\n\t\treturn this.model.getListIndex(node);\n\t}\n\n\tgetListRenderCount(location: T | null): number {\n\t\tconst node = this.getCompressedNode(location);\n\t\treturn this.model.getListRenderCount(node);\n\t}\n\n\tgetNode(location?: T | null | undefined): ITreeNode | null, TFilterData> {\n\t\tif (typeof location === 'undefined') {\n\t\t\treturn this.model.getNode();\n\t\t}\n\n\t\tconst node = this.getCompressedNode(location);\n\t\treturn this.model.getNode(node);\n\t}\n\n\t// TODO: review this\n\tgetNodeLocation(node: ITreeNode, TFilterData>): T | null {\n\t\tconst compressedNode = this.model.getNodeLocation(node);\n\n\t\tif (compressedNode === null) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn compressedNode.elements[compressedNode.elements.length - 1];\n\t}\n\n\t// TODO: review this\n\tgetParentNodeLocation(location: T | null): T | null {\n\t\tconst compressedNode = this.getCompressedNode(location);\n\t\tconst parentNode = this.model.getParentNodeLocation(compressedNode);\n\n\t\tif (parentNode === null) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn parentNode.elements[parentNode.elements.length - 1];\n\t}\n\n\tgetFirstElementChild(location: T | null): ICompressedTreeNode | null | undefined {\n\t\tconst compressedNode = this.getCompressedNode(location);\n\t\treturn this.model.getFirstElementChild(compressedNode);\n\t}\n\n\tisCollapsible(location: T | null): boolean {\n\t\tconst compressedNode = this.getCompressedNode(location);\n\t\treturn this.model.isCollapsible(compressedNode);\n\t}\n\n\tsetCollapsible(location: T | null, collapsible?: boolean): boolean {\n\t\tconst compressedNode = this.getCompressedNode(location);\n\t\treturn this.model.setCollapsible(compressedNode, collapsible);\n\t}\n\n\tisCollapsed(location: T | null): boolean {\n\t\tconst compressedNode = this.getCompressedNode(location);\n\t\treturn this.model.isCollapsed(compressedNode);\n\t}\n\n\tsetCollapsed(location: T | null, collapsed?: boolean | undefined, recursive?: boolean | undefined): boolean {\n\t\tconst compressedNode = this.getCompressedNode(location);\n\t\treturn this.model.setCollapsed(compressedNode, collapsed, recursive);\n\t}\n\n\texpandTo(location: T | null): void {\n\t\tconst compressedNode = this.getCompressedNode(location);\n\t\tthis.model.expandTo(compressedNode);\n\t}\n\n\trerender(location: T | null): void {\n\t\tconst compressedNode = this.getCompressedNode(location);\n\t\tthis.model.rerender(compressedNode);\n\t}\n\n\trefilter(): void {\n\t\tthis.model.refilter();\n\t}\n\n\tgetCompressedNode(element: T | null): ICompressedTreeNode | null {\n\t\tif (element === null) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst node = this.nodes.get(element);\n\n\t\tif (!node) {\n\t\t\tthrow new TreeError(this.user, `Tree element not found: ${element}`);\n\t\t}\n\n\t\treturn node;\n\t}\n}\n\n// Compressible Object Tree\n\nexport type ElementMapper = (elements: T[]) => T;\nexport const DefaultElementMapper: ElementMapper = elements => elements[elements.length - 1];\n\nexport type CompressedNodeUnwrapper = (node: ICompressedTreeNode) => T;\ntype CompressedNodeWeakMapper = WeakMapper | null, TFilterData>, ITreeNode>;\n\nclass CompressedTreeNodeWrapper implements ITreeNode {\n\n\tget element(): T | null { return this.node.element === null ? null : this.unwrapper(this.node.element); }\n\tget children(): ITreeNode[] { return this.node.children.map(node => new CompressedTreeNodeWrapper(this.unwrapper, node)); }\n\tget depth(): number { return this.node.depth; }\n\tget visibleChildrenCount(): number { return this.node.visibleChildrenCount; }\n\tget visibleChildIndex(): number { return this.node.visibleChildIndex; }\n\tget collapsible(): boolean { return this.node.collapsible; }\n\tget collapsed(): boolean { return this.node.collapsed; }\n\tget visible(): boolean { return this.node.visible; }\n\tget filterData(): TFilterData | undefined { return this.node.filterData; }\n\n\tconstructor(\n\t\tprivate unwrapper: CompressedNodeUnwrapper,\n\t\tprivate node: ITreeNode | null, TFilterData>\n\t) { }\n}\n\nfunction mapList(nodeMapper: CompressedNodeWeakMapper, list: IList>): IList, TFilterData>> {\n\treturn {\n\t\tsplice(start: number, deleteCount: number, toInsert: ITreeNode, TFilterData>[]): void {\n\t\t\tlist.splice(start, deleteCount, toInsert.map(node => nodeMapper.map(node)) as ITreeNode[]);\n\t\t},\n\t\tupdateElementHeight(index: number, height: number): void {\n\t\t\tlist.updateElementHeight(index, height);\n\t\t}\n\t};\n}\n\nfunction mapOptions(compressedNodeUnwrapper: CompressedNodeUnwrapper, options: ICompressibleObjectTreeModelOptions): ICompressedObjectTreeModelOptions {\n\treturn {\n\t\t...options,\n\t\tidentityProvider: options.identityProvider && {\n\t\t\tgetId(node: ICompressedTreeNode): { toString(): string } {\n\t\t\t\treturn options.identityProvider!.getId(compressedNodeUnwrapper(node));\n\t\t\t}\n\t\t},\n\t\tsorter: options.sorter && {\n\t\t\tcompare(node: ICompressedTreeNode, otherNode: ICompressedTreeNode): number {\n\t\t\t\treturn options.sorter!.compare(node.elements[0], otherNode.elements[0]);\n\t\t\t}\n\t\t},\n\t\tfilter: options.filter && {\n\t\t\tfilter(node: ICompressedTreeNode, parentVisibility: TreeVisibility): TreeFilterResult {\n\t\t\t\treturn options.filter!.filter(compressedNodeUnwrapper(node), parentVisibility);\n\t\t\t}\n\t\t}\n\t};\n}\n\nexport interface ICompressibleObjectTreeModelOptions extends IObjectTreeModelOptions {\n\treadonly elementMapper?: ElementMapper;\n}\n\nexport class CompressibleObjectTreeModel, TFilterData extends NonNullable = void> implements IObjectTreeModel {\n\n\treadonly rootRef = null;\n\n\tget onDidSplice(): Event> {\n\t\treturn Event.map(this.model.onDidSplice, ({ insertedNodes, deletedNodes }) => ({\n\t\t\tinsertedNodes: insertedNodes.map(node => this.nodeMapper.map(node)),\n\t\t\tdeletedNodes: deletedNodes.map(node => this.nodeMapper.map(node)),\n\t\t}));\n\t}\n\n\tget onDidChangeCollapseState(): Event> {\n\t\treturn Event.map(this.model.onDidChangeCollapseState, ({ node, deep }) => ({\n\t\t\tnode: this.nodeMapper.map(node),\n\t\t\tdeep\n\t\t}));\n\t}\n\n\tget onDidChangeRenderNodeCount(): Event> {\n\t\treturn Event.map(this.model.onDidChangeRenderNodeCount, node => this.nodeMapper.map(node));\n\t}\n\n\tprivate elementMapper: ElementMapper;\n\tprivate nodeMapper: CompressedNodeWeakMapper;\n\tprivate model: CompressedObjectTreeModel;\n\n\tconstructor(\n\t\tuser: string,\n\t\tlist: IList>,\n\t\toptions: ICompressibleObjectTreeModelOptions = {}\n\t) {\n\t\tthis.elementMapper = options.elementMapper || DefaultElementMapper;\n\t\tconst compressedNodeUnwrapper: CompressedNodeUnwrapper = node => this.elementMapper(node.elements);\n\t\tthis.nodeMapper = new WeakMapper(node => new CompressedTreeNodeWrapper(compressedNodeUnwrapper, node));\n\n\t\tthis.model = new CompressedObjectTreeModel(user, mapList(this.nodeMapper, list), mapOptions(compressedNodeUnwrapper, options));\n\t}\n\n\tsetChildren(\n\t\telement: T | null,\n\t\tchildren: Iterable> = Iterable.empty(),\n\t\toptions: IObjectTreeModelSetChildrenOptions = {},\n\t): void {\n\t\tthis.model.setChildren(element, children, options);\n\t}\n\n\tisCompressionEnabled(): boolean {\n\t\treturn this.model.isCompressionEnabled();\n\t}\n\n\tsetCompressionEnabled(enabled: boolean): void {\n\t\tthis.model.setCompressionEnabled(enabled);\n\t}\n\n\thas(location: T | null): boolean {\n\t\treturn this.model.has(location);\n\t}\n\n\tgetListIndex(location: T | null): number {\n\t\treturn this.model.getListIndex(location);\n\t}\n\n\tgetListRenderCount(location: T | null): number {\n\t\treturn this.model.getListRenderCount(location);\n\t}\n\n\tgetNode(location?: T | null | undefined): ITreeNode {\n\t\treturn this.nodeMapper.map(this.model.getNode(location));\n\t}\n\n\tgetNodeLocation(node: ITreeNode): T | null {\n\t\treturn node.element;\n\t}\n\n\tgetParentNodeLocation(location: T | null): T | null {\n\t\treturn this.model.getParentNodeLocation(location);\n\t}\n\n\tgetFirstElementChild(location: T | null): T | null | undefined {\n\t\tconst result = this.model.getFirstElementChild(location);\n\n\t\tif (result === null || typeof result === 'undefined') {\n\t\t\treturn result;\n\t\t}\n\n\t\treturn this.elementMapper(result.elements);\n\t}\n\n\tisCollapsible(location: T | null): boolean {\n\t\treturn this.model.isCollapsible(location);\n\t}\n\n\tsetCollapsible(location: T | null, collapsed?: boolean): boolean {\n\t\treturn this.model.setCollapsible(location, collapsed);\n\t}\n\n\tisCollapsed(location: T | null): boolean {\n\t\treturn this.model.isCollapsed(location);\n\t}\n\n\tsetCollapsed(location: T | null, collapsed?: boolean | undefined, recursive?: boolean | undefined): boolean {\n\t\treturn this.model.setCollapsed(location, collapsed, recursive);\n\t}\n\n\texpandTo(location: T | null): void {\n\t\treturn this.model.expandTo(location);\n\t}\n\n\trerender(location: T | null): void {\n\t\treturn this.model.rerender(location);\n\t}\n\n\trefilter(): void {\n\t\treturn this.model.refilter();\n\t}\n\n\tgetCompressedTreeNode(location: T | null = null): ITreeNode | null, TFilterData> {\n\t\treturn this.model.getNode(location);\n\t}\n}\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\nimport { INodeProcess, isMacintosh, isWindows } from 'vs/base/common/platform';\n\nlet safeProcess: Omit & { arch: string | undefined };\ndeclare const process: INodeProcess;\n\n// Native sandbox environment\nconst vscodeGlobal = (globalThis as any).vscode;\nif (typeof vscodeGlobal !== 'undefined' && typeof vscodeGlobal.process !== 'undefined') {\n\tconst sandboxProcess: INodeProcess = vscodeGlobal.process;\n\tsafeProcess = {\n\t\tget platform() { return sandboxProcess.platform; },\n\t\tget arch() { return sandboxProcess.arch; },\n\t\tget env() { return sandboxProcess.env; },\n\t\tcwd() { return sandboxProcess.cwd(); }\n\t};\n}\n\n// Native node.js environment\nelse if (typeof process !== 'undefined') {\n\tsafeProcess = {\n\t\tget platform() { return process.platform; },\n\t\tget arch() { return process.arch; },\n\t\tget env() { return process.env; },\n\t\tcwd() { return process.env['VSCODE_CWD'] || process.cwd(); }\n\t};\n}\n\n// Web environment\nelse {\n\tsafeProcess = {\n\n\t\t// Supported\n\t\tget platform() { return isWindows ? 'win32' : isMacintosh ? 'darwin' : 'linux'; },\n\t\tget arch() { return undefined; /* arch is undefined in web */ },\n\n\t\t// Unsupported\n\t\tget env() { return {}; },\n\t\tcwd() { return '/'; }\n\t};\n}\n\n/**\n * Provides safe access to the `cwd` property in node.js, sandboxed or web\n * environments.\n *\n * Note: in web, this property is hardcoded to be `/`.\n *\n * @skipMangle\n */\nexport const cwd = safeProcess.cwd;\n\n/**\n * Provides safe access to the `env` property in node.js, sandboxed or web\n * environments.\n *\n * Note: in web, this property is hardcoded to be `{}`.\n */\nexport const env = safeProcess.env;\n\n/**\n * Provides safe access to the `platform` property in node.js, sandboxed or web\n * environments.\n */\nexport const platform = safeProcess.platform;\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\nimport { IDisposable } from 'vs/base/common/lifecycle';\nimport { env } from 'vs/base/common/process';\n\nexport function isHotReloadEnabled(): boolean {\n\treturn env && !!env['VSCODE_DEV'];\n}\nexport function registerHotReloadHandler(handler: HotReloadHandler): IDisposable {\n\tif (!isHotReloadEnabled()) {\n\t\treturn { dispose() { } };\n\t} else {\n\t\tconst handlers = registerGlobalHotReloadHandler();\n\t\thandlers.add(handler);\n\t\treturn {\n\t\t\tdispose() { handlers.delete(handler); }\n\t\t};\n\t}\n}\n\n/**\n * Takes the old exports of the module to reload and returns a function to apply the new exports.\n * If `undefined` is returned, this handler is not able to handle the module.\n *\n * If no handler can apply the new exports, the module will not be reloaded.\n */\nexport type HotReloadHandler = (args: { oldExports: Record; newSrc: string; config: IHotReloadConfig }) => AcceptNewExportsHandler | undefined;\nexport type AcceptNewExportsHandler = (newExports: Record) => boolean;\nexport type IHotReloadConfig = HotReloadConfig;\n\nfunction registerGlobalHotReloadHandler() {\n\tif (!hotReloadHandlers) {\n\t\thotReloadHandlers = new Set();\n\t}\n\n\tconst g = globalThis as unknown as GlobalThisAddition;\n\tif (!g.$hotReload_applyNewExports) {\n\t\tg.$hotReload_applyNewExports = args => {\n\t\t\tconst args2 = { config: { mode: undefined }, ...args };\n\n\t\t\tfor (const h of hotReloadHandlers!) {\n\t\t\t\tconst result = h(args2);\n\t\t\t\tif (result) { return result; }\n\t\t\t}\n\t\t\treturn undefined;\n\t\t};\n\t}\n\n\treturn hotReloadHandlers;\n}\n\nlet hotReloadHandlers: Set<(args: { oldExports: Record; newSrc: string; config: HotReloadConfig }) => AcceptNewExportsFn | undefined> | undefined = undefined;\n\ninterface HotReloadConfig {\n\tmode?: 'patch-prototype' | undefined;\n}\n\ninterface GlobalThisAddition {\n\t$hotReload_applyNewExports?(args: { oldExports: Record; newSrc: string; config?: HotReloadConfig }): AcceptNewExportsFn | undefined;\n}\n\ntype AcceptNewExportsFn = (newExports: Record) => boolean;\n\nif (isHotReloadEnabled()) {\n\t// This code does not run in production.\n\tregisterHotReloadHandler(({ oldExports, newSrc, config }) => {\n\t\tif (config.mode !== 'patch-prototype') {\n\t\t\treturn undefined;\n\t\t}\n\n\t\treturn newExports => {\n\t\t\tfor (const key in newExports) {\n\t\t\t\tconst exportedItem = newExports[key];\n\t\t\t\tconsole.log(`[hot-reload] Patching prototype methods of '${key}'`, { exportedItem });\n\t\t\t\tif (typeof exportedItem === 'function' && exportedItem.prototype) {\n\t\t\t\t\tconst oldExportedItem = oldExports[key];\n\t\t\t\t\tif (oldExportedItem) {\n\t\t\t\t\t\tfor (const prop of Object.getOwnPropertyNames(exportedItem.prototype)) {\n\t\t\t\t\t\t\tconst descriptor = Object.getOwnPropertyDescriptor(exportedItem.prototype, prop)!;\n\t\t\t\t\t\t\tconst oldDescriptor = Object.getOwnPropertyDescriptor((oldExportedItem as any).prototype, prop);\n\n\t\t\t\t\t\t\tif (descriptor?.value?.toString() !== oldDescriptor?.value?.toString()) {\n\t\t\t\t\t\t\t\tconsole.log(`[hot-reload] Patching prototype method '${key}.${prop}'`);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tObject.defineProperty((oldExportedItem as any).prototype, prop, descriptor);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tnewExports[key] = oldExportedItem;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t};\n\t});\n}\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// NOTE: VSCode's copy of nodejs path library to be usable in common (non-node) namespace\n// Copied from: https://github.com/nodejs/node/blob/v16.14.2/lib/path.js\n\n/**\n * Copyright Joyent, Inc. and other Node contributors.\n *\n * Permission is hereby granted, free of charge, to any person obtaining a\n * copy of this software and associated documentation files (the\n * \"Software\"), to deal in the Software without restriction, including\n * without limitation the rights to use, copy, modify, merge, publish,\n * distribute, sublicense, and/or sell copies of the Software, and to permit\n * persons to whom the Software is furnished to do so, subject to the\n * following conditions:\n *\n * The above copyright notice and this permission notice shall be included\n * in all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n * USE OR OTHER DEALINGS IN THE SOFTWARE.\n */\n\nimport * as process from 'vs/base/common/process';\n\nconst CHAR_UPPERCASE_A = 65;/* A */\nconst CHAR_LOWERCASE_A = 97; /* a */\nconst CHAR_UPPERCASE_Z = 90; /* Z */\nconst CHAR_LOWERCASE_Z = 122; /* z */\nconst CHAR_DOT = 46; /* . */\nconst CHAR_FORWARD_SLASH = 47; /* / */\nconst CHAR_BACKWARD_SLASH = 92; /* \\ */\nconst CHAR_COLON = 58; /* : */\nconst CHAR_QUESTION_MARK = 63; /* ? */\n\nclass ErrorInvalidArgType extends Error {\n\tcode: 'ERR_INVALID_ARG_TYPE';\n\tconstructor(name: string, expected: string, actual: unknown) {\n\t\t// determiner: 'must be' or 'must not be'\n\t\tlet determiner;\n\t\tif (typeof expected === 'string' && expected.indexOf('not ') === 0) {\n\t\t\tdeterminer = 'must not be';\n\t\t\texpected = expected.replace(/^not /, '');\n\t\t} else {\n\t\t\tdeterminer = 'must be';\n\t\t}\n\n\t\tconst type = name.indexOf('.') !== -1 ? 'property' : 'argument';\n\t\tlet msg = `The \"${name}\" ${type} ${determiner} of type ${expected}`;\n\n\t\tmsg += `. Received type ${typeof actual}`;\n\t\tsuper(msg);\n\n\t\tthis.code = 'ERR_INVALID_ARG_TYPE';\n\t}\n}\n\nfunction validateObject(pathObject: object, name: string) {\n\tif (pathObject === null || typeof pathObject !== 'object') {\n\t\tthrow new ErrorInvalidArgType(name, 'Object', pathObject);\n\t}\n}\n\nfunction validateString(value: string, name: string) {\n\tif (typeof value !== 'string') {\n\t\tthrow new ErrorInvalidArgType(name, 'string', value);\n\t}\n}\n\nconst platformIsWin32 = (process.platform === 'win32');\n\nfunction isPathSeparator(code: number | undefined) {\n\treturn code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH;\n}\n\nfunction isPosixPathSeparator(code: number | undefined) {\n\treturn code === CHAR_FORWARD_SLASH;\n}\n\nfunction isWindowsDeviceRoot(code: number) {\n\treturn (code >= CHAR_UPPERCASE_A && code <= CHAR_UPPERCASE_Z) ||\n\t\t(code >= CHAR_LOWERCASE_A && code <= CHAR_LOWERCASE_Z);\n}\n\n// Resolves . and .. elements in a path with directory names\nfunction normalizeString(path: string, allowAboveRoot: boolean, separator: string, isPathSeparator: (code?: number) => boolean) {\n\tlet res = '';\n\tlet lastSegmentLength = 0;\n\tlet lastSlash = -1;\n\tlet dots = 0;\n\tlet code = 0;\n\tfor (let i = 0; i <= path.length; ++i) {\n\t\tif (i < path.length) {\n\t\t\tcode = path.charCodeAt(i);\n\t\t}\n\t\telse if (isPathSeparator(code)) {\n\t\t\tbreak;\n\t\t}\n\t\telse {\n\t\t\tcode = CHAR_FORWARD_SLASH;\n\t\t}\n\n\t\tif (isPathSeparator(code)) {\n\t\t\tif (lastSlash === i - 1 || dots === 1) {\n\t\t\t\t// NOOP\n\t\t\t} else if (dots === 2) {\n\t\t\t\tif (res.length < 2 || lastSegmentLength !== 2 ||\n\t\t\t\t\tres.charCodeAt(res.length - 1) !== CHAR_DOT ||\n\t\t\t\t\tres.charCodeAt(res.length - 2) !== CHAR_DOT) {\n\t\t\t\t\tif (res.length > 2) {\n\t\t\t\t\t\tconst lastSlashIndex = res.lastIndexOf(separator);\n\t\t\t\t\t\tif (lastSlashIndex === -1) {\n\t\t\t\t\t\t\tres = '';\n\t\t\t\t\t\t\tlastSegmentLength = 0;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tres = res.slice(0, lastSlashIndex);\n\t\t\t\t\t\t\tlastSegmentLength = res.length - 1 - res.lastIndexOf(separator);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tlastSlash = i;\n\t\t\t\t\t\tdots = 0;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t} else if (res.length !== 0) {\n\t\t\t\t\t\tres = '';\n\t\t\t\t\t\tlastSegmentLength = 0;\n\t\t\t\t\t\tlastSlash = i;\n\t\t\t\t\t\tdots = 0;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (allowAboveRoot) {\n\t\t\t\t\tres += res.length > 0 ? `${separator}..` : '..';\n\t\t\t\t\tlastSegmentLength = 2;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (res.length > 0) {\n\t\t\t\t\tres += `${separator}${path.slice(lastSlash + 1, i)}`;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tres = path.slice(lastSlash + 1, i);\n\t\t\t\t}\n\t\t\t\tlastSegmentLength = i - lastSlash - 1;\n\t\t\t}\n\t\t\tlastSlash = i;\n\t\t\tdots = 0;\n\t\t} else if (code === CHAR_DOT && dots !== -1) {\n\t\t\t++dots;\n\t\t} else {\n\t\t\tdots = -1;\n\t\t}\n\t}\n\treturn res;\n}\n\nfunction _format(sep: string, pathObject: ParsedPath) {\n\tvalidateObject(pathObject, 'pathObject');\n\tconst dir = pathObject.dir || pathObject.root;\n\tconst base = pathObject.base ||\n\t\t`${pathObject.name || ''}${pathObject.ext || ''}`;\n\tif (!dir) {\n\t\treturn base;\n\t}\n\treturn dir === pathObject.root ? `${dir}${base}` : `${dir}${sep}${base}`;\n}\n\nexport interface ParsedPath {\n\troot: string;\n\tdir: string;\n\tbase: string;\n\text: string;\n\tname: string;\n}\n\nexport interface IPath {\n\tnormalize(path: string): string;\n\tisAbsolute(path: string): boolean;\n\tjoin(...paths: string[]): string;\n\tresolve(...pathSegments: string[]): string;\n\trelative(from: string, to: string): string;\n\tdirname(path: string): string;\n\tbasename(path: string, ext?: string): string;\n\textname(path: string): string;\n\tformat(pathObject: ParsedPath): string;\n\tparse(path: string): ParsedPath;\n\ttoNamespacedPath(path: string): string;\n\tsep: '\\\\' | '/';\n\tdelimiter: string;\n\twin32: IPath | null;\n\tposix: IPath | null;\n}\n\nexport const win32: IPath = {\n\t// path.resolve([from ...], to)\n\tresolve(...pathSegments: string[]): string {\n\t\tlet resolvedDevice = '';\n\t\tlet resolvedTail = '';\n\t\tlet resolvedAbsolute = false;\n\n\t\tfor (let i = pathSegments.length - 1; i >= -1; i--) {\n\t\t\tlet path;\n\t\t\tif (i >= 0) {\n\t\t\t\tpath = pathSegments[i];\n\t\t\t\tvalidateString(path, 'path');\n\n\t\t\t\t// Skip empty entries\n\t\t\t\tif (path.length === 0) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t} else if (resolvedDevice.length === 0) {\n\t\t\t\tpath = process.cwd();\n\t\t\t} else {\n\t\t\t\t// Windows has the concept of drive-specific current working\n\t\t\t\t// directories. If we've resolved a drive letter but not yet an\n\t\t\t\t// absolute path, get cwd for that drive, or the process cwd if\n\t\t\t\t// the drive cwd is not available. We're sure the device is not\n\t\t\t\t// a UNC path at this points, because UNC paths are always absolute.\n\t\t\t\tpath = process.env[`=${resolvedDevice}`] || process.cwd();\n\n\t\t\t\t// Verify that a cwd was found and that it actually points\n\t\t\t\t// to our drive. If not, default to the drive's root.\n\t\t\t\tif (path === undefined ||\n\t\t\t\t\t(path.slice(0, 2).toLowerCase() !== resolvedDevice.toLowerCase() &&\n\t\t\t\t\t\tpath.charCodeAt(2) === CHAR_BACKWARD_SLASH)) {\n\t\t\t\t\tpath = `${resolvedDevice}\\\\`;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst len = path.length;\n\t\t\tlet rootEnd = 0;\n\t\t\tlet device = '';\n\t\t\tlet isAbsolute = false;\n\t\t\tconst code = path.charCodeAt(0);\n\n\t\t\t// Try to match a root\n\t\t\tif (len === 1) {\n\t\t\t\tif (isPathSeparator(code)) {\n\t\t\t\t\t// `path` contains just a path separator\n\t\t\t\t\trootEnd = 1;\n\t\t\t\t\tisAbsolute = true;\n\t\t\t\t}\n\t\t\t} else if (isPathSeparator(code)) {\n\t\t\t\t// Possible UNC root\n\n\t\t\t\t// If we started with a separator, we know we at least have an\n\t\t\t\t// absolute path of some kind (UNC or otherwise)\n\t\t\t\tisAbsolute = true;\n\n\t\t\t\tif (isPathSeparator(path.charCodeAt(1))) {\n\t\t\t\t\t// Matched double path separator at beginning\n\t\t\t\t\tlet j = 2;\n\t\t\t\t\tlet last = j;\n\t\t\t\t\t// Match 1 or more non-path separators\n\t\t\t\t\twhile (j < len && !isPathSeparator(path.charCodeAt(j))) {\n\t\t\t\t\t\tj++;\n\t\t\t\t\t}\n\t\t\t\t\tif (j < len && j !== last) {\n\t\t\t\t\t\tconst firstPart = path.slice(last, j);\n\t\t\t\t\t\t// Matched!\n\t\t\t\t\t\tlast = j;\n\t\t\t\t\t\t// Match 1 or more path separators\n\t\t\t\t\t\twhile (j < len && isPathSeparator(path.charCodeAt(j))) {\n\t\t\t\t\t\t\tj++;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (j < len && j !== last) {\n\t\t\t\t\t\t\t// Matched!\n\t\t\t\t\t\t\tlast = j;\n\t\t\t\t\t\t\t// Match 1 or more non-path separators\n\t\t\t\t\t\t\twhile (j < len && !isPathSeparator(path.charCodeAt(j))) {\n\t\t\t\t\t\t\t\tj++;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (j === len || j !== last) {\n\t\t\t\t\t\t\t\t// We matched a UNC root\n\t\t\t\t\t\t\t\tdevice = `\\\\\\\\${firstPart}\\\\${path.slice(last, j)}`;\n\t\t\t\t\t\t\t\trootEnd = j;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\trootEnd = 1;\n\t\t\t\t}\n\t\t\t} else if (isWindowsDeviceRoot(code) &&\n\t\t\t\tpath.charCodeAt(1) === CHAR_COLON) {\n\t\t\t\t// Possible device root\n\t\t\t\tdevice = path.slice(0, 2);\n\t\t\t\trootEnd = 2;\n\t\t\t\tif (len > 2 && isPathSeparator(path.charCodeAt(2))) {\n\t\t\t\t\t// Treat separator following drive name as an absolute path\n\t\t\t\t\t// indicator\n\t\t\t\t\tisAbsolute = true;\n\t\t\t\t\trootEnd = 3;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (device.length > 0) {\n\t\t\t\tif (resolvedDevice.length > 0) {\n\t\t\t\t\tif (device.toLowerCase() !== resolvedDevice.toLowerCase()) {\n\t\t\t\t\t\t// This path points to another device so it is not applicable\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tresolvedDevice = device;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (resolvedAbsolute) {\n\t\t\t\tif (resolvedDevice.length > 0) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tresolvedTail = `${path.slice(rootEnd)}\\\\${resolvedTail}`;\n\t\t\t\tresolvedAbsolute = isAbsolute;\n\t\t\t\tif (isAbsolute && resolvedDevice.length > 0) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// At this point the path should be resolved to a full absolute path,\n\t\t// but handle relative paths to be safe (might happen when process.cwd()\n\t\t// fails)\n\n\t\t// Normalize the tail path\n\t\tresolvedTail = normalizeString(resolvedTail, !resolvedAbsolute, '\\\\',\n\t\t\tisPathSeparator);\n\n\t\treturn resolvedAbsolute ?\n\t\t\t`${resolvedDevice}\\\\${resolvedTail}` :\n\t\t\t`${resolvedDevice}${resolvedTail}` || '.';\n\t},\n\n\tnormalize(path: string): string {\n\t\tvalidateString(path, 'path');\n\t\tconst len = path.length;\n\t\tif (len === 0) {\n\t\t\treturn '.';\n\t\t}\n\t\tlet rootEnd = 0;\n\t\tlet device;\n\t\tlet isAbsolute = false;\n\t\tconst code = path.charCodeAt(0);\n\n\t\t// Try to match a root\n\t\tif (len === 1) {\n\t\t\t// `path` contains just a single char, exit early to avoid\n\t\t\t// unnecessary work\n\t\t\treturn isPosixPathSeparator(code) ? '\\\\' : path;\n\t\t}\n\t\tif (isPathSeparator(code)) {\n\t\t\t// Possible UNC root\n\n\t\t\t// If we started with a separator, we know we at least have an absolute\n\t\t\t// path of some kind (UNC or otherwise)\n\t\t\tisAbsolute = true;\n\n\t\t\tif (isPathSeparator(path.charCodeAt(1))) {\n\t\t\t\t// Matched double path separator at beginning\n\t\t\t\tlet j = 2;\n\t\t\t\tlet last = j;\n\t\t\t\t// Match 1 or more non-path separators\n\t\t\t\twhile (j < len && !isPathSeparator(path.charCodeAt(j))) {\n\t\t\t\t\tj++;\n\t\t\t\t}\n\t\t\t\tif (j < len && j !== last) {\n\t\t\t\t\tconst firstPart = path.slice(last, j);\n\t\t\t\t\t// Matched!\n\t\t\t\t\tlast = j;\n\t\t\t\t\t// Match 1 or more path separators\n\t\t\t\t\twhile (j < len && isPathSeparator(path.charCodeAt(j))) {\n\t\t\t\t\t\tj++;\n\t\t\t\t\t}\n\t\t\t\t\tif (j < len && j !== last) {\n\t\t\t\t\t\t// Matched!\n\t\t\t\t\t\tlast = j;\n\t\t\t\t\t\t// Match 1 or more non-path separators\n\t\t\t\t\t\twhile (j < len && !isPathSeparator(path.charCodeAt(j))) {\n\t\t\t\t\t\t\tj++;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (j === len) {\n\t\t\t\t\t\t\t// We matched a UNC root only\n\t\t\t\t\t\t\t// Return the normalized version of the UNC root since there\n\t\t\t\t\t\t\t// is nothing left to process\n\t\t\t\t\t\t\treturn `\\\\\\\\${firstPart}\\\\${path.slice(last)}\\\\`;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (j !== last) {\n\t\t\t\t\t\t\t// We matched a UNC root with leftovers\n\t\t\t\t\t\t\tdevice = `\\\\\\\\${firstPart}\\\\${path.slice(last, j)}`;\n\t\t\t\t\t\t\trootEnd = j;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\trootEnd = 1;\n\t\t\t}\n\t\t} else if (isWindowsDeviceRoot(code) && path.charCodeAt(1) === CHAR_COLON) {\n\t\t\t// Possible device root\n\t\t\tdevice = path.slice(0, 2);\n\t\t\trootEnd = 2;\n\t\t\tif (len > 2 && isPathSeparator(path.charCodeAt(2))) {\n\t\t\t\t// Treat separator following drive name as an absolute path\n\t\t\t\t// indicator\n\t\t\t\tisAbsolute = true;\n\t\t\t\trootEnd = 3;\n\t\t\t}\n\t\t}\n\n\t\tlet tail = rootEnd < len ?\n\t\t\tnormalizeString(path.slice(rootEnd), !isAbsolute, '\\\\', isPathSeparator) :\n\t\t\t'';\n\t\tif (tail.length === 0 && !isAbsolute) {\n\t\t\ttail = '.';\n\t\t}\n\t\tif (tail.length > 0 && isPathSeparator(path.charCodeAt(len - 1))) {\n\t\t\ttail += '\\\\';\n\t\t}\n\t\tif (device === undefined) {\n\t\t\treturn isAbsolute ? `\\\\${tail}` : tail;\n\t\t}\n\t\treturn isAbsolute ? `${device}\\\\${tail}` : `${device}${tail}`;\n\t},\n\n\tisAbsolute(path: string): boolean {\n\t\tvalidateString(path, 'path');\n\t\tconst len = path.length;\n\t\tif (len === 0) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst code = path.charCodeAt(0);\n\t\treturn isPathSeparator(code) ||\n\t\t\t// Possible device root\n\t\t\t(len > 2 &&\n\t\t\t\tisWindowsDeviceRoot(code) &&\n\t\t\t\tpath.charCodeAt(1) === CHAR_COLON &&\n\t\t\t\tisPathSeparator(path.charCodeAt(2)));\n\t},\n\n\tjoin(...paths: string[]): string {\n\t\tif (paths.length === 0) {\n\t\t\treturn '.';\n\t\t}\n\n\t\tlet joined;\n\t\tlet firstPart: string | undefined;\n\t\tfor (let i = 0; i < paths.length; ++i) {\n\t\t\tconst arg = paths[i];\n\t\t\tvalidateString(arg, 'path');\n\t\t\tif (arg.length > 0) {\n\t\t\t\tif (joined === undefined) {\n\t\t\t\t\tjoined = firstPart = arg;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tjoined += `\\\\${arg}`;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (joined === undefined) {\n\t\t\treturn '.';\n\t\t}\n\n\t\t// Make sure that the joined path doesn't start with two slashes, because\n\t\t// normalize() will mistake it for a UNC path then.\n\t\t//\n\t\t// This step is skipped when it is very clear that the user actually\n\t\t// intended to point at a UNC path. This is assumed when the first\n\t\t// non-empty string arguments starts with exactly two slashes followed by\n\t\t// at least one more non-slash character.\n\t\t//\n\t\t// Note that for normalize() to treat a path as a UNC path it needs to\n\t\t// have at least 2 components, so we don't filter for that here.\n\t\t// This means that the user can use join to construct UNC paths from\n\t\t// a server name and a share name; for example:\n\t\t// path.join('//server', 'share') -> '\\\\\\\\server\\\\share\\\\')\n\t\tlet needsReplace = true;\n\t\tlet slashCount = 0;\n\t\tif (typeof firstPart === 'string' && isPathSeparator(firstPart.charCodeAt(0))) {\n\t\t\t++slashCount;\n\t\t\tconst firstLen = firstPart.length;\n\t\t\tif (firstLen > 1 && isPathSeparator(firstPart.charCodeAt(1))) {\n\t\t\t\t++slashCount;\n\t\t\t\tif (firstLen > 2) {\n\t\t\t\t\tif (isPathSeparator(firstPart.charCodeAt(2))) {\n\t\t\t\t\t\t++slashCount;\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// We matched a UNC path in the first part\n\t\t\t\t\t\tneedsReplace = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (needsReplace) {\n\t\t\t// Find any more consecutive slashes we need to replace\n\t\t\twhile (slashCount < joined.length &&\n\t\t\t\tisPathSeparator(joined.charCodeAt(slashCount))) {\n\t\t\t\tslashCount++;\n\t\t\t}\n\n\t\t\t// Replace the slashes if needed\n\t\t\tif (slashCount >= 2) {\n\t\t\t\tjoined = `\\\\${joined.slice(slashCount)}`;\n\t\t\t}\n\t\t}\n\n\t\treturn win32.normalize(joined);\n\t},\n\n\n\t// It will solve the relative path from `from` to `to`, for instance:\n\t// from = 'C:\\\\orandea\\\\test\\\\aaa'\n\t// to = 'C:\\\\orandea\\\\impl\\\\bbb'\n\t// The output of the function should be: '..\\\\..\\\\impl\\\\bbb'\n\trelative(from: string, to: string): string {\n\t\tvalidateString(from, 'from');\n\t\tvalidateString(to, 'to');\n\n\t\tif (from === to) {\n\t\t\treturn '';\n\t\t}\n\n\t\tconst fromOrig = win32.resolve(from);\n\t\tconst toOrig = win32.resolve(to);\n\n\t\tif (fromOrig === toOrig) {\n\t\t\treturn '';\n\t\t}\n\n\t\tfrom = fromOrig.toLowerCase();\n\t\tto = toOrig.toLowerCase();\n\n\t\tif (from === to) {\n\t\t\treturn '';\n\t\t}\n\n\t\t// Trim any leading backslashes\n\t\tlet fromStart = 0;\n\t\twhile (fromStart < from.length &&\n\t\t\tfrom.charCodeAt(fromStart) === CHAR_BACKWARD_SLASH) {\n\t\t\tfromStart++;\n\t\t}\n\t\t// Trim trailing backslashes (applicable to UNC paths only)\n\t\tlet fromEnd = from.length;\n\t\twhile (fromEnd - 1 > fromStart &&\n\t\t\tfrom.charCodeAt(fromEnd - 1) === CHAR_BACKWARD_SLASH) {\n\t\t\tfromEnd--;\n\t\t}\n\t\tconst fromLen = fromEnd - fromStart;\n\n\t\t// Trim any leading backslashes\n\t\tlet toStart = 0;\n\t\twhile (toStart < to.length &&\n\t\t\tto.charCodeAt(toStart) === CHAR_BACKWARD_SLASH) {\n\t\t\ttoStart++;\n\t\t}\n\t\t// Trim trailing backslashes (applicable to UNC paths only)\n\t\tlet toEnd = to.length;\n\t\twhile (toEnd - 1 > toStart &&\n\t\t\tto.charCodeAt(toEnd - 1) === CHAR_BACKWARD_SLASH) {\n\t\t\ttoEnd--;\n\t\t}\n\t\tconst toLen = toEnd - toStart;\n\n\t\t// Compare paths to find the longest common path from root\n\t\tconst length = fromLen < toLen ? fromLen : toLen;\n\t\tlet lastCommonSep = -1;\n\t\tlet i = 0;\n\t\tfor (; i < length; i++) {\n\t\t\tconst fromCode = from.charCodeAt(fromStart + i);\n\t\t\tif (fromCode !== to.charCodeAt(toStart + i)) {\n\t\t\t\tbreak;\n\t\t\t} else if (fromCode === CHAR_BACKWARD_SLASH) {\n\t\t\t\tlastCommonSep = i;\n\t\t\t}\n\t\t}\n\n\t\t// We found a mismatch before the first common path separator was seen, so\n\t\t// return the original `to`.\n\t\tif (i !== length) {\n\t\t\tif (lastCommonSep === -1) {\n\t\t\t\treturn toOrig;\n\t\t\t}\n\t\t} else {\n\t\t\tif (toLen > length) {\n\t\t\t\tif (to.charCodeAt(toStart + i) === CHAR_BACKWARD_SLASH) {\n\t\t\t\t\t// We get here if `from` is the exact base path for `to`.\n\t\t\t\t\t// For example: from='C:\\\\foo\\\\bar'; to='C:\\\\foo\\\\bar\\\\baz'\n\t\t\t\t\treturn toOrig.slice(toStart + i + 1);\n\t\t\t\t}\n\t\t\t\tif (i === 2) {\n\t\t\t\t\t// We get here if `from` is the device root.\n\t\t\t\t\t// For example: from='C:\\\\'; to='C:\\\\foo'\n\t\t\t\t\treturn toOrig.slice(toStart + i);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (fromLen > length) {\n\t\t\t\tif (from.charCodeAt(fromStart + i) === CHAR_BACKWARD_SLASH) {\n\t\t\t\t\t// We get here if `to` is the exact base path for `from`.\n\t\t\t\t\t// For example: from='C:\\\\foo\\\\bar'; to='C:\\\\foo'\n\t\t\t\t\tlastCommonSep = i;\n\t\t\t\t} else if (i === 2) {\n\t\t\t\t\t// We get here if `to` is the device root.\n\t\t\t\t\t// For example: from='C:\\\\foo\\\\bar'; to='C:\\\\'\n\t\t\t\t\tlastCommonSep = 3;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (lastCommonSep === -1) {\n\t\t\t\tlastCommonSep = 0;\n\t\t\t}\n\t\t}\n\n\t\tlet out = '';\n\t\t// Generate the relative path based on the path difference between `to` and\n\t\t// `from`\n\t\tfor (i = fromStart + lastCommonSep + 1; i <= fromEnd; ++i) {\n\t\t\tif (i === fromEnd || from.charCodeAt(i) === CHAR_BACKWARD_SLASH) {\n\t\t\t\tout += out.length === 0 ? '..' : '\\\\..';\n\t\t\t}\n\t\t}\n\n\t\ttoStart += lastCommonSep;\n\n\t\t// Lastly, append the rest of the destination (`to`) path that comes after\n\t\t// the common path parts\n\t\tif (out.length > 0) {\n\t\t\treturn `${out}${toOrig.slice(toStart, toEnd)}`;\n\t\t}\n\n\t\tif (toOrig.charCodeAt(toStart) === CHAR_BACKWARD_SLASH) {\n\t\t\t++toStart;\n\t\t}\n\n\t\treturn toOrig.slice(toStart, toEnd);\n\t},\n\n\ttoNamespacedPath(path: string): string {\n\t\t// Note: this will *probably* throw somewhere.\n\t\tif (typeof path !== 'string' || path.length === 0) {\n\t\t\treturn path;\n\t\t}\n\n\t\tconst resolvedPath = win32.resolve(path);\n\n\t\tif (resolvedPath.length <= 2) {\n\t\t\treturn path;\n\t\t}\n\n\t\tif (resolvedPath.charCodeAt(0) === CHAR_BACKWARD_SLASH) {\n\t\t\t// Possible UNC root\n\t\t\tif (resolvedPath.charCodeAt(1) === CHAR_BACKWARD_SLASH) {\n\t\t\t\tconst code = resolvedPath.charCodeAt(2);\n\t\t\t\tif (code !== CHAR_QUESTION_MARK && code !== CHAR_DOT) {\n\t\t\t\t\t// Matched non-long UNC root, convert the path to a long UNC path\n\t\t\t\t\treturn `\\\\\\\\?\\\\UNC\\\\${resolvedPath.slice(2)}`;\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (isWindowsDeviceRoot(resolvedPath.charCodeAt(0)) &&\n\t\t\tresolvedPath.charCodeAt(1) === CHAR_COLON &&\n\t\t\tresolvedPath.charCodeAt(2) === CHAR_BACKWARD_SLASH) {\n\t\t\t// Matched device root, convert the path to a long UNC path\n\t\t\treturn `\\\\\\\\?\\\\${resolvedPath}`;\n\t\t}\n\n\t\treturn path;\n\t},\n\n\tdirname(path: string): string {\n\t\tvalidateString(path, 'path');\n\t\tconst len = path.length;\n\t\tif (len === 0) {\n\t\t\treturn '.';\n\t\t}\n\t\tlet rootEnd = -1;\n\t\tlet offset = 0;\n\t\tconst code = path.charCodeAt(0);\n\n\t\tif (len === 1) {\n\t\t\t// `path` contains just a path separator, exit early to avoid\n\t\t\t// unnecessary work or a dot.\n\t\t\treturn isPathSeparator(code) ? path : '.';\n\t\t}\n\n\t\t// Try to match a root\n\t\tif (isPathSeparator(code)) {\n\t\t\t// Possible UNC root\n\n\t\t\trootEnd = offset = 1;\n\n\t\t\tif (isPathSeparator(path.charCodeAt(1))) {\n\t\t\t\t// Matched double path separator at beginning\n\t\t\t\tlet j = 2;\n\t\t\t\tlet last = j;\n\t\t\t\t// Match 1 or more non-path separators\n\t\t\t\twhile (j < len && !isPathSeparator(path.charCodeAt(j))) {\n\t\t\t\t\tj++;\n\t\t\t\t}\n\t\t\t\tif (j < len && j !== last) {\n\t\t\t\t\t// Matched!\n\t\t\t\t\tlast = j;\n\t\t\t\t\t// Match 1 or more path separators\n\t\t\t\t\twhile (j < len && isPathSeparator(path.charCodeAt(j))) {\n\t\t\t\t\t\tj++;\n\t\t\t\t\t}\n\t\t\t\t\tif (j < len && j !== last) {\n\t\t\t\t\t\t// Matched!\n\t\t\t\t\t\tlast = j;\n\t\t\t\t\t\t// Match 1 or more non-path separators\n\t\t\t\t\t\twhile (j < len && !isPathSeparator(path.charCodeAt(j))) {\n\t\t\t\t\t\t\tj++;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (j === len) {\n\t\t\t\t\t\t\t// We matched a UNC root only\n\t\t\t\t\t\t\treturn path;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (j !== last) {\n\t\t\t\t\t\t\t// We matched a UNC root with leftovers\n\n\t\t\t\t\t\t\t// Offset by 1 to include the separator after the UNC root to\n\t\t\t\t\t\t\t// treat it as a \"normal root\" on top of a (UNC) root\n\t\t\t\t\t\t\trootEnd = offset = j + 1;\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\t// Possible device root\n\t\t} else if (isWindowsDeviceRoot(code) && path.charCodeAt(1) === CHAR_COLON) {\n\t\t\trootEnd = len > 2 && isPathSeparator(path.charCodeAt(2)) ? 3 : 2;\n\t\t\toffset = rootEnd;\n\t\t}\n\n\t\tlet end = -1;\n\t\tlet matchedSlash = true;\n\t\tfor (let i = len - 1; i >= offset; --i) {\n\t\t\tif (isPathSeparator(path.charCodeAt(i))) {\n\t\t\t\tif (!matchedSlash) {\n\t\t\t\t\tend = i;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// We saw the first non-path separator\n\t\t\t\tmatchedSlash = false;\n\t\t\t}\n\t\t}\n\n\t\tif (end === -1) {\n\t\t\tif (rootEnd === -1) {\n\t\t\t\treturn '.';\n\t\t\t}\n\n\t\t\tend = rootEnd;\n\t\t}\n\t\treturn path.slice(0, end);\n\t},\n\n\tbasename(path: string, ext?: string): string {\n\t\tif (ext !== undefined) {\n\t\t\tvalidateString(ext, 'ext');\n\t\t}\n\t\tvalidateString(path, 'path');\n\t\tlet start = 0;\n\t\tlet end = -1;\n\t\tlet matchedSlash = true;\n\t\tlet i;\n\n\t\t// Check for a drive letter prefix so as not to mistake the following\n\t\t// path separator as an extra separator at the end of the path that can be\n\t\t// disregarded\n\t\tif (path.length >= 2 &&\n\t\t\tisWindowsDeviceRoot(path.charCodeAt(0)) &&\n\t\t\tpath.charCodeAt(1) === CHAR_COLON) {\n\t\t\tstart = 2;\n\t\t}\n\n\t\tif (ext !== undefined && ext.length > 0 && ext.length <= path.length) {\n\t\t\tif (ext === path) {\n\t\t\t\treturn '';\n\t\t\t}\n\t\t\tlet extIdx = ext.length - 1;\n\t\t\tlet firstNonSlashEnd = -1;\n\t\t\tfor (i = path.length - 1; i >= start; --i) {\n\t\t\t\tconst code = path.charCodeAt(i);\n\t\t\t\tif (isPathSeparator(code)) {\n\t\t\t\t\t// If we reached a path separator that was not part of a set of path\n\t\t\t\t\t// separators at the end of the string, stop now\n\t\t\t\t\tif (!matchedSlash) {\n\t\t\t\t\t\tstart = i + 1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif (firstNonSlashEnd === -1) {\n\t\t\t\t\t\t// We saw the first non-path separator, remember this index in case\n\t\t\t\t\t\t// we need it if the extension ends up not matching\n\t\t\t\t\t\tmatchedSlash = false;\n\t\t\t\t\t\tfirstNonSlashEnd = i + 1;\n\t\t\t\t\t}\n\t\t\t\t\tif (extIdx >= 0) {\n\t\t\t\t\t\t// Try to match the explicit extension\n\t\t\t\t\t\tif (code === ext.charCodeAt(extIdx)) {\n\t\t\t\t\t\t\tif (--extIdx === -1) {\n\t\t\t\t\t\t\t\t// We matched the extension, so mark this as the end of our path\n\t\t\t\t\t\t\t\t// component\n\t\t\t\t\t\t\t\tend = i;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Extension does not match, so our result is the entire path\n\t\t\t\t\t\t\t// component\n\t\t\t\t\t\t\textIdx = -1;\n\t\t\t\t\t\t\tend = firstNonSlashEnd;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (start === end) {\n\t\t\t\tend = firstNonSlashEnd;\n\t\t\t} else if (end === -1) {\n\t\t\t\tend = path.length;\n\t\t\t}\n\t\t\treturn path.slice(start, end);\n\t\t}\n\t\tfor (i = path.length - 1; i >= start; --i) {\n\t\t\tif (isPathSeparator(path.charCodeAt(i))) {\n\t\t\t\t// If we reached a path separator that was not part of a set of path\n\t\t\t\t// separators at the end of the string, stop now\n\t\t\t\tif (!matchedSlash) {\n\t\t\t\t\tstart = i + 1;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} else if (end === -1) {\n\t\t\t\t// We saw the first non-path separator, mark this as the end of our\n\t\t\t\t// path component\n\t\t\t\tmatchedSlash = false;\n\t\t\t\tend = i + 1;\n\t\t\t}\n\t\t}\n\n\t\tif (end === -1) {\n\t\t\treturn '';\n\t\t}\n\t\treturn path.slice(start, end);\n\t},\n\n\textname(path: string): string {\n\t\tvalidateString(path, 'path');\n\t\tlet start = 0;\n\t\tlet startDot = -1;\n\t\tlet startPart = 0;\n\t\tlet end = -1;\n\t\tlet matchedSlash = true;\n\t\t// Track the state of characters (if any) we see before our first dot and\n\t\t// after any path separator we find\n\t\tlet preDotState = 0;\n\n\t\t// Check for a drive letter prefix so as not to mistake the following\n\t\t// path separator as an extra separator at the end of the path that can be\n\t\t// disregarded\n\n\t\tif (path.length >= 2 &&\n\t\t\tpath.charCodeAt(1) === CHAR_COLON &&\n\t\t\tisWindowsDeviceRoot(path.charCodeAt(0))) {\n\t\t\tstart = startPart = 2;\n\t\t}\n\n\t\tfor (let i = path.length - 1; i >= start; --i) {\n\t\t\tconst code = path.charCodeAt(i);\n\t\t\tif (isPathSeparator(code)) {\n\t\t\t\t// If we reached a path separator that was not part of a set of path\n\t\t\t\t// separators at the end of the string, stop now\n\t\t\t\tif (!matchedSlash) {\n\t\t\t\t\tstartPart = i + 1;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (end === -1) {\n\t\t\t\t// We saw the first non-path separator, mark this as the end of our\n\t\t\t\t// extension\n\t\t\t\tmatchedSlash = false;\n\t\t\t\tend = i + 1;\n\t\t\t}\n\t\t\tif (code === CHAR_DOT) {\n\t\t\t\t// If this is our first dot, mark it as the start of our extension\n\t\t\t\tif (startDot === -1) {\n\t\t\t\t\tstartDot = i;\n\t\t\t\t}\n\t\t\t\telse if (preDotState !== 1) {\n\t\t\t\t\tpreDotState = 1;\n\t\t\t\t}\n\t\t\t} else if (startDot !== -1) {\n\t\t\t\t// We saw a non-dot and non-path separator before our dot, so we should\n\t\t\t\t// have a good chance at having a non-empty extension\n\t\t\t\tpreDotState = -1;\n\t\t\t}\n\t\t}\n\n\t\tif (startDot === -1 ||\n\t\t\tend === -1 ||\n\t\t\t// We saw a non-dot character immediately before the dot\n\t\t\tpreDotState === 0 ||\n\t\t\t// The (right-most) trimmed path component is exactly '..'\n\t\t\t(preDotState === 1 &&\n\t\t\t\tstartDot === end - 1 &&\n\t\t\t\tstartDot === startPart + 1)) {\n\t\t\treturn '';\n\t\t}\n\t\treturn path.slice(startDot, end);\n\t},\n\n\tformat: _format.bind(null, '\\\\'),\n\n\tparse(path) {\n\t\tvalidateString(path, 'path');\n\n\t\tconst ret = { root: '', dir: '', base: '', ext: '', name: '' };\n\t\tif (path.length === 0) {\n\t\t\treturn ret;\n\t\t}\n\n\t\tconst len = path.length;\n\t\tlet rootEnd = 0;\n\t\tlet code = path.charCodeAt(0);\n\n\t\tif (len === 1) {\n\t\t\tif (isPathSeparator(code)) {\n\t\t\t\t// `path` contains just a path separator, exit early to avoid\n\t\t\t\t// unnecessary work\n\t\t\t\tret.root = ret.dir = path;\n\t\t\t\treturn ret;\n\t\t\t}\n\t\t\tret.base = ret.name = path;\n\t\t\treturn ret;\n\t\t}\n\t\t// Try to match a root\n\t\tif (isPathSeparator(code)) {\n\t\t\t// Possible UNC root\n\n\t\t\trootEnd = 1;\n\t\t\tif (isPathSeparator(path.charCodeAt(1))) {\n\t\t\t\t// Matched double path separator at beginning\n\t\t\t\tlet j = 2;\n\t\t\t\tlet last = j;\n\t\t\t\t// Match 1 or more non-path separators\n\t\t\t\twhile (j < len && !isPathSeparator(path.charCodeAt(j))) {\n\t\t\t\t\tj++;\n\t\t\t\t}\n\t\t\t\tif (j < len && j !== last) {\n\t\t\t\t\t// Matched!\n\t\t\t\t\tlast = j;\n\t\t\t\t\t// Match 1 or more path separators\n\t\t\t\t\twhile (j < len && isPathSeparator(path.charCodeAt(j))) {\n\t\t\t\t\t\tj++;\n\t\t\t\t\t}\n\t\t\t\t\tif (j < len && j !== last) {\n\t\t\t\t\t\t// Matched!\n\t\t\t\t\t\tlast = j;\n\t\t\t\t\t\t// Match 1 or more non-path separators\n\t\t\t\t\t\twhile (j < len && !isPathSeparator(path.charCodeAt(j))) {\n\t\t\t\t\t\t\tj++;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (j === len) {\n\t\t\t\t\t\t\t// We matched a UNC root only\n\t\t\t\t\t\t\trootEnd = j;\n\t\t\t\t\t\t} else if (j !== last) {\n\t\t\t\t\t\t\t// We matched a UNC root with leftovers\n\t\t\t\t\t\t\trootEnd = j + 1;\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} else if (isWindowsDeviceRoot(code) && path.charCodeAt(1) === CHAR_COLON) {\n\t\t\t// Possible device root\n\t\t\tif (len <= 2) {\n\t\t\t\t// `path` contains just a drive root, exit early to avoid\n\t\t\t\t// unnecessary work\n\t\t\t\tret.root = ret.dir = path;\n\t\t\t\treturn ret;\n\t\t\t}\n\t\t\trootEnd = 2;\n\t\t\tif (isPathSeparator(path.charCodeAt(2))) {\n\t\t\t\tif (len === 3) {\n\t\t\t\t\t// `path` contains just a drive root, exit early to avoid\n\t\t\t\t\t// unnecessary work\n\t\t\t\t\tret.root = ret.dir = path;\n\t\t\t\t\treturn ret;\n\t\t\t\t}\n\t\t\t\trootEnd = 3;\n\t\t\t}\n\t\t}\n\t\tif (rootEnd > 0) {\n\t\t\tret.root = path.slice(0, rootEnd);\n\t\t}\n\n\t\tlet startDot = -1;\n\t\tlet startPart = rootEnd;\n\t\tlet end = -1;\n\t\tlet matchedSlash = true;\n\t\tlet i = path.length - 1;\n\n\t\t// Track the state of characters (if any) we see before our first dot and\n\t\t// after any path separator we find\n\t\tlet preDotState = 0;\n\n\t\t// Get non-dir info\n\t\tfor (; i >= rootEnd; --i) {\n\t\t\tcode = path.charCodeAt(i);\n\t\t\tif (isPathSeparator(code)) {\n\t\t\t\t// If we reached a path separator that was not part of a set of path\n\t\t\t\t// separators at the end of the string, stop now\n\t\t\t\tif (!matchedSlash) {\n\t\t\t\t\tstartPart = i + 1;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (end === -1) {\n\t\t\t\t// We saw the first non-path separator, mark this as the end of our\n\t\t\t\t// extension\n\t\t\t\tmatchedSlash = false;\n\t\t\t\tend = i + 1;\n\t\t\t}\n\t\t\tif (code === CHAR_DOT) {\n\t\t\t\t// If this is our first dot, mark it as the start of our extension\n\t\t\t\tif (startDot === -1) {\n\t\t\t\t\tstartDot = i;\n\t\t\t\t} else if (preDotState !== 1) {\n\t\t\t\t\tpreDotState = 1;\n\t\t\t\t}\n\t\t\t} else if (startDot !== -1) {\n\t\t\t\t// We saw a non-dot and non-path separator before our dot, so we should\n\t\t\t\t// have a good chance at having a non-empty extension\n\t\t\t\tpreDotState = -1;\n\t\t\t}\n\t\t}\n\n\t\tif (end !== -1) {\n\t\t\tif (startDot === -1 ||\n\t\t\t\t// We saw a non-dot character immediately before the dot\n\t\t\t\tpreDotState === 0 ||\n\t\t\t\t// The (right-most) trimmed path component is exactly '..'\n\t\t\t\t(preDotState === 1 &&\n\t\t\t\t\tstartDot === end - 1 &&\n\t\t\t\t\tstartDot === startPart + 1)) {\n\t\t\t\tret.base = ret.name = path.slice(startPart, end);\n\t\t\t} else {\n\t\t\t\tret.name = path.slice(startPart, startDot);\n\t\t\t\tret.base = path.slice(startPart, end);\n\t\t\t\tret.ext = path.slice(startDot, end);\n\t\t\t}\n\t\t}\n\n\t\t// If the directory is the root, use the entire root as the `dir` including\n\t\t// the trailing slash if any (`C:\\abc` -> `C:\\`). Otherwise, strip out the\n\t\t// trailing slash (`C:\\abc\\def` -> `C:\\abc`).\n\t\tif (startPart > 0 && startPart !== rootEnd) {\n\t\t\tret.dir = path.slice(0, startPart - 1);\n\t\t} else {\n\t\t\tret.dir = ret.root;\n\t\t}\n\n\t\treturn ret;\n\t},\n\n\tsep: '\\\\',\n\tdelimiter: ';',\n\twin32: null,\n\tposix: null\n};\n\nconst posixCwd = (() => {\n\tif (platformIsWin32) {\n\t\t// Converts Windows' backslash path separators to POSIX forward slashes\n\t\t// and truncates any drive indicator\n\t\tconst regexp = /\\\\/g;\n\t\treturn () => {\n\t\t\tconst cwd = process.cwd().replace(regexp, '/');\n\t\t\treturn cwd.slice(cwd.indexOf('/'));\n\t\t};\n\t}\n\n\t// We're already on POSIX, no need for any transformations\n\treturn () => process.cwd();\n})();\n\nexport const posix: IPath = {\n\t// path.resolve([from ...], to)\n\tresolve(...pathSegments: string[]): string {\n\t\tlet resolvedPath = '';\n\t\tlet resolvedAbsolute = false;\n\n\t\tfor (let i = pathSegments.length - 1; i >= -1 && !resolvedAbsolute; i--) {\n\t\t\tconst path = i >= 0 ? pathSegments[i] : posixCwd();\n\n\t\t\tvalidateString(path, 'path');\n\n\t\t\t// Skip empty entries\n\t\t\tif (path.length === 0) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tresolvedPath = `${path}/${resolvedPath}`;\n\t\t\tresolvedAbsolute = path.charCodeAt(0) === CHAR_FORWARD_SLASH;\n\t\t}\n\n\t\t// At this point the path should be resolved to a full absolute path, but\n\t\t// handle relative paths to be safe (might happen when process.cwd() fails)\n\n\t\t// Normalize the path\n\t\tresolvedPath = normalizeString(resolvedPath, !resolvedAbsolute, '/',\n\t\t\tisPosixPathSeparator);\n\n\t\tif (resolvedAbsolute) {\n\t\t\treturn `/${resolvedPath}`;\n\t\t}\n\t\treturn resolvedPath.length > 0 ? resolvedPath : '.';\n\t},\n\n\tnormalize(path: string): string {\n\t\tvalidateString(path, 'path');\n\n\t\tif (path.length === 0) {\n\t\t\treturn '.';\n\t\t}\n\n\t\tconst isAbsolute = path.charCodeAt(0) === CHAR_FORWARD_SLASH;\n\t\tconst trailingSeparator =\n\t\t\tpath.charCodeAt(path.length - 1) === CHAR_FORWARD_SLASH;\n\n\t\t// Normalize the path\n\t\tpath = normalizeString(path, !isAbsolute, '/', isPosixPathSeparator);\n\n\t\tif (path.length === 0) {\n\t\t\tif (isAbsolute) {\n\t\t\t\treturn '/';\n\t\t\t}\n\t\t\treturn trailingSeparator ? './' : '.';\n\t\t}\n\t\tif (trailingSeparator) {\n\t\t\tpath += '/';\n\t\t}\n\n\t\treturn isAbsolute ? `/${path}` : path;\n\t},\n\n\tisAbsolute(path: string): boolean {\n\t\tvalidateString(path, 'path');\n\t\treturn path.length > 0 && path.charCodeAt(0) === CHAR_FORWARD_SLASH;\n\t},\n\n\tjoin(...paths: string[]): string {\n\t\tif (paths.length === 0) {\n\t\t\treturn '.';\n\t\t}\n\t\tlet joined;\n\t\tfor (let i = 0; i < paths.length; ++i) {\n\t\t\tconst arg = paths[i];\n\t\t\tvalidateString(arg, 'path');\n\t\t\tif (arg.length > 0) {\n\t\t\t\tif (joined === undefined) {\n\t\t\t\t\tjoined = arg;\n\t\t\t\t} else {\n\t\t\t\t\tjoined += `/${arg}`;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (joined === undefined) {\n\t\t\treturn '.';\n\t\t}\n\t\treturn posix.normalize(joined);\n\t},\n\n\trelative(from: string, to: string): string {\n\t\tvalidateString(from, 'from');\n\t\tvalidateString(to, 'to');\n\n\t\tif (from === to) {\n\t\t\treturn '';\n\t\t}\n\n\t\t// Trim leading forward slashes.\n\t\tfrom = posix.resolve(from);\n\t\tto = posix.resolve(to);\n\n\t\tif (from === to) {\n\t\t\treturn '';\n\t\t}\n\n\t\tconst fromStart = 1;\n\t\tconst fromEnd = from.length;\n\t\tconst fromLen = fromEnd - fromStart;\n\t\tconst toStart = 1;\n\t\tconst toLen = to.length - toStart;\n\n\t\t// Compare paths to find the longest common path from root\n\t\tconst length = (fromLen < toLen ? fromLen : toLen);\n\t\tlet lastCommonSep = -1;\n\t\tlet i = 0;\n\t\tfor (; i < length; i++) {\n\t\t\tconst fromCode = from.charCodeAt(fromStart + i);\n\t\t\tif (fromCode !== to.charCodeAt(toStart + i)) {\n\t\t\t\tbreak;\n\t\t\t} else if (fromCode === CHAR_FORWARD_SLASH) {\n\t\t\t\tlastCommonSep = i;\n\t\t\t}\n\t\t}\n\t\tif (i === length) {\n\t\t\tif (toLen > length) {\n\t\t\t\tif (to.charCodeAt(toStart + i) === CHAR_FORWARD_SLASH) {\n\t\t\t\t\t// We get here if `from` is the exact base path for `to`.\n\t\t\t\t\t// For example: from='/foo/bar'; to='/foo/bar/baz'\n\t\t\t\t\treturn to.slice(toStart + i + 1);\n\t\t\t\t}\n\t\t\t\tif (i === 0) {\n\t\t\t\t\t// We get here if `from` is the root\n\t\t\t\t\t// For example: from='/'; to='/foo'\n\t\t\t\t\treturn to.slice(toStart + i);\n\t\t\t\t}\n\t\t\t} else if (fromLen > length) {\n\t\t\t\tif (from.charCodeAt(fromStart + i) === CHAR_FORWARD_SLASH) {\n\t\t\t\t\t// We get here if `to` is the exact base path for `from`.\n\t\t\t\t\t// For example: from='/foo/bar/baz'; to='/foo/bar'\n\t\t\t\t\tlastCommonSep = i;\n\t\t\t\t} else if (i === 0) {\n\t\t\t\t\t// We get here if `to` is the root.\n\t\t\t\t\t// For example: from='/foo/bar'; to='/'\n\t\t\t\t\tlastCommonSep = 0;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tlet out = '';\n\t\t// Generate the relative path based on the path difference between `to`\n\t\t// and `from`.\n\t\tfor (i = fromStart + lastCommonSep + 1; i <= fromEnd; ++i) {\n\t\t\tif (i === fromEnd || from.charCodeAt(i) === CHAR_FORWARD_SLASH) {\n\t\t\t\tout += out.length === 0 ? '..' : '/..';\n\t\t\t}\n\t\t}\n\n\t\t// Lastly, append the rest of the destination (`to`) path that comes after\n\t\t// the common path parts.\n\t\treturn `${out}${to.slice(toStart + lastCommonSep)}`;\n\t},\n\n\ttoNamespacedPath(path: string): string {\n\t\t// Non-op on posix systems\n\t\treturn path;\n\t},\n\n\tdirname(path: string): string {\n\t\tvalidateString(path, 'path');\n\t\tif (path.length === 0) {\n\t\t\treturn '.';\n\t\t}\n\t\tconst hasRoot = path.charCodeAt(0) === CHAR_FORWARD_SLASH;\n\t\tlet end = -1;\n\t\tlet matchedSlash = true;\n\t\tfor (let i = path.length - 1; i >= 1; --i) {\n\t\t\tif (path.charCodeAt(i) === CHAR_FORWARD_SLASH) {\n\t\t\t\tif (!matchedSlash) {\n\t\t\t\t\tend = i;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// We saw the first non-path separator\n\t\t\t\tmatchedSlash = false;\n\t\t\t}\n\t\t}\n\n\t\tif (end === -1) {\n\t\t\treturn hasRoot ? '/' : '.';\n\t\t}\n\t\tif (hasRoot && end === 1) {\n\t\t\treturn '//';\n\t\t}\n\t\treturn path.slice(0, end);\n\t},\n\n\tbasename(path: string, ext?: string): string {\n\t\tif (ext !== undefined) {\n\t\t\tvalidateString(ext, 'ext');\n\t\t}\n\t\tvalidateString(path, 'path');\n\n\t\tlet start = 0;\n\t\tlet end = -1;\n\t\tlet matchedSlash = true;\n\t\tlet i;\n\n\t\tif (ext !== undefined && ext.length > 0 && ext.length <= path.length) {\n\t\t\tif (ext === path) {\n\t\t\t\treturn '';\n\t\t\t}\n\t\t\tlet extIdx = ext.length - 1;\n\t\t\tlet firstNonSlashEnd = -1;\n\t\t\tfor (i = path.length - 1; i >= 0; --i) {\n\t\t\t\tconst code = path.charCodeAt(i);\n\t\t\t\tif (code === CHAR_FORWARD_SLASH) {\n\t\t\t\t\t// If we reached a path separator that was not part of a set of path\n\t\t\t\t\t// separators at the end of the string, stop now\n\t\t\t\t\tif (!matchedSlash) {\n\t\t\t\t\t\tstart = i + 1;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif (firstNonSlashEnd === -1) {\n\t\t\t\t\t\t// We saw the first non-path separator, remember this index in case\n\t\t\t\t\t\t// we need it if the extension ends up not matching\n\t\t\t\t\t\tmatchedSlash = false;\n\t\t\t\t\t\tfirstNonSlashEnd = i + 1;\n\t\t\t\t\t}\n\t\t\t\t\tif (extIdx >= 0) {\n\t\t\t\t\t\t// Try to match the explicit extension\n\t\t\t\t\t\tif (code === ext.charCodeAt(extIdx)) {\n\t\t\t\t\t\t\tif (--extIdx === -1) {\n\t\t\t\t\t\t\t\t// We matched the extension, so mark this as the end of our path\n\t\t\t\t\t\t\t\t// component\n\t\t\t\t\t\t\t\tend = i;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Extension does not match, so our result is the entire path\n\t\t\t\t\t\t\t// component\n\t\t\t\t\t\t\textIdx = -1;\n\t\t\t\t\t\t\tend = firstNonSlashEnd;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (start === end) {\n\t\t\t\tend = firstNonSlashEnd;\n\t\t\t} else if (end === -1) {\n\t\t\t\tend = path.length;\n\t\t\t}\n\t\t\treturn path.slice(start, end);\n\t\t}\n\t\tfor (i = path.length - 1; i >= 0; --i) {\n\t\t\tif (path.charCodeAt(i) === CHAR_FORWARD_SLASH) {\n\t\t\t\t// If we reached a path separator that was not part of a set of path\n\t\t\t\t// separators at the end of the string, stop now\n\t\t\t\tif (!matchedSlash) {\n\t\t\t\t\tstart = i + 1;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} else if (end === -1) {\n\t\t\t\t// We saw the first non-path separator, mark this as the end of our\n\t\t\t\t// path component\n\t\t\t\tmatchedSlash = false;\n\t\t\t\tend = i + 1;\n\t\t\t}\n\t\t}\n\n\t\tif (end === -1) {\n\t\t\treturn '';\n\t\t}\n\t\treturn path.slice(start, end);\n\t},\n\n\textname(path: string): string {\n\t\tvalidateString(path, 'path');\n\t\tlet startDot = -1;\n\t\tlet startPart = 0;\n\t\tlet end = -1;\n\t\tlet matchedSlash = true;\n\t\t// Track the state of characters (if any) we see before our first dot and\n\t\t// after any path separator we find\n\t\tlet preDotState = 0;\n\t\tfor (let i = path.length - 1; i >= 0; --i) {\n\t\t\tconst code = path.charCodeAt(i);\n\t\t\tif (code === CHAR_FORWARD_SLASH) {\n\t\t\t\t// If we reached a path separator that was not part of a set of path\n\t\t\t\t// separators at the end of the string, stop now\n\t\t\t\tif (!matchedSlash) {\n\t\t\t\t\tstartPart = i + 1;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (end === -1) {\n\t\t\t\t// We saw the first non-path separator, mark this as the end of our\n\t\t\t\t// extension\n\t\t\t\tmatchedSlash = false;\n\t\t\t\tend = i + 1;\n\t\t\t}\n\t\t\tif (code === CHAR_DOT) {\n\t\t\t\t// If this is our first dot, mark it as the start of our extension\n\t\t\t\tif (startDot === -1) {\n\t\t\t\t\tstartDot = i;\n\t\t\t\t}\n\t\t\t\telse if (preDotState !== 1) {\n\t\t\t\t\tpreDotState = 1;\n\t\t\t\t}\n\t\t\t} else if (startDot !== -1) {\n\t\t\t\t// We saw a non-dot and non-path separator before our dot, so we should\n\t\t\t\t// have a good chance at having a non-empty extension\n\t\t\t\tpreDotState = -1;\n\t\t\t}\n\t\t}\n\n\t\tif (startDot === -1 ||\n\t\t\tend === -1 ||\n\t\t\t// We saw a non-dot character immediately before the dot\n\t\t\tpreDotState === 0 ||\n\t\t\t// The (right-most) trimmed path component is exactly '..'\n\t\t\t(preDotState === 1 &&\n\t\t\t\tstartDot === end - 1 &&\n\t\t\t\tstartDot === startPart + 1)) {\n\t\t\treturn '';\n\t\t}\n\t\treturn path.slice(startDot, end);\n\t},\n\n\tformat: _format.bind(null, '/'),\n\n\tparse(path: string): ParsedPath {\n\t\tvalidateString(path, 'path');\n\n\t\tconst ret = { root: '', dir: '', base: '', ext: '', name: '' };\n\t\tif (path.length === 0) {\n\t\t\treturn ret;\n\t\t}\n\t\tconst isAbsolute = path.charCodeAt(0) === CHAR_FORWARD_SLASH;\n\t\tlet start;\n\t\tif (isAbsolute) {\n\t\t\tret.root = '/';\n\t\t\tstart = 1;\n\t\t} else {\n\t\t\tstart = 0;\n\t\t}\n\t\tlet startDot = -1;\n\t\tlet startPart = 0;\n\t\tlet end = -1;\n\t\tlet matchedSlash = true;\n\t\tlet i = path.length - 1;\n\n\t\t// Track the state of characters (if any) we see before our first dot and\n\t\t// after any path separator we find\n\t\tlet preDotState = 0;\n\n\t\t// Get non-dir info\n\t\tfor (; i >= start; --i) {\n\t\t\tconst code = path.charCodeAt(i);\n\t\t\tif (code === CHAR_FORWARD_SLASH) {\n\t\t\t\t// If we reached a path separator that was not part of a set of path\n\t\t\t\t// separators at the end of the string, stop now\n\t\t\t\tif (!matchedSlash) {\n\t\t\t\t\tstartPart = i + 1;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (end === -1) {\n\t\t\t\t// We saw the first non-path separator, mark this as the end of our\n\t\t\t\t// extension\n\t\t\t\tmatchedSlash = false;\n\t\t\t\tend = i + 1;\n\t\t\t}\n\t\t\tif (code === CHAR_DOT) {\n\t\t\t\t// If this is our first dot, mark it as the start of our extension\n\t\t\t\tif (startDot === -1) {\n\t\t\t\t\tstartDot = i;\n\t\t\t\t} else if (preDotState !== 1) {\n\t\t\t\t\tpreDotState = 1;\n\t\t\t\t}\n\t\t\t} else if (startDot !== -1) {\n\t\t\t\t// We saw a non-dot and non-path separator before our dot, so we should\n\t\t\t\t// have a good chance at having a non-empty extension\n\t\t\t\tpreDotState = -1;\n\t\t\t}\n\t\t}\n\n\t\tif (end !== -1) {\n\t\t\tconst start = startPart === 0 && isAbsolute ? 1 : startPart;\n\t\t\tif (startDot === -1 ||\n\t\t\t\t// We saw a non-dot character immediately before the dot\n\t\t\t\tpreDotState === 0 ||\n\t\t\t\t// The (right-most) trimmed path component is exactly '..'\n\t\t\t\t(preDotState === 1 &&\n\t\t\t\t\tstartDot === end - 1 &&\n\t\t\t\t\tstartDot === startPart + 1)) {\n\t\t\t\tret.base = ret.name = path.slice(start, end);\n\t\t\t} else {\n\t\t\t\tret.name = path.slice(start, startDot);\n\t\t\t\tret.base = path.slice(start, end);\n\t\t\t\tret.ext = path.slice(startDot, end);\n\t\t\t}\n\t\t}\n\n\t\tif (startPart > 0) {\n\t\t\tret.dir = path.slice(0, startPart - 1);\n\t\t} else if (isAbsolute) {\n\t\t\tret.dir = '/';\n\t\t}\n\n\t\treturn ret;\n\t},\n\n\tsep: '/',\n\tdelimiter: ':',\n\twin32: null,\n\tposix: null\n};\n\nposix.win32 = win32.win32 = win32;\nposix.posix = win32.posix = posix;\n\nexport const normalize = (platformIsWin32 ? win32.normalize : posix.normalize);\nexport const resolve = (platformIsWin32 ? win32.resolve : posix.resolve);\nexport const relative = (platformIsWin32 ? win32.relative : posix.relative);\nexport const dirname = (platformIsWin32 ? win32.dirname : posix.dirname);\nexport const basename = (platformIsWin32 ? win32.basename : posix.basename);\nexport const extname = (platformIsWin32 ? win32.extname : posix.extname);\nexport const sep = (platformIsWin32 ? win32.sep : posix.sep);\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\nimport { CharCode } from 'vs/base/common/charCode';\nimport { posix, sep } from 'vs/base/common/path';\nimport { isWindows } from 'vs/base/common/platform';\nimport { startsWithIgnoreCase } from 'vs/base/common/strings';\n\nexport function isPathSeparator(code: number) {\n\treturn code === CharCode.Slash || code === CharCode.Backslash;\n}\n\n/**\n * Takes a Windows OS path and changes backward slashes to forward slashes.\n * This should only be done for OS paths from Windows (or user provided paths potentially from Windows).\n * Using it on a Linux or MaxOS path might change it.\n */\nexport function toSlashes(osPath: string) {\n\treturn osPath.replace(/[\\\\/]/g, posix.sep);\n}\n\n/**\n * Takes a Windows OS path (using backward or forward slashes) and turns it into a posix path:\n * - turns backward slashes into forward slashes\n * - makes it absolute if it starts with a drive letter\n * This should only be done for OS paths from Windows (or user provided paths potentially from Windows).\n * Using it on a Linux or MaxOS path might change it.\n */\nexport function toPosixPath(osPath: string) {\n\tif (osPath.indexOf('/') === -1) {\n\t\tosPath = toSlashes(osPath);\n\t}\n\tif (/^[a-zA-Z]:(\\/|$)/.test(osPath)) { // starts with a drive letter\n\t\tosPath = '/' + osPath;\n\t}\n\treturn osPath;\n}\n\n/**\n * Computes the _root_ this path, like `getRoot('c:\\files') === c:\\`,\n * `getRoot('files:///files/path') === files:///`,\n * or `getRoot('\\\\server\\shares\\path') === \\\\server\\shares\\`\n */\nexport function getRoot(path: string, sep: string = posix.sep): string {\n\tif (!path) {\n\t\treturn '';\n\t}\n\n\tconst len = path.length;\n\tconst firstLetter = path.charCodeAt(0);\n\tif (isPathSeparator(firstLetter)) {\n\t\tif (isPathSeparator(path.charCodeAt(1))) {\n\t\t\t// UNC candidate \\\\localhost\\shares\\ddd\n\t\t\t// ^^^^^^^^^^^^^^^^^^^\n\t\t\tif (!isPathSeparator(path.charCodeAt(2))) {\n\t\t\t\tlet pos = 3;\n\t\t\t\tconst start = pos;\n\t\t\t\tfor (; pos < len; pos++) {\n\t\t\t\t\tif (isPathSeparator(path.charCodeAt(pos))) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (start !== pos && !isPathSeparator(path.charCodeAt(pos + 1))) {\n\t\t\t\t\tpos += 1;\n\t\t\t\t\tfor (; pos < len; pos++) {\n\t\t\t\t\t\tif (isPathSeparator(path.charCodeAt(pos))) {\n\t\t\t\t\t\t\treturn path.slice(0, pos + 1) // consume this separator\n\t\t\t\t\t\t\t\t.replace(/[\\\\/]/g, sep);\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}\n\n\t\t// /user/far\n\t\t// ^\n\t\treturn sep;\n\n\t} else if (isWindowsDriveLetter(firstLetter)) {\n\t\t// check for windows drive letter c:\\ or c:\n\n\t\tif (path.charCodeAt(1) === CharCode.Colon) {\n\t\t\tif (isPathSeparator(path.charCodeAt(2))) {\n\t\t\t\t// C:\\fff\n\t\t\t\t// ^^^\n\t\t\t\treturn path.slice(0, 2) + sep;\n\t\t\t} else {\n\t\t\t\t// C:\n\t\t\t\t// ^^\n\t\t\t\treturn path.slice(0, 2);\n\t\t\t}\n\t\t}\n\t}\n\n\t// check for URI\n\t// scheme://authority/path\n\t// ^^^^^^^^^^^^^^^^^^^\n\tlet pos = path.indexOf('://');\n\tif (pos !== -1) {\n\t\tpos += 3; // 3 -> \"://\".length\n\t\tfor (; pos < len; pos++) {\n\t\t\tif (isPathSeparator(path.charCodeAt(pos))) {\n\t\t\t\treturn path.slice(0, pos + 1); // consume this separator\n\t\t\t}\n\t\t}\n\t}\n\n\treturn '';\n}\n\n/**\n * @deprecated please use `IUriIdentityService.extUri.isEqualOrParent` instead. If\n * you are in a context without services, consider to pass down the `extUri` from the\n * outside, or use `extUriBiasedIgnorePathCase` if you know what you are doing.\n */\nexport function isEqualOrParent(base: string, parentCandidate: string, ignoreCase?: boolean, separator = sep): boolean {\n\tif (base === parentCandidate) {\n\t\treturn true;\n\t}\n\n\tif (!base || !parentCandidate) {\n\t\treturn false;\n\t}\n\n\tif (parentCandidate.length > base.length) {\n\t\treturn false;\n\t}\n\n\tif (ignoreCase) {\n\t\tconst beginsWith = startsWithIgnoreCase(base, parentCandidate);\n\t\tif (!beginsWith) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (parentCandidate.length === base.length) {\n\t\t\treturn true; // same path, different casing\n\t\t}\n\n\t\tlet sepOffset = parentCandidate.length;\n\t\tif (parentCandidate.charAt(parentCandidate.length - 1) === separator) {\n\t\t\tsepOffset--; // adjust the expected sep offset in case our candidate already ends in separator character\n\t\t}\n\n\t\treturn base.charAt(sepOffset) === separator;\n\t}\n\n\tif (parentCandidate.charAt(parentCandidate.length - 1) !== separator) {\n\t\tparentCandidate += separator;\n\t}\n\n\treturn base.indexOf(parentCandidate) === 0;\n}\n\nexport function isWindowsDriveLetter(char0: number): boolean {\n\treturn char0 >= CharCode.A && char0 <= CharCode.Z || char0 >= CharCode.a && char0 <= CharCode.z;\n}\n\nexport function hasDriveLetter(path: string, isWindowsOS: boolean = isWindows): boolean {\n\tif (isWindowsOS) {\n\t\treturn isWindowsDriveLetter(path.charCodeAt(0)) && path.charCodeAt(1) === CharCode.Colon;\n\t}\n\n\treturn false;\n}\n","\nimport { createMatches as createFuzzyMatches, fuzzyScore, IMatch } from 'vs/base/common/filters';\nimport { sep } from 'vs/base/common/path';\nimport { isWindows } from 'vs/base/common/platform';\nimport { stripWildcards } from 'vs/base/common/strings';\n\n// function printMatrix(query: string, target: string, matches: number[], scores: number[]): void {\n// \tconsole.log('\\t' + target.split('').join('\\t'));\n// \tfor (let queryIndex = 0; queryIndex < query.length; queryIndex++) {\n// \t\tlet line = query[queryIndex] + '\\t';\n// \t\tfor (let targetIndex = 0; targetIndex < target.length; targetIndex++) {\n// \t\t\tconst currentIndex = queryIndex * target.length + targetIndex;\n// \t\t\tline = line + 'M' + matches[currentIndex] + '/' + 'S' + scores[currentIndex] + '\\t';\n// \t\t}\n\n// \t\tconsole.log(line);\n// \t}\n// }\n\n//#endregion\n\n\n//#region Alternate fuzzy scorer implementation that is e.g. used for symbols\n\nexport type FuzzyScore2 = [number | undefined /* score */, IMatch[]];\n\nconst NO_SCORE2: FuzzyScore2 = [undefined, []];\n\nexport function scoreFuzzy2(target: string, query: IPreparedQuery | IPreparedQueryPiece, patternStart = 0, wordStart = 0): FuzzyScore2 {\n\n\t// Score: multiple inputs\n\tconst preparedQuery = query as IPreparedQuery;\n\tif (preparedQuery.values && preparedQuery.values.length > 1) {\n\t\treturn doScoreFuzzy2Multiple(target, preparedQuery.values, patternStart, wordStart);\n\t}\n\n\t// Score: single input\n\treturn doScoreFuzzy2Single(target, query, patternStart, wordStart);\n}\n\nfunction doScoreFuzzy2Multiple(target: string, query: IPreparedQueryPiece[], patternStart: number, wordStart: number): FuzzyScore2 {\n\tlet totalScore = 0;\n\tconst totalMatches: IMatch[] = [];\n\n\tfor (const queryPiece of query) {\n\t\tconst [score, matches] = doScoreFuzzy2Single(target, queryPiece, patternStart, wordStart);\n\t\tif (typeof score !== 'number') {\n\t\t\t// if a single query value does not match, return with\n\t\t\t// no score entirely, we require all queries to match\n\t\t\treturn NO_SCORE2;\n\t\t}\n\n\t\ttotalScore += score;\n\t\ttotalMatches.push(...matches);\n\t}\n\n\t// if we have a score, ensure that the positions are\n\t// sorted in ascending order and distinct\n\treturn [totalScore, normalizeMatches(totalMatches)];\n}\n\nfunction doScoreFuzzy2Single(target: string, query: IPreparedQueryPiece, patternStart: number, wordStart: number): FuzzyScore2 {\n\tconst score = fuzzyScore(query.original, query.originalLowercase, patternStart, target, target.toLowerCase(), wordStart, { firstMatchCanBeWeak: true, boostFullMatch: true });\n\tif (!score) {\n\t\treturn NO_SCORE2;\n\t}\n\n\treturn [score[0], createFuzzyMatches(score)];\n}\n\n//#endregion\n\n\n//#region Item (label, description, path) scorer\n\n/**\n * Scoring on structural items that have a label and optional description.\n */\nexport interface IItemScore {\n\n\t/**\n\t * Overall score.\n\t */\n\tscore: number;\n}\n\nconst NO_ITEM_SCORE = Object.freeze({ score: 0 });\n\nexport interface IItemAccessor {\n}\n\nfunction normalizeMatches(matches: IMatch[]): IMatch[] {\n\n\t// sort matches by start to be able to normalize\n\tconst sortedMatches = matches.sort((matchA, matchB) => {\n\t\treturn matchA.start - matchB.start;\n\t});\n\n\t// merge matches that overlap\n\tconst normalizedMatches: IMatch[] = [];\n\tlet currentMatch: IMatch | undefined = undefined;\n\tfor (const match of sortedMatches) {\n\n\t\t// if we have no current match or the matches\n\t\t// do not overlap, we take it as is and remember\n\t\t// it for future merging\n\t\tif (!currentMatch || !matchOverlaps(currentMatch, match)) {\n\t\t\tcurrentMatch = match;\n\t\t\tnormalizedMatches.push(match);\n\t\t}\n\n\t\t// otherwise we merge the matches\n\t\telse {\n\t\t\tcurrentMatch.start = Math.min(currentMatch.start, match.start);\n\t\t\tcurrentMatch.end = Math.max(currentMatch.end, match.end);\n\t\t}\n\t}\n\n\treturn normalizedMatches;\n}\n\nfunction matchOverlaps(matchA: IMatch, matchB: IMatch): boolean {\n\tif (matchA.end < matchB.start) {\n\t\treturn false;\t// A ends before B starts\n\t}\n\n\tif (matchB.end < matchA.start) {\n\t\treturn false; // B ends before A starts\n\t}\n\n\treturn true;\n}\n\n//#endregion\n\n\n//#region Query Normalizer\n\nexport interface IPreparedQueryPiece {\n\n\t/**\n\t * The original query as provided as input.\n\t */\n\toriginal: string;\n\toriginalLowercase: string;\n\n\t/**\n\t * Original normalized to platform separators:\n\t * - Windows: \\\n\t * - Posix: /\n\t */\n\tpathNormalized: string;\n\n\t/**\n\t * In addition to the normalized path, will have\n\t * whitespace and wildcards removed.\n\t */\n\tnormalized: string;\n\tnormalizedLowercase: string;\n\n\t/**\n\t * The query is wrapped in quotes which means\n\t * this query must be a substring of the input.\n\t * In other words, no fuzzy matching is used.\n\t */\n\texpectContiguousMatch: boolean;\n}\n\nexport interface IPreparedQuery extends IPreparedQueryPiece {\n\n\t/**\n\t * Query split by spaces into pieces.\n\t */\n\tvalues: IPreparedQueryPiece[] | undefined;\n\n\t/**\n\t * Whether the query contains path separator(s) or not.\n\t */\n\tcontainsPathSeparator: boolean;\n}\n\n/*\n * If a query is wrapped in quotes, the user does not want to\n * use fuzzy search for this query.\n */\nfunction queryExpectsExactMatch(query: string) {\n\treturn query.startsWith('\"') && query.endsWith('\"');\n}\n\n/**\n * Helper function to prepare a search value for scoring by removing unwanted characters\n * and allowing to score on multiple pieces separated by whitespace character.\n */\nconst MULTIPLE_QUERY_VALUES_SEPARATOR = ' ';\nexport function prepareQuery(original: string): IPreparedQuery {\n\tif (typeof original !== 'string') {\n\t\toriginal = '';\n\t}\n\n\tconst originalLowercase = original.toLowerCase();\n\tconst { pathNormalized, normalized, normalizedLowercase } = normalizeQuery(original);\n\tconst containsPathSeparator = pathNormalized.indexOf(sep) >= 0;\n\tconst expectExactMatch = queryExpectsExactMatch(original);\n\n\tlet values: IPreparedQueryPiece[] | undefined = undefined;\n\n\tconst originalSplit = original.split(MULTIPLE_QUERY_VALUES_SEPARATOR);\n\tif (originalSplit.length > 1) {\n\t\tfor (const originalPiece of originalSplit) {\n\t\t\tconst expectExactMatchPiece = queryExpectsExactMatch(originalPiece);\n\t\t\tconst {\n\t\t\t\tpathNormalized: pathNormalizedPiece,\n\t\t\t\tnormalized: normalizedPiece,\n\t\t\t\tnormalizedLowercase: normalizedLowercasePiece\n\t\t\t} = normalizeQuery(originalPiece);\n\n\t\t\tif (normalizedPiece) {\n\t\t\t\tif (!values) {\n\t\t\t\t\tvalues = [];\n\t\t\t\t}\n\n\t\t\t\tvalues.push({\n\t\t\t\t\toriginal: originalPiece,\n\t\t\t\t\toriginalLowercase: originalPiece.toLowerCase(),\n\t\t\t\t\tpathNormalized: pathNormalizedPiece,\n\t\t\t\t\tnormalized: normalizedPiece,\n\t\t\t\t\tnormalizedLowercase: normalizedLowercasePiece,\n\t\t\t\t\texpectContiguousMatch: expectExactMatchPiece\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\treturn { original, originalLowercase, pathNormalized, normalized, normalizedLowercase, values, containsPathSeparator, expectContiguousMatch: expectExactMatch };\n}\n\nfunction normalizeQuery(original: string): { pathNormalized: string; normalized: string; normalizedLowercase: string } {\n\tlet pathNormalized: string;\n\tif (isWindows) {\n\t\tpathNormalized = original.replace(/\\//g, sep); // Help Windows users to search for paths when using slash\n\t} else {\n\t\tpathNormalized = original.replace(/\\\\/g, sep); // Help macOS/Linux users to search for paths when using backslash\n\t}\n\n\t// we remove quotes here because quotes are used for exact match search\n\tconst normalized = stripWildcards(pathNormalized).replace(/\\s|\"/g, '');\n\n\treturn {\n\t\tpathNormalized,\n\t\tnormalized,\n\t\tnormalizedLowercase: normalized.toLowerCase()\n\t};\n}\n\nexport function pieceToQuery(piece: IPreparedQueryPiece): IPreparedQuery;\nexport function pieceToQuery(pieces: IPreparedQueryPiece[]): IPreparedQuery;\nexport function pieceToQuery(arg1: IPreparedQueryPiece | IPreparedQueryPiece[]): IPreparedQuery {\n\tif (Array.isArray(arg1)) {\n\t\treturn prepareQuery(arg1.map(piece => piece.original).join(MULTIPLE_QUERY_VALUES_SEPARATOR));\n\t}\n\n\treturn prepareQuery(arg1.original);\n}\n\n//#endregion\n","\nimport { isThenable } from 'vs/base/common/async';\nimport { CharCode } from 'vs/base/common/charCode';\nimport { isEqualOrParent } from 'vs/base/common/extpath';\nimport { LRUCache } from 'vs/base/common/map';\nimport { basename, extname, posix, sep } from 'vs/base/common/path';\nimport { isLinux } from 'vs/base/common/platform';\nimport { escapeRegExpCharacters, ltrim } from 'vs/base/common/strings';\n\nexport interface IRelativePattern {\n\n\t/**\n\t * A base file path to which this pattern will be matched against relatively.\n\t */\n\treadonly base: string;\n\n\t/**\n\t * A file glob pattern like `*.{ts,js}` that will be matched on file paths\n\t * relative to the base path.\n\t *\n\t * Example: Given a base of `/home/work/folder` and a file path of `/home/work/folder/index.js`,\n\t * the file glob pattern will match on `index.js`.\n\t */\n\treadonly pattern: string;\n}\n\nexport interface IExpression {\n\t[pattern: string]: boolean | SiblingClause;\n}\n\ninterface SiblingClause {\n\twhen: string;\n}\n\nexport const GLOBSTAR = '**';\nexport const GLOB_SPLIT = '/';\n\nconst PATH_REGEX = '[/\\\\\\\\]';\t\t// any slash or backslash\nconst NO_PATH_REGEX = '[^/\\\\\\\\]';\t// any non-slash and non-backslash\nconst ALL_FORWARD_SLASHES = /\\//g;\n\nfunction starsToRegExp(starCount: number, isLastPattern?: boolean): string {\n\tswitch (starCount) {\n\t\tcase 0:\n\t\t\treturn '';\n\t\tcase 1:\n\t\t\treturn `${NO_PATH_REGEX}*?`; // 1 star matches any number of characters except path separator (/ and \\) - non greedy (?)\n\t\tdefault:\n\t\t\t// Matches: (Path Sep OR Path Val followed by Path Sep) 0-many times except when it's the last pattern\n\t\t\t// in which case also matches (Path Sep followed by Path Val)\n\t\t\t// Group is non capturing because we don't need to capture at all (?:...)\n\t\t\t// Overall we use non-greedy matching because it could be that we match too much\n\t\t\treturn `(?:${PATH_REGEX}|${NO_PATH_REGEX}+${PATH_REGEX}${isLastPattern ? `|${PATH_REGEX}${NO_PATH_REGEX}+` : ''})*?`;\n\t}\n}\n\nexport function splitGlobAware(pattern: string, splitChar: string): string[] {\n\tif (!pattern) {\n\t\treturn [];\n\t}\n\n\tconst segments: string[] = [];\n\n\tlet inBraces = false;\n\tlet inBrackets = false;\n\n\tlet curVal = '';\n\tfor (const char of pattern) {\n\t\tswitch (char) {\n\t\t\tcase splitChar:\n\t\t\t\tif (!inBraces && !inBrackets) {\n\t\t\t\t\tsegments.push(curVal);\n\t\t\t\t\tcurVal = '';\n\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase '{':\n\t\t\t\tinBraces = true;\n\t\t\t\tbreak;\n\t\t\tcase '}':\n\t\t\t\tinBraces = false;\n\t\t\t\tbreak;\n\t\t\tcase '[':\n\t\t\t\tinBrackets = true;\n\t\t\t\tbreak;\n\t\t\tcase ']':\n\t\t\t\tinBrackets = false;\n\t\t\t\tbreak;\n\t\t}\n\n\t\tcurVal += char;\n\t}\n\n\t// Tail\n\tif (curVal) {\n\t\tsegments.push(curVal);\n\t}\n\n\treturn segments;\n}\n\nfunction parseRegExp(pattern: string): string {\n\tif (!pattern) {\n\t\treturn '';\n\t}\n\n\tlet regEx = '';\n\n\t// Split up into segments for each slash found\n\tconst segments = splitGlobAware(pattern, GLOB_SPLIT);\n\n\t// Special case where we only have globstars\n\tif (segments.every(segment => segment === GLOBSTAR)) {\n\t\tregEx = '.*';\n\t}\n\n\t// Build regex over segments\n\telse {\n\t\tlet previousSegmentWasGlobStar = false;\n\t\tsegments.forEach((segment, index) => {\n\n\t\t\t// Treat globstar specially\n\t\t\tif (segment === GLOBSTAR) {\n\n\t\t\t\t// if we have more than one globstar after another, just ignore it\n\t\t\t\tif (previousSegmentWasGlobStar) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tregEx += starsToRegExp(2, index === segments.length - 1);\n\t\t\t}\n\n\t\t\t// Anything else, not globstar\n\t\t\telse {\n\n\t\t\t\t// States\n\t\t\t\tlet inBraces = false;\n\t\t\t\tlet braceVal = '';\n\n\t\t\t\tlet inBrackets = false;\n\t\t\t\tlet bracketVal = '';\n\n\t\t\t\tfor (const char of segment) {\n\n\t\t\t\t\t// Support brace expansion\n\t\t\t\t\tif (char !== '}' && inBraces) {\n\t\t\t\t\t\tbraceVal += char;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Support brackets\n\t\t\t\t\tif (inBrackets && (char !== ']' || !bracketVal) /* ] is literally only allowed as first character in brackets to match it */) {\n\t\t\t\t\t\tlet res: string;\n\n\t\t\t\t\t\t// range operator\n\t\t\t\t\t\tif (char === '-') {\n\t\t\t\t\t\t\tres = char;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// negation operator (only valid on first index in bracket)\n\t\t\t\t\t\telse if ((char === '^' || char === '!') && !bracketVal) {\n\t\t\t\t\t\t\tres = '^';\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// glob split matching is not allowed within character ranges\n\t\t\t\t\t\t// see http://man7.org/linux/man-pages/man7/glob.7.html\n\t\t\t\t\t\telse if (char === GLOB_SPLIT) {\n\t\t\t\t\t\t\tres = '';\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// anything else gets escaped\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tres = escapeRegExpCharacters(char);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tbracketVal += res;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tswitch (char) {\n\t\t\t\t\t\tcase '{':\n\t\t\t\t\t\t\tinBraces = true;\n\t\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t\tcase '[':\n\t\t\t\t\t\t\tinBrackets = true;\n\t\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t\tcase '}': {\n\t\t\t\t\t\t\tconst choices = splitGlobAware(braceVal, ',');\n\n\t\t\t\t\t\t\t// Converts {foo,bar} => [foo|bar]\n\t\t\t\t\t\t\tconst braceRegExp = `(?:${choices.map(choice => parseRegExp(choice)).join('|')})`;\n\n\t\t\t\t\t\t\tregEx += braceRegExp;\n\n\t\t\t\t\t\t\tinBraces = false;\n\t\t\t\t\t\t\tbraceVal = '';\n\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcase ']': {\n\t\t\t\t\t\t\tregEx += ('[' + bracketVal + ']');\n\n\t\t\t\t\t\t\tinBrackets = false;\n\t\t\t\t\t\t\tbracketVal = '';\n\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcase '?':\n\t\t\t\t\t\t\tregEx += NO_PATH_REGEX; // 1 ? matches any single character except path separator (/ and \\)\n\t\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t\tcase '*':\n\t\t\t\t\t\t\tregEx += starsToRegExp(1);\n\t\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\tregEx += escapeRegExpCharacters(char);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Tail: Add the slash we had split on if there is more to\n\t\t\t\t// come and the remaining pattern is not a globstar\n\t\t\t\t// For example if pattern: some/**/*.js we want the \"/\" after\n\t\t\t\t// some to be included in the RegEx to prevent a folder called\n\t\t\t\t// \"something\" to match as well.\n\t\t\t\tif (\n\t\t\t\t\tindex < segments.length - 1 &&\t\t\t// more segments to come after this\n\t\t\t\t\t(\n\t\t\t\t\t\tsegments[index + 1] !== GLOBSTAR ||\t// next segment is not **, or...\n\t\t\t\t\t\tindex + 2 < segments.length\t\t\t// ...next segment is ** but there is more segments after that\n\t\t\t\t\t)\n\t\t\t\t) {\n\t\t\t\t\tregEx += PATH_REGEX;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// update globstar state\n\t\t\tpreviousSegmentWasGlobStar = (segment === GLOBSTAR);\n\t\t});\n\t}\n\n\treturn regEx;\n}\n\n// regexes to check for trivial glob patterns that just check for String#endsWith\nconst T1 = /^\\*\\*\\/\\*\\.[\\w\\.-]+$/; \t\t\t\t\t\t\t\t\t\t\t\t\t// **/*.something\nconst T2 = /^\\*\\*\\/([\\w\\.-]+)\\/?$/; \t\t\t\t\t\t\t\t\t\t\t\t// **/something\nconst T3 = /^{\\*\\*\\/\\*?[\\w\\.-]+\\/?(,\\*\\*\\/\\*?[\\w\\.-]+\\/?)*}$/; \t\t\t\t\t\t// {**/*.something,**/*.else} or {**/package.json,**/project.json}\nconst T3_2 = /^{\\*\\*\\/\\*?[\\w\\.-]+(\\/(\\*\\*)?)?(,\\*\\*\\/\\*?[\\w\\.-]+(\\/(\\*\\*)?)?)*}$/; \t// Like T3, with optional trailing /**\nconst T4 = /^\\*\\*((\\/[\\w\\.-]+)+)\\/?$/; \t\t\t\t\t\t\t\t\t\t\t\t// **/something/else\nconst T5 = /^([\\w\\.-]+(\\/[\\w\\.-]+)*)\\/?$/; \t\t\t\t\t\t\t\t\t\t\t// something/else\n\nexport type ParsedPattern = (path: string, basename?: string) => boolean;\n\n// The `ParsedExpression` returns a `Promise`\n// iff `hasSibling` returns a `Promise`.\nexport type ParsedExpression = (path: string, basename?: string, hasSibling?: (name: string) => boolean | Promise) => string | null | Promise /* the matching pattern */;\n\ninterface IGlobOptions {\n\n\t/**\n\t * Simplify patterns for use as exclusion filters during\n\t * tree traversal to skip entire subtrees. Cannot be used\n\t * outside of a tree traversal.\n\t */\n\ttrimForExclusions?: boolean;\n}\n\ninterface ParsedStringPattern {\n\t(path: string, basename?: string): string | null | Promise /* the matching pattern */;\n\tbasenames?: string[];\n\tpatterns?: string[];\n\tallBasenames?: string[];\n\tallPaths?: string[];\n}\n\ninterface ParsedExpressionPattern {\n\t(path: string, basename?: string, name?: string, hasSibling?: (name: string) => boolean | Promise): string | null | Promise /* the matching pattern */;\n\trequiresSiblings?: boolean;\n\tallBasenames?: string[];\n\tallPaths?: string[];\n}\n\nconst CACHE = new LRUCache(10000); // bounded to 10000 elements\n\nconst FALSE = function () {\n\treturn false;\n};\n\nconst NULL = function (): string | null {\n\treturn null;\n};\n\nfunction parsePattern(arg1: string | IRelativePattern, options: IGlobOptions): ParsedStringPattern {\n\tif (!arg1) {\n\t\treturn NULL;\n\t}\n\n\t// Handle relative patterns\n\tlet pattern: string;\n\tif (typeof arg1 !== 'string') {\n\t\tpattern = arg1.pattern;\n\t} else {\n\t\tpattern = arg1;\n\t}\n\n\t// Whitespace trimming\n\tpattern = pattern.trim();\n\n\t// Check cache\n\tconst patternKey = `${pattern}_${!!options.trimForExclusions}`;\n\tlet parsedPattern = CACHE.get(patternKey);\n\tif (parsedPattern) {\n\t\treturn wrapRelativePattern(parsedPattern, arg1);\n\t}\n\n\t// Check for Trivials\n\tlet match: RegExpExecArray | null;\n\tif (T1.test(pattern)) {\n\t\tparsedPattern = trivia1(pattern.substr(4), pattern); \t\t\t// common pattern: **/*.txt just need endsWith check\n\t} else if (match = T2.exec(trimForExclusions(pattern, options))) { \t// common pattern: **/some.txt just need basename check\n\t\tparsedPattern = trivia2(match[1], pattern);\n\t} else if ((options.trimForExclusions ? T3_2 : T3).test(pattern)) { // repetition of common patterns (see above) {**/*.txt,**/*.png}\n\t\tparsedPattern = trivia3(pattern, options);\n\t} else if (match = T4.exec(trimForExclusions(pattern, options))) { \t// common pattern: **/something/else just need endsWith check\n\t\tparsedPattern = trivia4and5(match[1].substr(1), pattern, true);\n\t} else if (match = T5.exec(trimForExclusions(pattern, options))) { \t// common pattern: something/else just need equals check\n\t\tparsedPattern = trivia4and5(match[1], pattern, false);\n\t}\n\n\t// Otherwise convert to pattern\n\telse {\n\t\tparsedPattern = toRegExp(pattern);\n\t}\n\n\t// Cache\n\tCACHE.set(patternKey, parsedPattern);\n\n\treturn wrapRelativePattern(parsedPattern, arg1);\n}\n\nfunction wrapRelativePattern(parsedPattern: ParsedStringPattern, arg2: string | IRelativePattern): ParsedStringPattern {\n\tif (typeof arg2 === 'string') {\n\t\treturn parsedPattern;\n\t}\n\n\tconst wrappedPattern: ParsedStringPattern = function (path, basename) {\n\t\tif (!isEqualOrParent(path, arg2.base, !isLinux)) {\n\t\t\t// skip glob matching if `base` is not a parent of `path`\n\t\t\treturn null;\n\t\t}\n\n\t\t// Given we have checked `base` being a parent of `path`,\n\t\t// we can now remove the `base` portion of the `path`\n\t\t// and only match on the remaining path components\n\t\t// For that we try to extract the portion of the `path`\n\t\t// that comes after the `base` portion. We have to account\n\t\t// for the fact that `base` might end in a path separator\n\t\t// (https://github.com/microsoft/vscode/issues/162498)\n\n\t\treturn parsedPattern(ltrim(path.substr(arg2.base.length), sep), basename);\n\t};\n\n\t// Make sure to preserve associated metadata\n\twrappedPattern.allBasenames = parsedPattern.allBasenames;\n\twrappedPattern.allPaths = parsedPattern.allPaths;\n\twrappedPattern.basenames = parsedPattern.basenames;\n\twrappedPattern.patterns = parsedPattern.patterns;\n\n\treturn wrappedPattern;\n}\n\nfunction trimForExclusions(pattern: string, options: IGlobOptions): string {\n\treturn options.trimForExclusions && pattern.endsWith('/**') ? pattern.substr(0, pattern.length - 2) : pattern; // dropping **, tailing / is dropped later\n}\n\n// common pattern: **/*.txt just need endsWith check\nfunction trivia1(base: string, pattern: string): ParsedStringPattern {\n\treturn function (path: string, basename?: string) {\n\t\treturn typeof path === 'string' && path.endsWith(base) ? pattern : null;\n\t};\n}\n\n// common pattern: **/some.txt just need basename check\nfunction trivia2(base: string, pattern: string): ParsedStringPattern {\n\tconst slashBase = `/${base}`;\n\tconst backslashBase = `\\\\${base}`;\n\n\tconst parsedPattern: ParsedStringPattern = function (path: string, basename?: string) {\n\t\tif (typeof path !== 'string') {\n\t\t\treturn null;\n\t\t}\n\n\t\tif (basename) {\n\t\t\treturn basename === base ? pattern : null;\n\t\t}\n\n\t\treturn path === base || path.endsWith(slashBase) || path.endsWith(backslashBase) ? pattern : null;\n\t};\n\n\tconst basenames = [base];\n\tparsedPattern.basenames = basenames;\n\tparsedPattern.patterns = [pattern];\n\tparsedPattern.allBasenames = basenames;\n\n\treturn parsedPattern;\n}\n\n// repetition of common patterns (see above) {**/*.txt,**/*.png}\nfunction trivia3(pattern: string, options: IGlobOptions): ParsedStringPattern {\n\tconst parsedPatterns = aggregateBasenameMatches(pattern.slice(1, -1)\n\t\t.split(',')\n\t\t.map(pattern => parsePattern(pattern, options))\n\t\t.filter(pattern => pattern !== NULL), pattern);\n\n\tconst patternsLength = parsedPatterns.length;\n\tif (!patternsLength) {\n\t\treturn NULL;\n\t}\n\n\tif (patternsLength === 1) {\n\t\treturn parsedPatterns[0];\n\t}\n\n\tconst parsedPattern: ParsedStringPattern = function (path: string, basename?: string) {\n\t\tfor (let i = 0, n = parsedPatterns.length; i < n; i++) {\n\t\t\tif (parsedPatterns[i](path, basename)) {\n\t\t\t\treturn pattern;\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t};\n\n\tconst withBasenames = parsedPatterns.find(pattern => !!pattern.allBasenames);\n\tif (withBasenames) {\n\t\tparsedPattern.allBasenames = withBasenames.allBasenames;\n\t}\n\n\tconst allPaths = parsedPatterns.reduce((all, current) => current.allPaths ? all.concat(current.allPaths) : all, [] as string[]);\n\tif (allPaths.length) {\n\t\tparsedPattern.allPaths = allPaths;\n\t}\n\n\treturn parsedPattern;\n}\n\n// common patterns: **/something/else just need endsWith check, something/else just needs and equals check\nfunction trivia4and5(targetPath: string, pattern: string, matchPathEnds: boolean): ParsedStringPattern {\n\tconst usingPosixSep = sep === posix.sep;\n\tconst nativePath = usingPosixSep ? targetPath : targetPath.replace(ALL_FORWARD_SLASHES, sep);\n\tconst nativePathEnd = sep + nativePath;\n\tconst targetPathEnd = posix.sep + targetPath;\n\n\tlet parsedPattern: ParsedStringPattern;\n\tif (matchPathEnds) {\n\t\tparsedPattern = function (path: string, basename?: string) {\n\t\t\treturn typeof path === 'string' && ((path === nativePath || path.endsWith(nativePathEnd)) || !usingPosixSep && (path === targetPath || path.endsWith(targetPathEnd))) ? pattern : null;\n\t\t};\n\t} else {\n\t\tparsedPattern = function (path: string, basename?: string) {\n\t\t\treturn typeof path === 'string' && (path === nativePath || (!usingPosixSep && path === targetPath)) ? pattern : null;\n\t\t};\n\t}\n\n\tparsedPattern.allPaths = [(matchPathEnds ? '*/' : './') + targetPath];\n\n\treturn parsedPattern;\n}\n\nfunction toRegExp(pattern: string): ParsedStringPattern {\n\ttry {\n\t\tconst regExp = new RegExp(`^${parseRegExp(pattern)}$`);\n\t\treturn function (path: string) {\n\t\t\tregExp.lastIndex = 0; // reset RegExp to its initial state to reuse it!\n\n\t\t\treturn typeof path === 'string' && regExp.test(path) ? pattern : null;\n\t\t};\n\t} catch (error) {\n\t\treturn NULL;\n\t}\n}\n\n/**\n * Simplified glob matching. Supports a subset of glob patterns:\n * * `*` to match zero or more characters in a path segment\n * * `?` to match on one character in a path segment\n * * `**` to match any number of path segments, including none\n * * `{}` to group conditions (e.g. *.{ts,js} matches all TypeScript and JavaScript files)\n * * `[]` to declare a range of characters to match in a path segment (e.g., `example.[0-9]` to match on `example.0`, `example.1`, …)\n * * `[!...]` to negate a range of characters to match in a path segment (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, but not `example.0`)\n */\nexport function match(pattern: string | IRelativePattern, path: string): boolean;\nexport function match(expression: IExpression, path: string, hasSibling?: (name: string) => boolean): string /* the matching pattern */;\nexport function match(arg1: string | IExpression | IRelativePattern, path: string, hasSibling?: (name: string) => boolean): boolean | string | null | Promise {\n\tif (!arg1 || typeof path !== 'string') {\n\t\treturn false;\n\t}\n\n\treturn parse(arg1)(path, undefined, hasSibling);\n}\n\n/**\n * Simplified glob matching. Supports a subset of glob patterns:\n * * `*` to match zero or more characters in a path segment\n * * `?` to match on one character in a path segment\n * * `**` to match any number of path segments, including none\n * * `{}` to group conditions (e.g. *.{ts,js} matches all TypeScript and JavaScript files)\n * * `[]` to declare a range of characters to match in a path segment (e.g., `example.[0-9]` to match on `example.0`, `example.1`, …)\n * * `[!...]` to negate a range of characters to match in a path segment (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, but not `example.0`)\n */\nexport function parse(pattern: string | IRelativePattern, options?: IGlobOptions): ParsedPattern;\nexport function parse(expression: IExpression, options?: IGlobOptions): ParsedExpression;\nexport function parse(arg1: string | IExpression | IRelativePattern, options?: IGlobOptions): ParsedPattern | ParsedExpression;\nexport function parse(arg1: string | IExpression | IRelativePattern, options: IGlobOptions = {}): ParsedPattern | ParsedExpression {\n\tif (!arg1) {\n\t\treturn FALSE;\n\t}\n\n\t// Glob with String\n\tif (typeof arg1 === 'string' || isRelativePattern(arg1)) {\n\t\tconst parsedPattern = parsePattern(arg1, options);\n\t\tif (parsedPattern === NULL) {\n\t\t\treturn FALSE;\n\t\t}\n\n\t\tconst resultPattern: ParsedPattern & { allBasenames?: string[]; allPaths?: string[] } = function (path: string, basename?: string) {\n\t\t\treturn !!parsedPattern(path, basename);\n\t\t};\n\n\t\tif (parsedPattern.allBasenames) {\n\t\t\tresultPattern.allBasenames = parsedPattern.allBasenames;\n\t\t}\n\n\t\tif (parsedPattern.allPaths) {\n\t\t\tresultPattern.allPaths = parsedPattern.allPaths;\n\t\t}\n\n\t\treturn resultPattern;\n\t}\n\n\t// Glob with Expression\n\treturn parsedExpression(arg1, options);\n}\n\nexport function isRelativePattern(obj: unknown): obj is IRelativePattern {\n\tconst rp = obj as IRelativePattern | undefined | null;\n\tif (!rp) {\n\t\treturn false;\n\t}\n\n\treturn typeof rp.base === 'string' && typeof rp.pattern === 'string';\n}\n\nfunction parsedExpression(expression: IExpression, options: IGlobOptions): ParsedExpression {\n\tconst parsedPatterns = aggregateBasenameMatches(Object.getOwnPropertyNames(expression)\n\t\t.map(pattern => parseExpressionPattern(pattern, expression[pattern], options))\n\t\t.filter(pattern => pattern !== NULL));\n\n\tconst patternsLength = parsedPatterns.length;\n\tif (!patternsLength) {\n\t\treturn NULL;\n\t}\n\n\tif (!parsedPatterns.some(parsedPattern => !!(parsedPattern).requiresSiblings)) {\n\t\tif (patternsLength === 1) {\n\t\t\treturn parsedPatterns[0] as ParsedStringPattern;\n\t\t}\n\n\t\tconst resultExpression: ParsedStringPattern = function (path: string, basename?: string) {\n\t\t\tlet resultPromises: Promise[] | undefined = undefined;\n\n\t\t\tfor (let i = 0, n = parsedPatterns.length; i < n; i++) {\n\t\t\t\tconst result = parsedPatterns[i](path, basename);\n\t\t\t\tif (typeof result === 'string') {\n\t\t\t\t\treturn result; // immediately return as soon as the first expression matches\n\t\t\t\t}\n\n\t\t\t\t// If the result is a promise, we have to keep it for\n\t\t\t\t// later processing and await the result properly.\n\t\t\t\tif (isThenable(result)) {\n\t\t\t\t\tif (!resultPromises) {\n\t\t\t\t\t\tresultPromises = [];\n\t\t\t\t\t}\n\n\t\t\t\t\tresultPromises.push(result);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// With result promises, we have to loop over each and\n\t\t\t// await the result before we can return any result.\n\t\t\tif (resultPromises) {\n\t\t\t\treturn (async () => {\n\t\t\t\t\tfor (const resultPromise of resultPromises) {\n\t\t\t\t\t\tconst result = await resultPromise;\n\t\t\t\t\t\tif (typeof result === 'string') {\n\t\t\t\t\t\t\treturn result;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn null;\n\t\t\t\t})();\n\t\t\t}\n\n\t\t\treturn null;\n\t\t};\n\n\t\tconst withBasenames = parsedPatterns.find(pattern => !!pattern.allBasenames);\n\t\tif (withBasenames) {\n\t\t\tresultExpression.allBasenames = withBasenames.allBasenames;\n\t\t}\n\n\t\tconst allPaths = parsedPatterns.reduce((all, current) => current.allPaths ? all.concat(current.allPaths) : all, [] as string[]);\n\t\tif (allPaths.length) {\n\t\t\tresultExpression.allPaths = allPaths;\n\t\t}\n\n\t\treturn resultExpression;\n\t}\n\n\tconst resultExpression: ParsedStringPattern = function (path: string, base?: string, hasSibling?: (name: string) => boolean | Promise) {\n\t\tlet name: string | undefined = undefined;\n\t\tlet resultPromises: Promise[] | undefined = undefined;\n\n\t\tfor (let i = 0, n = parsedPatterns.length; i < n; i++) {\n\n\t\t\t// Pattern matches path\n\t\t\tconst parsedPattern = (parsedPatterns[i]);\n\t\t\tif (parsedPattern.requiresSiblings && hasSibling) {\n\t\t\t\tif (!base) {\n\t\t\t\t\tbase = basename(path);\n\t\t\t\t}\n\n\t\t\t\tif (!name) {\n\t\t\t\t\tname = base.substr(0, base.length - extname(path).length);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst result = parsedPattern(path, base, name, hasSibling);\n\t\t\tif (typeof result === 'string') {\n\t\t\t\treturn result; // immediately return as soon as the first expression matches\n\t\t\t}\n\n\t\t\t// If the result is a promise, we have to keep it for\n\t\t\t// later processing and await the result properly.\n\t\t\tif (isThenable(result)) {\n\t\t\t\tif (!resultPromises) {\n\t\t\t\t\tresultPromises = [];\n\t\t\t\t}\n\n\t\t\t\tresultPromises.push(result);\n\t\t\t}\n\t\t}\n\n\t\t// With result promises, we have to loop over each and\n\t\t// await the result before we can return any result.\n\t\tif (resultPromises) {\n\t\t\treturn (async () => {\n\t\t\t\tfor (const resultPromise of resultPromises) {\n\t\t\t\t\tconst result = await resultPromise;\n\t\t\t\t\tif (typeof result === 'string') {\n\t\t\t\t\t\treturn result;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn null;\n\t\t\t})();\n\t\t}\n\n\t\treturn null;\n\t};\n\n\tconst withBasenames = parsedPatterns.find(pattern => !!pattern.allBasenames);\n\tif (withBasenames) {\n\t\tresultExpression.allBasenames = withBasenames.allBasenames;\n\t}\n\n\tconst allPaths = parsedPatterns.reduce((all, current) => current.allPaths ? all.concat(current.allPaths) : all, [] as string[]);\n\tif (allPaths.length) {\n\t\tresultExpression.allPaths = allPaths;\n\t}\n\n\treturn resultExpression;\n}\n\nfunction parseExpressionPattern(pattern: string, value: boolean | SiblingClause, options: IGlobOptions): (ParsedStringPattern | ParsedExpressionPattern) {\n\tif (value === false) {\n\t\treturn NULL; // pattern is disabled\n\t}\n\n\tconst parsedPattern = parsePattern(pattern, options);\n\tif (parsedPattern === NULL) {\n\t\treturn NULL;\n\t}\n\n\t// Expression Pattern is \n\tif (typeof value === 'boolean') {\n\t\treturn parsedPattern;\n\t}\n\n\t// Expression Pattern is \n\tif (value) {\n\t\tconst when = value.when;\n\t\tif (typeof when === 'string') {\n\t\t\tconst result: ParsedExpressionPattern = (path: string, basename?: string, name?: string, hasSibling?: (name: string) => boolean | Promise) => {\n\t\t\t\tif (!hasSibling || !parsedPattern(path, basename)) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\tconst clausePattern = when.replace('$(basename)', () => name!);\n\t\t\t\tconst matched = hasSibling(clausePattern);\n\t\t\t\treturn isThenable(matched) ?\n\t\t\t\t\tmatched.then(match => match ? pattern : null) :\n\t\t\t\t\tmatched ? pattern : null;\n\t\t\t};\n\n\t\t\tresult.requiresSiblings = true;\n\n\t\t\treturn result;\n\t\t}\n\t}\n\n\t// Expression is anything\n\treturn parsedPattern;\n}\n\nfunction aggregateBasenameMatches(parsedPatterns: Array, result?: string): Array {\n\tconst basenamePatterns = parsedPatterns.filter(parsedPattern => !!(parsedPattern).basenames);\n\tif (basenamePatterns.length < 2) {\n\t\treturn parsedPatterns;\n\t}\n\n\tconst basenames = basenamePatterns.reduce((all, current) => {\n\t\tconst basenames = (current).basenames;\n\n\t\treturn basenames ? all.concat(basenames) : all;\n\t}, [] as string[]);\n\n\tlet patterns: string[];\n\tif (result) {\n\t\tpatterns = [];\n\n\t\tfor (let i = 0, n = basenames.length; i < n; i++) {\n\t\t\tpatterns.push(result);\n\t\t}\n\t} else {\n\t\tpatterns = basenamePatterns.reduce((all, current) => {\n\t\t\tconst patterns = (current).patterns;\n\n\t\t\treturn patterns ? all.concat(patterns) : all;\n\t\t}, [] as string[]);\n\t}\n\n\tconst aggregate: ParsedStringPattern = function (path: string, basename?: string) {\n\t\tif (typeof path !== 'string') {\n\t\t\treturn null;\n\t\t}\n\n\t\tif (!basename) {\n\t\t\tlet i: number;\n\t\t\tfor (i = path.length; i > 0; i--) {\n\t\t\t\tconst ch = path.charCodeAt(i - 1);\n\t\t\t\tif (ch === CharCode.Slash || ch === CharCode.Backslash) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tbasename = path.substr(i);\n\t\t}\n\n\t\tconst index = basenames.indexOf(basename);\n\t\treturn index !== -1 ? patterns[index] : null;\n\t};\n\n\taggregate.basenames = basenames;\n\taggregate.patterns = patterns;\n\taggregate.allBasenames = basenames;\n\n\tconst aggregatedPatterns = parsedPatterns.filter(parsedPattern => !(parsedPattern).basenames);\n\taggregatedPatterns.push(aggregate);\n\n\treturn aggregatedPatterns;\n}\n","\nimport { hasDriveLetter } from 'vs/base/common/extpath';\nimport { isWindows } from 'vs/base/common/platform';\n\nexport function normalizeDriveLetter(path: string, isWindowsOS: boolean = isWindows): string {\n\tif (hasDriveLetter(path, isWindowsOS)) {\n\t\treturn path.charAt(0).toUpperCase() + path.slice(1);\n\t}\n\n\treturn path;\n}\n\nlet normalizedUserHomeCached: { original: string; normalized: string } = Object.create(null);\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\nimport { CharCode } from 'vs/base/common/charCode';\nimport { MarshalledId } from 'vs/base/common/marshallingIds';\nimport * as paths from 'vs/base/common/path';\nimport { isWindows } from 'vs/base/common/platform';\n\nconst _schemePattern = /^\\w[\\w\\d+.-]*$/;\nconst _singleSlashStart = /^\\//;\nconst _doubleSlashStart = /^\\/\\//;\n\nfunction _validateUri(ret: URI, _strict?: boolean): void {\n\n\t// scheme, must be set\n\tif (!ret.scheme && _strict) {\n\t\tthrow new Error(`[UriError]: Scheme is missing: {scheme: \"\", authority: \"${ret.authority}\", path: \"${ret.path}\", query: \"${ret.query}\", fragment: \"${ret.fragment}\"}`);\n\t}\n\n\t// scheme, https://tools.ietf.org/html/rfc3986#section-3.1\n\t// ALPHA *( ALPHA / DIGIT / \"+\" / \"-\" / \".\" )\n\tif (ret.scheme && !_schemePattern.test(ret.scheme)) {\n\t\tthrow new Error('[UriError]: Scheme contains illegal characters.');\n\t}\n\n\t// path, http://tools.ietf.org/html/rfc3986#section-3.3\n\t// If a URI contains an authority component, then the path component\n\t// must either be empty or begin with a slash (\"/\") character. If a URI\n\t// does not contain an authority component, then the path cannot begin\n\t// with two slash characters (\"//\").\n\tif (ret.path) {\n\t\tif (ret.authority) {\n\t\t\tif (!_singleSlashStart.test(ret.path)) {\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');\n\t\t\t}\n\t\t} else {\n\t\t\tif (_doubleSlashStart.test(ret.path)) {\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 (\"//\")');\n\t\t\t}\n\t\t}\n\t}\n}\n\n// for a while we allowed uris *without* schemes and this is the migration\n// for them, e.g. an uri without scheme and without strict-mode warns and falls\n// back to the file-scheme. that should cause the least carnage and still be a\n// clear warning\nfunction _schemeFix(scheme: string, _strict: boolean): string {\n\tif (!scheme && !_strict) {\n\t\treturn 'file';\n\t}\n\treturn scheme;\n}\n\n// implements a bit of https://tools.ietf.org/html/rfc3986#section-5\nfunction _referenceResolution(scheme: string, path: string): string {\n\n\t// the slash-character is our 'default base' as we don't\n\t// support constructing URIs relative to other URIs. This\n\t// also means that we alter and potentially break paths.\n\t// see https://tools.ietf.org/html/rfc3986#section-5.1.4\n\tswitch (scheme) {\n\t\tcase 'https':\n\t\tcase 'http':\n\t\tcase 'file':\n\t\t\tif (!path) {\n\t\t\t\tpath = _slash;\n\t\t\t} else if (path[0] !== _slash) {\n\t\t\t\tpath = _slash + path;\n\t\t\t}\n\t\t\tbreak;\n\t}\n\treturn path;\n}\n\nconst _empty = '';\nconst _slash = '/';\nconst _regexp = /^(([^:/?#]+?):)?(\\/\\/([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?/;\n\n/**\n * Uniform Resource Identifier (URI) http://tools.ietf.org/html/rfc3986.\n * This class is a simple parser which creates the basic component parts\n * (http://tools.ietf.org/html/rfc3986#section-3) with minimal validation\n * and encoding.\n *\n * ```txt\n * foo://example.com:8042/over/there?name=ferret#nose\n * \\_/ \\______________/\\_________/ \\_________/ \\__/\n * | | | | |\n * scheme authority path query fragment\n * | _____________________|__\n * / \\ / \\\n * urn:example:animal:ferret:nose\n * ```\n */\nexport class URI implements UriComponents {\n\n\tstatic isUri(thing: any): thing is URI {\n\t\tif (thing instanceof URI) {\n\t\t\treturn true;\n\t\t}\n\t\tif (!thing) {\n\t\t\treturn false;\n\t\t}\n\t\treturn typeof (thing).authority === 'string'\n\t\t\t&& typeof (thing).fragment === 'string'\n\t\t\t&& typeof (thing).path === 'string'\n\t\t\t&& typeof (thing).query === 'string'\n\t\t\t&& typeof (thing).scheme === 'string'\n\t\t\t&& typeof (thing).fsPath === 'string'\n\t\t\t&& typeof (thing).with === 'function'\n\t\t\t&& typeof (thing).toString === 'function';\n\t}\n\n\t/**\n\t * scheme is the 'http' part of 'http://www.example.com/some/path?query#fragment'.\n\t * The part before the first colon.\n\t */\n\treadonly scheme: string;\n\n\t/**\n\t * authority is the 'www.example.com' part of 'http://www.example.com/some/path?query#fragment'.\n\t * The part between the first double slashes and the next slash.\n\t */\n\treadonly authority: string;\n\n\t/**\n\t * path is the '/some/path' part of 'http://www.example.com/some/path?query#fragment'.\n\t */\n\treadonly path: string;\n\n\t/**\n\t * query is the 'query' part of 'http://www.example.com/some/path?query#fragment'.\n\t */\n\treadonly query: string;\n\n\t/**\n\t * fragment is the 'fragment' part of 'http://www.example.com/some/path?query#fragment'.\n\t */\n\treadonly fragment: string;\n\n\t/**\n\t * @internal\n\t */\n\tprotected constructor(scheme: string, authority?: string, path?: string, query?: string, fragment?: string, _strict?: boolean);\n\n\t/**\n\t * @internal\n\t */\n\tprotected constructor(components: UriComponents);\n\n\t/**\n\t * @internal\n\t */\n\tprotected constructor(schemeOrData: string | UriComponents, authority?: string, path?: string, query?: string, fragment?: string, _strict: boolean = false) {\n\n\t\tif (typeof schemeOrData === 'object') {\n\t\t\tthis.scheme = schemeOrData.scheme || _empty;\n\t\t\tthis.authority = schemeOrData.authority || _empty;\n\t\t\tthis.path = schemeOrData.path || _empty;\n\t\t\tthis.query = schemeOrData.query || _empty;\n\t\t\tthis.fragment = schemeOrData.fragment || _empty;\n\t\t\t// no validation because it's this URI\n\t\t\t// that creates uri components.\n\t\t\t// _validateUri(this);\n\t\t} else {\n\t\t\tthis.scheme = _schemeFix(schemeOrData, _strict);\n\t\t\tthis.authority = authority || _empty;\n\t\t\tthis.path = _referenceResolution(this.scheme, path || _empty);\n\t\t\tthis.query = query || _empty;\n\t\t\tthis.fragment = fragment || _empty;\n\n\t\t\t_validateUri(this, _strict);\n\t\t}\n\t}\n\n\t// ---- filesystem path -----------------------\n\n\t/**\n\t * Returns a string representing the corresponding file system path of this URI.\n\t * Will handle UNC paths, normalizes windows drive letters to lower-case, and uses the\n\t * platform specific path separator.\n\t *\n\t * * Will *not* validate the path for invalid characters and semantics.\n\t * * Will *not* look at the scheme of this URI.\n\t * * The result shall *not* be used for display purposes but for accessing a file on disk.\n\t *\n\t *\n\t * The *difference* to `URI#path` is the use of the platform specific separator and the handling\n\t * of UNC paths. See the below sample of a file-uri with an authority (UNC path).\n\t *\n\t * ```ts\n\t\tconst u = URI.parse('file://server/c$/folder/file.txt')\n\t\tu.authority === 'server'\n\t\tu.path === '/shares/c$/file.txt'\n\t\tu.fsPath === '\\\\server\\c$\\folder\\file.txt'\n\t```\n\t *\n\t * Using `URI#path` to read a file (using fs-apis) would not be enough because parts of the path,\n\t * namely the server name, would be missing. Therefore `URI#fsPath` exists - it's sugar to ease working\n\t * with URIs that represent files on disk (`file` scheme).\n\t */\n\tget fsPath(): string {\n\t\t// if (this.scheme !== 'file') {\n\t\t// \tconsole.warn(`[UriError] calling fsPath with scheme ${this.scheme}`);\n\t\t// }\n\t\treturn uriToFsPath(this, false);\n\t}\n\n\t// ---- modify to new -------------------------\n\n\twith(change: { scheme?: string; authority?: string | null; path?: string | null; query?: string | null; fragment?: string | null }): URI {\n\n\t\tif (!change) {\n\t\t\treturn this;\n\t\t}\n\n\t\tlet { scheme, authority, path, query, fragment } = change;\n\t\tif (scheme === undefined) {\n\t\t\tscheme = this.scheme;\n\t\t} else if (scheme === null) {\n\t\t\tscheme = _empty;\n\t\t}\n\t\tif (authority === undefined) {\n\t\t\tauthority = this.authority;\n\t\t} else if (authority === null) {\n\t\t\tauthority = _empty;\n\t\t}\n\t\tif (path === undefined) {\n\t\t\tpath = this.path;\n\t\t} else if (path === null) {\n\t\t\tpath = _empty;\n\t\t}\n\t\tif (query === undefined) {\n\t\t\tquery = this.query;\n\t\t} else if (query === null) {\n\t\t\tquery = _empty;\n\t\t}\n\t\tif (fragment === undefined) {\n\t\t\tfragment = this.fragment;\n\t\t} else if (fragment === null) {\n\t\t\tfragment = _empty;\n\t\t}\n\n\t\tif (scheme === this.scheme\n\t\t\t&& authority === this.authority\n\t\t\t&& path === this.path\n\t\t\t&& query === this.query\n\t\t\t&& fragment === this.fragment) {\n\n\t\t\treturn this;\n\t\t}\n\n\t\treturn new Uri(scheme, authority, path, query, fragment);\n\t}\n\n\t// ---- parse & validate ------------------------\n\n\t/**\n\t * Creates a new URI from a string, e.g. `http://www.example.com/some/path`,\n\t * `file:///usr/home`, or `scheme:with/path`.\n\t *\n\t * @param value A string which represents an URI (see `URI#toString`).\n\t */\n\tstatic parse(value: string, _strict: boolean = false): URI {\n\t\tconst match = _regexp.exec(value);\n\t\tif (!match) {\n\t\t\treturn new Uri(_empty, _empty, _empty, _empty, _empty);\n\t\t}\n\t\treturn new Uri(\n\t\t\tmatch[2] || _empty,\n\t\t\tpercentDecode(match[4] || _empty),\n\t\t\tpercentDecode(match[5] || _empty),\n\t\t\tpercentDecode(match[7] || _empty),\n\t\t\tpercentDecode(match[9] || _empty),\n\t\t\t_strict\n\t\t);\n\t}\n\n\t/**\n\t * Creates a new URI from a file system path, e.g. `c:\\my\\files`,\n\t * `/usr/home`, or `\\\\server\\share\\some\\path`.\n\t *\n\t * The *difference* between `URI#parse` and `URI#file` is that the latter treats the argument\n\t * as path, not as stringified-uri. E.g. `URI.file(path)` is **not the same as**\n\t * `URI.parse('file://' + path)` because the path might contain characters that are\n\t * interpreted (# and ?). See the following sample:\n\t * ```ts\n\tconst good = URI.file('/coding/c#/project1');\n\tgood.scheme === 'file';\n\tgood.path === '/coding/c#/project1';\n\tgood.fragment === '';\n\tconst bad = URI.parse('file://' + '/coding/c#/project1');\n\tbad.scheme === 'file';\n\tbad.path === '/coding/c'; // path is now broken\n\tbad.fragment === '/project1';\n\t```\n\t *\n\t * @param path A file system path (see `URI#fsPath`)\n\t */\n\tstatic file(path: string): URI {\n\n\t\tlet authority = _empty;\n\n\t\t// normalize to fwd-slashes on windows,\n\t\t// on other systems bwd-slashes are valid\n\t\t// filename character, eg /f\\oo/ba\\r.txt\n\t\tif (isWindows) {\n\t\t\tpath = path.replace(/\\\\/g, _slash);\n\t\t}\n\n\t\t// check for authority as used in UNC shares\n\t\t// or use the path as given\n\t\tif (path[0] === _slash && path[1] === _slash) {\n\t\t\tconst idx = path.indexOf(_slash, 2);\n\t\t\tif (idx === -1) {\n\t\t\t\tauthority = path.substring(2);\n\t\t\t\tpath = _slash;\n\t\t\t} else {\n\t\t\t\tauthority = path.substring(2, idx);\n\t\t\t\tpath = path.substring(idx) || _slash;\n\t\t\t}\n\t\t}\n\n\t\treturn new Uri('file', authority, path, _empty, _empty);\n\t}\n\n\t/**\n\t * Creates new URI from uri components.\n\t *\n\t * Unless `strict` is `true` the scheme is defaults to be `file`. This function performs\n\t * validation and should be used for untrusted uri components retrieved from storage,\n\t * user input, command arguments etc\n\t */\n\tstatic from(components: UriComponents, strict?: boolean): URI {\n\t\tconst result = new Uri(\n\t\t\tcomponents.scheme,\n\t\t\tcomponents.authority,\n\t\t\tcomponents.path,\n\t\t\tcomponents.query,\n\t\t\tcomponents.fragment,\n\t\t\tstrict\n\t\t);\n\t\treturn result;\n\t}\n\n\t/**\n\t * Join a URI path with path fragments and normalizes the resulting path.\n\t *\n\t * @param uri The input URI.\n\t * @param pathFragment The path fragment to add to the URI path.\n\t * @returns The resulting URI.\n\t */\n\tstatic joinPath(uri: URI, ...pathFragment: string[]): URI {\n\t\tif (!uri.path) {\n\t\t\tthrow new Error(`[UriError]: cannot call joinPath on URI without path`);\n\t\t}\n\t\tlet newPath: string;\n\t\tif (isWindows && uri.scheme === 'file') {\n\t\t\tnewPath = URI.file(paths.win32.join(uriToFsPath(uri, true), ...pathFragment)).path;\n\t\t} else {\n\t\t\tnewPath = paths.posix.join(uri.path, ...pathFragment);\n\t\t}\n\t\treturn uri.with({ path: newPath });\n\t}\n\n\t// ---- printing/externalize ---------------------------\n\n\t/**\n\t * Creates a string representation for this URI. It's guaranteed that calling\n\t * `URI.parse` with the result of this function creates an URI which is equal\n\t * to this URI.\n\t *\n\t * * The result shall *not* be used for display purposes but for externalization or transport.\n\t * * The result will be encoded using the percentage encoding and encoding happens mostly\n\t * ignore the scheme-specific encoding rules.\n\t *\n\t * @param skipEncoding Do not encode the result, default is `false`\n\t */\n\ttoString(skipEncoding: boolean = false): string {\n\t\treturn _asFormatted(this, skipEncoding);\n\t}\n\n\ttoJSON(): UriComponents {\n\t\treturn this;\n\t}\n\n\t/**\n\t * A helper function to revive URIs.\n\t *\n\t * **Note** that this function should only be used when receiving URI#toJSON generated data\n\t * and that it doesn't do any validation. Use {@link URI.from} when received \"untrusted\"\n\t * uri components such as command arguments or data from storage.\n\t *\n\t * @param data The URI components or URI to revive.\n\t * @returns The revived URI or undefined or null.\n\t */\n\tstatic revive(data: UriComponents | URI): URI;\n\tstatic revive(data: UriComponents | URI | undefined): URI | undefined;\n\tstatic revive(data: UriComponents | URI | null): URI | null;\n\tstatic revive(data: UriComponents | URI | undefined | null): URI | undefined | null;\n\tstatic revive(data: UriComponents | URI | undefined | null): URI | undefined | null {\n\t\tif (!data) {\n\t\t\treturn data;\n\t\t} else if (data instanceof URI) {\n\t\t\treturn data;\n\t\t} else {\n\t\t\tconst result = new Uri(data);\n\t\t\tresult._formatted = (data).external ?? null;\n\t\t\tresult._fsPath = (data)._sep === _pathSepMarker ? (data).fsPath ?? null : null;\n\t\t\treturn result;\n\t\t}\n\t}\n}\n\nexport interface UriComponents {\n\tscheme: string;\n\tauthority?: string;\n\tpath?: string;\n\tquery?: string;\n\tfragment?: string;\n}\n\ninterface UriState extends UriComponents {\n\t$mid: MarshalledId.Uri;\n\texternal?: string;\n\tfsPath?: string;\n\t_sep?: 1;\n}\n\nconst _pathSepMarker = isWindows ? 1 : undefined;\n\n// This class exists so that URI is compatible with vscode.Uri (API).\nclass Uri extends URI {\n\n\t_formatted: string | null = null;\n\t_fsPath: string | null = null;\n\n\toverride get fsPath(): string {\n\t\tif (!this._fsPath) {\n\t\t\tthis._fsPath = uriToFsPath(this, false);\n\t\t}\n\t\treturn this._fsPath;\n\t}\n\n\toverride toString(skipEncoding: boolean = false): string {\n\t\tif (!skipEncoding) {\n\t\t\tif (!this._formatted) {\n\t\t\t\tthis._formatted = _asFormatted(this, false);\n\t\t\t}\n\t\t\treturn this._formatted;\n\t\t} else {\n\t\t\t// we don't cache that\n\t\t\treturn _asFormatted(this, true);\n\t\t}\n\t}\n\n\toverride toJSON(): UriComponents {\n\t\tconst res = {\n\t\t\t$mid: MarshalledId.Uri\n\t\t};\n\t\t// cached state\n\t\tif (this._fsPath) {\n\t\t\tres.fsPath = this._fsPath;\n\t\t\tres._sep = _pathSepMarker;\n\t\t}\n\t\tif (this._formatted) {\n\t\t\tres.external = this._formatted;\n\t\t}\n\t\t//--- uri components\n\t\tif (this.path) {\n\t\t\tres.path = this.path;\n\t\t}\n\t\t// TODO\n\t\t// this isn't correct and can violate the UriComponents contract but\n\t\t// this is part of the vscode.Uri API and we shouldn't change how that\n\t\t// works anymore\n\t\tif (this.scheme) {\n\t\t\tres.scheme = this.scheme;\n\t\t}\n\t\tif (this.authority) {\n\t\t\tres.authority = this.authority;\n\t\t}\n\t\tif (this.query) {\n\t\t\tres.query = this.query;\n\t\t}\n\t\tif (this.fragment) {\n\t\t\tres.fragment = this.fragment;\n\t\t}\n\t\treturn res;\n\t}\n}\n\n// reserved characters: https://tools.ietf.org/html/rfc3986#section-2.2\nconst encodeTable: { [ch: number]: string } = {\n\t[CharCode.Colon]: '%3A', // gen-delims\n\t[CharCode.Slash]: '%2F',\n\t[CharCode.QuestionMark]: '%3F',\n\t[CharCode.Hash]: '%23',\n\t[CharCode.OpenSquareBracket]: '%5B',\n\t[CharCode.CloseSquareBracket]: '%5D',\n\t[CharCode.AtSign]: '%40',\n\n\t[CharCode.ExclamationMark]: '%21', // sub-delims\n\t[CharCode.DollarSign]: '%24',\n\t[CharCode.Ampersand]: '%26',\n\t[CharCode.SingleQuote]: '%27',\n\t[CharCode.OpenParen]: '%28',\n\t[CharCode.CloseParen]: '%29',\n\t[CharCode.Asterisk]: '%2A',\n\t[CharCode.Plus]: '%2B',\n\t[CharCode.Comma]: '%2C',\n\t[CharCode.Semicolon]: '%3B',\n\t[CharCode.Equals]: '%3D',\n\n\t[CharCode.Space]: '%20',\n};\n\nfunction encodeURIComponentFast(uriComponent: string, isPath: boolean, isAuthority: boolean): string {\n\tlet res: string | undefined = undefined;\n\tlet nativeEncodePos = -1;\n\n\tfor (let pos = 0; pos < uriComponent.length; pos++) {\n\t\tconst code = uriComponent.charCodeAt(pos);\n\n\t\t// unreserved characters: https://tools.ietf.org/html/rfc3986#section-2.3\n\t\tif (\n\t\t\t(code >= CharCode.a && code <= CharCode.z)\n\t\t\t|| (code >= CharCode.A && code <= CharCode.Z)\n\t\t\t|| (code >= CharCode.Digit0 && code <= CharCode.Digit9)\n\t\t\t|| code === CharCode.Dash\n\t\t\t|| code === CharCode.Period\n\t\t\t|| code === CharCode.Underline\n\t\t\t|| code === CharCode.Tilde\n\t\t\t|| (isPath && code === CharCode.Slash)\n\t\t\t|| (isAuthority && code === CharCode.OpenSquareBracket)\n\t\t\t|| (isAuthority && code === CharCode.CloseSquareBracket)\n\t\t\t|| (isAuthority && code === CharCode.Colon)\n\t\t) {\n\t\t\t// check if we are delaying native encode\n\t\t\tif (nativeEncodePos !== -1) {\n\t\t\t\tres += encodeURIComponent(uriComponent.substring(nativeEncodePos, pos));\n\t\t\t\tnativeEncodePos = -1;\n\t\t\t}\n\t\t\t// check if we write into a new string (by default we try to return the param)\n\t\t\tif (res !== undefined) {\n\t\t\t\tres += uriComponent.charAt(pos);\n\t\t\t}\n\n\t\t} else {\n\t\t\t// encoding needed, we need to allocate a new string\n\t\t\tif (res === undefined) {\n\t\t\t\tres = uriComponent.substr(0, pos);\n\t\t\t}\n\n\t\t\t// check with default table first\n\t\t\tconst escaped = encodeTable[code];\n\t\t\tif (escaped !== undefined) {\n\n\t\t\t\t// check if we are delaying native encode\n\t\t\t\tif (nativeEncodePos !== -1) {\n\t\t\t\t\tres += encodeURIComponent(uriComponent.substring(nativeEncodePos, pos));\n\t\t\t\t\tnativeEncodePos = -1;\n\t\t\t\t}\n\n\t\t\t\t// append escaped variant to result\n\t\t\t\tres += escaped;\n\n\t\t\t} else if (nativeEncodePos === -1) {\n\t\t\t\t// use native encode only when needed\n\t\t\t\tnativeEncodePos = pos;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (nativeEncodePos !== -1) {\n\t\tres += encodeURIComponent(uriComponent.substring(nativeEncodePos));\n\t}\n\n\treturn res !== undefined ? res : uriComponent;\n}\n\nfunction encodeURIComponentMinimal(path: string): string {\n\tlet res: string | undefined = undefined;\n\tfor (let pos = 0; pos < path.length; pos++) {\n\t\tconst code = path.charCodeAt(pos);\n\t\tif (code === CharCode.Hash || code === CharCode.QuestionMark) {\n\t\t\tif (res === undefined) {\n\t\t\t\tres = path.substr(0, pos);\n\t\t\t}\n\t\t\tres += encodeTable[code];\n\t\t} else {\n\t\t\tif (res !== undefined) {\n\t\t\t\tres += path[pos];\n\t\t\t}\n\t\t}\n\t}\n\treturn res !== undefined ? res : path;\n}\n\n/**\n * Compute `fsPath` for the given uri\n */\nexport function uriToFsPath(uri: URI, keepDriveLetterCasing: boolean): string {\n\n\tlet value: string;\n\tif (uri.authority && uri.path.length > 1 && uri.scheme === 'file') {\n\t\t// unc path: file://shares/c$/far/boo\n\t\tvalue = `//${uri.authority}${uri.path}`;\n\t} else if (\n\t\turi.path.charCodeAt(0) === CharCode.Slash\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)\n\t\t&& uri.path.charCodeAt(2) === CharCode.Colon\n\t) {\n\t\tif (!keepDriveLetterCasing) {\n\t\t\t// windows drive letter: file:///c:/far/boo\n\t\t\tvalue = uri.path[1].toLowerCase() + uri.path.substr(2);\n\t\t} else {\n\t\t\tvalue = uri.path.substr(1);\n\t\t}\n\t} else {\n\t\t// other path\n\t\tvalue = uri.path;\n\t}\n\tif (isWindows) {\n\t\tvalue = value.replace(/\\//g, '\\\\');\n\t}\n\treturn value;\n}\n\n/**\n * Create the external version of a uri\n */\nfunction _asFormatted(uri: URI, skipEncoding: boolean): string {\n\n\tconst encoder = !skipEncoding\n\t\t? encodeURIComponentFast\n\t\t: encodeURIComponentMinimal;\n\n\tlet res = '';\n\tlet { scheme, authority, path, query, fragment } = uri;\n\tif (scheme) {\n\t\tres += scheme;\n\t\tres += ':';\n\t}\n\tif (authority || scheme === 'file') {\n\t\tres += _slash;\n\t\tres += _slash;\n\t}\n\tif (authority) {\n\t\tlet idx = authority.indexOf('@');\n\t\tif (idx !== -1) {\n\t\t\t// @\n\t\t\tconst userinfo = authority.substr(0, idx);\n\t\t\tauthority = authority.substr(idx + 1);\n\t\t\tidx = userinfo.lastIndexOf(':');\n\t\t\tif (idx === -1) {\n\t\t\t\tres += encoder(userinfo, false, false);\n\t\t\t} else {\n\t\t\t\t// :@\n\t\t\t\tres += encoder(userinfo.substr(0, idx), false, false);\n\t\t\t\tres += ':';\n\t\t\t\tres += encoder(userinfo.substr(idx + 1), false, true);\n\t\t\t}\n\t\t\tres += '@';\n\t\t}\n\t\tauthority = authority.toLowerCase();\n\t\tidx = authority.lastIndexOf(':');\n\t\tif (idx === -1) {\n\t\t\tres += encoder(authority, false, true);\n\t\t} else {\n\t\t\t// :\n\t\t\tres += encoder(authority.substr(0, idx), false, true);\n\t\t\tres += authority.substr(idx);\n\t\t}\n\t}\n\tif (path) {\n\t\t// lower-case windows drive letters in /C:/fff or C:/fff\n\t\tif (path.length >= 3 && path.charCodeAt(0) === CharCode.Slash && path.charCodeAt(2) === CharCode.Colon) {\n\t\t\tconst code = path.charCodeAt(1);\n\t\t\tif (code >= CharCode.A && code <= CharCode.Z) {\n\t\t\t\tpath = `/${String.fromCharCode(code + 32)}:${path.substr(3)}`; // \"/c:\".length === 3\n\t\t\t}\n\t\t} else if (path.length >= 2 && path.charCodeAt(1) === CharCode.Colon) {\n\t\t\tconst code = path.charCodeAt(0);\n\t\t\tif (code >= CharCode.A && code <= CharCode.Z) {\n\t\t\t\tpath = `${String.fromCharCode(code + 32)}:${path.substr(2)}`; // \"/c:\".length === 3\n\t\t\t}\n\t\t}\n\t\t// encode the rest of the path\n\t\tres += encoder(path, true, false);\n\t}\n\tif (query) {\n\t\tres += '?';\n\t\tres += encoder(query, false, false);\n\t}\n\tif (fragment) {\n\t\tres += '#';\n\t\tres += !skipEncoding ? encodeURIComponentFast(fragment, false, false) : fragment;\n\t}\n\treturn res;\n}\n\n// --- decode\n\nfunction decodeURIComponentGraceful(str: string): string {\n\ttry {\n\t\treturn decodeURIComponent(str);\n\t} catch {\n\t\tif (str.length > 3) {\n\t\t\treturn str.substr(0, 3) + decodeURIComponentGraceful(str.substr(3));\n\t\t} else {\n\t\t\treturn str;\n\t\t}\n\t}\n}\n\nconst _rEncodedAsHex = /(%[0-9A-Za-z][0-9A-Za-z])+/g;\n\nfunction percentDecode(str: string): string {\n\tif (!str.match(_rEncodedAsHex)) {\n\t\treturn str;\n\t}\n\treturn str.replace(_rEncodedAsHex, (match) => decodeURIComponentGraceful(match));\n}\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\nimport { VSBuffer } from 'vs/base/common/buffer';\nimport { URI, UriComponents } from 'vs/base/common/uri';\nimport { MarshalledId } from './marshallingIds';\n\nexport function stringify(obj: any): string {\n\treturn JSON.stringify(obj, replacer);\n}\n\nexport function parse(text: string): any {\n\tlet data = JSON.parse(text);\n\tdata = revive(data);\n\treturn data;\n}\n\nexport interface MarshalledObject {\n\t$mid: MarshalledId;\n}\n\nfunction replacer(key: string, value: any): any {\n\t// URI is done via toJSON-member\n\tif (value instanceof RegExp) {\n\t\treturn {\n\t\t\t$mid: MarshalledId.Regexp,\n\t\t\tsource: value.source,\n\t\t\tflags: value.flags,\n\t\t};\n\t}\n\treturn value;\n}\n\n\ntype Deserialize = T extends UriComponents ? URI\n\t: T extends VSBuffer ? VSBuffer\n\t: T extends object\n\t? Revived\n\t: T;\n\nexport type Revived = { [K in keyof T]: Deserialize };\n\nexport function revive(obj: any, depth = 0): Revived {\n\tif (!obj || depth > 200) {\n\t\treturn obj;\n\t}\n\n\tif (typeof obj === 'object') {\n\n\t\tswitch ((obj).$mid) {\n\t\t\tcase MarshalledId.Uri: return URI.revive(obj);\n\t\t\tcase MarshalledId.Regexp: return new RegExp(obj.source, obj.flags);\n\t\t\tcase MarshalledId.Date: return new Date(obj.source);\n\t\t}\n\n\t\tif (\n\t\t\tobj instanceof VSBuffer\n\t\t\t|| obj instanceof Uint8Array\n\t\t) {\n\t\t\treturn obj;\n\t\t}\n\n\t\tif (Array.isArray(obj)) {\n\t\t\tfor (let i = 0; i < obj.length; ++i) {\n\t\t\t\tobj[i] = revive(obj[i], depth + 1);\n\t\t\t}\n\t\t} else {\n\t\t\t// walk object\n\t\t\tfor (const key in obj) {\n\t\t\t\tif (Object.hasOwnProperty.call(obj, key)) {\n\t\t\t\t\tobj[key] = revive(obj[key], depth + 1);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn obj;\n}\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\nimport * as errors from 'vs/base/common/errors';\nimport * as platform from 'vs/base/common/platform';\nimport { equalsIgnoreCase, startsWithIgnoreCase } from 'vs/base/common/strings';\nimport { URI } from 'vs/base/common/uri';\nimport * as paths from 'vs/base/common/path';\n\nexport namespace Schemas {\n\n\t/**\n\t * A schema that is used for models that exist in memory\n\t * only and that have no correspondence on a server or such.\n\t */\n\texport const inMemory = 'inmemory';\n\n\t/**\n\t * A schema that is used for setting files\n\t */\n\texport const vscode = 'vscode';\n\n\t/**\n\t * A schema that is used for internal private files\n\t */\n\texport const internal = 'private';\n\n\t/**\n\t * A walk-through document.\n\t */\n\texport const walkThrough = 'walkThrough';\n\n\t/**\n\t * An embedded code snippet.\n\t */\n\texport const walkThroughSnippet = 'walkThroughSnippet';\n\n\texport const http = 'http';\n\n\texport const https = 'https';\n\n\texport const file = 'file';\n\n\texport const mailto = 'mailto';\n\n\texport const untitled = 'untitled';\n\n\texport const data = 'data';\n\n\texport const command = 'command';\n\n\texport const vscodeRemote = 'vscode-remote';\n\n\texport const vscodeRemoteResource = 'vscode-remote-resource';\n\n\texport const vscodeManagedRemoteResource = 'vscode-managed-remote-resource';\n\n\texport const vscodeUserData = 'vscode-userdata';\n\n\texport const vscodeCustomEditor = 'vscode-custom-editor';\n\n\texport const vscodeNotebookCell = 'vscode-notebook-cell';\n\texport const vscodeNotebookCellMetadata = 'vscode-notebook-cell-metadata';\n\texport const vscodeNotebookCellOutput = 'vscode-notebook-cell-output';\n\texport const vscodeInteractiveInput = 'vscode-interactive-input';\n\n\texport const vscodeSettings = 'vscode-settings';\n\n\texport const vscodeWorkspaceTrust = 'vscode-workspace-trust';\n\n\texport const vscodeTerminal = 'vscode-terminal';\n\n\t/** Scheme used for code blocks in chat. */\n\texport const vscodeChatCodeBlock = 'vscode-chat-code-block';\n\t/** Scheme used for LHS of code compare (aka diff) blocks in chat. */\n\texport const vscodeChatCodeCompareBlock = 'vscode-chat-code-compare-block';\n\t/** Scheme used for the chat input editor. */\n\texport const vscodeChatSesssion = 'vscode-chat-editor';\n\n\t/**\n\t * Scheme used internally for webviews that aren't linked to a resource (i.e. not custom editors)\n\t */\n\texport const webviewPanel = 'webview-panel';\n\n\t/**\n\t * Scheme used for loading the wrapper html and script in webviews.\n\t */\n\texport const vscodeWebview = 'vscode-webview';\n\n\t/**\n\t * Scheme used for extension pages\n\t */\n\texport const extension = 'extension';\n\n\t/**\n\t * Scheme used as a replacement of `file` scheme to load\n\t * files with our custom protocol handler (desktop only).\n\t */\n\texport const vscodeFileResource = 'vscode-file';\n\n\t/**\n\t * Scheme used for temporary resources\n\t */\n\texport const tmp = 'tmp';\n\n\t/**\n\t * Scheme used vs live share\n\t */\n\texport const vsls = 'vsls';\n\n\t/**\n\t * Scheme used for the Source Control commit input's text document\n\t */\n\texport const vscodeSourceControl = 'vscode-scm';\n\n\t/**\n\t * Scheme used for input box for creating comments.\n\t */\n\texport const commentsInput = 'comment';\n\n\t/**\n\t * Scheme used for special rendering of settings in the release notes\n\t */\n\texport const codeSetting = 'code-setting';\n}\n\nexport function matchesScheme(target: URI | string, scheme: string): boolean {\n\tif (URI.isUri(target)) {\n\t\treturn equalsIgnoreCase(target.scheme, scheme);\n\t} else {\n\t\treturn startsWithIgnoreCase(target, scheme + ':');\n\t}\n}\n\nexport function matchesSomeScheme(target: URI | string, ...schemes: string[]): boolean {\n\treturn schemes.some(scheme => matchesScheme(target, scheme));\n}\nexport const connectionTokenQueryName = 'tkn';\n\nclass RemoteAuthoritiesImpl {\n\tprivate readonly _hosts: { [authority: string]: string | undefined } = Object.create(null);\n\tprivate readonly _ports: { [authority: string]: number | undefined } = Object.create(null);\n\tprivate readonly _connectionTokens: { [authority: string]: string | undefined } = Object.create(null);\n\tprivate _preferredWebSchema: 'http' | 'https' = 'http';\n\tprivate _delegate: ((uri: URI) => URI) | null = null;\n\tprivate _serverRootPath: string = '/';\n\n\tsetPreferredWebSchema(schema: 'http' | 'https') {\n\t\tthis._preferredWebSchema = schema;\n\t}\n\n\tprivate get _remoteResourcesPath(): string {\n\t\treturn paths.posix.join(this._serverRootPath, Schemas.vscodeRemoteResource);\n\t}\n\n\trewrite(uri: URI): URI {\n\t\tif (this._delegate) {\n\t\t\ttry {\n\t\t\t\treturn this._delegate(uri);\n\t\t\t} catch (err) {\n\t\t\t\terrors.onUnexpectedError(err);\n\t\t\t\treturn uri;\n\t\t\t}\n\t\t}\n\t\tconst authority = uri.authority;\n\t\tlet host = this._hosts[authority];\n\t\tif (host && host.indexOf(':') !== -1 && host.indexOf('[') === -1) {\n\t\t\thost = `[${host}]`;\n\t\t}\n\t\tconst port = this._ports[authority];\n\t\tconst connectionToken = this._connectionTokens[authority];\n\t\tlet query = `path=${encodeURIComponent(uri.path)}`;\n\t\tif (typeof connectionToken === 'string') {\n\t\t\tquery += `&${connectionTokenQueryName}=${encodeURIComponent(connectionToken)}`;\n\t\t}\n\t\treturn URI.from({\n\t\t\tscheme: platform.isWeb ? this._preferredWebSchema : Schemas.vscodeRemoteResource,\n\t\t\tauthority: `${host}:${port}`,\n\t\t\tpath: this._remoteResourcesPath,\n\t\t\tquery\n\t\t});\n\t}\n}\n\nexport const RemoteAuthorities = new RemoteAuthoritiesImpl();\n\nexport const VSCODE_AUTHORITY = 'vscode-app';\n\nclass FileAccessImpl {\n\n\tprivate static readonly FALLBACK_AUTHORITY = VSCODE_AUTHORITY;\n\n\t/**\n\t * Returns a URI to use in contexts where the browser is responsible\n\t * for loading (e.g. fetch()) or when used within the DOM.\n\t *\n\t * **Note:** use `dom.ts#asCSSUrl` whenever the URL is to be used in CSS context.\n\t */\n\turiToBrowserUri(uri: URI): URI {\n\t\t// Handle remote URIs via `RemoteAuthorities`\n\t\tif (uri.scheme === Schemas.vscodeRemote) {\n\t\t\treturn RemoteAuthorities.rewrite(uri);\n\t\t}\n\n\t\t// Convert to `vscode-file` resource..\n\t\tif (\n\t\t\t// ...only ever for `file` resources\n\t\t\turi.scheme === Schemas.file &&\n\t\t\t(\n\t\t\t\t// ...and we run in native environments\n\t\t\t\tplatform.isNative ||\n\t\t\t\t// ...or web worker extensions on desktop\n\t\t\t\t(platform.webWorkerOrigin === `${Schemas.vscodeFileResource}://${FileAccessImpl.FALLBACK_AUTHORITY}`)\n\t\t\t)\n\t\t) {\n\t\t\treturn uri.with({\n\t\t\t\tscheme: Schemas.vscodeFileResource,\n\t\t\t\t// We need to provide an authority here so that it can serve\n\t\t\t\t// as origin for network and loading matters in chromium.\n\t\t\t\t// If the URI is not coming with an authority already, we\n\t\t\t\t// add our own\n\t\t\t\tauthority: uri.authority || FileAccessImpl.FALLBACK_AUTHORITY,\n\t\t\t\tquery: null,\n\t\t\t\tfragment: null\n\t\t\t});\n\t\t}\n\n\t\treturn uri;\n\t}\n}\n\nexport const FileAccess = new FileAccessImpl();\n\n\nexport namespace COI {\n\n\tconst coiHeaders = new Map<'3' | '2' | '1' | string, Record>([\n\t\t['1', { 'Cross-Origin-Opener-Policy': 'same-origin' }],\n\t\t['2', { 'Cross-Origin-Embedder-Policy': 'require-corp' }],\n\t\t['3', { 'Cross-Origin-Opener-Policy': 'same-origin', 'Cross-Origin-Embedder-Policy': 'require-corp' }],\n\t]);\n\n\texport const CoopAndCoep = Object.freeze(coiHeaders.get('3'));\n\n\tconst coiSearchParamName = 'vscode-coi';\n\n\t/**\n\t * Extract desired headers from `vscode-coi` invocation\n\t */\n\texport function getHeadersFromQuery(url: string | URI | URL): Record | undefined {\n\t\tlet params: URLSearchParams | undefined;\n\t\tif (typeof url === 'string') {\n\t\t\tparams = new URL(url).searchParams;\n\t\t} else if (url instanceof URL) {\n\t\t\tparams = url.searchParams;\n\t\t} else if (URI.isUri(url)) {\n\t\t\tparams = new URL(url.toString(true)).searchParams;\n\t\t}\n\t\tconst value = params?.get(coiSearchParamName);\n\t\tif (!value) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn coiHeaders.get(value);\n\t}\n\n\t/**\n\t * Add the `vscode-coi` query attribute based on wanting `COOP` and `COEP`. Will be a noop when `crossOriginIsolated`\n\t * isn't enabled the current context\n\t */\n\texport function addSearchParam(urlOrSearch: URLSearchParams | Record, coop: boolean, coep: boolean): void {\n\t\tif (!(globalThis).crossOriginIsolated) {\n\t\t\t// depends on the current context being COI\n\t\t\treturn;\n\t\t}\n\t\tconst value = coop && coep ? '3' : coep ? '2' : '1';\n\t\tif (urlOrSearch instanceof URLSearchParams) {\n\t\t\turlOrSearch.set(coiSearchParamName, value);\n\t\t} else {\n\t\t\t(>urlOrSearch)[coiSearchParamName] = value;\n\t\t}\n\t}\n}\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\nimport * as browser from 'vs/base/browser/browser';\nimport { BrowserFeatures } from 'vs/base/browser/canIUse';\nimport { IKeyboardEvent, StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';\nimport { IMouseEvent, StandardMouseEvent } from 'vs/base/browser/mouseEvent';\nimport { AbstractIdleValue, IntervalTimer, _runWhenIdle, IdleDeadline } from 'vs/base/common/async';\nimport { onUnexpectedError } from 'vs/base/common/errors';\nimport * as event from 'vs/base/common/event';\nimport * as dompurify from 'vs/base/browser/dompurify/dompurify';\nimport { KeyCode } from 'vs/base/common/keyCodes';\nimport { Disposable, DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle';\nimport { FileAccess, RemoteAuthorities } from 'vs/base/common/network';\nimport * as platform from 'vs/base/common/platform';\nimport { URI } from 'vs/base/common/uri';\nimport { hash } from 'vs/base/common/hash';\nimport { CodeWindow, ensureCodeWindow, mainWindow } from 'vs/base/browser/window';\n\nexport interface IRegisteredCodeWindow {\n\treadonly window: CodeWindow;\n\treadonly disposables: DisposableStore;\n}\n\n//# region Multi-Window Support Utilities\n\nexport const {\n\tregisterWindow,\n\tgetWindow,\n\tgetDocument,\n\tgetWindows,\n\tgetWindowsCount,\n\tgetWindowId,\n\tgetWindowById,\n\thasWindow,\n\tonDidRegisterWindow,\n\tonWillUnregisterWindow,\n\tonDidUnregisterWindow\n} = (function () {\n\tconst windows = new Map();\n\n\tensureCodeWindow(mainWindow, 1);\n\tconst mainWindowRegistration = { window: mainWindow, disposables: new DisposableStore() };\n\twindows.set(mainWindow.vscodeWindowId, mainWindowRegistration);\n\n\tconst onDidRegisterWindow = new event.Emitter();\n\tconst onDidUnregisterWindow = new event.Emitter();\n\tconst onWillUnregisterWindow = new event.Emitter();\n\n\tfunction getWindowById(windowId: number): IRegisteredCodeWindow | undefined;\n\tfunction getWindowById(windowId: number | undefined, fallbackToMain: true): IRegisteredCodeWindow;\n\tfunction getWindowById(windowId: number | undefined, fallbackToMain?: boolean): IRegisteredCodeWindow | undefined {\n\t\tconst window = typeof windowId === 'number' ? windows.get(windowId) : undefined;\n\n\t\treturn window ?? (fallbackToMain ? mainWindowRegistration : undefined);\n\t}\n\n\treturn {\n\t\tonDidRegisterWindow: onDidRegisterWindow.event,\n\t\tonWillUnregisterWindow: onWillUnregisterWindow.event,\n\t\tonDidUnregisterWindow: onDidUnregisterWindow.event,\n\t\tregisterWindow(window: CodeWindow): IDisposable {\n\t\t\tif (windows.has(window.vscodeWindowId)) {\n\t\t\t\treturn Disposable.None;\n\t\t\t}\n\n\t\t\tconst disposables = new DisposableStore();\n\n\t\t\tconst registeredWindow = {\n\t\t\t\twindow,\n\t\t\t\tdisposables: disposables.add(new DisposableStore())\n\t\t\t};\n\t\t\twindows.set(window.vscodeWindowId, registeredWindow);\n\n\t\t\tdisposables.add(toDisposable(() => {\n\t\t\t\twindows.delete(window.vscodeWindowId);\n\t\t\t\tonDidUnregisterWindow.fire(window);\n\t\t\t}));\n\n\t\t\tdisposables.add(addDisposableListener(window, EventType.BEFORE_UNLOAD, () => {\n\t\t\t\tonWillUnregisterWindow.fire(window);\n\t\t\t}));\n\n\t\t\tonDidRegisterWindow.fire(registeredWindow);\n\n\t\t\treturn disposables;\n\t\t},\n\t\tgetWindows(): Iterable {\n\t\t\treturn windows.values();\n\t\t},\n\t\tgetWindowsCount(): number {\n\t\t\treturn windows.size;\n\t\t},\n\t\tgetWindowId(targetWindow: Window): number {\n\t\t\treturn (targetWindow as CodeWindow).vscodeWindowId;\n\t\t},\n\t\thasWindow(windowId: number): boolean {\n\t\t\treturn windows.has(windowId);\n\t\t},\n\t\tgetWindowById,\n\t\tgetWindow(e: Node | UIEvent | undefined | null): CodeWindow {\n\t\t\tconst candidateNode = e as Node | undefined | null;\n\t\t\tif (candidateNode?.ownerDocument?.defaultView) {\n\t\t\t\treturn candidateNode.ownerDocument.defaultView.window as CodeWindow;\n\t\t\t}\n\n\t\t\tconst candidateEvent = e as UIEvent | undefined | null;\n\t\t\tif (candidateEvent?.view) {\n\t\t\t\treturn candidateEvent.view.window as CodeWindow;\n\t\t\t}\n\n\t\t\treturn mainWindow;\n\t\t},\n\t\tgetDocument(e: Node | UIEvent | undefined | null): Document {\n\t\t\tconst candidateNode = e as Node | undefined | null;\n\t\t\treturn getWindow(candidateNode).document;\n\t\t}\n\t};\n})();\n\n//#endregion\n\nexport function clearNode(node: HTMLElement): void {\n\twhile (node.firstChild) {\n\t\tnode.firstChild.remove();\n\t}\n}\n\nclass DomListener implements IDisposable {\n\n\tprivate _handler: (e: any) => void;\n\tprivate _node: EventTarget;\n\tprivate readonly _type: string;\n\tprivate readonly _options: boolean | AddEventListenerOptions;\n\n\tconstructor(node: EventTarget, type: string, handler: (e: any) => void, options?: boolean | AddEventListenerOptions) {\n\t\tthis._node = node;\n\t\tthis._type = type;\n\t\tthis._handler = handler;\n\t\tthis._options = (options || false);\n\t\tthis._node.addEventListener(this._type, this._handler, this._options);\n\t}\n\n\tdispose(): void {\n\t\tif (!this._handler) {\n\t\t\t// Already disposed\n\t\t\treturn;\n\t\t}\n\n\t\tthis._node.removeEventListener(this._type, this._handler, this._options);\n\n\t\t// Prevent leakers from holding on to the dom or handler func\n\t\tthis._node = null!;\n\t\tthis._handler = null!;\n\t}\n}\n\nexport function addDisposableListener(node: EventTarget, type: K, handler: (event: GlobalEventHandlersEventMap[K]) => void, useCapture?: boolean): IDisposable;\nexport function addDisposableListener(node: EventTarget, type: string, handler: (event: any) => void, useCapture?: boolean): IDisposable;\nexport function addDisposableListener(node: EventTarget, type: string, handler: (event: any) => void, options: AddEventListenerOptions): IDisposable;\nexport function addDisposableListener(node: EventTarget, type: string, handler: (event: any) => void, useCaptureOrOptions?: boolean | AddEventListenerOptions): IDisposable {\n\treturn new DomListener(node, type, handler, useCaptureOrOptions);\n}\n\nexport interface IAddStandardDisposableListenerSignature {\n\t(node: HTMLElement, type: 'click', handler: (event: IMouseEvent) => void, useCapture?: boolean): IDisposable;\n\t(node: HTMLElement, type: 'mousedown', handler: (event: IMouseEvent) => void, useCapture?: boolean): IDisposable;\n\t(node: HTMLElement, type: 'keydown', handler: (event: IKeyboardEvent) => void, useCapture?: boolean): IDisposable;\n\t(node: HTMLElement, type: 'keypress', handler: (event: IKeyboardEvent) => void, useCapture?: boolean): IDisposable;\n\t(node: HTMLElement, type: 'keyup', handler: (event: IKeyboardEvent) => void, useCapture?: boolean): IDisposable;\n\t(node: HTMLElement, type: 'pointerdown', handler: (event: PointerEvent) => void, useCapture?: boolean): IDisposable;\n\t(node: HTMLElement, type: 'pointermove', handler: (event: PointerEvent) => void, useCapture?: boolean): IDisposable;\n\t(node: HTMLElement, type: 'pointerup', handler: (event: PointerEvent) => void, useCapture?: boolean): IDisposable;\n\t(node: HTMLElement, type: string, handler: (event: any) => void, useCapture?: boolean): IDisposable;\n}\nfunction _wrapAsStandardMouseEvent(targetWindow: Window, handler: (e: IMouseEvent) => void): (e: MouseEvent) => void {\n\treturn function (e: MouseEvent) {\n\t\treturn handler(new StandardMouseEvent(targetWindow, e));\n\t};\n}\nfunction _wrapAsStandardKeyboardEvent(handler: (e: IKeyboardEvent) => void): (e: KeyboardEvent) => void {\n\treturn function (e: KeyboardEvent) {\n\t\treturn handler(new StandardKeyboardEvent(e));\n\t};\n}\nexport const addStandardDisposableListener: IAddStandardDisposableListenerSignature = function addStandardDisposableListener(node: HTMLElement, type: string, handler: (event: any) => void, useCapture?: boolean): IDisposable {\n\tlet wrapHandler = handler;\n\n\tif (type === 'click' || type === 'mousedown' || type === 'contextmenu') {\n\t\twrapHandler = _wrapAsStandardMouseEvent(getWindow(node), handler);\n\t} else if (type === 'keydown' || type === 'keypress' || type === 'keyup') {\n\t\twrapHandler = _wrapAsStandardKeyboardEvent(handler);\n\t}\n\n\treturn addDisposableListener(node, type, wrapHandler, useCapture);\n};\n\nexport const addStandardDisposableGenericMouseDownListener = function addStandardDisposableListener(node: HTMLElement, handler: (event: any) => void, useCapture?: boolean): IDisposable {\n\tconst wrapHandler = _wrapAsStandardMouseEvent(getWindow(node), handler);\n\n\treturn addDisposableGenericMouseDownListener(node, wrapHandler, useCapture);\n};\n\nexport const addStandardDisposableGenericMouseUpListener = function addStandardDisposableListener(node: HTMLElement, handler: (event: any) => void, useCapture?: boolean): IDisposable {\n\tconst wrapHandler = _wrapAsStandardMouseEvent(getWindow(node), handler);\n\n\treturn addDisposableGenericMouseUpListener(node, wrapHandler, useCapture);\n};\nexport function addDisposableGenericMouseDownListener(node: EventTarget, handler: (event: any) => void, useCapture?: boolean): IDisposable {\n\treturn addDisposableListener(node, platform.isIOS && BrowserFeatures.pointerEvents ? EventType.POINTER_DOWN : EventType.MOUSE_DOWN, handler, useCapture);\n}\n\nexport function addDisposableGenericMouseUpListener(node: EventTarget, handler: (event: any) => void, useCapture?: boolean): IDisposable {\n\treturn addDisposableListener(node, platform.isIOS && BrowserFeatures.pointerEvents ? EventType.POINTER_UP : EventType.MOUSE_UP, handler, useCapture);\n}\n\n/**\n * Execute the callback the next time the browser is idle, returning an\n * {@link IDisposable} that will cancel the callback when disposed. This wraps\n * [requestIdleCallback] so it will fallback to [setTimeout] if the environment\n * doesn't support it.\n *\n * @param targetWindow The window for which to run the idle callback\n * @param callback The callback to run when idle, this includes an\n * [IdleDeadline] that provides the time alloted for the idle callback by the\n * browser. Not respecting this deadline will result in a degraded user\n * experience.\n * @param timeout A timeout at which point to queue no longer wait for an idle\n * callback but queue it on the regular event loop (like setTimeout). Typically\n * this should not be used.\n *\n * [IdleDeadline]: https://developer.mozilla.org/en-US/docs/Web/API/IdleDeadline\n * [requestIdleCallback]: https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback\n * [setTimeout]: https://developer.mozilla.org/en-US/docs/Web/API/Window/setTimeout\n */\nexport function runWhenWindowIdle(targetWindow: Window | typeof globalThis, callback: (idle: IdleDeadline) => void, timeout?: number): IDisposable {\n\treturn _runWhenIdle(targetWindow, callback, timeout);\n}\n\n/**\n * An implementation of the \"idle-until-urgent\"-strategy as introduced\n * here: https://philipwalton.com/articles/idle-until-urgent/\n */\nexport class WindowIdleValue extends AbstractIdleValue {\n\tconstructor(targetWindow: Window | typeof globalThis, executor: () => T) {\n\t\tsuper(targetWindow, executor);\n\t}\n}\n\n/**\n * Schedule a callback to be run at the next animation frame.\n * This allows multiple parties to register callbacks that should run at the next animation frame.\n * If currently in an animation frame, `runner` will be executed immediately.\n * @return token that can be used to cancel the scheduled runner (only if `runner` was not executed immediately).\n */\nexport let runAtThisOrScheduleAtNextAnimationFrame: (targetWindow: Window, runner: () => void, priority?: number) => IDisposable;\n/**\n * Schedule a callback to be run at the next animation frame.\n * This allows multiple parties to register callbacks that should run at the next animation frame.\n * If currently in an animation frame, `runner` will be executed at the next animation frame.\n * @return token that can be used to cancel the scheduled runner.\n */\nexport let scheduleAtNextAnimationFrame: (targetWindow: Window, runner: () => void, priority?: number) => IDisposable;\n\nexport class WindowIntervalTimer extends IntervalTimer {\n\n\tprivate readonly defaultTarget?: Window & typeof globalThis;\n\n\t/**\n\t *\n\t * @param node The optional node from which the target window is determined\n\t */\n\tconstructor(node?: Node) {\n\t\tsuper();\n\t\tthis.defaultTarget = node && getWindow(node);\n\t}\n\n\toverride cancelAndSet(runner: () => void, interval: number, targetWindow?: Window & typeof globalThis): void {\n\t\treturn super.cancelAndSet(runner, interval, targetWindow ?? this.defaultTarget);\n\t}\n}\n\nclass AnimationFrameQueueItem implements IDisposable {\n\n\tprivate _runner: () => void;\n\tpublic priority: number;\n\tprivate _canceled: boolean;\n\n\tconstructor(runner: () => void, priority: number = 0) {\n\t\tthis._runner = runner;\n\t\tthis.priority = priority;\n\t\tthis._canceled = false;\n\t}\n\n\tdispose(): void {\n\t\tthis._canceled = true;\n\t}\n\n\texecute(): void {\n\t\tif (this._canceled) {\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tthis._runner();\n\t\t} catch (e) {\n\t\t\tonUnexpectedError(e);\n\t\t}\n\t}\n\n\t// Sort by priority (largest to lowest)\n\tstatic sort(a: AnimationFrameQueueItem, b: AnimationFrameQueueItem): number {\n\t\treturn b.priority - a.priority;\n\t}\n}\n\n(function () {\n\t/**\n\t * The runners scheduled at the next animation frame\n\t */\n\tconst NEXT_QUEUE = new Map();\n\t/**\n\t * The runners scheduled at the current animation frame\n\t */\n\tconst CURRENT_QUEUE = new Map();\n\t/**\n\t * A flag to keep track if the native requestAnimationFrame was already called\n\t */\n\tconst animFrameRequested = new Map();\n\t/**\n\t * A flag to indicate if currently handling a native requestAnimationFrame callback\n\t */\n\tconst inAnimationFrameRunner = new Map();\n\n\tconst animationFrameRunner = (targetWindowId: number) => {\n\t\tanimFrameRequested.set(targetWindowId, false);\n\n\t\tconst currentQueue = NEXT_QUEUE.get(targetWindowId) ?? [];\n\t\tCURRENT_QUEUE.set(targetWindowId, currentQueue);\n\t\tNEXT_QUEUE.set(targetWindowId, []);\n\n\t\tinAnimationFrameRunner.set(targetWindowId, true);\n\t\twhile (currentQueue.length > 0) {\n\t\t\tcurrentQueue.sort(AnimationFrameQueueItem.sort);\n\t\t\tconst top = currentQueue.shift()!;\n\t\t\ttop.execute();\n\t\t}\n\t\tinAnimationFrameRunner.set(targetWindowId, false);\n\t};\n\n\tscheduleAtNextAnimationFrame = (targetWindow: Window, runner: () => void, priority: number = 0) => {\n\t\tconst targetWindowId = getWindowId(targetWindow);\n\t\tconst item = new AnimationFrameQueueItem(runner, priority);\n\n\t\tlet nextQueue = NEXT_QUEUE.get(targetWindowId);\n\t\tif (!nextQueue) {\n\t\t\tnextQueue = [];\n\t\t\tNEXT_QUEUE.set(targetWindowId, nextQueue);\n\t\t}\n\t\tnextQueue.push(item);\n\n\t\tif (!animFrameRequested.get(targetWindowId)) {\n\t\t\tanimFrameRequested.set(targetWindowId, true);\n\t\t\ttargetWindow.requestAnimationFrame(() => animationFrameRunner(targetWindowId));\n\t\t}\n\n\t\treturn item;\n\t};\n\n\trunAtThisOrScheduleAtNextAnimationFrame = (targetWindow: Window, runner: () => void, priority?: number) => {\n\t\tconst targetWindowId = getWindowId(targetWindow);\n\t\tif (inAnimationFrameRunner.get(targetWindowId)) {\n\t\t\tconst item = new AnimationFrameQueueItem(runner, priority);\n\t\t\tlet currentQueue = CURRENT_QUEUE.get(targetWindowId);\n\t\t\tif (!currentQueue) {\n\t\t\t\tcurrentQueue = [];\n\t\t\t\tCURRENT_QUEUE.set(targetWindowId, currentQueue);\n\t\t\t}\n\t\t\tcurrentQueue.push(item);\n\t\t\treturn item;\n\t\t} else {\n\t\t\treturn scheduleAtNextAnimationFrame(targetWindow, runner, priority);\n\t\t}\n\t};\n})();\n\nexport function getComputedStyle(el: HTMLElement): CSSStyleDeclaration {\n\treturn getWindow(el).getComputedStyle(el, null);\n}\n\nexport function getClientArea(element: HTMLElement, fallback?: HTMLElement): Dimension {\n\tconst elWindow = getWindow(element);\n\tconst elDocument = elWindow.document;\n\n\t// Try with DOM clientWidth / clientHeight\n\tif (element !== elDocument.body) {\n\t\treturn new Dimension(element.clientWidth, element.clientHeight);\n\t}\n\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\n\tif (platform.isIOS && elWindow?.visualViewport) {\n\t\treturn new Dimension(elWindow.visualViewport.width, elWindow.visualViewport.height);\n\t}\n\n\t// Try innerWidth / innerHeight\n\tif (elWindow?.innerWidth && elWindow.innerHeight) {\n\t\treturn new Dimension(elWindow.innerWidth, elWindow.innerHeight);\n\t}\n\n\t// Try with document.body.clientWidth / document.body.clientHeight\n\tif (elDocument.body && elDocument.body.clientWidth && elDocument.body.clientHeight) {\n\t\treturn new Dimension(elDocument.body.clientWidth, elDocument.body.clientHeight);\n\t}\n\n\t// Try with document.documentElement.clientWidth / document.documentElement.clientHeight\n\tif (elDocument.documentElement && elDocument.documentElement.clientWidth && elDocument.documentElement.clientHeight) {\n\t\treturn new Dimension(elDocument.documentElement.clientWidth, elDocument.documentElement.clientHeight);\n\t}\n\n\tif (fallback) {\n\t\treturn getClientArea(fallback);\n\t}\n\n\tthrow new Error('Unable to figure out browser width and height');\n}\n\nclass SizeUtils {\n\t// Adapted from WinJS\n\t// Converts a CSS positioning string for the specified element to pixels.\n\tprivate static convertToPixels(element: HTMLElement, value: string): number {\n\t\treturn parseFloat(value) || 0;\n\t}\n\n\tprivate static getDimension(element: HTMLElement, cssPropertyName: string, jsPropertyName: string): number {\n\t\tconst computedStyle = getComputedStyle(element);\n\t\tconst value = computedStyle ? computedStyle.getPropertyValue(cssPropertyName) : '0';\n\t\treturn SizeUtils.convertToPixels(element, value);\n\t}\n\n\tstatic getBorderLeftWidth(element: HTMLElement): number {\n\t\treturn SizeUtils.getDimension(element, 'border-left-width', 'borderLeftWidth');\n\t}\n\tstatic getBorderRightWidth(element: HTMLElement): number {\n\t\treturn SizeUtils.getDimension(element, 'border-right-width', 'borderRightWidth');\n\t}\n\tstatic getBorderTopWidth(element: HTMLElement): number {\n\t\treturn SizeUtils.getDimension(element, 'border-top-width', 'borderTopWidth');\n\t}\n\tstatic getBorderBottomWidth(element: HTMLElement): number {\n\t\treturn SizeUtils.getDimension(element, 'border-bottom-width', 'borderBottomWidth');\n\t}\n\n\tstatic getPaddingLeft(element: HTMLElement): number {\n\t\treturn SizeUtils.getDimension(element, 'padding-left', 'paddingLeft');\n\t}\n\tstatic getPaddingRight(element: HTMLElement): number {\n\t\treturn SizeUtils.getDimension(element, 'padding-right', 'paddingRight');\n\t}\n\tstatic getPaddingTop(element: HTMLElement): number {\n\t\treturn SizeUtils.getDimension(element, 'padding-top', 'paddingTop');\n\t}\n\tstatic getPaddingBottom(element: HTMLElement): number {\n\t\treturn SizeUtils.getDimension(element, 'padding-bottom', 'paddingBottom');\n\t}\n\n\tstatic getMarginLeft(element: HTMLElement): number {\n\t\treturn SizeUtils.getDimension(element, 'margin-left', 'marginLeft');\n\t}\n\tstatic getMarginTop(element: HTMLElement): number {\n\t\treturn SizeUtils.getDimension(element, 'margin-top', 'marginTop');\n\t}\n\tstatic getMarginRight(element: HTMLElement): number {\n\t\treturn SizeUtils.getDimension(element, 'margin-right', 'marginRight');\n\t}\n\tstatic getMarginBottom(element: HTMLElement): number {\n\t\treturn SizeUtils.getDimension(element, 'margin-bottom', 'marginBottom');\n\t}\n}\n\n// ----------------------------------------------------------------------------------------\n// Position & Dimension\n\nexport interface IDimension {\n\treadonly width: number;\n\treadonly height: number;\n}\n\nexport class Dimension implements IDimension {\n\n\tstatic readonly None = new Dimension(0, 0);\n\n\tconstructor(\n\t\treadonly width: number,\n\t\treadonly height: number,\n\t) { }\n\n\twith(width: number = this.width, height: number = this.height): Dimension {\n\t\tif (width !== this.width || height !== this.height) {\n\t\t\treturn new Dimension(width, height);\n\t\t} else {\n\t\t\treturn this;\n\t\t}\n\t}\n\n\tstatic is(obj: unknown): obj is IDimension {\n\t\treturn typeof obj === 'object' && typeof (obj).height === 'number' && typeof (obj).width === 'number';\n\t}\n\n\tstatic lift(obj: IDimension): Dimension {\n\t\tif (obj instanceof Dimension) {\n\t\t\treturn obj;\n\t\t} else {\n\t\t\treturn new Dimension(obj.width, obj.height);\n\t\t}\n\t}\n\n\tstatic equals(a: Dimension | undefined, b: Dimension | undefined): boolean {\n\t\tif (a === b) {\n\t\t\treturn true;\n\t\t}\n\t\tif (!a || !b) {\n\t\t\treturn false;\n\t\t}\n\t\treturn a.width === b.width && a.height === b.height;\n\t}\n}\n\nexport interface IDomPosition {\n\treadonly left: number;\n\treadonly top: number;\n}\n\nexport function getTopLeftOffset(element: HTMLElement): IDomPosition {\n\t// Adapted from WinJS.Utilities.getPosition\n\t// and added borders to the mix\n\n\tlet offsetParent = element.offsetParent;\n\tlet top = element.offsetTop;\n\tlet left = element.offsetLeft;\n\n\twhile (\n\t\t(element = element.parentNode) !== null\n\t\t&& element !== element.ownerDocument.body\n\t\t&& element !== element.ownerDocument.documentElement\n\t) {\n\t\ttop -= element.scrollTop;\n\t\tconst c = isShadowRoot(element) ? null : getComputedStyle(element);\n\t\tif (c) {\n\t\t\tleft -= c.direction !== 'rtl' ? element.scrollLeft : -element.scrollLeft;\n\t\t}\n\n\t\tif (element === offsetParent) {\n\t\t\tleft += SizeUtils.getBorderLeftWidth(element);\n\t\t\ttop += SizeUtils.getBorderTopWidth(element);\n\t\t\ttop += element.offsetTop;\n\t\t\tleft += element.offsetLeft;\n\t\t\toffsetParent = element.offsetParent;\n\t\t}\n\t}\n\n\treturn {\n\t\tleft: left,\n\t\ttop: top\n\t};\n}\n\nexport interface IDomNodePagePosition {\n\tleft: number;\n\ttop: number;\n\twidth: number;\n\theight: number;\n}\n\nexport function size(element: HTMLElement, width: number | null, height: number | null): void {\n\tif (typeof width === 'number') {\n\t\telement.style.width = `${width}px`;\n\t}\n\n\tif (typeof height === 'number') {\n\t\telement.style.height = `${height}px`;\n\t}\n}\n\n/**\n * Returns the position of a dom node relative to the entire page.\n */\nexport function getDomNodePagePosition(domNode: HTMLElement): IDomNodePagePosition {\n\tconst bb = domNode.getBoundingClientRect();\n\tconst window = getWindow(domNode);\n\treturn {\n\t\tleft: bb.left + window.scrollX,\n\t\ttop: bb.top + window.scrollY,\n\t\twidth: bb.width,\n\t\theight: bb.height\n\t};\n}\n\n/**\n * Returns the effective zoom on a given element before window zoom level is applied\n */\nexport function getDomNodeZoomLevel(domNode: HTMLElement): number {\n\tlet testElement: HTMLElement | null = domNode;\n\tlet zoom = 1.0;\n\tdo {\n\t\tconst elementZoomLevel = (getComputedStyle(testElement) as any).zoom;\n\t\tif (elementZoomLevel !== null && elementZoomLevel !== undefined && elementZoomLevel !== '1') {\n\t\t\tzoom *= elementZoomLevel;\n\t\t}\n\n\t\ttestElement = testElement.parentElement;\n\t} while (testElement !== null && testElement !== testElement.ownerDocument.documentElement);\n\n\treturn zoom;\n}\n\n\n// Adapted from WinJS\n// Gets the width of the element, including margins.\nexport function getTotalWidth(element: HTMLElement): number {\n\tconst margin = SizeUtils.getMarginLeft(element) + SizeUtils.getMarginRight(element);\n\treturn element.offsetWidth + margin;\n}\n\nexport function getContentWidth(element: HTMLElement): number {\n\tconst border = SizeUtils.getBorderLeftWidth(element) + SizeUtils.getBorderRightWidth(element);\n\tconst padding = SizeUtils.getPaddingLeft(element) + SizeUtils.getPaddingRight(element);\n\treturn element.offsetWidth - border - padding;\n}\n\n// Adapted from WinJS\n// Gets the height of the content of the specified element. The content height does not include borders or padding.\nexport function getContentHeight(element: HTMLElement): number {\n\tconst border = SizeUtils.getBorderTopWidth(element) + SizeUtils.getBorderBottomWidth(element);\n\tconst padding = SizeUtils.getPaddingTop(element) + SizeUtils.getPaddingBottom(element);\n\treturn element.offsetHeight - border - padding;\n}\n\n// Adapted from WinJS\n// Gets the height of the element, including its margins.\nexport function getTotalHeight(element: HTMLElement): number {\n\tconst margin = SizeUtils.getMarginTop(element) + SizeUtils.getMarginBottom(element);\n\treturn element.offsetHeight + margin;\n}\n\n// ----------------------------------------------------------------------------------------\n\nexport function isAncestor(testChild: Node | null, testAncestor: Node | null): boolean {\n\treturn Boolean(testAncestor?.contains(testChild));\n}\n\nexport function findParentWithClass(node: HTMLElement, clazz: string, stopAtClazzOrNode?: string | HTMLElement): HTMLElement | null {\n\twhile (node && node.nodeType === node.ELEMENT_NODE) {\n\t\tif (node.classList.contains(clazz)) {\n\t\t\treturn node;\n\t\t}\n\n\t\tif (stopAtClazzOrNode) {\n\t\t\tif (typeof stopAtClazzOrNode === 'string') {\n\t\t\t\tif (node.classList.contains(stopAtClazzOrNode)) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (node === stopAtClazzOrNode) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tnode = node.parentNode;\n\t}\n\n\treturn null;\n}\n\nexport function hasParentWithClass(node: HTMLElement, clazz: string, stopAtClazzOrNode?: string | HTMLElement): boolean {\n\treturn !!findParentWithClass(node, clazz, stopAtClazzOrNode);\n}\n\nexport function isShadowRoot(node: Node): node is ShadowRoot {\n\treturn (\n\t\tnode && !!(node).host && !!(node).mode\n\t);\n}\n\nexport function isInShadowDOM(domNode: Node): boolean {\n\treturn !!getShadowRoot(domNode);\n}\n\nexport function getShadowRoot(domNode: Node): ShadowRoot | null {\n\twhile (domNode.parentNode) {\n\t\tif (domNode === domNode.ownerDocument?.body) {\n\t\t\t// reached the body\n\t\t\treturn null;\n\t\t}\n\t\tdomNode = domNode.parentNode;\n\t}\n\treturn isShadowRoot(domNode) ? domNode : null;\n}\n\n/**\n * Returns the active element across all child windows\n * based on document focus. Falls back to the main\n * window if no window has focus.\n */\nexport function getActiveElement(): Element | null {\n\tlet result = getActiveDocument().activeElement;\n\n\twhile (result?.shadowRoot) {\n\t\tresult = result.shadowRoot.activeElement;\n\t}\n\n\treturn result;\n}\n\n/**\n * Returns true if the focused window active element matches\n * the provided element. Falls back to the main window if no\n * window has focus.\n */\nexport function isActiveElement(element: Element): boolean {\n\treturn getActiveElement() === element;\n}\n\n/**\n * Returns true if the focused window active element is contained in\n * `ancestor`. Falls back to the main window if no window has focus.\n */\nexport function isAncestorOfActiveElement(ancestor: Element): boolean {\n\treturn isAncestor(getActiveElement(), ancestor);\n}\n\n/**\n * Returns the active document across main and child windows.\n * Prefers the window with focus, otherwise falls back to\n * the main windows document.\n */\nexport function getActiveDocument(): Document {\n\tif (getWindowsCount() <= 1) {\n\t\treturn mainWindow.document;\n\t}\n\n\tconst documents = Array.from(getWindows()).map(({ window }) => window.document);\n\treturn documents.find(doc => doc.hasFocus()) ?? mainWindow.document;\n}\n\n/**\n * Returns the active window across main and child windows.\n * Prefers the window with focus, otherwise falls back to\n * the main window.\n */\nexport function getActiveWindow(): CodeWindow {\n\tconst document = getActiveDocument();\n\treturn (document.defaultView?.window ?? mainWindow) as CodeWindow;\n}\n\nconst globalStylesheets = new Map>();\n\n/**\n * A version of createStyleSheet which has a unified API to initialize/set the style content.\n */\nexport function createStyleSheet2(): WrappedStyleElement {\n\treturn new WrappedStyleElement();\n}\n\nclass WrappedStyleElement {\n\tprivate _currentCssStyle = '';\n\tprivate _styleSheet: HTMLStyleElement | undefined = undefined;\n\n\tpublic setStyle(cssStyle: string): void {\n\t\tif (cssStyle === this._currentCssStyle) {\n\t\t\treturn;\n\t\t}\n\t\tthis._currentCssStyle = cssStyle;\n\n\t\tif (!this._styleSheet) {\n\t\t\tthis._styleSheet = createStyleSheet(mainWindow.document.head, (s) => s.innerText = cssStyle);\n\t\t} else {\n\t\t\tthis._styleSheet.innerText = cssStyle;\n\t\t}\n\t}\n\n\tpublic dispose(): void {\n\t\tif (this._styleSheet) {\n\t\t\tthis._styleSheet.remove();\n\t\t\tthis._styleSheet = undefined;\n\t\t}\n\t}\n}\n\nexport function createStyleSheet(container: HTMLElement = mainWindow.document.head, beforeAppend?: (style: HTMLStyleElement) => void, disposableStore?: DisposableStore): HTMLStyleElement {\n\tconst style = document.createElement('style');\n\tstyle.type = 'text/css';\n\tstyle.media = 'screen';\n\tbeforeAppend?.(style);\n\tcontainer.appendChild(style);\n\n\tif (disposableStore) {\n\t\tdisposableStore.add(toDisposable(() => container.removeChild(style)));\n\t}\n\n\t// With as container, the stylesheet becomes global and is tracked\n\t// to support auxiliary windows to clone the stylesheet.\n\tif (container === mainWindow.document.head) {\n\t\tconst globalStylesheetClones = new Set();\n\t\tglobalStylesheets.set(style, globalStylesheetClones);\n\n\t\tfor (const { window: targetWindow, disposables } of getWindows()) {\n\t\t\tif (targetWindow === mainWindow) {\n\t\t\t\tcontinue; // main window is already tracked\n\t\t\t}\n\n\t\t\tconst cloneDisposable = disposables.add(cloneGlobalStyleSheet(style, globalStylesheetClones, targetWindow));\n\t\t\tdisposableStore?.add(cloneDisposable);\n\t\t}\n\t}\n\n\treturn style;\n}\n\nfunction cloneGlobalStyleSheet(globalStylesheet: HTMLStyleElement, globalStylesheetClones: Set, targetWindow: Window): IDisposable {\n\tconst disposables = new DisposableStore();\n\n\tconst clone = globalStylesheet.cloneNode(true) as HTMLStyleElement;\n\ttargetWindow.document.head.appendChild(clone);\n\tdisposables.add(toDisposable(() => targetWindow.document.head.removeChild(clone)));\n\n\tfor (const rule of getDynamicStyleSheetRules(globalStylesheet)) {\n\t\tclone.sheet?.insertRule(rule.cssText, clone.sheet?.cssRules.length);\n\t}\n\n\tdisposables.add(sharedMutationObserver.observe(globalStylesheet, disposables, { childList: true })(() => {\n\t\tclone.textContent = globalStylesheet.textContent;\n\t}));\n\n\tglobalStylesheetClones.add(clone);\n\tdisposables.add(toDisposable(() => globalStylesheetClones.delete(clone)));\n\n\treturn disposables;\n}\n\ninterface IMutationObserver {\n\tusers: number;\n\treadonly observer: MutationObserver;\n\treadonly onDidMutate: event.Event;\n}\n\nexport const sharedMutationObserver = new class {\n\n\treadonly mutationObservers = new Map>();\n\n\tobserve(target: Node, disposables: DisposableStore, options?: MutationObserverInit): event.Event {\n\t\tlet mutationObserversPerTarget = this.mutationObservers.get(target);\n\t\tif (!mutationObserversPerTarget) {\n\t\t\tmutationObserversPerTarget = new Map();\n\t\t\tthis.mutationObservers.set(target, mutationObserversPerTarget);\n\t\t}\n\n\t\tconst optionsHash = hash(options);\n\t\tlet mutationObserverPerOptions = mutationObserversPerTarget.get(optionsHash);\n\t\tif (!mutationObserverPerOptions) {\n\t\t\tconst onDidMutate = new event.Emitter();\n\t\t\tconst observer = new MutationObserver(mutations => onDidMutate.fire(mutations));\n\t\t\tobserver.observe(target, options);\n\n\t\t\tconst resolvedMutationObserverPerOptions = mutationObserverPerOptions = {\n\t\t\t\tusers: 1,\n\t\t\t\tobserver,\n\t\t\t\tonDidMutate: onDidMutate.event\n\t\t\t};\n\n\t\t\tdisposables.add(toDisposable(() => {\n\t\t\t\tresolvedMutationObserverPerOptions.users -= 1;\n\n\t\t\t\tif (resolvedMutationObserverPerOptions.users === 0) {\n\t\t\t\t\tonDidMutate.dispose();\n\t\t\t\t\tobserver.disconnect();\n\n\t\t\t\t\tmutationObserversPerTarget?.delete(optionsHash);\n\t\t\t\t\tif (mutationObserversPerTarget?.size === 0) {\n\t\t\t\t\t\tthis.mutationObservers.delete(target);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}));\n\n\t\t\tmutationObserversPerTarget.set(optionsHash, mutationObserverPerOptions);\n\t\t} else {\n\t\t\tmutationObserverPerOptions.users += 1;\n\t\t}\n\n\t\treturn mutationObserverPerOptions.onDidMutate;\n\t}\n};\n\nlet _sharedStyleSheet: HTMLStyleElement | null = null;\nfunction getSharedStyleSheet(): HTMLStyleElement {\n\tif (!_sharedStyleSheet) {\n\t\t_sharedStyleSheet = createStyleSheet();\n\t}\n\treturn _sharedStyleSheet;\n}\n\nfunction getDynamicStyleSheetRules(style: HTMLStyleElement) {\n\tif (style?.sheet?.rules) {\n\t\t// Chrome, IE\n\t\treturn style.sheet.rules;\n\t}\n\tif (style?.sheet?.cssRules) {\n\t\t// FF\n\t\treturn style.sheet.cssRules;\n\t}\n\treturn [];\n}\n\nexport function createCSSRule(selector: string, cssText: string, style = getSharedStyleSheet()): void {\n\tif (!style || !cssText) {\n\t\treturn;\n\t}\n\n\tstyle.sheet?.insertRule(`${selector} {${cssText}}`, 0);\n\n\t// Apply rule also to all cloned global stylesheets\n\tfor (const clonedGlobalStylesheet of globalStylesheets.get(style) ?? []) {\n\t\tcreateCSSRule(selector, cssText, clonedGlobalStylesheet);\n\t}\n}\n\nexport function removeCSSRulesContainingSelector(ruleName: string, style = getSharedStyleSheet()): void {\n\tif (!style) {\n\t\treturn;\n\t}\n\n\tconst rules = getDynamicStyleSheetRules(style);\n\tconst toDelete: number[] = [];\n\tfor (let i = 0; i < rules.length; i++) {\n\t\tconst rule = rules[i];\n\t\tif (isCSSStyleRule(rule) && rule.selectorText.indexOf(ruleName) !== -1) {\n\t\t\ttoDelete.push(i);\n\t\t}\n\t}\n\n\tfor (let i = toDelete.length - 1; i >= 0; i--) {\n\t\tstyle.sheet?.deleteRule(toDelete[i]);\n\t}\n\n\t// Remove rules also from all cloned global stylesheets\n\tfor (const clonedGlobalStylesheet of globalStylesheets.get(style) ?? []) {\n\t\tremoveCSSRulesContainingSelector(ruleName, clonedGlobalStylesheet);\n\t}\n}\n\nfunction isCSSStyleRule(rule: CSSRule): rule is CSSStyleRule {\n\treturn typeof (rule as CSSStyleRule).selectorText === 'string';\n}\n\nexport function isMouseEvent(e: unknown): e is MouseEvent {\n\t// eslint-disable-next-line no-restricted-syntax\n\treturn e instanceof MouseEvent || e instanceof getWindow(e as UIEvent).MouseEvent;\n}\n\nexport function isKeyboardEvent(e: unknown): e is KeyboardEvent {\n\t// eslint-disable-next-line no-restricted-syntax\n\treturn e instanceof KeyboardEvent || e instanceof getWindow(e as UIEvent).KeyboardEvent;\n}\n\nexport const EventType = {\n\t// Mouse\n\tCLICK: 'click',\n\tAUXCLICK: 'auxclick',\n\tDBLCLICK: 'dblclick',\n\tMOUSE_UP: 'mouseup',\n\tMOUSE_DOWN: 'mousedown',\n\tMOUSE_OVER: 'mouseover',\n\tMOUSE_MOVE: 'mousemove',\n\tMOUSE_OUT: 'mouseout',\n\tMOUSE_ENTER: 'mouseenter',\n\tMOUSE_LEAVE: 'mouseleave',\n\tMOUSE_WHEEL: 'wheel',\n\tPOINTER_UP: 'pointerup',\n\tPOINTER_DOWN: 'pointerdown',\n\tPOINTER_MOVE: 'pointermove',\n\tPOINTER_LEAVE: 'pointerleave',\n\tCONTEXT_MENU: 'contextmenu',\n\tWHEEL: 'wheel',\n\t// Keyboard\n\tKEY_DOWN: 'keydown',\n\tKEY_PRESS: 'keypress',\n\tKEY_UP: 'keyup',\n\t// HTML Document\n\tLOAD: 'load',\n\tBEFORE_UNLOAD: 'beforeunload',\n\tUNLOAD: 'unload',\n\tPAGE_SHOW: 'pageshow',\n\tPAGE_HIDE: 'pagehide',\n\tPASTE: 'paste',\n\tABORT: 'abort',\n\tERROR: 'error',\n\tRESIZE: 'resize',\n\tSCROLL: 'scroll',\n\tFULLSCREEN_CHANGE: 'fullscreenchange',\n\tWK_FULLSCREEN_CHANGE: 'webkitfullscreenchange',\n\t// Form\n\tSELECT: 'select',\n\tCHANGE: 'change',\n\tSUBMIT: 'submit',\n\tRESET: 'reset',\n\tFOCUS: 'focus',\n\tFOCUS_IN: 'focusin',\n\tFOCUS_OUT: 'focusout',\n\tBLUR: 'blur',\n\tINPUT: 'input',\n\t// Local Storage\n\tSTORAGE: 'storage',\n\t// Drag\n\tDRAG_START: 'dragstart',\n\tDRAG: 'drag',\n\tDRAG_ENTER: 'dragenter',\n\tDRAG_LEAVE: 'dragleave',\n\tDRAG_OVER: 'dragover',\n\tDROP: 'drop',\n\tDRAG_END: 'dragend',\n\t// Animation\n\tANIMATION_START: browser.isWebKit ? 'webkitAnimationStart' : 'animationstart',\n\tANIMATION_END: browser.isWebKit ? 'webkitAnimationEnd' : 'animationend',\n\tANIMATION_ITERATION: browser.isWebKit ? 'webkitAnimationIteration' : 'animationiteration'\n} as const;\n\nexport interface EventLike {\n\tpreventDefault(): void;\n\tstopPropagation(): void;\n}\n\nexport function isEventLike(obj: unknown): obj is EventLike {\n\tconst candidate = obj as EventLike | undefined;\n\n\treturn !!(candidate && typeof candidate.preventDefault === 'function' && typeof candidate.stopPropagation === 'function');\n}\n\nexport const EventHelper = {\n\tstop: (e: T, cancelBubble?: boolean): T => {\n\t\te.preventDefault();\n\t\tif (cancelBubble) {\n\t\t\te.stopPropagation();\n\t\t}\n\t\treturn e;\n\t}\n};\n\nexport interface IFocusTracker extends Disposable {\n\treadonly onDidFocus: event.Event;\n\treadonly onDidBlur: event.Event;\n}\n\nexport function saveParentsScrollTop(node: Element): number[] {\n\tconst r: number[] = [];\n\tfor (let i = 0; node && node.nodeType === node.ELEMENT_NODE; i++) {\n\t\tr[i] = node.scrollTop;\n\t\tnode = node.parentNode;\n\t}\n\treturn r;\n}\n\nexport function restoreParentsScrollTop(node: Element, state: number[]): void {\n\tfor (let i = 0; node && node.nodeType === node.ELEMENT_NODE; i++) {\n\t\tif (node.scrollTop !== state[i]) {\n\t\t\tnode.scrollTop = state[i];\n\t\t}\n\t\tnode = node.parentNode;\n\t}\n}\n\nclass FocusTracker extends Disposable implements IFocusTracker {\n\n\tprivate readonly _onDidFocus = this._register(new event.Emitter());\n\treadonly onDidFocus = this._onDidFocus.event;\n\n\tprivate readonly _onDidBlur = this._register(new event.Emitter());\n\treadonly onDidBlur = this._onDidBlur.event;\n\n\tprivate _refreshStateHandler: () => void;\n\n\tprivate static hasFocusWithin(element: HTMLElement | Window): boolean {\n\t\tif (element instanceof HTMLElement) {\n\t\t\tconst shadowRoot = getShadowRoot(element);\n\t\t\tconst activeElement = (shadowRoot ? shadowRoot.activeElement : element.ownerDocument.activeElement);\n\t\t\treturn isAncestor(activeElement, element);\n\t\t} else {\n\t\t\tconst window = element;\n\t\t\treturn isAncestor(window.document.activeElement, window.document);\n\t\t}\n\t}\n\n\tconstructor(element: HTMLElement | Window) {\n\t\tsuper();\n\t\tlet hasFocus = FocusTracker.hasFocusWithin(element);\n\t\tlet loosingFocus = false;\n\n\t\tconst onFocus = () => {\n\t\t\tloosingFocus = false;\n\t\t\tif (!hasFocus) {\n\t\t\t\thasFocus = true;\n\t\t\t\tthis._onDidFocus.fire();\n\t\t\t}\n\t\t};\n\n\t\tconst onBlur = () => {\n\t\t\tif (hasFocus) {\n\t\t\t\tloosingFocus = true;\n\t\t\t\t(element instanceof HTMLElement ? getWindow(element) : element).setTimeout(() => {\n\t\t\t\t\tif (loosingFocus) {\n\t\t\t\t\t\tloosingFocus = false;\n\t\t\t\t\t\thasFocus = false;\n\t\t\t\t\t\tthis._onDidBlur.fire();\n\t\t\t\t\t}\n\t\t\t\t}, 0);\n\t\t\t}\n\t\t};\n\n\t\tthis._refreshStateHandler = () => {\n\t\t\tconst currentNodeHasFocus = FocusTracker.hasFocusWithin(element);\n\t\t\tif (currentNodeHasFocus !== hasFocus) {\n\t\t\t\tif (hasFocus) {\n\t\t\t\t\tonBlur();\n\t\t\t\t} else {\n\t\t\t\t\tonFocus();\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tthis._register(addDisposableListener(element, EventType.FOCUS, onFocus, true));\n\t\tthis._register(addDisposableListener(element, EventType.BLUR, onBlur, true));\n\t\tif (element instanceof HTMLElement) {\n\t\t\tthis._register(addDisposableListener(element, EventType.FOCUS_IN, () => this._refreshStateHandler()));\n\t\t\tthis._register(addDisposableListener(element, EventType.FOCUS_OUT, () => this._refreshStateHandler()));\n\t\t}\n\n\t}\n}\n\n/**\n * Creates a new `IFocusTracker` instance that tracks focus changes on the given `element` and its descendants.\n *\n * @param element The `HTMLElement` or `Window` to track focus changes on.\n * @returns An `IFocusTracker` instance.\n */\nexport function trackFocus(element: HTMLElement | Window): IFocusTracker {\n\treturn new FocusTracker(element);\n}\n\nexport function after(sibling: HTMLElement, child: T): T {\n\tsibling.after(child);\n\treturn child;\n}\n\nexport function append(parent: HTMLElement, child: T): T;\nexport function append(parent: HTMLElement, ...children: (T | string)[]): void;\nexport function append(parent: HTMLElement, ...children: (T | string)[]): T | void {\n\tparent.append(...children);\n\tif (children.length === 1 && typeof children[0] !== 'string') {\n\t\treturn children[0];\n\t}\n}\n\nexport function prepend(parent: HTMLElement, child: T): T {\n\tparent.insertBefore(child, parent.firstChild);\n\treturn child;\n}\n\n/**\n * Removes all children from `parent` and appends `children`\n */\nexport function reset(parent: HTMLElement, ...children: Array): void {\n\tparent.innerText = '';\n\tappend(parent, ...children);\n}\n\nconst SELECTOR_REGEX = /([\\w\\-]+)?(#([\\w\\-]+))?((\\.([\\w\\-]+))*)/;\n\nexport enum Namespace {\n\tHTML = 'http://www.w3.org/1999/xhtml',\n\tSVG = 'http://www.w3.org/2000/svg'\n}\n\nfunction _$(namespace: Namespace, description: string, attrs?: { [key: string]: any }, ...children: Array): T {\n\tconst match = SELECTOR_REGEX.exec(description);\n\n\tif (!match) {\n\t\tthrow new Error('Bad use of emmet');\n\t}\n\n\tconst tagName = match[1] || 'div';\n\tlet result: T;\n\n\tif (namespace !== Namespace.HTML) {\n\t\tresult = document.createElementNS(namespace as string, tagName) as T;\n\t} else {\n\t\tresult = document.createElement(tagName) as unknown as T;\n\t}\n\n\tif (match[3]) {\n\t\tresult.id = match[3];\n\t}\n\tif (match[4]) {\n\t\tresult.className = match[4].replace(/\\./g, ' ').trim();\n\t}\n\n\tif (attrs) {\n\t\tObject.entries(attrs).forEach(([name, value]) => {\n\t\t\tif (typeof value === 'undefined') {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (/^on\\w+$/.test(name)) {\n\t\t\t\t(result)[name] = value;\n\t\t\t} else if (name === 'selected') {\n\t\t\t\tif (value) {\n\t\t\t\t\tresult.setAttribute(name, 'true');\n\t\t\t\t}\n\n\t\t\t} else {\n\t\t\t\tresult.setAttribute(name, value);\n\t\t\t}\n\t\t});\n\t}\n\n\tresult.append(...children);\n\n\treturn result as T;\n}\n\nexport function $(description: string, attrs?: { [key: string]: any }, ...children: Array): T {\n\treturn _$(Namespace.HTML, description, attrs, ...children);\n}\n\n$.SVG = function (description: string, attrs?: { [key: string]: any }, ...children: Array): T {\n\treturn _$(Namespace.SVG, description, attrs, ...children);\n};\n\nexport function setVisibility(visible: boolean, ...elements: HTMLElement[]): void {\n\tif (visible) {\n\t\tshow(...elements);\n\t} else {\n\t\thide(...elements);\n\t}\n}\n\nexport function show(...elements: HTMLElement[]): void {\n\tfor (const element of elements) {\n\t\telement.style.display = '';\n\t\telement.removeAttribute('aria-hidden');\n\t}\n}\n\nexport function hide(...elements: HTMLElement[]): void {\n\tfor (const element of elements) {\n\t\telement.style.display = 'none';\n\t\telement.setAttribute('aria-hidden', 'true');\n\t}\n}\n\n/**\n * Find a value usable for a dom node size such that the likelihood that it would be\n * displayed with constant screen pixels size is as high as possible.\n *\n * e.g. We would desire for the cursors to be 2px (CSS px) wide. Under a devicePixelRatio\n * of 1.25, the cursor will be 2.5 screen pixels wide. Depending on how the dom node aligns/\"snaps\"\n * with the screen pixels, it will sometimes be rendered with 2 screen pixels, and sometimes with 3 screen pixels.\n */\nexport function computeScreenAwareSize(window: Window, cssPx: number): number {\n\tconst screenPx = window.devicePixelRatio * cssPx;\n\treturn Math.max(1, Math.floor(screenPx)) / window.devicePixelRatio;\n}\n\n/**\n * Open safely a new window. This is the best way to do so, but you cannot tell\n * if the window was opened or if it was blocked by the browser's popup blocker.\n * If you want to tell if the browser blocked the new window, use {@link windowOpenWithSuccess}.\n *\n * See https://github.com/microsoft/monaco-editor/issues/601\n * To protect against malicious code in the linked site, particularly phishing attempts,\n * the window.opener should be set to null to prevent the linked site from having access\n * to change the location of the current page.\n * See https://mathiasbynens.github.io/rel-noopener/\n */\nexport function windowOpenNoOpener(url: string): void {\n\t// By using 'noopener' in the `windowFeatures` argument, the newly created window will\n\t// not be able to use `window.opener` to reach back to the current page.\n\t// See https://stackoverflow.com/a/46958731\n\t// See https://developer.mozilla.org/en-US/docs/Web/API/Window/open#noopener\n\t// However, this also doesn't allow us to realize if the browser blocked\n\t// the creation of the window.\n\tmainWindow.open(url, '_blank', 'noopener');\n}\n\nexport function animate(targetWindow: Window, fn: () => void): IDisposable {\n\tconst step = () => {\n\t\tfn();\n\t\tstepDisposable = scheduleAtNextAnimationFrame(targetWindow, step);\n\t};\n\n\tlet stepDisposable = scheduleAtNextAnimationFrame(targetWindow, step);\n\treturn toDisposable(() => stepDisposable.dispose());\n}\n\nRemoteAuthorities.setPreferredWebSchema(/^https:/.test(mainWindow.location.href) ? 'https' : 'http');\n\n/**\n * returns url('...')\n */\nexport function asCSSUrl(uri: URI | null | undefined): string {\n\tif (!uri) {\n\t\treturn `url('')`;\n\t}\n\treturn `url('${FileAccess.uriToBrowserUri(uri).toString(true).replace(/'/g, '%27')}')`;\n}\n\nexport function asCSSPropertyValue(value: string) {\n\treturn `'${value.replace(/'/g, '%27')}'`;\n}\n\nexport function asCssValueWithDefault(cssPropertyValue: string | undefined, dflt: string): string {\n\tif (cssPropertyValue !== undefined) {\n\t\tconst variableMatch = cssPropertyValue.match(/^\\s*var\\((.+)\\)$/);\n\t\tif (variableMatch) {\n\t\t\tconst varArguments = variableMatch[1].split(',', 2);\n\t\t\tif (varArguments.length === 2) {\n\t\t\t\tdflt = asCssValueWithDefault(varArguments[1].trim(), dflt);\n\t\t\t}\n\t\t\treturn `var(${varArguments[0]}, ${dflt})`;\n\t\t}\n\t\treturn cssPropertyValue;\n\t}\n\treturn dflt;\n}\n\n// -- sanitize and trusted html\n\n/**\n * Hooks dompurify using `afterSanitizeAttributes` to check that all `href` and `src`\n * attributes are valid.\n */\nexport function hookDomPurifyHrefAndSrcSanitizer(allowedProtocols: readonly string[], allowDataImages = false): IDisposable {\n\t// https://github.com/cure53/DOMPurify/blob/main/demos/hooks-scheme-allowlist.html\n\n\t// build an anchor to map URLs to\n\tconst anchor = document.createElement('a');\n\n\tdompurify.addHook('afterSanitizeAttributes', (node) => {\n\t\t// check all href/src attributes for validity\n\t\tfor (const attr of ['href', 'src']) {\n\t\t\tif (node.hasAttribute(attr)) {\n\t\t\t\tconst attrValue = node.getAttribute(attr) as string;\n\t\t\t\tif (attr === 'href' && attrValue.startsWith('#')) {\n\t\t\t\t\t// Allow fragment links\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tanchor.href = attrValue;\n\t\t\t\tif (!allowedProtocols.includes(anchor.protocol.replace(/:$/, ''))) {\n\t\t\t\t\tif (allowDataImages && attr === 'src' && anchor.href.startsWith('data:')) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tnode.removeAttribute(attr);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t});\n\n\treturn toDisposable(() => {\n\t\tdompurify.removeHook('afterSanitizeAttributes');\n\t});\n}\n\n/**\n * List of safe, non-input html tags.\n */\nexport const basicMarkupHtmlTags = Object.freeze([\n\t'a',\n\t'abbr',\n\t'b',\n\t'bdo',\n\t'blockquote',\n\t'br',\n\t'caption',\n\t'cite',\n\t'code',\n\t'col',\n\t'colgroup',\n\t'dd',\n\t'del',\n\t'details',\n\t'dfn',\n\t'div',\n\t'dl',\n\t'dt',\n\t'em',\n\t'figcaption',\n\t'figure',\n\t'h1',\n\t'h2',\n\t'h3',\n\t'h4',\n\t'h5',\n\t'h6',\n\t'hr',\n\t'i',\n\t'img',\n\t'input',\n\t'ins',\n\t'kbd',\n\t'label',\n\t'li',\n\t'mark',\n\t'ol',\n\t'p',\n\t'pre',\n\t'q',\n\t'rp',\n\t'rt',\n\t'ruby',\n\t'samp',\n\t'small',\n\t'small',\n\t'source',\n\t'span',\n\t'strike',\n\t'strong',\n\t'sub',\n\t'summary',\n\t'sup',\n\t'table',\n\t'tbody',\n\t'td',\n\t'tfoot',\n\t'th',\n\t'thead',\n\t'time',\n\t'tr',\n\t'tt',\n\t'u',\n\t'ul',\n\t'var',\n\t'video',\n\t'wbr',\n]);\n\nconst defaultDomPurifyConfig = Object.freeze({\n\tALLOWED_TAGS: ['a', 'button', 'blockquote', 'code', 'div', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'input', 'label', 'li', 'p', 'pre', 'select', 'small', 'span', 'strong', 'textarea', 'ul', 'ol'],\n\tALLOWED_ATTR: ['href', 'data-href', 'data-command', 'target', 'title', 'name', 'src', 'alt', 'class', 'id', 'role', 'tabindex', 'style', 'data-code', 'width', 'height', 'align', 'x-dispatch', 'required', 'checked', 'placeholder', 'type', 'start'],\n\tRETURN_DOM: false,\n\tRETURN_DOM_FRAGMENT: false,\n\tRETURN_TRUSTED_TYPE: true\n});\n\ntype ModifierKey = 'alt' | 'ctrl' | 'shift' | 'meta';\n\nexport interface IModifierKeyStatus {\n\taltKey: boolean;\n\tshiftKey: boolean;\n\tctrlKey: boolean;\n\tmetaKey: boolean;\n\tlastKeyPressed?: ModifierKey;\n\tlastKeyReleased?: ModifierKey;\n\tevent?: KeyboardEvent;\n}\n\nexport class ModifierKeyEmitter extends event.Emitter {\n\n\tprivate readonly _subscriptions = new DisposableStore();\n\tprivate _keyStatus: IModifierKeyStatus;\n\tprivate static instance: ModifierKeyEmitter;\n\n\tprivate constructor() {\n\t\tsuper();\n\n\t\tthis._keyStatus = {\n\t\t\taltKey: false,\n\t\t\tshiftKey: false,\n\t\t\tctrlKey: false,\n\t\t\tmetaKey: false\n\t\t};\n\n\t\tthis._subscriptions.add(event.Event.runAndSubscribe(onDidRegisterWindow, ({ window, disposables }) => this.registerListeners(window, disposables), { window: mainWindow, disposables: this._subscriptions }));\n\t}\n\n\tprivate registerListeners(window: Window, disposables: DisposableStore): void {\n\t\tdisposables.add(addDisposableListener(window, 'keydown', e => {\n\t\t\tif (e.defaultPrevented) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst event = new StandardKeyboardEvent(e);\n\t\t\t// If Alt-key keydown event is repeated, ignore it #112347\n\t\t\t// Only known to be necessary for Alt-Key at the moment #115810\n\t\t\tif (event.keyCode === KeyCode.Alt && e.repeat) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (e.altKey && !this._keyStatus.altKey) {\n\t\t\t\tthis._keyStatus.lastKeyPressed = 'alt';\n\t\t\t} else if (e.ctrlKey && !this._keyStatus.ctrlKey) {\n\t\t\t\tthis._keyStatus.lastKeyPressed = 'ctrl';\n\t\t\t} else if (e.metaKey && !this._keyStatus.metaKey) {\n\t\t\t\tthis._keyStatus.lastKeyPressed = 'meta';\n\t\t\t} else if (e.shiftKey && !this._keyStatus.shiftKey) {\n\t\t\t\tthis._keyStatus.lastKeyPressed = 'shift';\n\t\t\t} else if (event.keyCode !== KeyCode.Alt) {\n\t\t\t\tthis._keyStatus.lastKeyPressed = undefined;\n\t\t\t} else {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis._keyStatus.altKey = e.altKey;\n\t\t\tthis._keyStatus.ctrlKey = e.ctrlKey;\n\t\t\tthis._keyStatus.metaKey = e.metaKey;\n\t\t\tthis._keyStatus.shiftKey = e.shiftKey;\n\n\t\t\tif (this._keyStatus.lastKeyPressed) {\n\t\t\t\tthis._keyStatus.event = e;\n\t\t\t\tthis.fire(this._keyStatus);\n\t\t\t}\n\t\t}, true));\n\n\t\tdisposables.add(addDisposableListener(window, 'keyup', e => {\n\t\t\tif (e.defaultPrevented) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (!e.altKey && this._keyStatus.altKey) {\n\t\t\t\tthis._keyStatus.lastKeyReleased = 'alt';\n\t\t\t} else if (!e.ctrlKey && this._keyStatus.ctrlKey) {\n\t\t\t\tthis._keyStatus.lastKeyReleased = 'ctrl';\n\t\t\t} else if (!e.metaKey && this._keyStatus.metaKey) {\n\t\t\t\tthis._keyStatus.lastKeyReleased = 'meta';\n\t\t\t} else if (!e.shiftKey && this._keyStatus.shiftKey) {\n\t\t\t\tthis._keyStatus.lastKeyReleased = 'shift';\n\t\t\t} else {\n\t\t\t\tthis._keyStatus.lastKeyReleased = undefined;\n\t\t\t}\n\n\t\t\tif (this._keyStatus.lastKeyPressed !== this._keyStatus.lastKeyReleased) {\n\t\t\t\tthis._keyStatus.lastKeyPressed = undefined;\n\t\t\t}\n\n\t\t\tthis._keyStatus.altKey = e.altKey;\n\t\t\tthis._keyStatus.ctrlKey = e.ctrlKey;\n\t\t\tthis._keyStatus.metaKey = e.metaKey;\n\t\t\tthis._keyStatus.shiftKey = e.shiftKey;\n\n\t\t\tif (this._keyStatus.lastKeyReleased) {\n\t\t\t\tthis._keyStatus.event = e;\n\t\t\t\tthis.fire(this._keyStatus);\n\t\t\t}\n\t\t}, true));\n\n\t\tdisposables.add(addDisposableListener(window.document.body, 'mousedown', () => {\n\t\t\tthis._keyStatus.lastKeyPressed = undefined;\n\t\t}, true));\n\n\t\tdisposables.add(addDisposableListener(window.document.body, 'mouseup', () => {\n\t\t\tthis._keyStatus.lastKeyPressed = undefined;\n\t\t}, true));\n\n\t\tdisposables.add(addDisposableListener(window.document.body, 'mousemove', e => {\n\t\t\tif (e.buttons) {\n\t\t\t\tthis._keyStatus.lastKeyPressed = undefined;\n\t\t\t}\n\t\t}, true));\n\n\t\tdisposables.add(addDisposableListener(window, 'blur', () => {\n\t\t\tthis.resetKeyStatus();\n\t\t}));\n\t}\n\n\tget keyStatus(): IModifierKeyStatus {\n\t\treturn this._keyStatus;\n\t}\n\n\t/**\n\t * Allows to explicitly reset the key status based on more knowledge (#109062)\n\t */\n\tresetKeyStatus(): void {\n\t\tthis.doResetKeyStatus();\n\t\tthis.fire(this._keyStatus);\n\t}\n\n\tprivate doResetKeyStatus(): void {\n\t\tthis._keyStatus = {\n\t\t\taltKey: false,\n\t\t\tshiftKey: false,\n\t\t\tctrlKey: false,\n\t\t\tmetaKey: false\n\t\t};\n\t}\n\n\tstatic getInstance() {\n\t\tif (!ModifierKeyEmitter.instance) {\n\t\t\tModifierKeyEmitter.instance = new ModifierKeyEmitter();\n\t\t}\n\n\t\treturn ModifierKeyEmitter.instance;\n\t}\n\n\toverride dispose() {\n\t\tsuper.dispose();\n\t\tthis._subscriptions.dispose();\n\t}\n}\n\nexport interface IDragAndDropObserverCallbacks {\n\treadonly onDragEnter?: (e: DragEvent) => void;\n\treadonly onDragLeave?: (e: DragEvent) => void;\n\treadonly onDrop?: (e: DragEvent) => void;\n\treadonly onDragEnd?: (e: DragEvent) => void;\n\treadonly onDragStart?: (e: DragEvent) => void;\n\treadonly onDrag?: (e: DragEvent) => void;\n\treadonly onDragOver?: (e: DragEvent, dragDuration: number) => void;\n}\n\nexport class DragAndDropObserver extends Disposable {\n\n\t// A helper to fix issues with repeated DRAG_ENTER / DRAG_LEAVE\n\t// calls see https://github.com/microsoft/vscode/issues/14470\n\t// when the element has child elements where the events are fired\n\t// repeadedly.\n\tprivate counter: number = 0;\n\n\t// Allows to measure the duration of the drag operation.\n\tprivate dragStartTime = 0;\n\n\tconstructor(private readonly element: HTMLElement, private readonly callbacks: IDragAndDropObserverCallbacks) {\n\t\tsuper();\n\n\t\tthis.registerListeners();\n\t}\n\n\tprivate registerListeners(): void {\n\t\tif (this.callbacks.onDragStart) {\n\t\t\tthis._register(addDisposableListener(this.element, EventType.DRAG_START, (e: DragEvent) => {\n\t\t\t\tthis.callbacks.onDragStart?.(e);\n\t\t\t}));\n\t\t}\n\n\t\tif (this.callbacks.onDrag) {\n\t\t\tthis._register(addDisposableListener(this.element, EventType.DRAG, (e: DragEvent) => {\n\t\t\t\tthis.callbacks.onDrag?.(e);\n\t\t\t}));\n\t\t}\n\n\t\tthis._register(addDisposableListener(this.element, EventType.DRAG_ENTER, (e: DragEvent) => {\n\t\t\tthis.counter++;\n\t\t\tthis.dragStartTime = e.timeStamp;\n\n\t\t\tthis.callbacks.onDragEnter?.(e);\n\t\t}));\n\n\t\tthis._register(addDisposableListener(this.element, EventType.DRAG_OVER, (e: DragEvent) => {\n\t\t\te.preventDefault(); // needed so that the drop event fires (https://stackoverflow.com/questions/21339924/drop-event-not-firing-in-chrome)\n\n\t\t\tthis.callbacks.onDragOver?.(e, e.timeStamp - this.dragStartTime);\n\t\t}));\n\n\t\tthis._register(addDisposableListener(this.element, EventType.DRAG_LEAVE, (e: DragEvent) => {\n\t\t\tthis.counter--;\n\n\t\t\tif (this.counter === 0) {\n\t\t\t\tthis.dragStartTime = 0;\n\n\t\t\t\tthis.callbacks.onDragLeave?.(e);\n\t\t\t}\n\t\t}));\n\n\t\tthis._register(addDisposableListener(this.element, EventType.DRAG_END, (e: DragEvent) => {\n\t\t\tthis.counter = 0;\n\t\t\tthis.dragStartTime = 0;\n\n\t\t\tthis.callbacks.onDragEnd?.(e);\n\t\t}));\n\n\t\tthis._register(addDisposableListener(this.element, EventType.DROP, (e: DragEvent) => {\n\t\t\tthis.counter = 0;\n\t\t\tthis.dragStartTime = 0;\n\n\t\t\tthis.callbacks.onDrop?.(e);\n\t\t}));\n\t}\n}\n\ntype HTMLElementAttributeKeys = Partial<{ [K in keyof T]: T[K] extends Function ? never : T[K] extends object ? HTMLElementAttributeKeys : T[K] }>;\ntype ElementAttributes = HTMLElementAttributeKeys & Record;\ntype RemoveHTMLElement = T extends HTMLElement ? never : T;\ntype UnionToIntersection = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;\ntype ArrayToObj = UnionToIntersection>;\ntype HHTMLElementTagNameMap = HTMLElementTagNameMap & { '': HTMLDivElement };\n\ntype TagToElement = T extends `${infer TStart}#${string}`\n\t? TStart extends keyof HHTMLElementTagNameMap\n\t? HHTMLElementTagNameMap[TStart]\n\t: HTMLElement\n\t: T extends `${infer TStart}.${string}`\n\t? TStart extends keyof HHTMLElementTagNameMap\n\t? HHTMLElementTagNameMap[TStart]\n\t: HTMLElement\n\t: T extends keyof HTMLElementTagNameMap\n\t? HTMLElementTagNameMap[T]\n\t: HTMLElement;\n\ntype TagToElementAndId = TTag extends `${infer TTag}@${infer TId}`\n\t? { element: TagToElement; id: TId }\n\t: { element: TagToElement; id: 'root' };\n\ntype TagToRecord = TagToElementAndId extends { element: infer TElement; id: infer TId }\n\t? Record<(TId extends string ? TId : never) | 'root', TElement>\n\t: never;\n\ntype Child = HTMLElement | string | Record;\n\nconst H_REGEX = /(?[\\w\\-]+)?(?:#(?[\\w\\-]+))?(?(?:\\.(?:[\\w\\-]+))*)(?:@(?(?:[\\w\\_])+))?/;\n\n/**\n * A helper function to create nested dom nodes.\n *\n *\n * ```ts\n * const elements = h('div.code-view', [\n * \th('div.title@title'),\n * \th('div.container', [\n * \t\th('div.gutter@gutterDiv'),\n * \t\th('div@editor'),\n * \t]),\n * ]);\n * const editor = createEditor(elements.editor);\n * ```\n*/\nexport function h\n\t(tag: TTag):\n\tTagToRecord extends infer Y ? { [TKey in keyof Y]: Y[TKey] } : never;\n\nexport function h\n\t(tag: TTag, children: [...T]):\n\t(ArrayToObj & TagToRecord) extends infer Y ? { [TKey in keyof Y]: Y[TKey] } : never;\n\nexport function h\n\t(tag: TTag, attributes: Partial>>):\n\tTagToRecord extends infer Y ? { [TKey in keyof Y]: Y[TKey] } : never;\n\nexport function h\n\t(tag: TTag, attributes: Partial>>, children: [...T]):\n\t(ArrayToObj & TagToRecord) extends infer Y ? { [TKey in keyof Y]: Y[TKey] } : never;\n\nexport function h(tag: string, ...args: [] | [attributes: { $: string } & Partial> | Record, children?: any[]] | [children: any[]]): Record {\n\tlet attributes: { $?: string } & Partial>;\n\tlet children: (Record | HTMLElement)[] | undefined;\n\n\tif (Array.isArray(args[0])) {\n\t\tattributes = {};\n\t\tchildren = args[0];\n\t} else {\n\t\tattributes = args[0] as any || {};\n\t\tchildren = args[1];\n\t}\n\n\tconst match = H_REGEX.exec(tag);\n\n\tif (!match || !match.groups) {\n\t\tthrow new Error('Bad use of h');\n\t}\n\n\tconst tagName = match.groups['tag'] || 'div';\n\tconst el = document.createElement(tagName);\n\n\tif (match.groups['id']) {\n\t\tel.id = match.groups['id'];\n\t}\n\n\tconst classNames = [];\n\tif (match.groups['class']) {\n\t\tfor (const className of match.groups['class'].split('.')) {\n\t\t\tif (className !== '') {\n\t\t\t\tclassNames.push(className);\n\t\t\t}\n\t\t}\n\t}\n\tif (attributes.className !== undefined) {\n\t\tfor (const className of attributes.className.split('.')) {\n\t\t\tif (className !== '') {\n\t\t\t\tclassNames.push(className);\n\t\t\t}\n\t\t}\n\t}\n\tif (classNames.length > 0) {\n\t\tel.className = classNames.join(' ');\n\t}\n\n\tconst result: Record = {};\n\n\tif (match.groups['name']) {\n\t\tresult[match.groups['name']] = el;\n\t}\n\n\tif (children) {\n\t\tfor (const c of children) {\n\t\t\tif (c instanceof HTMLElement) {\n\t\t\t\tel.appendChild(c);\n\t\t\t} else if (typeof c === 'string') {\n\t\t\t\tel.append(c);\n\t\t\t} else if ('root' in c) {\n\t\t\t\tObject.assign(result, c);\n\t\t\t\tel.appendChild(c.root);\n\t\t\t}\n\t\t}\n\t}\n\n\tfor (const [key, value] of Object.entries(attributes)) {\n\t\tif (key === 'className') {\n\t\t\tcontinue;\n\t\t} else if (key === 'style') {\n\t\t\tfor (const [cssKey, cssValue] of Object.entries(value)) {\n\t\t\t\tel.style.setProperty(\n\t\t\t\t\tcamelCaseToHyphenCase(cssKey),\n\t\t\t\t\ttypeof cssValue === 'number' ? cssValue + 'px' : '' + cssValue\n\t\t\t\t);\n\t\t\t}\n\t\t} else if (key === 'tabIndex') {\n\t\t\tel.tabIndex = value;\n\t\t} else {\n\t\t\tel.setAttribute(camelCaseToHyphenCase(key), value.toString());\n\t\t}\n\t}\n\n\tresult['root'] = el;\n\n\treturn result;\n}\n\nfunction camelCaseToHyphenCase(str: string) {\n\treturn str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();\n}\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\nimport * as DOM from 'vs/base/browser/dom';\nimport { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';\nimport { IMouseEvent } from 'vs/base/browser/mouseEvent';\nimport { DisposableStore } from 'vs/base/common/lifecycle';\n\nexport interface IContentActionHandler {\n\tcallback: (content: string, event: IMouseEvent | IKeyboardEvent) => void;\n\treadonly disposables: DisposableStore;\n}\n\nexport interface FormattedTextRenderOptions {\n\treadonly className?: string;\n\treadonly inline?: boolean;\n\treadonly actionHandler?: IContentActionHandler;\n\treadonly renderCodeSegments?: boolean;\n}\n\nexport function renderText(text: string, options: FormattedTextRenderOptions = {}): HTMLElement {\n\tconst element = createElement(options);\n\telement.textContent = text;\n\treturn element;\n}\n\nexport function renderFormattedText(formattedText: string, options: FormattedTextRenderOptions = {}): HTMLElement {\n\tconst element = createElement(options);\n\t_renderFormattedText(element, parseFormattedText(formattedText, !!options.renderCodeSegments), options.actionHandler, options.renderCodeSegments);\n\treturn element;\n}\n\nexport function createElement(options: FormattedTextRenderOptions): HTMLElement {\n\tconst tagName = options.inline ? 'span' : 'div';\n\tconst element = document.createElement(tagName);\n\tif (options.className) {\n\t\telement.className = options.className;\n\t}\n\treturn element;\n}\n\nclass StringStream {\n\tprivate source: string;\n\tprivate index: number;\n\n\tconstructor(source: string) {\n\t\tthis.source = source;\n\t\tthis.index = 0;\n\t}\n\n\tpublic eos(): boolean {\n\t\treturn this.index >= this.source.length;\n\t}\n\n\tpublic next(): string {\n\t\tconst next = this.peek();\n\t\tthis.advance();\n\t\treturn next;\n\t}\n\n\tpublic peek(): string {\n\t\treturn this.source[this.index];\n\t}\n\n\tpublic advance(): void {\n\t\tthis.index++;\n\t}\n}\n\nconst enum FormatType {\n\tInvalid,\n\tRoot,\n\tText,\n\tBold,\n\tItalics,\n\tAction,\n\tActionClose,\n\tCode,\n\tNewLine\n}\n\ninterface IFormatParseTree {\n\ttype: FormatType;\n\tcontent?: string;\n\tindex?: number;\n\tchildren?: IFormatParseTree[];\n}\n\nfunction _renderFormattedText(element: Node, treeNode: IFormatParseTree, actionHandler?: IContentActionHandler, renderCodeSegments?: boolean) {\n\tlet child: Node | undefined;\n\n\tif (treeNode.type === FormatType.Text) {\n\t\tchild = document.createTextNode(treeNode.content || '');\n\t} else if (treeNode.type === FormatType.Bold) {\n\t\tchild = document.createElement('b');\n\t} else if (treeNode.type === FormatType.Italics) {\n\t\tchild = document.createElement('i');\n\t} else if (treeNode.type === FormatType.Code && renderCodeSegments) {\n\t\tchild = document.createElement('code');\n\t} else if (treeNode.type === FormatType.Action && actionHandler) {\n\t\tconst a = document.createElement('a');\n\t\tactionHandler.disposables.add(DOM.addStandardDisposableListener(a, 'click', (event) => {\n\t\t\tactionHandler.callback(String(treeNode.index), event);\n\t\t}));\n\n\t\tchild = a;\n\t} else if (treeNode.type === FormatType.NewLine) {\n\t\tchild = document.createElement('br');\n\t} else if (treeNode.type === FormatType.Root) {\n\t\tchild = element;\n\t}\n\n\tif (child && element !== child) {\n\t\telement.appendChild(child);\n\t}\n\n\tif (child && Array.isArray(treeNode.children)) {\n\t\ttreeNode.children.forEach((nodeChild) => {\n\t\t\t_renderFormattedText(child, nodeChild, actionHandler, renderCodeSegments);\n\t\t});\n\t}\n}\n\nfunction parseFormattedText(content: string, parseCodeSegments: boolean): IFormatParseTree {\n\n\tconst root: IFormatParseTree = {\n\t\ttype: FormatType.Root,\n\t\tchildren: []\n\t};\n\n\tlet actionViewItemIndex = 0;\n\tlet current = root;\n\tconst stack: IFormatParseTree[] = [];\n\tconst stream = new StringStream(content);\n\n\twhile (!stream.eos()) {\n\t\tlet next = stream.next();\n\n\t\tconst isEscapedFormatType = (next === '\\\\' && formatTagType(stream.peek(), parseCodeSegments) !== FormatType.Invalid);\n\t\tif (isEscapedFormatType) {\n\t\t\tnext = stream.next(); // unread the backslash if it escapes a format tag type\n\t\t}\n\n\t\tif (!isEscapedFormatType && isFormatTag(next, parseCodeSegments) && next === stream.peek()) {\n\t\t\tstream.advance();\n\n\t\t\tif (current.type === FormatType.Text) {\n\t\t\t\tcurrent = stack.pop()!;\n\t\t\t}\n\n\t\t\tconst type = formatTagType(next, parseCodeSegments);\n\t\t\tif (current.type === type || (current.type === FormatType.Action && type === FormatType.ActionClose)) {\n\t\t\t\tcurrent = stack.pop()!;\n\t\t\t} else {\n\t\t\t\tconst newCurrent: IFormatParseTree = {\n\t\t\t\t\ttype: type,\n\t\t\t\t\tchildren: []\n\t\t\t\t};\n\n\t\t\t\tif (type === FormatType.Action) {\n\t\t\t\t\tnewCurrent.index = actionViewItemIndex;\n\t\t\t\t\tactionViewItemIndex++;\n\t\t\t\t}\n\n\t\t\t\tcurrent.children!.push(newCurrent);\n\t\t\t\tstack.push(current);\n\t\t\t\tcurrent = newCurrent;\n\t\t\t}\n\t\t} else if (next === '\\n') {\n\t\t\tif (current.type === FormatType.Text) {\n\t\t\t\tcurrent = stack.pop()!;\n\t\t\t}\n\n\t\t\tcurrent.children!.push({\n\t\t\t\ttype: FormatType.NewLine\n\t\t\t});\n\n\t\t} else {\n\t\t\tif (current.type !== FormatType.Text) {\n\t\t\t\tconst textCurrent: IFormatParseTree = {\n\t\t\t\t\ttype: FormatType.Text,\n\t\t\t\t\tcontent: next\n\t\t\t\t};\n\t\t\t\tcurrent.children!.push(textCurrent);\n\t\t\t\tstack.push(current);\n\t\t\t\tcurrent = textCurrent;\n\n\t\t\t} else {\n\t\t\t\tcurrent.content += next;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (current.type === FormatType.Text) {\n\t\tcurrent = stack.pop()!;\n\t}\n\n\tif (stack.length) {\n\t\t// incorrectly formatted string literal\n\t}\n\n\treturn root;\n}\n\nfunction isFormatTag(char: string, supportCodeSegments: boolean): boolean {\n\treturn formatTagType(char, supportCodeSegments) !== FormatType.Invalid;\n}\n\nfunction formatTagType(char: string, supportCodeSegments: boolean): FormatType {\n\tswitch (char) {\n\t\tcase '*':\n\t\t\treturn FormatType.Bold;\n\t\tcase '_':\n\t\t\treturn FormatType.Italics;\n\t\tcase '[':\n\t\t\treturn FormatType.Action;\n\t\tcase ']':\n\t\t\treturn FormatType.ActionClose;\n\t\tcase '`':\n\t\t\treturn supportCodeSegments ? FormatType.Code : FormatType.Invalid;\n\t\tdefault:\n\t\t\treturn FormatType.Invalid;\n\t}\n}\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\nimport * as dom from 'vs/base/browser/dom';\nimport { DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle';\n\nexport interface IPointerMoveCallback {\n\t(event: PointerEvent): void;\n}\n\nexport interface IOnStopCallback {\n\t(browserEvent?: PointerEvent | KeyboardEvent): void;\n}\n\nexport class GlobalPointerMoveMonitor implements IDisposable {\n\n\tprivate readonly _hooks = new DisposableStore();\n\tprivate _pointerMoveCallback: IPointerMoveCallback | null = null;\n\tprivate _onStopCallback: IOnStopCallback | null = null;\n\n\tpublic dispose(): void {\n\t\tthis.stopMonitoring(false);\n\t\tthis._hooks.dispose();\n\t}\n\n\tpublic stopMonitoring(invokeStopCallback: boolean, browserEvent?: PointerEvent | KeyboardEvent): void {\n\t\tif (!this.isMonitoring()) {\n\t\t\t// Not monitoring\n\t\t\treturn;\n\t\t}\n\n\t\t// Unhook\n\t\tthis._hooks.clear();\n\t\tthis._pointerMoveCallback = null;\n\t\tconst onStopCallback = this._onStopCallback;\n\t\tthis._onStopCallback = null;\n\n\t\tif (invokeStopCallback && onStopCallback) {\n\t\t\tonStopCallback(browserEvent);\n\t\t}\n\t}\n\n\tpublic isMonitoring(): boolean {\n\t\treturn !!this._pointerMoveCallback;\n\t}\n\n\tpublic startMonitoring(\n\t\tinitialElement: Element,\n\t\tpointerId: number,\n\t\tinitialButtons: number,\n\t\tpointerMoveCallback: IPointerMoveCallback,\n\t\tonStopCallback: IOnStopCallback\n\t): void {\n\t\tif (this.isMonitoring()) {\n\t\t\tthis.stopMonitoring(false);\n\t\t}\n\t\tthis._pointerMoveCallback = pointerMoveCallback;\n\t\tthis._onStopCallback = onStopCallback;\n\n\t\tlet eventSource: Element | Window = initialElement;\n\n\t\ttry {\n\t\t\tinitialElement.setPointerCapture(pointerId);\n\t\t\tthis._hooks.add(toDisposable(() => {\n\t\t\t\ttry {\n\t\t\t\t\tinitialElement.releasePointerCapture(pointerId);\n\t\t\t\t} catch (err) {\n\t\t\t\t\t// See https://github.com/microsoft/vscode/issues/161731\n\t\t\t\t\t//\n\t\t\t\t\t// `releasePointerCapture` sometimes fails when being invoked with the exception:\n\t\t\t\t\t// DOMException: Failed to execute 'releasePointerCapture' on 'Element':\n\t\t\t\t\t// No active pointer with the given id is found.\n\t\t\t\t\t//\n\t\t\t\t\t// There's no need to do anything in case of failure\n\t\t\t\t}\n\t\t\t}));\n\t\t} catch (err) {\n\t\t\t// See https://github.com/microsoft/vscode/issues/144584\n\t\t\t// See https://github.com/microsoft/vscode/issues/146947\n\t\t\t// `setPointerCapture` sometimes fails when being invoked\n\t\t\t// from a `mousedown` listener on macOS and Windows\n\t\t\t// and it always fails on Linux with the exception:\n\t\t\t// DOMException: Failed to execute 'setPointerCapture' on 'Element':\n\t\t\t// No active pointer with the given id is found.\n\t\t\t// In case of failure, we bind the listeners on the window\n\t\t\teventSource = dom.getWindow(initialElement);\n\t\t}\n\n\t\tthis._hooks.add(dom.addDisposableListener(\n\t\t\teventSource,\n\t\t\tdom.EventType.POINTER_MOVE,\n\t\t\t(e) => {\n\t\t\t\tif (e.buttons !== initialButtons) {\n\t\t\t\t\t// Buttons state has changed in the meantime\n\t\t\t\t\tthis.stopMonitoring(true);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\te.preventDefault();\n\t\t\t\tthis._pointerMoveCallback!(e);\n\t\t\t}\n\t\t));\n\n\t\tthis._hooks.add(dom.addDisposableListener(\n\t\t\teventSource,\n\t\t\tdom.EventType.POINTER_UP,\n\t\t\t(e: PointerEvent) => this.stopMonitoring(true)\n\t\t));\n\t}\n}\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\nimport { getWindowId, onDidUnregisterWindow } from 'vs/base/browser/dom';\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { Disposable, markAsSingleton } from 'vs/base/common/lifecycle';\n\n/**\n * See https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio#monitoring_screen_resolution_or_zoom_level_changes\n */\nclass DevicePixelRatioMonitor extends Disposable {\n\n\tprivate readonly _onDidChange = this._register(new Emitter());\n\treadonly onDidChange = this._onDidChange.event;\n\n\tprivate readonly _listener: () => void;\n\tprivate _mediaQueryList: MediaQueryList | null;\n\n\tconstructor(targetWindow: Window) {\n\t\tsuper();\n\n\t\tthis._listener = () => this._handleChange(targetWindow, true);\n\t\tthis._mediaQueryList = null;\n\t\tthis._handleChange(targetWindow, false);\n\t}\n\n\tprivate _handleChange(targetWindow: Window, fireEvent: boolean): void {\n\t\tthis._mediaQueryList?.removeEventListener('change', this._listener);\n\n\t\tthis._mediaQueryList = targetWindow.matchMedia(`(resolution: ${targetWindow.devicePixelRatio}dppx)`);\n\t\tthis._mediaQueryList.addEventListener('change', this._listener);\n\n\t\tif (fireEvent) {\n\t\t\tthis._onDidChange.fire();\n\t\t}\n\t}\n}\n\nexport interface IPixelRatioMonitor {\n\treadonly value: number;\n\treadonly onDidChange: Event;\n}\n\nclass PixelRatioMonitorImpl extends Disposable implements IPixelRatioMonitor {\n\n\tprivate readonly _onDidChange = this._register(new Emitter());\n\treadonly onDidChange = this._onDidChange.event;\n\n\tprivate _value: number;\n\n\tget value(): number {\n\t\treturn this._value;\n\t}\n\n\tconstructor(targetWindow: Window) {\n\t\tsuper();\n\n\t\tthis._value = this._getPixelRatio(targetWindow);\n\n\t\tconst dprMonitor = this._register(new DevicePixelRatioMonitor(targetWindow));\n\t\tthis._register(dprMonitor.onDidChange(() => {\n\t\t\tthis._value = this._getPixelRatio(targetWindow);\n\t\t\tthis._onDidChange.fire(this._value);\n\t\t}));\n\t}\n\n\tprivate _getPixelRatio(targetWindow: Window): number {\n\t\tconst ctx: any = document.createElement('canvas').getContext('2d');\n\t\tconst dpr = targetWindow.devicePixelRatio || 1;\n\t\tconst bsr = ctx.webkitBackingStorePixelRatio ||\n\t\t\tctx.mozBackingStorePixelRatio ||\n\t\t\tctx.msBackingStorePixelRatio ||\n\t\t\tctx.oBackingStorePixelRatio ||\n\t\t\tctx.backingStorePixelRatio || 1;\n\t\treturn dpr / bsr;\n\t}\n}\n\nclass PixelRatioMonitorFacade {\n\n\tprivate readonly mapWindowIdToPixelRatioMonitor = new Map();\n\n\tprivate _getOrCreatePixelRatioMonitor(targetWindow: Window): PixelRatioMonitorImpl {\n\t\tconst targetWindowId = getWindowId(targetWindow);\n\t\tlet pixelRatioMonitor = this.mapWindowIdToPixelRatioMonitor.get(targetWindowId);\n\t\tif (!pixelRatioMonitor) {\n\t\t\tpixelRatioMonitor = markAsSingleton(new PixelRatioMonitorImpl(targetWindow));\n\t\t\tthis.mapWindowIdToPixelRatioMonitor.set(targetWindowId, pixelRatioMonitor);\n\n\t\t\tmarkAsSingleton(Event.once(onDidUnregisterWindow)(({ vscodeWindowId }) => {\n\t\t\t\tif (vscodeWindowId === targetWindowId) {\n\t\t\t\t\tpixelRatioMonitor?.dispose();\n\t\t\t\t\tthis.mapWindowIdToPixelRatioMonitor.delete(targetWindowId);\n\t\t\t\t}\n\t\t\t}));\n\t\t}\n\t\treturn pixelRatioMonitor;\n\t}\n\n\tgetInstance(targetWindow: Window): IPixelRatioMonitor {\n\t\treturn this._getOrCreatePixelRatioMonitor(targetWindow);\n\t}\n}\n\n/**\n * Returns the pixel ratio.\n *\n * This is useful for rendering elements at native screen resolution or for being used as\n * a cache key when storing font measurements. Fonts might render differently depending on resolution\n * and any measurements need to be discarded for example when a window is moved from a monitor to another.\n */\nexport const PixelRatio = new PixelRatioMonitorFacade();\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\nimport * as DomUtils from 'vs/base/browser/dom';\nimport { mainWindow } from 'vs/base/browser/window';\nimport * as arrays from 'vs/base/common/arrays';\nimport { memoize } from 'vs/base/common/decorators';\nimport { Event as EventUtils } from 'vs/base/common/event';\nimport { Disposable, IDisposable, markAsSingleton, toDisposable } from 'vs/base/common/lifecycle';\nimport { LinkedList } from 'vs/base/common/linkedList';\n\nexport namespace EventType {\n\texport const Tap = '-monaco-gesturetap';\n\texport const Change = '-monaco-gesturechange';\n\texport const Start = '-monaco-gesturestart';\n\texport const End = '-monaco-gesturesend';\n\texport const Contextmenu = '-monaco-gesturecontextmenu';\n}\n\ninterface TouchData {\n\tid: number;\n\tinitialTarget: EventTarget;\n\tinitialTimeStamp: number;\n\tinitialPageX: number;\n\tinitialPageY: number;\n\trollingTimestamps: number[];\n\trollingPageX: number[];\n\trollingPageY: number[];\n}\n\nexport interface GestureEvent extends MouseEvent {\n\tinitialTarget: EventTarget | undefined;\n\ttranslationX: number;\n\ttranslationY: number;\n\tpageX: number;\n\tpageY: number;\n\ttapCount: number;\n}\n\ninterface Touch {\n\tidentifier: number;\n\tpageX: number;\n\tpageY: number;\n\ttarget: Element;\n}\n\ninterface TouchList {\n\t[i: number]: Touch;\n\tlength: number;\n\titem(index: number): Touch;\n}\n\ninterface TouchEvent extends Event {\n\ttouches: TouchList;\n\ttargetTouches: TouchList;\n\tchangedTouches: TouchList;\n}\n\nexport class Gesture extends Disposable {\n\n\tprivate static readonly SCROLL_FRICTION = -0.005;\n\tprivate static INSTANCE: Gesture;\n\tprivate static readonly HOLD_DELAY = 700;\n\n\tprivate dispatched = false;\n\tprivate readonly targets = new LinkedList();\n\tprivate readonly ignoreTargets = new LinkedList();\n\tprivate handle: IDisposable | null;\n\n\tprivate readonly activeTouches: { [id: number]: TouchData };\n\n\tprivate _lastSetTapCountTime: number;\n\n\tprivate static readonly CLEAR_TAP_COUNT_TIME = 400; // ms\n\n\n\tprivate constructor() {\n\t\tsuper();\n\n\t\tthis.activeTouches = {};\n\t\tthis.handle = null;\n\t\tthis._lastSetTapCountTime = 0;\n\n\t\tthis._register(EventUtils.runAndSubscribe(DomUtils.onDidRegisterWindow, ({ window, disposables }) => {\n\t\t\tdisposables.add(DomUtils.addDisposableListener(window.document, 'touchstart', (e: TouchEvent) => this.onTouchStart(e), { passive: false }));\n\t\t\tdisposables.add(DomUtils.addDisposableListener(window.document, 'touchend', (e: TouchEvent) => this.onTouchEnd(window, e)));\n\t\t\tdisposables.add(DomUtils.addDisposableListener(window.document, 'touchmove', (e: TouchEvent) => this.onTouchMove(e), { passive: false }));\n\t\t}, { window: mainWindow, disposables: this._store }));\n\t}\n\n\tpublic static addTarget(element: HTMLElement): IDisposable {\n\t\tif (!Gesture.isTouchDevice()) {\n\t\t\treturn Disposable.None;\n\t\t}\n\t\tif (!Gesture.INSTANCE) {\n\t\t\tGesture.INSTANCE = markAsSingleton(new Gesture());\n\t\t}\n\n\t\tconst remove = Gesture.INSTANCE.targets.push(element);\n\t\treturn toDisposable(remove);\n\t}\n\n\tpublic static ignoreTarget(element: HTMLElement): IDisposable {\n\t\tif (!Gesture.isTouchDevice()) {\n\t\t\treturn Disposable.None;\n\t\t}\n\t\tif (!Gesture.INSTANCE) {\n\t\t\tGesture.INSTANCE = markAsSingleton(new Gesture());\n\t\t}\n\n\t\tconst remove = Gesture.INSTANCE.ignoreTargets.push(element);\n\t\treturn toDisposable(remove);\n\t}\n\n\t@memoize\n\tstatic isTouchDevice(): boolean {\n\t\t// `'ontouchstart' in window` always evaluates to true with typescript's modern typings. This causes `window` to be\n\t\t// `never` later in `window.navigator`. That's why we need the explicit `window as Window` cast\n\t\treturn 'ontouchstart' in mainWindow || navigator.maxTouchPoints > 0;\n\t}\n\n\tpublic override dispose(): void {\n\t\tif (this.handle) {\n\t\t\tthis.handle.dispose();\n\t\t\tthis.handle = null;\n\t\t}\n\n\t\tsuper.dispose();\n\t}\n\n\tprivate onTouchStart(e: TouchEvent): void {\n\t\tconst timestamp = Date.now(); // use Date.now() because on FF e.timeStamp is not epoch based.\n\n\t\tif (this.handle) {\n\t\t\tthis.handle.dispose();\n\t\t\tthis.handle = null;\n\t\t}\n\n\t\tfor (let i = 0, len = e.targetTouches.length; i < len; i++) {\n\t\t\tconst touch = e.targetTouches.item(i);\n\n\t\t\tthis.activeTouches[touch.identifier] = {\n\t\t\t\tid: touch.identifier,\n\t\t\t\tinitialTarget: touch.target,\n\t\t\t\tinitialTimeStamp: timestamp,\n\t\t\t\tinitialPageX: touch.pageX,\n\t\t\t\tinitialPageY: touch.pageY,\n\t\t\t\trollingTimestamps: [timestamp],\n\t\t\t\trollingPageX: [touch.pageX],\n\t\t\t\trollingPageY: [touch.pageY]\n\t\t\t};\n\n\t\t\tconst evt = this.newGestureEvent(EventType.Start, touch.target);\n\t\t\tevt.pageX = touch.pageX;\n\t\t\tevt.pageY = touch.pageY;\n\t\t\tthis.dispatchEvent(evt);\n\t\t}\n\n\t\tif (this.dispatched) {\n\t\t\te.preventDefault();\n\t\t\te.stopPropagation();\n\t\t\tthis.dispatched = false;\n\t\t}\n\t}\n\n\tprivate onTouchEnd(targetWindow: Window, e: TouchEvent): void {\n\t\tconst timestamp = Date.now(); // use Date.now() because on FF e.timeStamp is not epoch based.\n\n\t\tconst activeTouchCount = Object.keys(this.activeTouches).length;\n\n\t\tfor (let i = 0, len = e.changedTouches.length; i < len; i++) {\n\n\t\t\tconst touch = e.changedTouches.item(i);\n\n\t\t\tif (!this.activeTouches.hasOwnProperty(String(touch.identifier))) {\n\t\t\t\tconsole.warn('move of an UNKNOWN touch', touch);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst data = this.activeTouches[touch.identifier],\n\t\t\t\tholdTime = Date.now() - data.initialTimeStamp;\n\n\t\t\tif (holdTime < Gesture.HOLD_DELAY\n\t\t\t\t&& Math.abs(data.initialPageX - arrays.tail(data.rollingPageX)!) < 30\n\t\t\t\t&& Math.abs(data.initialPageY - arrays.tail(data.rollingPageY)!) < 30) {\n\n\t\t\t\tconst evt = this.newGestureEvent(EventType.Tap, data.initialTarget);\n\t\t\t\tevt.pageX = arrays.tail(data.rollingPageX)!;\n\t\t\t\tevt.pageY = arrays.tail(data.rollingPageY)!;\n\t\t\t\tthis.dispatchEvent(evt);\n\n\t\t\t} else if (holdTime >= Gesture.HOLD_DELAY\n\t\t\t\t&& Math.abs(data.initialPageX - arrays.tail(data.rollingPageX)!) < 30\n\t\t\t\t&& Math.abs(data.initialPageY - arrays.tail(data.rollingPageY)!) < 30) {\n\n\t\t\t\tconst evt = this.newGestureEvent(EventType.Contextmenu, data.initialTarget);\n\t\t\t\tevt.pageX = arrays.tail(data.rollingPageX)!;\n\t\t\t\tevt.pageY = arrays.tail(data.rollingPageY)!;\n\t\t\t\tthis.dispatchEvent(evt);\n\n\t\t\t} else if (activeTouchCount === 1) {\n\t\t\t\tconst finalX = arrays.tail(data.rollingPageX)!;\n\t\t\t\tconst finalY = arrays.tail(data.rollingPageY)!;\n\n\t\t\t\tconst deltaT = arrays.tail(data.rollingTimestamps)! - data.rollingTimestamps[0];\n\t\t\t\tconst deltaX = finalX - data.rollingPageX[0];\n\t\t\t\tconst deltaY = finalY - data.rollingPageY[0];\n\n\t\t\t\t// We need to get all the dispatch targets on the start of the inertia event\n\t\t\t\tconst dispatchTo = [...this.targets].filter(t => data.initialTarget instanceof Node && t.contains(data.initialTarget));\n\t\t\t\tthis.inertia(targetWindow, dispatchTo, timestamp,\t// time now\n\t\t\t\t\tMath.abs(deltaX) / deltaT,\t\t\t\t\t\t// speed\n\t\t\t\t\tdeltaX > 0 ? 1 : -1,\t\t\t\t\t\t\t// x direction\n\t\t\t\t\tfinalX,\t\t\t\t\t\t\t\t\t\t\t// x now\n\t\t\t\t\tMath.abs(deltaY) / deltaT, \t\t\t\t\t// y speed\n\t\t\t\t\tdeltaY > 0 ? 1 : -1,\t\t\t\t\t\t\t// y direction\n\t\t\t\t\tfinalY\t\t\t\t\t\t\t\t\t\t\t// y now\n\t\t\t\t);\n\t\t\t}\n\n\n\t\t\tthis.dispatchEvent(this.newGestureEvent(EventType.End, data.initialTarget));\n\t\t\t// forget about this touch\n\t\t\tdelete this.activeTouches[touch.identifier];\n\t\t}\n\n\t\tif (this.dispatched) {\n\t\t\te.preventDefault();\n\t\t\te.stopPropagation();\n\t\t\tthis.dispatched = false;\n\t\t}\n\t}\n\n\tprivate newGestureEvent(type: string, initialTarget?: EventTarget): GestureEvent {\n\t\tconst event = document.createEvent('CustomEvent') as unknown as GestureEvent;\n\t\tevent.initEvent(type, false, true);\n\t\tevent.initialTarget = initialTarget;\n\t\tevent.tapCount = 0;\n\t\treturn event;\n\t}\n\n\tprivate dispatchEvent(event: GestureEvent): void {\n\t\tif (event.type === EventType.Tap) {\n\t\t\tconst currentTime = (new Date()).getTime();\n\t\t\tlet setTapCount = 0;\n\t\t\tif (currentTime - this._lastSetTapCountTime > Gesture.CLEAR_TAP_COUNT_TIME) {\n\t\t\t\tsetTapCount = 1;\n\t\t\t} else {\n\t\t\t\tsetTapCount = 2;\n\t\t\t}\n\n\t\t\tthis._lastSetTapCountTime = currentTime;\n\t\t\tevent.tapCount = setTapCount;\n\t\t} else if (event.type === EventType.Change || event.type === EventType.Contextmenu) {\n\t\t\t// tap is canceled by scrolling or context menu\n\t\t\tthis._lastSetTapCountTime = 0;\n\t\t}\n\n\t\tif (event.initialTarget instanceof Node) {\n\t\t\tfor (const ignoreTarget of this.ignoreTargets) {\n\t\t\t\tif (ignoreTarget.contains(event.initialTarget)) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst targets: [number, HTMLElement][] = [];\n\t\t\tfor (const target of this.targets) {\n\t\t\t\tif (target.contains(event.initialTarget)) {\n\t\t\t\t\tlet depth = 0;\n\t\t\t\t\tlet now: Node | null = event.initialTarget;\n\t\t\t\t\twhile (now && now !== target) {\n\t\t\t\t\t\tdepth++;\n\t\t\t\t\t\tnow = now.parentElement;\n\t\t\t\t\t}\n\t\t\t\t\ttargets.push([depth, target]);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttargets.sort((a, b) => a[0] - b[0]);\n\n\t\t\tfor (const [_, target] of targets) {\n\t\t\t\ttarget.dispatchEvent(event);\n\t\t\t\tthis.dispatched = true;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate inertia(targetWindow: Window, dispatchTo: readonly EventTarget[], t1: number, vX: number, dirX: number, x: number, vY: number, dirY: number, y: number): void {\n\t\tthis.handle = DomUtils.scheduleAtNextAnimationFrame(targetWindow, () => {\n\t\t\tconst now = Date.now();\n\n\t\t\t// velocity: old speed + accel_over_time\n\t\t\tconst deltaT = now - t1;\n\t\t\tlet delta_pos_x = 0, delta_pos_y = 0;\n\t\t\tlet stopped = true;\n\n\t\t\tvX += Gesture.SCROLL_FRICTION * deltaT;\n\t\t\tvY += Gesture.SCROLL_FRICTION * deltaT;\n\n\t\t\tif (vX > 0) {\n\t\t\t\tstopped = false;\n\t\t\t\tdelta_pos_x = dirX * vX * deltaT;\n\t\t\t}\n\n\t\t\tif (vY > 0) {\n\t\t\t\tstopped = false;\n\t\t\t\tdelta_pos_y = dirY * vY * deltaT;\n\t\t\t}\n\n\t\t\t// dispatch translation event\n\t\t\tconst evt = this.newGestureEvent(EventType.Change);\n\t\t\tevt.translationX = delta_pos_x;\n\t\t\tevt.translationY = delta_pos_y;\n\t\t\tdispatchTo.forEach(d => d.dispatchEvent(evt));\n\n\t\t\tif (!stopped) {\n\t\t\t\tthis.inertia(targetWindow, dispatchTo, now, vX, dirX, x + delta_pos_x, vY, dirY, y + delta_pos_y);\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate onTouchMove(e: TouchEvent): void {\n\t\tconst timestamp = Date.now(); // use Date.now() because on FF e.timeStamp is not epoch based.\n\n\t\tfor (let i = 0, len = e.changedTouches.length; i < len; i++) {\n\n\t\t\tconst touch = e.changedTouches.item(i);\n\n\t\t\tif (!this.activeTouches.hasOwnProperty(String(touch.identifier))) {\n\t\t\t\tconsole.warn('end of an UNKNOWN touch', touch);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst data = this.activeTouches[touch.identifier];\n\n\t\t\tconst evt = this.newGestureEvent(EventType.Change, data.initialTarget);\n\t\t\tevt.translationX = touch.pageX - arrays.tail(data.rollingPageX)!;\n\t\t\tevt.translationY = touch.pageY - arrays.tail(data.rollingPageY)!;\n\t\t\tevt.pageX = touch.pageX;\n\t\t\tevt.pageY = touch.pageY;\n\t\t\tthis.dispatchEvent(evt);\n\n\t\t\t// only keep a few data points, to average the final speed\n\t\t\tif (data.rollingPageX.length > 3) {\n\t\t\t\tdata.rollingPageX.shift();\n\t\t\t\tdata.rollingPageY.shift();\n\t\t\t\tdata.rollingTimestamps.shift();\n\t\t\t}\n\n\t\t\tdata.rollingPageX.push(touch.pageX);\n\t\t\tdata.rollingPageY.push(touch.pageY);\n\t\t\tdata.rollingTimestamps.push(timestamp);\n\t\t}\n\n\t\tif (this.dispatched) {\n\t\t\te.preventDefault();\n\t\t\te.stopPropagation();\n\t\t\tthis.dispatched = false;\n\t\t}\n\t}\n}\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\nimport * as dom from 'vs/base/browser/dom';\nimport 'vs/css!./aria';\n\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\nconst MAX_MESSAGE_LENGTH = 20000;\nlet ariaContainer: HTMLElement;\nlet alertContainer: HTMLElement;\nlet alertContainer2: HTMLElement;\nlet statusContainer: HTMLElement;\nlet statusContainer2: HTMLElement;\nexport function setARIAContainer(parent: HTMLElement) {\n\tariaContainer = document.createElement('div');\n\tariaContainer.className = 'monaco-aria-container';\n\n\tconst createAlertContainer = () => {\n\t\tconst element = document.createElement('div');\n\t\telement.className = 'monaco-alert';\n\t\telement.setAttribute('role', 'alert');\n\t\telement.setAttribute('aria-atomic', 'true');\n\t\tariaContainer.appendChild(element);\n\t\treturn element;\n\t};\n\talertContainer = createAlertContainer();\n\talertContainer2 = createAlertContainer();\n\n\tconst createStatusContainer = () => {\n\t\tconst element = document.createElement('div');\n\t\telement.className = 'monaco-status';\n\t\telement.setAttribute('aria-live', 'polite');\n\t\telement.setAttribute('aria-atomic', 'true');\n\t\tariaContainer.appendChild(element);\n\t\treturn element;\n\t};\n\tstatusContainer = createStatusContainer();\n\tstatusContainer2 = createStatusContainer();\n\n\tparent.appendChild(ariaContainer);\n}\n/**\n * Given the provided message, will make sure that it is read as alert to screen readers.\n */\nexport function alert(msg: string): void {\n\tif (!ariaContainer) {\n\t\treturn;\n\t}\n\n\t// Use alternate containers such that duplicated messages get read out by screen readers #99466\n\tif (alertContainer.textContent !== msg) {\n\t\tdom.clearNode(alertContainer2);\n\t\tinsertMessage(alertContainer, msg);\n\t} else {\n\t\tdom.clearNode(alertContainer);\n\t\tinsertMessage(alertContainer2, msg);\n\t}\n}\n\n/**\n * Given the provided message, will make sure that it is read as status to screen readers.\n */\nexport function status(msg: string): void {\n\tif (!ariaContainer) {\n\t\treturn;\n\t}\n\n\tif (statusContainer.textContent !== msg) {\n\t\tdom.clearNode(statusContainer2);\n\t\tinsertMessage(statusContainer, msg);\n\t} else {\n\t\tdom.clearNode(statusContainer);\n\t\tinsertMessage(statusContainer2, msg);\n\t}\n}\n\nfunction insertMessage(target: HTMLElement, msg: string): void {\n\tdom.clearNode(target);\n\tif (msg.length > MAX_MESSAGE_LENGTH) {\n\t\tmsg = msg.substr(0, MAX_MESSAGE_LENGTH);\n\t}\n\ttarget.textContent = msg;\n\n\t// See https://www.paciellogroup.com/blog/2012/06/html5-accessibility-chops-aria-rolealert-browser-support/\n\ttarget.style.visibility = 'hidden';\n\ttarget.style.visibility = 'visible';\n}\n\n// Copied from @types/react which original came from https://www.w3.org/TR/wai-aria-1.1/#role_definitions\nexport type AriaRole =\n\t| 'alert'\n\t| 'alertdialog'\n\t| 'application'\n\t| 'article'\n\t| 'banner'\n\t| 'button'\n\t| 'cell'\n\t| 'checkbox'\n\t| 'columnheader'\n\t| 'combobox'\n\t| 'complementary'\n\t| 'contentinfo'\n\t| 'definition'\n\t| 'dialog'\n\t| 'directory'\n\t| 'document'\n\t| 'feed'\n\t| 'figure'\n\t| 'form'\n\t| 'grid'\n\t| 'gridcell'\n\t| 'group'\n\t| 'heading'\n\t| 'img'\n\t| 'link'\n\t| 'list'\n\t| 'listbox'\n\t| 'listitem'\n\t| 'log'\n\t| 'main'\n\t| 'marquee'\n\t| 'math'\n\t| 'menu'\n\t| 'menubar'\n\t| 'menuitem'\n\t| 'menuitemcheckbox'\n\t| 'menuitemradio'\n\t| 'navigation'\n\t| 'none'\n\t| 'note'\n\t| 'option'\n\t| 'presentation'\n\t| 'progressbar'\n\t| 'radio'\n\t| 'radiogroup'\n\t| 'region'\n\t| 'row'\n\t| 'rowgroup'\n\t| 'rowheader'\n\t| 'scrollbar'\n\t| 'search'\n\t| 'searchbox'\n\t| 'separator'\n\t| 'slider'\n\t| 'spinbutton'\n\t| 'status'\n\t| 'switch'\n\t| 'tab'\n\t| 'table'\n\t| 'tablist'\n\t| 'tabpanel'\n\t| 'term'\n\t| 'textbox'\n\t| 'timer'\n\t| 'toolbar'\n\t| 'tooltip'\n\t| 'tree'\n\t| 'treegrid'\n\t| 'treeitem'\n\t| (string & {}) // Prevent type collapsing to `string`\n\t;\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\nimport { BrowserFeatures } from 'vs/base/browser/canIUse';\nimport * as DOM from 'vs/base/browser/dom';\nimport { StandardMouseEvent } from 'vs/base/browser/mouseEvent';\nimport { Disposable, DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle';\nimport * as platform from 'vs/base/common/platform';\nimport { Range } from 'vs/base/common/range';\nimport { OmitOptional } from 'vs/base/common/types';\nimport 'vs/css!./contextview';\n\nexport const enum ContextViewDOMPosition {\n\tABSOLUTE = 1,\n\tFIXED,\n\tFIXED_SHADOW\n}\n\nexport interface IAnchor {\n\tx: number;\n\ty: number;\n\twidth?: number;\n\theight?: number;\n}\n\nexport function isAnchor(obj: unknown): obj is IAnchor | OmitOptional {\n\tconst anchor = obj as IAnchor | OmitOptional | undefined;\n\n\treturn !!anchor && typeof anchor.x === 'number' && typeof anchor.y === 'number';\n}\n\nexport const enum AnchorAlignment {\n\tLEFT, RIGHT\n}\n\nexport const enum AnchorPosition {\n\tBELOW, ABOVE\n}\n\nexport const enum AnchorAxisAlignment {\n\tVERTICAL, HORIZONTAL\n}\n\nexport interface IDelegate {\n\t/**\n\t * The anchor where to position the context view.\n\t * Use a `HTMLElement` to position the view at the element,\n\t * a `StandardMouseEvent` to position it at the mouse position\n\t * or an `IAnchor` to position it at a specific location.\n\t */\n\tgetAnchor(): HTMLElement | StandardMouseEvent | IAnchor;\n\trender(container: HTMLElement): IDisposable | null;\n\tfocus?(): void;\n\tlayout?(): void;\n\tanchorAlignment?: AnchorAlignment; // default: left\n\tanchorPosition?: AnchorPosition; // default: below\n\tanchorAxisAlignment?: AnchorAxisAlignment; // default: vertical\n\tcanRelayout?: boolean; // default: true\n\tonDOMEvent?(e: Event, activeElement: HTMLElement): void;\n\tonHide?(data?: unknown): void;\n\n\t// context views with higher layers are rendered over contet views with lower layers\n\tlayer?: number; // Default: 0\n}\n\nexport interface IContextViewProvider {\n\tshowContextView(delegate: IDelegate, container?: HTMLElement): void;\n\thideContextView(): void;\n\tlayout(): void;\n}\n\nexport interface IPosition {\n\ttop: number;\n\tleft: number;\n}\n\nexport interface ISize {\n\twidth: number;\n\theight: number;\n}\n\nexport interface IView extends IPosition, ISize { }\n\nexport const enum LayoutAnchorPosition {\n\tBefore,\n\tAfter\n}\n\nexport enum LayoutAnchorMode {\n\tAVOID,\n\tALIGN\n}\n\nexport interface ILayoutAnchor {\n\toffset: number;\n\tsize: number;\n\tmode?: LayoutAnchorMode; // default: AVOID\n\tposition: LayoutAnchorPosition;\n}\n\n/**\n * Lays out a one dimensional view next to an anchor in a viewport.\n *\n * @returns The view offset within the viewport.\n */\nexport function layout(viewportSize: number, viewSize: number, anchor: ILayoutAnchor): number {\n\tconst layoutAfterAnchorBoundary = anchor.mode === LayoutAnchorMode.ALIGN ? anchor.offset : anchor.offset + anchor.size;\n\tconst layoutBeforeAnchorBoundary = anchor.mode === LayoutAnchorMode.ALIGN ? anchor.offset + anchor.size : anchor.offset;\n\n\tif (anchor.position === LayoutAnchorPosition.Before) {\n\t\tif (viewSize <= viewportSize - layoutAfterAnchorBoundary) {\n\t\t\treturn layoutAfterAnchorBoundary; // happy case, lay it out after the anchor\n\t\t}\n\n\t\tif (viewSize <= layoutBeforeAnchorBoundary) {\n\t\t\treturn layoutBeforeAnchorBoundary - viewSize; // ok case, lay it out before the anchor\n\t\t}\n\n\t\treturn Math.max(viewportSize - viewSize, 0); // sad case, lay it over the anchor\n\t} else {\n\t\tif (viewSize <= layoutBeforeAnchorBoundary) {\n\t\t\treturn layoutBeforeAnchorBoundary - viewSize; // happy case, lay it out before the anchor\n\t\t}\n\n\t\tif (viewSize <= viewportSize - layoutAfterAnchorBoundary) {\n\t\t\treturn layoutAfterAnchorBoundary; // ok case, lay it out after the anchor\n\t\t}\n\n\t\treturn 0; // sad case, lay it over the anchor\n\t}\n}\n\nexport class ContextView extends Disposable {\n\n\tprivate static readonly BUBBLE_UP_EVENTS = ['click', 'keydown', 'focus', 'blur'];\n\tprivate static readonly BUBBLE_DOWN_EVENTS = ['click'];\n\n\tprivate container: HTMLElement | null = null;\n\tprivate view: HTMLElement;\n\tprivate useFixedPosition = false;\n\tprivate useShadowDOM = false;\n\tprivate delegate: IDelegate | null = null;\n\tprivate toDisposeOnClean: IDisposable = Disposable.None;\n\tprivate toDisposeOnSetContainer: IDisposable = Disposable.None;\n\tprivate shadowRoot: ShadowRoot | null = null;\n\tprivate shadowRootHostElement: HTMLElement | null = null;\n\n\tconstructor(container: HTMLElement, domPosition: ContextViewDOMPosition) {\n\t\tsuper();\n\n\t\tthis.view = DOM.$('.context-view');\n\t\tDOM.hide(this.view);\n\n\t\tthis.setContainer(container, domPosition);\n\t\tthis._register(toDisposable(() => this.setContainer(null, ContextViewDOMPosition.ABSOLUTE)));\n\t}\n\n\tsetContainer(container: HTMLElement | null, domPosition: ContextViewDOMPosition): void {\n\t\tthis.useFixedPosition = domPosition !== ContextViewDOMPosition.ABSOLUTE;\n\t\tconst usedShadowDOM = this.useShadowDOM;\n\t\tthis.useShadowDOM = domPosition === ContextViewDOMPosition.FIXED_SHADOW;\n\n\t\tif (container === this.container && usedShadowDOM === this.useShadowDOM) {\n\t\t\treturn; // container is the same and no shadow DOM usage has changed\n\t\t}\n\n\t\tif (this.container) {\n\t\t\tthis.toDisposeOnSetContainer.dispose();\n\n\t\t\tif (this.shadowRoot) {\n\t\t\t\tthis.shadowRoot.removeChild(this.view);\n\t\t\t\tthis.shadowRoot = null;\n\t\t\t\tthis.shadowRootHostElement?.remove();\n\t\t\t\tthis.shadowRootHostElement = null;\n\t\t\t} else {\n\t\t\t\tthis.container.removeChild(this.view);\n\t\t\t}\n\n\t\t\tthis.container = null;\n\t\t}\n\n\t\tif (container) {\n\t\t\tthis.container = container;\n\n\t\t\tif (this.useShadowDOM) {\n\t\t\t\tthis.shadowRootHostElement = DOM.$('.shadow-root-host');\n\t\t\t\tthis.container.appendChild(this.shadowRootHostElement);\n\t\t\t\tthis.shadowRoot = this.shadowRootHostElement.attachShadow({ mode: 'open' });\n\t\t\t\tconst style = document.createElement('style');\n\t\t\t\tstyle.textContent = SHADOW_ROOT_CSS;\n\t\t\t\tthis.shadowRoot.appendChild(style);\n\t\t\t\tthis.shadowRoot.appendChild(this.view);\n\t\t\t\tthis.shadowRoot.appendChild(DOM.$('slot'));\n\t\t\t} else {\n\t\t\t\tthis.container.appendChild(this.view);\n\t\t\t}\n\n\t\t\tconst toDisposeOnSetContainer = new DisposableStore();\n\n\t\t\tContextView.BUBBLE_UP_EVENTS.forEach(event => {\n\t\t\t\ttoDisposeOnSetContainer.add(DOM.addStandardDisposableListener(this.container!, event, e => {\n\t\t\t\t\tthis.onDOMEvent(e, false);\n\t\t\t\t}));\n\t\t\t});\n\n\t\t\tContextView.BUBBLE_DOWN_EVENTS.forEach(event => {\n\t\t\t\ttoDisposeOnSetContainer.add(DOM.addStandardDisposableListener(this.container!, event, e => {\n\t\t\t\t\tthis.onDOMEvent(e, true);\n\t\t\t\t}, true));\n\t\t\t});\n\n\t\t\tthis.toDisposeOnSetContainer = toDisposeOnSetContainer;\n\t\t}\n\t}\n\n\tshow(delegate: IDelegate): void {\n\t\tif (this.isVisible()) {\n\t\t\tthis.hide();\n\t\t}\n\n\t\t// Show static box\n\t\tDOM.clearNode(this.view);\n\t\tthis.view.className = 'context-view monaco-component';\n\t\tthis.view.style.top = '0px';\n\t\tthis.view.style.left = '0px';\n\t\tthis.view.style.zIndex = `${2575 + (delegate.layer ?? 0)}`;\n\t\tthis.view.style.position = this.useFixedPosition ? 'fixed' : 'absolute';\n\t\tDOM.show(this.view);\n\n\t\t// Render content\n\t\tthis.toDisposeOnClean = delegate.render(this.view) || Disposable.None;\n\n\t\t// Set active delegate\n\t\tthis.delegate = delegate;\n\n\t\t// Layout\n\t\tthis.doLayout();\n\n\t\t// Focus\n\t\tthis.delegate.focus?.();\n\t}\n\n\tgetViewElement(): HTMLElement {\n\t\treturn this.view;\n\t}\n\n\tlayout(): void {\n\t\tif (!this.isVisible()) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.delegate!.canRelayout === false && !(platform.isIOS && BrowserFeatures.pointerEvents)) {\n\t\t\tthis.hide();\n\t\t\treturn;\n\t\t}\n\n\t\tthis.delegate?.layout?.();\n\n\t\tthis.doLayout();\n\t}\n\n\tprivate doLayout(): void {\n\t\t// Check that we still have a delegate - this.delegate.layout may have hidden\n\t\tif (!this.isVisible()) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Get anchor\n\t\tconst anchor = this.delegate!.getAnchor();\n\n\t\t// Compute around\n\t\tlet around: IView;\n\n\t\t// Get the element's position and size (to anchor the view)\n\t\tif (anchor instanceof HTMLElement) {\n\t\t\tconst elementPosition = DOM.getDomNodePagePosition(anchor);\n\n\t\t\t// In areas where zoom is applied to the element or its ancestors, we need to adjust the size of the element\n\t\t\t// e.g. The title bar has counter zoom behavior meaning it applies the inverse of zoom level.\n\t\t\t// Window Zoom Level: 1.5, Title Bar Zoom: 1/1.5, Size Multiplier: 1.5\n\t\t\tconst zoom = DOM.getDomNodeZoomLevel(anchor);\n\n\t\t\taround = {\n\t\t\t\ttop: elementPosition.top * zoom,\n\t\t\t\tleft: elementPosition.left * zoom,\n\t\t\t\twidth: elementPosition.width * zoom,\n\t\t\t\theight: elementPosition.height * zoom\n\t\t\t};\n\t\t} else if (isAnchor(anchor)) {\n\t\t\taround = {\n\t\t\t\ttop: anchor.y,\n\t\t\t\tleft: anchor.x,\n\t\t\t\twidth: anchor.width || 1,\n\t\t\t\theight: anchor.height || 2\n\t\t\t};\n\t\t} else {\n\t\t\taround = {\n\t\t\t\ttop: anchor.posy,\n\t\t\t\tleft: anchor.posx,\n\t\t\t\t// We are about to position the context view where the mouse\n\t\t\t\t// cursor is. To prevent the view being exactly under the mouse\n\t\t\t\t// when showing and thus potentially triggering an action within,\n\t\t\t\t// we treat the mouse location like a small sized block element.\n\t\t\t\twidth: 2,\n\t\t\t\theight: 2\n\t\t\t};\n\t\t}\n\n\t\tconst viewSizeWidth = DOM.getTotalWidth(this.view);\n\t\tconst viewSizeHeight = DOM.getTotalHeight(this.view);\n\n\t\tconst anchorPosition = this.delegate!.anchorPosition || AnchorPosition.BELOW;\n\t\tconst anchorAlignment = this.delegate!.anchorAlignment || AnchorAlignment.LEFT;\n\t\tconst anchorAxisAlignment = this.delegate!.anchorAxisAlignment || AnchorAxisAlignment.VERTICAL;\n\n\t\tlet top: number;\n\t\tlet left: number;\n\n\t\tconst activeWindow = DOM.getActiveWindow();\n\t\tif (anchorAxisAlignment === AnchorAxisAlignment.VERTICAL) {\n\t\t\tconst verticalAnchor: ILayoutAnchor = { offset: around.top - activeWindow.pageYOffset, size: around.height, position: anchorPosition === AnchorPosition.BELOW ? LayoutAnchorPosition.Before : LayoutAnchorPosition.After };\n\t\t\tconst horizontalAnchor: ILayoutAnchor = { offset: around.left, size: around.width, position: anchorAlignment === AnchorAlignment.LEFT ? LayoutAnchorPosition.Before : LayoutAnchorPosition.After, mode: LayoutAnchorMode.ALIGN };\n\n\t\t\ttop = layout(activeWindow.innerHeight, viewSizeHeight, verticalAnchor) + activeWindow.pageYOffset;\n\n\t\t\t// if view intersects vertically with anchor, we must avoid the anchor\n\t\t\tif (Range.intersects({ start: top, end: top + viewSizeHeight }, { start: verticalAnchor.offset, end: verticalAnchor.offset + verticalAnchor.size })) {\n\t\t\t\thorizontalAnchor.mode = LayoutAnchorMode.AVOID;\n\t\t\t}\n\n\t\t\tleft = layout(activeWindow.innerWidth, viewSizeWidth, horizontalAnchor);\n\t\t} else {\n\t\t\tconst horizontalAnchor: ILayoutAnchor = { offset: around.left, size: around.width, position: anchorAlignment === AnchorAlignment.LEFT ? LayoutAnchorPosition.Before : LayoutAnchorPosition.After };\n\t\t\tconst verticalAnchor: ILayoutAnchor = { offset: around.top, size: around.height, position: anchorPosition === AnchorPosition.BELOW ? LayoutAnchorPosition.Before : LayoutAnchorPosition.After, mode: LayoutAnchorMode.ALIGN };\n\n\t\t\tleft = layout(activeWindow.innerWidth, viewSizeWidth, horizontalAnchor);\n\n\t\t\t// if view intersects horizontally with anchor, we must avoid the anchor\n\t\t\tif (Range.intersects({ start: left, end: left + viewSizeWidth }, { start: horizontalAnchor.offset, end: horizontalAnchor.offset + horizontalAnchor.size })) {\n\t\t\t\tverticalAnchor.mode = LayoutAnchorMode.AVOID;\n\t\t\t}\n\n\t\t\ttop = layout(activeWindow.innerHeight, viewSizeHeight, verticalAnchor) + activeWindow.pageYOffset;\n\t\t}\n\n\t\tthis.view.classList.remove('top', 'bottom', 'left', 'right');\n\t\tthis.view.classList.add(anchorPosition === AnchorPosition.BELOW ? 'bottom' : 'top');\n\t\tthis.view.classList.add(anchorAlignment === AnchorAlignment.LEFT ? 'left' : 'right');\n\t\tthis.view.classList.toggle('fixed', this.useFixedPosition);\n\n\t\tconst containerPosition = DOM.getDomNodePagePosition(this.container!);\n\t\tthis.view.style.top = `${top - (this.useFixedPosition ? DOM.getDomNodePagePosition(this.view).top : containerPosition.top)}px`;\n\t\tthis.view.style.left = `${left - (this.useFixedPosition ? DOM.getDomNodePagePosition(this.view).left : containerPosition.left)}px`;\n\t\tthis.view.style.width = 'initial';\n\t}\n\n\thide(data?: unknown): void {\n\t\tconst delegate = this.delegate;\n\t\tthis.delegate = null;\n\n\t\tif (delegate?.onHide) {\n\t\t\tdelegate.onHide(data);\n\t\t}\n\n\t\tthis.toDisposeOnClean.dispose();\n\n\t\tDOM.hide(this.view);\n\t}\n\n\tprivate isVisible(): boolean {\n\t\treturn !!this.delegate;\n\t}\n\n\tprivate onDOMEvent(e: UIEvent, onCapture: boolean): void {\n\t\tif (this.delegate) {\n\t\t\tif (this.delegate.onDOMEvent) {\n\t\t\t\tthis.delegate.onDOMEvent(e, DOM.getWindow(e).document.activeElement);\n\t\t\t} else if (onCapture && !DOM.isAncestor(e.target, this.container)) {\n\t\t\t\tthis.hide();\n\t\t\t}\n\t\t}\n\t}\n\n\toverride dispose(): void {\n\t\tthis.hide();\n\n\t\tsuper.dispose();\n\t}\n}\n\nconst SHADOW_ROOT_CSS = /* css */ `\n\t:host {\n\t\tall: initial; /* 1st rule so subsequent properties are reset. */\n\t}\n\n\t.codicon[class*='codicon-'] {\n\t\tfont: normal normal normal 16px/1 codicon;\n\t\tdisplay: inline-block;\n\t\ttext-decoration: none;\n\t\ttext-rendering: auto;\n\t\ttext-align: center;\n\t\t-webkit-font-smoothing: antialiased;\n\t\t-moz-osx-font-smoothing: grayscale;\n\t\tuser-select: none;\n\t\t-webkit-user-select: none;\n\t\t-ms-user-select: none;\n\t}\n\n\t:host {\n\t\tfont-family: -apple-system, BlinkMacSystemFont, \"Segoe WPC\", \"Segoe UI\", \"HelveticaNeue-Light\", system-ui, \"Ubuntu\", \"Droid Sans\", sans-serif;\n\t}\n\n\t:host-context(.mac) { font-family: -apple-system, BlinkMacSystemFont, sans-serif; }\n\t:host-context(.mac:lang(zh-Hans)) { font-family: -apple-system, BlinkMacSystemFont, \"PingFang SC\", \"Hiragino Sans GB\", sans-serif; }\n\t:host-context(.mac:lang(zh-Hant)) { font-family: -apple-system, BlinkMacSystemFont, \"PingFang TC\", sans-serif; }\n\t:host-context(.mac:lang(ja)) { font-family: -apple-system, BlinkMacSystemFont, \"Hiragino Kaku Gothic Pro\", sans-serif; }\n\t:host-context(.mac:lang(ko)) { font-family: -apple-system, BlinkMacSystemFont, \"Nanum Gothic\", \"Apple SD Gothic Neo\", \"AppleGothic\", sans-serif; }\n\n\t:host-context(.windows) { font-family: \"Segoe WPC\", \"Segoe UI\", sans-serif; }\n\t:host-context(.windows:lang(zh-Hans)) { font-family: \"Segoe WPC\", \"Segoe UI\", \"Microsoft YaHei\", sans-serif; }\n\t:host-context(.windows:lang(zh-Hant)) { font-family: \"Segoe WPC\", \"Segoe UI\", \"Microsoft Jhenghei\", sans-serif; }\n\t:host-context(.windows:lang(ja)) { font-family: \"Segoe WPC\", \"Segoe UI\", \"Yu Gothic UI\", \"Meiryo UI\", sans-serif; }\n\t:host-context(.windows:lang(ko)) { font-family: \"Segoe WPC\", \"Segoe UI\", \"Malgun Gothic\", \"Dotom\", sans-serif; }\n\n\t:host-context(.linux) { font-family: system-ui, \"Ubuntu\", \"Droid Sans\", sans-serif; }\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; }\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; }\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; }\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; }\n`;\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\nimport { $, append } from 'vs/base/browser/dom';\nimport { format } from 'vs/base/common/strings';\nimport 'vs/css!./countBadge';\n\nexport interface ICountBadgeOptions {\n\treadonly count?: number;\n\treadonly countFormat?: string;\n\treadonly titleFormat?: string;\n}\n\nexport interface ICountBadgeStyles {\n\treadonly badgeBackground: string | undefined;\n\treadonly badgeForeground: string | undefined;\n\treadonly badgeBorder: string | undefined;\n}\n\nexport class CountBadge {\n\n\tprivate element: HTMLElement;\n\tprivate count: number = 0;\n\tprivate countFormat: string;\n\tprivate titleFormat: string;\n\n\tconstructor(container: HTMLElement, private readonly options: ICountBadgeOptions, private readonly styles: ICountBadgeStyles) {\n\n\t\tthis.element = append(container, $('.monaco-count-badge'));\n\t\tthis.countFormat = this.options.countFormat || '{0}';\n\t\tthis.titleFormat = this.options.titleFormat || '';\n\t\tthis.setCount(this.options.count || 0);\n\t}\n\n\tsetCount(count: number) {\n\t\tthis.count = count;\n\t\tthis.render();\n\t}\n\n\tsetTitleFormat(titleFormat: string) {\n\t\tthis.titleFormat = titleFormat;\n\t\tthis.render();\n\t}\n\n\tprivate render() {\n\t\tthis.element.textContent = format(this.countFormat, this.count);\n\t\tthis.element.title = format(this.titleFormat, this.count);\n\n\t\tthis.element.style.backgroundColor = this.styles.badgeBackground ?? '';\n\t\tthis.element.style.color = this.styles.badgeForeground ?? '';\n\n\t\tif (this.styles.badgeBorder) {\n\t\t\tthis.element.style.border = `1px solid ${this.styles.badgeBorder}`;\n\t\t}\n\t}\n}\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\nimport { IContextMenuProvider } from 'vs/base/browser/contextmenu';\nimport { $, addDisposableListener, append, EventHelper, EventType, isMouseEvent } from 'vs/base/browser/dom';\nimport { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';\nimport { EventType as GestureEventType, Gesture } from 'vs/base/browser/touch';\nimport { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview';\nimport { IMenuOptions } from 'vs/base/browser/ui/menu/menu';\nimport { ActionRunner, IAction } from 'vs/base/common/actions';\nimport { Emitter } from 'vs/base/common/event';\nimport { KeyCode } from 'vs/base/common/keyCodes';\nimport { IDisposable } from 'vs/base/common/lifecycle';\nimport 'vs/css!./dropdown';\n\nexport interface ILabelRenderer {\n\t(container: HTMLElement): IDisposable | null;\n}\n\ninterface IBaseDropdownOptions {\n\tlabel?: string;\n\tlabelRenderer?: ILabelRenderer;\n}\n\nclass BaseDropdown extends ActionRunner {\n\tprivate _element: HTMLElement;\n\tprivate boxContainer?: HTMLElement;\n\tprivate _label?: HTMLElement;\n\tprivate contents?: HTMLElement;\n\n\tprivate visible: boolean | undefined;\n\tprivate _onDidChangeVisibility = this._register(new Emitter());\n\treadonly onDidChangeVisibility = this._onDidChangeVisibility.event;\n\n\tconstructor(container: HTMLElement, options: IBaseDropdownOptions) {\n\t\tsuper();\n\n\t\tthis._element = append(container, $('.monaco-dropdown'));\n\n\t\tthis._label = append(this._element, $('.dropdown-label'));\n\n\t\tlet labelRenderer = options.labelRenderer;\n\t\tif (!labelRenderer) {\n\t\t\tlabelRenderer = (container: HTMLElement): IDisposable | null => {\n\t\t\t\tcontainer.textContent = options.label || '';\n\n\t\t\t\treturn null;\n\t\t\t};\n\t\t}\n\n\t\tfor (const event of [EventType.CLICK, EventType.MOUSE_DOWN, GestureEventType.Tap]) {\n\t\t\tthis._register(addDisposableListener(this.element, event, e => EventHelper.stop(e, true))); // prevent default click behaviour to trigger\n\t\t}\n\n\t\tfor (const event of [EventType.MOUSE_DOWN, GestureEventType.Tap]) {\n\t\t\tthis._register(addDisposableListener(this._label, event, e => {\n\t\t\t\tif (isMouseEvent(e) && (e.detail > 1 || e.button !== 0)) {\n\t\t\t\t\t// prevent right click trigger to allow separate context menu (https://github.com/microsoft/vscode/issues/151064)\n\t\t\t\t\t// prevent multiple clicks to open multiple context menus (https://github.com/microsoft/vscode/issues/41363)\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (this.visible) {\n\t\t\t\t\tthis.hide();\n\t\t\t\t} else {\n\t\t\t\t\tthis.show();\n\t\t\t\t}\n\t\t\t}));\n\t\t}\n\n\t\tthis._register(addDisposableListener(this._label, EventType.KEY_UP, e => {\n\t\t\tconst event = new StandardKeyboardEvent(e);\n\t\t\tif (event.equals(KeyCode.Enter) || event.equals(KeyCode.Space)) {\n\t\t\t\tEventHelper.stop(e, true); // https://github.com/microsoft/vscode/issues/57997\n\n\t\t\t\tif (this.visible) {\n\t\t\t\t\tthis.hide();\n\t\t\t\t} else {\n\t\t\t\t\tthis.show();\n\t\t\t\t}\n\t\t\t}\n\t\t}));\n\n\t\tconst cleanupFn = labelRenderer(this._label);\n\t\tif (cleanupFn) {\n\t\t\tthis._register(cleanupFn);\n\t\t}\n\n\t\tthis._register(Gesture.addTarget(this._label));\n\t}\n\n\tget element(): HTMLElement {\n\t\treturn this._element;\n\t}\n\n\tshow(): void {\n\t\tif (!this.visible) {\n\t\t\tthis.visible = true;\n\t\t\tthis._onDidChangeVisibility.fire(true);\n\t\t}\n\t}\n\n\thide(): void {\n\t\tif (this.visible) {\n\t\t\tthis.visible = false;\n\t\t\tthis._onDidChangeVisibility.fire(false);\n\t\t}\n\t}\n\n\toverride dispose(): void {\n\t\tsuper.dispose();\n\t\tthis.hide();\n\n\t\tif (this.boxContainer) {\n\t\t\tthis.boxContainer.remove();\n\t\t\tthis.boxContainer = undefined;\n\t\t}\n\n\t\tif (this.contents) {\n\t\t\tthis.contents.remove();\n\t\t\tthis.contents = undefined;\n\t\t}\n\n\t\tif (this._label) {\n\t\t\tthis._label.remove();\n\t\t\tthis._label = undefined;\n\t\t}\n\t}\n}\n\nexport interface IActionProvider {\n\tgetActions(): readonly IAction[];\n}\n\nexport interface IDropdownMenuOptions extends IBaseDropdownOptions {\n\tcontextMenuProvider: IContextMenuProvider;\n\treadonly actions?: IAction[];\n\treadonly actionProvider?: IActionProvider;\n\tmenuClassName?: string;\n\tmenuAsChild?: boolean; // scope down for #99448\n\treadonly skipTelemetry?: boolean;\n}\n\nexport class DropdownMenu extends BaseDropdown {\n\tprivate _menuOptions: IMenuOptions | undefined;\n\tprivate _actions: readonly IAction[] = [];\n\n\tconstructor(container: HTMLElement, private readonly _options: IDropdownMenuOptions) {\n\t\tsuper(container, _options);\n\n\t\tthis.actions = _options.actions || [];\n\t}\n\n\tset menuOptions(options: IMenuOptions | undefined) {\n\t\tthis._menuOptions = options;\n\t}\n\n\tget menuOptions(): IMenuOptions | undefined {\n\t\treturn this._menuOptions;\n\t}\n\n\tprivate get actions(): readonly IAction[] {\n\t\tif (this._options.actionProvider) {\n\t\t\treturn this._options.actionProvider.getActions();\n\t\t}\n\n\t\treturn this._actions;\n\t}\n\n\tprivate set actions(actions: readonly IAction[]) {\n\t\tthis._actions = actions;\n\t}\n\n\toverride show(): void {\n\t\tsuper.show();\n\n\t\tthis.element.classList.add('active');\n\n\t\tthis._options.contextMenuProvider.showContextMenu({\n\t\t\tgetAnchor: () => this.element,\n\t\t\tgetActions: () => this.actions,\n\t\t\tgetActionsContext: () => this.menuOptions ? this.menuOptions.context : null,\n\t\t\tgetActionViewItem: (action, options) => this.menuOptions && this.menuOptions.actionViewItemProvider ? this.menuOptions.actionViewItemProvider(action, options) : undefined,\n\t\t\tgetKeyBinding: action => this.menuOptions && this.menuOptions.getKeyBinding ? this.menuOptions.getKeyBinding(action) : undefined,\n\t\t\tgetMenuClassName: () => this._options.menuClassName || '',\n\t\t\tonHide: () => this.onHide(),\n\t\t\tactionRunner: this.menuOptions ? this.menuOptions.actionRunner : undefined,\n\t\t\tanchorAlignment: this.menuOptions ? this.menuOptions.anchorAlignment : AnchorAlignment.LEFT,\n\t\t\tdomForShadowRoot: this._options.menuAsChild ? this.element : undefined,\n\t\t\tskipTelemetry: this._options.skipTelemetry\n\t\t});\n\t}\n\n\toverride hide(): void {\n\t\tsuper.hide();\n\t}\n\n\tprivate onHide(): void {\n\t\tthis.hide();\n\t\tthis.element.classList.remove('active');\n\t}\n}\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\nimport * as dom from 'vs/base/browser/dom';\nimport { ThemeIcon } from 'vs/base/common/themables';\n\nconst labelWithIconsRegex = new RegExp(`(\\\\\\\\)?\\\\$\\\\((${ThemeIcon.iconNameExpression}(?:${ThemeIcon.iconModifierExpression})?)\\\\)`, 'g');\nexport function renderLabelWithIcons(text: string): Array {\n\tconst elements = new Array();\n\tlet match: RegExpExecArray | null;\n\n\tlet textStart = 0, textStop = 0;\n\twhile ((match = labelWithIconsRegex.exec(text)) !== null) {\n\t\ttextStop = match.index || 0;\n\t\tif (textStart < textStop) {\n\t\t\telements.push(text.substring(textStart, textStop));\n\t\t}\n\t\ttextStart = (match.index || 0) + match[0].length;\n\n\t\tconst [, escaped, codicon] = match;\n\t\telements.push(escaped ? `$(${codicon})` : renderIcon({ id: codicon }));\n\t}\n\n\tif (textStart < text.length) {\n\t\telements.push(text.substring(textStart));\n\t}\n\treturn elements;\n}\n\nexport function renderIcon(icon: ThemeIcon): HTMLSpanElement {\n\tconst node = dom.$(`span`);\n\tnode.classList.add(...ThemeIcon.asClassNameArray(icon));\n\treturn node;\n}\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\nimport * as dom from 'vs/base/browser/dom';\nimport { IUpdatableHover } from 'vs/base/browser/ui/hover/hover';\nimport { IHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate';\nimport { getBaseLayerHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate2';\nimport { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegateFactory';\nimport { renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels';\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport * as objects from 'vs/base/common/objects';\n\n/**\n * A range to be highlighted.\n */\nexport interface IHighlight {\n\tstart: number;\n\tend: number;\n\treadonly extraClasses?: readonly string[];\n}\n\nexport interface IHighlightedLabelOptions {\n\n\t/**\n\t * Whether the label supports rendering icons.\n\t */\n\treadonly supportIcons?: boolean;\n\n\treadonly hoverDelegate?: IHoverDelegate;\n}\n\n/**\n * A widget which can render a label with substring highlights, often\n * originating from a filter function like the fuzzy matcher.\n */\nexport class HighlightedLabel extends Disposable {\n\n\tprivate readonly domNode: HTMLElement;\n\tprivate text: string = '';\n\tprivate title: string = '';\n\tprivate highlights: readonly IHighlight[] = [];\n\tprivate supportIcons: boolean;\n\tprivate didEverRender: boolean = false;\n\tprivate customHover: IUpdatableHover | undefined;\n\n\t/**\n\t * Create a new {@link HighlightedLabel}.\n\t *\n\t * @param container The parent container to append to.\n\t */\n\tconstructor(container: HTMLElement, private readonly options?: IHighlightedLabelOptions) {\n\t\tsuper();\n\n\t\tthis.supportIcons = options?.supportIcons ?? false;\n\t\tthis.domNode = dom.append(container, dom.$('span.monaco-highlighted-label'));\n\t}\n\n\t/**\n\t * The label's DOM node.\n\t */\n\tget element(): HTMLElement {\n\t\treturn this.domNode;\n\t}\n\n\t/**\n\t * Set the label and highlights.\n\t *\n\t * @param text The label to display.\n\t * @param highlights The ranges to highlight.\n\t * @param title An optional title for the hover tooltip.\n\t * @param escapeNewLines Whether to escape new lines.\n\t * @returns\n\t */\n\tset(text: string | undefined, highlights: readonly IHighlight[] = [], title: string = '', escapeNewLines?: boolean) {\n\t\tif (!text) {\n\t\t\ttext = '';\n\t\t}\n\n\t\tif (escapeNewLines) {\n\t\t\t// adjusts highlights inplace\n\t\t\ttext = HighlightedLabel.escapeNewLines(text, highlights);\n\t\t}\n\n\t\tif (this.didEverRender && this.text === text && this.title === title && objects.equals(this.highlights, highlights)) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.text = text;\n\t\tthis.title = title;\n\t\tthis.highlights = highlights;\n\t\tthis.render();\n\t}\n\n\tprivate render(): void {\n\n\t\tconst children: Array = [];\n\t\tlet pos = 0;\n\n\t\tfor (const highlight of this.highlights) {\n\t\t\tif (highlight.end === highlight.start) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (pos < highlight.start) {\n\t\t\t\tconst substring = this.text.substring(pos, highlight.start);\n\t\t\t\tif (this.supportIcons) {\n\t\t\t\t\tchildren.push(...renderLabelWithIcons(substring));\n\t\t\t\t} else {\n\t\t\t\t\tchildren.push(substring);\n\t\t\t\t}\n\t\t\t\tpos = highlight.start;\n\t\t\t}\n\n\t\t\tconst substring = this.text.substring(pos, highlight.end);\n\t\t\tconst element = dom.$('span.highlight', undefined, ...this.supportIcons ? renderLabelWithIcons(substring) : [substring]);\n\n\t\t\tif (highlight.extraClasses) {\n\t\t\t\telement.classList.add(...highlight.extraClasses);\n\t\t\t}\n\n\t\t\tchildren.push(element);\n\t\t\tpos = highlight.end;\n\t\t}\n\n\t\tif (pos < this.text.length) {\n\t\t\tconst substring = this.text.substring(pos,);\n\t\t\tif (this.supportIcons) {\n\t\t\t\tchildren.push(...renderLabelWithIcons(substring));\n\t\t\t} else {\n\t\t\t\tchildren.push(substring);\n\t\t\t}\n\t\t}\n\n\t\tdom.reset(this.domNode, ...children);\n\n\t\tif (this.options?.hoverDelegate?.showNativeHover) {\n\t\t\t/* While custom hover is not inside custom hover */\n\t\t\tthis.domNode.title = this.title;\n\t\t} else {\n\t\t\tif (!this.customHover && this.title !== '') {\n\t\t\t\tconst hoverDelegate = this.options?.hoverDelegate ?? getDefaultHoverDelegate('mouse');\n\t\t\t\tthis.customHover = this._register(getBaseLayerHoverDelegate().setupUpdatableHover(hoverDelegate, this.domNode, this.title));\n\t\t\t} else if (this.customHover) {\n\t\t\t\tthis.customHover.update(this.title);\n\t\t\t}\n\t\t}\n\n\t\tthis.didEverRender = true;\n\t}\n\n\tstatic escapeNewLines(text: string, highlights: readonly IHighlight[]): string {\n\t\tlet total = 0;\n\t\tlet extra = 0;\n\n\t\treturn text.replace(/\\r\\n|\\r|\\n/g, (match, offset) => {\n\t\t\textra = match === '\\r\\n' ? -1 : 0;\n\t\t\toffset += total;\n\n\t\t\tfor (const highlight of highlights) {\n\t\t\t\tif (highlight.end <= offset) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (highlight.start >= offset) {\n\t\t\t\t\thighlight.start += extra;\n\t\t\t\t}\n\t\t\t\tif (highlight.end >= offset) {\n\t\t\t\t\thighlight.end += extra;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttotal += extra;\n\t\t\treturn '\\u23CE';\n\t\t});\n\t}\n}\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\nimport 'vs/css!./iconlabel';\nimport * as dom from 'vs/base/browser/dom';\nimport { HighlightedLabel } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel';\nimport { IHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate';\nimport { IMatch } from 'vs/base/common/filters';\nimport { Disposable, IDisposable } from 'vs/base/common/lifecycle';\nimport { equals } from 'vs/base/common/objects';\nimport { Range } from 'vs/base/common/range';\nimport { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegateFactory';\nimport { IUpdatableHoverTooltipMarkdownString } from 'vs/base/browser/ui/hover/hover';\nimport { getBaseLayerHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate2';\nimport { isString } from 'vs/base/common/types';\nimport { stripIcons } from 'vs/base/common/iconLabels';\nimport { URI } from 'vs/base/common/uri';\n\nexport interface IIconLabelCreationOptions {\n\treadonly supportHighlights?: boolean;\n\treadonly supportDescriptionHighlights?: boolean;\n\treadonly supportIcons?: boolean;\n\treadonly hoverDelegate?: IHoverDelegate;\n}\n\nexport interface IIconLabelValueOptions {\n\ttitle?: string | IUpdatableHoverTooltipMarkdownString;\n\tdescriptionTitle?: string | IUpdatableHoverTooltipMarkdownString;\n\tsuffix?: string;\n\textraClasses?: readonly string[];\n\titalic?: boolean;\n\tstrikethrough?: boolean;\n\tmatches?: readonly IMatch[];\n\tlabelEscapeNewLines?: boolean;\n\tdescriptionMatches?: readonly IMatch[];\n\tdisabledCommand?: boolean;\n\treadonly separator?: string;\n\treadonly domId?: string;\n\ticonPath?: URI;\n}\n\nclass FastLabelNode {\n\tprivate disposed: boolean | undefined;\n\tprivate _textContent: string | undefined;\n\tprivate _className: string | undefined;\n\tprivate _empty: boolean | undefined;\n\n\tconstructor(private _element: HTMLElement) {\n\t}\n\n\tget element(): HTMLElement {\n\t\treturn this._element;\n\t}\n\n\tset textContent(content: string) {\n\t\tif (this.disposed || content === this._textContent) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._textContent = content;\n\t\tthis._element.textContent = content;\n\t}\n\n\tset className(className: string) {\n\t\tif (this.disposed || className === this._className) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._className = className;\n\t\tthis._element.className = className;\n\t}\n\n\tset empty(empty: boolean) {\n\t\tif (this.disposed || empty === this._empty) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._empty = empty;\n\t\tthis._element.style.marginLeft = empty ? '0' : '';\n\t}\n\n\tdispose(): void {\n\t\tthis.disposed = true;\n\t}\n}\n\nexport class IconLabel extends Disposable {\n\n\tprivate readonly creationOptions?: IIconLabelCreationOptions;\n\n\tprivate readonly domNode: FastLabelNode;\n\tprivate readonly nameContainer: HTMLElement;\n\tprivate readonly nameNode: Label | LabelWithHighlights;\n\n\tprivate descriptionNode: FastLabelNode | HighlightedLabel | undefined;\n\tprivate suffixNode: FastLabelNode | undefined;\n\n\tprivate readonly labelContainer: HTMLElement;\n\n\tprivate readonly hoverDelegate: IHoverDelegate;\n\tprivate readonly customHovers: Map = new Map();\n\n\tconstructor(container: HTMLElement, options?: IIconLabelCreationOptions) {\n\t\tsuper();\n\t\tthis.creationOptions = options;\n\n\t\tthis.domNode = this._register(new FastLabelNode(dom.append(container, dom.$('.monaco-icon-label'))));\n\n\t\tthis.labelContainer = dom.append(this.domNode.element, dom.$('.monaco-icon-label-container'));\n\n\t\tthis.nameContainer = dom.append(this.labelContainer, dom.$('span.monaco-icon-name-container'));\n\n\t\tif (options?.supportHighlights || options?.supportIcons) {\n\t\t\tthis.nameNode = this._register(new LabelWithHighlights(this.nameContainer, !!options.supportIcons));\n\t\t} else {\n\t\t\tthis.nameNode = new Label(this.nameContainer);\n\t\t}\n\n\t\tthis.hoverDelegate = options?.hoverDelegate ?? getDefaultHoverDelegate('mouse');\n\t}\n\n\tget element(): HTMLElement {\n\t\treturn this.domNode.element;\n\t}\n\n\tsetLabel(label: string | string[], description?: string, options?: IIconLabelValueOptions): void {\n\t\tconst labelClasses = ['monaco-icon-label'];\n\t\tconst containerClasses = ['monaco-icon-label-container'];\n\t\tlet ariaLabel: string = '';\n\t\tif (options) {\n\t\t\tif (options.extraClasses) {\n\t\t\t\tlabelClasses.push(...options.extraClasses);\n\t\t\t}\n\n\t\t\tif (options.italic) {\n\t\t\t\tlabelClasses.push('italic');\n\t\t\t}\n\n\t\t\tif (options.strikethrough) {\n\t\t\t\tlabelClasses.push('strikethrough');\n\t\t\t}\n\n\t\t\tif (options.disabledCommand) {\n\t\t\t\tcontainerClasses.push('disabled');\n\t\t\t}\n\t\t\tif (options.title) {\n\t\t\t\tif (typeof options.title === 'string') {\n\t\t\t\t\tariaLabel += options.title;\n\t\t\t\t} else {\n\t\t\t\t\tariaLabel += label;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst existingIconNode = this.domNode.element.querySelector('.monaco-icon-label-iconpath');\n\t\tif (options?.iconPath) {\n\t\t\tlet iconNode;\n\t\t\tif (!existingIconNode || !(existingIconNode instanceof HTMLElement)) {\n\t\t\t\ticonNode = dom.$('.monaco-icon-label-iconpath');\n\t\t\t\tthis.domNode.element.prepend(iconNode);\n\t\t\t} else {\n\t\t\t\ticonNode = existingIconNode;\n\t\t\t}\n\t\t\ticonNode.style.backgroundImage = dom.asCSSUrl(options?.iconPath);\n\t\t} else if (existingIconNode) {\n\t\t\texistingIconNode.remove();\n\t\t}\n\n\t\tthis.domNode.className = labelClasses.join(' ');\n\t\tthis.domNode.element.setAttribute('aria-label', ariaLabel);\n\t\tthis.labelContainer.className = containerClasses.join(' ');\n\t\tthis.setupHover(options?.descriptionTitle ? this.labelContainer : this.element, options?.title);\n\n\t\tthis.nameNode.setLabel(label, options);\n\n\t\tif (description || this.descriptionNode) {\n\t\t\tconst descriptionNode = this.getOrCreateDescriptionNode();\n\t\t\tif (descriptionNode instanceof HighlightedLabel) {\n\t\t\t\tdescriptionNode.set(description || '', options ? options.descriptionMatches : undefined, undefined, options?.labelEscapeNewLines);\n\t\t\t\tthis.setupHover(descriptionNode.element, options?.descriptionTitle);\n\t\t\t} else {\n\t\t\t\tdescriptionNode.textContent = description && options?.labelEscapeNewLines ? HighlightedLabel.escapeNewLines(description, []) : (description || '');\n\t\t\t\tthis.setupHover(descriptionNode.element, options?.descriptionTitle || '');\n\t\t\t\tdescriptionNode.empty = !description;\n\t\t\t}\n\t\t}\n\n\t\tif (options?.suffix || this.suffixNode) {\n\t\t\tconst suffixNode = this.getOrCreateSuffixNode();\n\t\t\tsuffixNode.textContent = options?.suffix ?? '';\n\t\t}\n\t}\n\n\tprivate setupHover(htmlElement: HTMLElement, tooltip: string | IUpdatableHoverTooltipMarkdownString | undefined): void {\n\t\tconst previousCustomHover = this.customHovers.get(htmlElement);\n\t\tif (previousCustomHover) {\n\t\t\tpreviousCustomHover.dispose();\n\t\t\tthis.customHovers.delete(htmlElement);\n\t\t}\n\n\t\tif (!tooltip) {\n\t\t\thtmlElement.removeAttribute('title');\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.hoverDelegate.showNativeHover) {\n\t\t\tfunction setupNativeHover(htmlElement: HTMLElement, tooltip: string | IUpdatableHoverTooltipMarkdownString | undefined): void {\n\t\t\t\tif (isString(tooltip)) {\n\t\t\t\t\t// Icons don't render in the native hover so we strip them out\n\t\t\t\t\thtmlElement.title = stripIcons(tooltip);\n\t\t\t\t} else if (tooltip?.markdownNotSupportedFallback) {\n\t\t\t\t\thtmlElement.title = tooltip.markdownNotSupportedFallback;\n\t\t\t\t} else {\n\t\t\t\t\thtmlElement.removeAttribute('title');\n\t\t\t\t}\n\t\t\t}\n\t\t\tsetupNativeHover(htmlElement, tooltip);\n\t\t} else {\n\t\t\tconst hoverDisposable = getBaseLayerHoverDelegate().setupUpdatableHover(this.hoverDelegate, htmlElement, tooltip);\n\t\t\tif (hoverDisposable) {\n\t\t\t\tthis.customHovers.set(htmlElement, hoverDisposable);\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic override dispose() {\n\t\tsuper.dispose();\n\t\tfor (const disposable of this.customHovers.values()) {\n\t\t\tdisposable.dispose();\n\t\t}\n\t\tthis.customHovers.clear();\n\t}\n\n\tprivate getOrCreateSuffixNode() {\n\t\tif (!this.suffixNode) {\n\t\t\tconst suffixContainer = this._register(new FastLabelNode(dom.after(this.nameContainer, dom.$('span.monaco-icon-suffix-container'))));\n\t\t\tthis.suffixNode = this._register(new FastLabelNode(dom.append(suffixContainer.element, dom.$('span.label-suffix'))));\n\t\t}\n\n\t\treturn this.suffixNode;\n\t}\n\n\tprivate getOrCreateDescriptionNode() {\n\t\tif (!this.descriptionNode) {\n\t\t\tconst descriptionContainer = this._register(new FastLabelNode(dom.append(this.labelContainer, dom.$('span.monaco-icon-description-container'))));\n\t\t\tif (this.creationOptions?.supportDescriptionHighlights) {\n\t\t\t\tthis.descriptionNode = this._register(new HighlightedLabel(dom.append(descriptionContainer.element, dom.$('span.label-description')), { supportIcons: !!this.creationOptions.supportIcons }));\n\t\t\t} else {\n\t\t\t\tthis.descriptionNode = this._register(new FastLabelNode(dom.append(descriptionContainer.element, dom.$('span.label-description'))));\n\t\t\t}\n\t\t}\n\n\t\treturn this.descriptionNode;\n\t}\n}\n\nclass Label {\n\n\tprivate label: string | string[] | undefined = undefined;\n\tprivate singleLabel: HTMLElement | undefined = undefined;\n\tprivate options: IIconLabelValueOptions | undefined;\n\n\tconstructor(private container: HTMLElement) { }\n\n\tsetLabel(label: string | string[], options?: IIconLabelValueOptions): void {\n\t\tif (this.label === label && equals(this.options, options)) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.label = label;\n\t\tthis.options = options;\n\n\t\tif (typeof label === 'string') {\n\t\t\tif (!this.singleLabel) {\n\t\t\t\tthis.container.innerText = '';\n\t\t\t\tthis.container.classList.remove('multiple');\n\t\t\t\tthis.singleLabel = dom.append(this.container, dom.$('a.label-name', { id: options?.domId }));\n\t\t\t}\n\n\t\t\tthis.singleLabel.textContent = label;\n\t\t} else {\n\t\t\tthis.container.innerText = '';\n\t\t\tthis.container.classList.add('multiple');\n\t\t\tthis.singleLabel = undefined;\n\n\t\t\tfor (let i = 0; i < label.length; i++) {\n\t\t\t\tconst l = label[i];\n\t\t\t\tconst id = options?.domId && `${options?.domId}_${i}`;\n\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));\n\n\t\t\t\tif (i < label.length - 1) {\n\t\t\t\t\tdom.append(this.container, dom.$('span.label-separator', undefined, options?.separator || '/'));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction splitMatches(labels: string[], separator: string, matches: readonly IMatch[] | undefined): IMatch[][] | undefined {\n\tif (!matches) {\n\t\treturn undefined;\n\t}\n\n\tlet labelStart = 0;\n\n\treturn labels.map(label => {\n\t\tconst labelRange = { start: labelStart, end: labelStart + label.length };\n\n\t\tconst result = matches\n\t\t\t.map(match => Range.intersect(labelRange, match))\n\t\t\t.filter(range => !Range.isEmpty(range))\n\t\t\t.map(({ start, end }) => ({ start: start - labelStart, end: end - labelStart }));\n\n\t\tlabelStart = labelRange.end + separator.length;\n\t\treturn result;\n\t});\n}\n\nclass LabelWithHighlights extends Disposable {\n\n\tprivate label: string | string[] | undefined = undefined;\n\tprivate singleLabel: HighlightedLabel | undefined = undefined;\n\tprivate options: IIconLabelValueOptions | undefined;\n\n\tconstructor(private container: HTMLElement, private supportIcons: boolean) {\n\t\tsuper();\n\t}\n\n\tsetLabel(label: string | string[], options?: IIconLabelValueOptions): void {\n\t\tif (this.label === label && equals(this.options, options)) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.label = label;\n\t\tthis.options = options;\n\n\t\tif (typeof label === 'string') {\n\t\t\tif (!this.singleLabel) {\n\t\t\t\tthis.container.innerText = '';\n\t\t\t\tthis.container.classList.remove('multiple');\n\t\t\t\tthis.singleLabel = this._register(new HighlightedLabel(dom.append(this.container, dom.$('a.label-name', { id: options?.domId })), { supportIcons: this.supportIcons }));\n\t\t\t}\n\n\t\t\tthis.singleLabel.set(label, options?.matches, undefined, options?.labelEscapeNewLines);\n\t\t} else {\n\t\t\tthis.container.innerText = '';\n\t\t\tthis.container.classList.add('multiple');\n\t\t\tthis.singleLabel = undefined;\n\n\t\t\tconst separator = options?.separator || '/';\n\t\t\tconst matches = splitMatches(label, separator, options?.matches);\n\n\t\t\tfor (let i = 0; i < label.length; i++) {\n\t\t\t\tconst l = label[i];\n\t\t\t\tconst m = matches ? matches[i] : undefined;\n\t\t\t\tconst id = options?.domId && `${options?.domId}_${i}`;\n\n\t\t\t\tconst name = dom.$('a.label-name', { id, 'data-icon-label-count': label.length, 'data-icon-label-index': i, 'role': 'treeitem' });\n\t\t\t\tconst highlightedLabel = this._register(new HighlightedLabel(dom.append(this.container, name), { supportIcons: this.supportIcons }));\n\t\t\t\thighlightedLabel.set(l, m, undefined, options?.labelEscapeNewLines);\n\n\t\t\t\tif (i < label.length - 1) {\n\t\t\t\t\tdom.append(name, dom.$('span.label-separator', undefined, separator));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\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\nimport * as dom from 'vs/base/browser/dom';\nimport { IUpdatableHover } from 'vs/base/browser/ui/hover/hover';\nimport { getBaseLayerHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate2';\nimport { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegateFactory';\nimport { UILabelProvider } from 'vs/base/common/keybindingLabels';\nimport { ResolvedKeybinding, ResolvedChord } from 'vs/base/common/keybindings';\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport { equals } from 'vs/base/common/objects';\nimport { OperatingSystem } from 'vs/base/common/platform';\nimport 'vs/css!./keybindingLabel';\nimport { localize } from 'vs/nls';\n\nconst $ = dom.$;\n\nexport interface ChordMatches {\n\tctrlKey?: boolean;\n\tshiftKey?: boolean;\n\taltKey?: boolean;\n\tmetaKey?: boolean;\n\tkeyCode?: boolean;\n}\n\nexport interface Matches {\n\tfirstPart: ChordMatches;\n\tchordPart: ChordMatches;\n}\n\nexport interface KeybindingLabelOptions extends IKeybindingLabelStyles {\n\trenderUnboundKeybindings?: boolean;\n\t/**\n\t * Default false.\n\t */\n\tdisableTitle?: boolean;\n}\n\nexport interface IKeybindingLabelStyles {\n\tkeybindingLabelBackground: string | undefined;\n\tkeybindingLabelForeground: string | undefined;\n\tkeybindingLabelBorder: string | undefined;\n\tkeybindingLabelBottomBorder: string | undefined;\n\tkeybindingLabelShadow: string | undefined;\n}\n\nexport const unthemedKeybindingLabelOptions: KeybindingLabelOptions = {\n\tkeybindingLabelBackground: undefined,\n\tkeybindingLabelForeground: undefined,\n\tkeybindingLabelBorder: undefined,\n\tkeybindingLabelBottomBorder: undefined,\n\tkeybindingLabelShadow: undefined\n};\n\nexport class KeybindingLabel extends Disposable {\n\n\tprivate domNode: HTMLElement;\n\tprivate options: KeybindingLabelOptions;\n\n\tprivate readonly keyElements = new Set();\n\n\tprivate hover: IUpdatableHover;\n\tprivate keybinding: ResolvedKeybinding | undefined;\n\tprivate matches: Matches | undefined;\n\tprivate didEverRender: boolean;\n\n\tconstructor(container: HTMLElement, private os: OperatingSystem, options?: KeybindingLabelOptions) {\n\t\tsuper();\n\n\t\tthis.options = options || Object.create(null);\n\n\t\tconst labelForeground = this.options.keybindingLabelForeground;\n\n\t\tthis.domNode = dom.append(container, $('.monaco-keybinding'));\n\t\tif (labelForeground) {\n\t\t\tthis.domNode.style.color = labelForeground;\n\t\t}\n\n\t\tthis.hover = this._register(getBaseLayerHoverDelegate().setupUpdatableHover(getDefaultHoverDelegate('mouse'), this.domNode, ''));\n\n\t\tthis.didEverRender = false;\n\t\tcontainer.appendChild(this.domNode);\n\t}\n\n\tget element(): HTMLElement {\n\t\treturn this.domNode;\n\t}\n\n\tset(keybinding: ResolvedKeybinding | undefined, matches?: Matches) {\n\t\tif (this.didEverRender && this.keybinding === keybinding && KeybindingLabel.areSame(this.matches, matches)) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.keybinding = keybinding;\n\t\tthis.matches = matches;\n\t\tthis.render();\n\t}\n\n\tprivate render() {\n\t\tthis.clear();\n\n\t\tif (this.keybinding) {\n\t\t\tconst chords = this.keybinding.getChords();\n\t\t\tif (chords[0]) {\n\t\t\t\tthis.renderChord(this.domNode, chords[0], this.matches ? this.matches.firstPart : null);\n\t\t\t}\n\t\t\tfor (let i = 1; i < chords.length; i++) {\n\t\t\t\tdom.append(this.domNode, $('span.monaco-keybinding-key-chord-separator', undefined, ' '));\n\t\t\t\tthis.renderChord(this.domNode, chords[i], this.matches ? this.matches.chordPart : null);\n\t\t\t}\n\t\t\tconst title = (this.options.disableTitle ?? false) ? undefined : this.keybinding.getAriaLabel() || undefined;\n\t\t\tthis.hover.update(title);\n\t\t\tthis.domNode.setAttribute('aria-label', title || '');\n\t\t} else if (this.options && this.options.renderUnboundKeybindings) {\n\t\t\tthis.renderUnbound(this.domNode);\n\t\t}\n\n\t\tthis.didEverRender = true;\n\t}\n\n\tprivate clear(): void {\n\t\tdom.clearNode(this.domNode);\n\t\tthis.keyElements.clear();\n\t}\n\n\tprivate renderChord(parent: HTMLElement, chord: ResolvedChord, match: ChordMatches | null) {\n\t\tconst modifierLabels = UILabelProvider.modifierLabels[this.os];\n\t\tif (chord.ctrlKey) {\n\t\t\tthis.renderKey(parent, modifierLabels.ctrlKey, Boolean(match?.ctrlKey), modifierLabels.separator);\n\t\t}\n\t\tif (chord.shiftKey) {\n\t\t\tthis.renderKey(parent, modifierLabels.shiftKey, Boolean(match?.shiftKey), modifierLabels.separator);\n\t\t}\n\t\tif (chord.altKey) {\n\t\t\tthis.renderKey(parent, modifierLabels.altKey, Boolean(match?.altKey), modifierLabels.separator);\n\t\t}\n\t\tif (chord.metaKey) {\n\t\t\tthis.renderKey(parent, modifierLabels.metaKey, Boolean(match?.metaKey), modifierLabels.separator);\n\t\t}\n\t\tconst keyLabel = chord.keyLabel;\n\t\tif (keyLabel) {\n\t\t\tthis.renderKey(parent, keyLabel, Boolean(match?.keyCode), '');\n\t\t}\n\t}\n\n\tprivate renderKey(parent: HTMLElement, label: string, highlight: boolean, separator: string): void {\n\t\tdom.append(parent, this.createKeyElement(label, highlight ? '.highlight' : ''));\n\t\tif (separator) {\n\t\t\tdom.append(parent, $('span.monaco-keybinding-key-separator', undefined, separator));\n\t\t}\n\t}\n\n\tprivate renderUnbound(parent: HTMLElement): void {\n\t\tdom.append(parent, this.createKeyElement(localize('unbound', \"Unbound\")));\n\t}\n\n\tprivate createKeyElement(label: string, extraClass = ''): HTMLElement {\n\t\tconst keyElement = $('span.monaco-keybinding-key' + extraClass, undefined, label);\n\t\tthis.keyElements.add(keyElement);\n\n\t\tif (this.options.keybindingLabelBackground) {\n\t\t\tkeyElement.style.backgroundColor = this.options.keybindingLabelBackground;\n\t\t}\n\t\tif (this.options.keybindingLabelBorder) {\n\t\t\tkeyElement.style.borderColor = this.options.keybindingLabelBorder;\n\t\t}\n\t\tif (this.options.keybindingLabelBottomBorder) {\n\t\t\tkeyElement.style.borderBottomColor = this.options.keybindingLabelBottomBorder;\n\t\t}\n\t\tif (this.options.keybindingLabelShadow) {\n\t\t\tkeyElement.style.boxShadow = `inset 0 -1px 0 ${this.options.keybindingLabelShadow}`;\n\t\t}\n\n\t\treturn keyElement;\n\t}\n\n\tprivate static areSame(a: Matches | undefined, b: Matches | undefined): boolean {\n\t\tif (a === b || (!a && !b)) {\n\t\t\treturn true;\n\t\t}\n\t\treturn !!a && !!b && equals(a.firstPart, b.firstPart) && equals(a.chordPart, b.chordPart);\n\t}\n}\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\nimport { $ } from 'vs/base/browser/dom';\nimport { IDisposable } from 'vs/base/common/lifecycle';\nimport { IListRenderer } from './list';\n\nexport interface IRow {\n\tdomNode: HTMLElement;\n\ttemplateId: string;\n\ttemplateData: any;\n}\n\nfunction removeFromParent(element: HTMLElement): void {\n\ttry {\n\t\telement.parentElement?.removeChild(element);\n\t} catch (e) {\n\t\t// this will throw if this happens due to a blur event, nasty business\n\t}\n}\n\nexport class RowCache implements IDisposable {\n\n\tprivate cache = new Map();\n\n\tprivate readonly transactionNodesPendingRemoval = new Set();\n\tprivate inTransaction = false;\n\n\tconstructor(private renderers: Map>) { }\n\n\t/**\n\t * Returns a row either by creating a new one or reusing\n\t * a previously released row which shares the same templateId.\n\t *\n\t * @returns A row and `isReusingConnectedDomNode` if the row's node is already in the dom in a stale position.\n\t */\n\talloc(templateId: string): { row: IRow; isReusingConnectedDomNode: boolean } {\n\t\tlet result = this.getTemplateCache(templateId).pop();\n\n\t\tlet isStale = false;\n\t\tif (result) {\n\t\t\tisStale = this.transactionNodesPendingRemoval.has(result.domNode);\n\t\t\tif (isStale) {\n\t\t\t\tthis.transactionNodesPendingRemoval.delete(result.domNode);\n\t\t\t}\n\t\t} else {\n\t\t\tconst domNode = $('.monaco-list-row');\n\t\t\tconst renderer = this.getRenderer(templateId);\n\t\t\tconst templateData = renderer.renderTemplate(domNode);\n\t\t\tresult = { domNode, templateId, templateData };\n\t\t}\n\n\t\treturn { row: result, isReusingConnectedDomNode: isStale };\n\t}\n\n\t/**\n\t * Releases the row for eventual reuse.\n\t */\n\trelease(row: IRow): void {\n\t\tif (!row) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.releaseRow(row);\n\t}\n\n\t/**\n\t * Begin a set of changes that use the cache. This lets us skip work when a row is removed and then inserted again.\n\t */\n\ttransact(makeChanges: () => void) {\n\t\tif (this.inTransaction) {\n\t\t\tthrow new Error('Already in transaction');\n\t\t}\n\n\t\tthis.inTransaction = true;\n\n\t\ttry {\n\t\t\tmakeChanges();\n\t\t} finally {\n\t\t\tfor (const domNode of this.transactionNodesPendingRemoval) {\n\t\t\t\tthis.doRemoveNode(domNode);\n\t\t\t}\n\n\t\t\tthis.transactionNodesPendingRemoval.clear();\n\t\t\tthis.inTransaction = false;\n\t\t}\n\t}\n\n\tprivate releaseRow(row: IRow): void {\n\t\tconst { domNode, templateId } = row;\n\t\tif (domNode) {\n\t\t\tif (this.inTransaction) {\n\t\t\t\tthis.transactionNodesPendingRemoval.add(domNode);\n\t\t\t} else {\n\t\t\t\tthis.doRemoveNode(domNode);\n\t\t\t}\n\t\t}\n\n\t\tconst cache = this.getTemplateCache(templateId);\n\t\tcache.push(row);\n\t}\n\n\tprivate doRemoveNode(domNode: HTMLElement) {\n\t\tdomNode.classList.remove('scrolling');\n\t\tremoveFromParent(domNode);\n\t}\n\n\tprivate getTemplateCache(templateId: string): IRow[] {\n\t\tlet result = this.cache.get(templateId);\n\n\t\tif (!result) {\n\t\t\tresult = [];\n\t\t\tthis.cache.set(templateId, result);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tdispose(): void {\n\t\tthis.cache.forEach((cachedRows, templateId) => {\n\t\t\tfor (const cachedRow of cachedRows) {\n\t\t\t\tconst renderer = this.getRenderer(templateId);\n\t\t\t\trenderer.disposeTemplate(cachedRow.templateData);\n\t\t\t\tcachedRow.templateData = null;\n\t\t\t}\n\t\t});\n\n\t\tthis.cache.clear();\n\t\tthis.transactionNodesPendingRemoval.clear();\n\t}\n\n\tprivate getRenderer(templateId: string): IListRenderer {\n\t\tconst renderer = this.renderers.get(templateId);\n\t\tif (!renderer) {\n\t\t\tthrow new Error(`No renderer found for ${templateId}`);\n\t\t}\n\t\treturn renderer;\n\t}\n}\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\nimport { show } from 'vs/base/browser/dom';\nimport { RunOnceScheduler } from 'vs/base/common/async';\nimport { Disposable, IDisposable, MutableDisposable } from 'vs/base/common/lifecycle';\nimport 'vs/css!./progressbar';\n\nconst CSS_DONE = 'done';\nconst CSS_ACTIVE = 'active';\nconst CSS_INFINITE = 'infinite';\nconst CSS_INFINITE_LONG_RUNNING = 'infinite-long-running';\nconst CSS_DISCRETE = 'discrete';\n\nexport interface IProgressBarOptions extends IProgressBarStyles {\n}\n\nexport interface IProgressBarStyles {\n\tprogressBarBackground: string | undefined;\n}\n\n/**\n * A progress bar with support for infinite or discrete progress.\n */\nexport class ProgressBar extends Disposable {\n\n\t/**\n\t * After a certain time of showing the progress bar, switch\n\t * to long-running mode and throttle animations to reduce\n\t * the pressure on the GPU process.\n\t *\n\t * https://github.com/microsoft/vscode/issues/97900\n\t * https://github.com/microsoft/vscode/issues/138396\n\t */\n\tprivate static readonly LONG_RUNNING_INFINITE_THRESHOLD = 10000;\n\n\tprivate workedVal: number;\n\tprivate element!: HTMLElement;\n\tprivate bit!: HTMLElement;\n\tprivate totalWork: number | undefined;\n\tprivate showDelayedScheduler: RunOnceScheduler;\n\tprivate longRunningScheduler: RunOnceScheduler;\n\tprivate readonly progressSignal = this._register(new MutableDisposable());\n\n\tconstructor(container: HTMLElement, options?: IProgressBarOptions) {\n\t\tsuper();\n\n\t\tthis.workedVal = 0;\n\n\t\tthis.showDelayedScheduler = this._register(new RunOnceScheduler(() => show(this.element), 0));\n\t\tthis.longRunningScheduler = this._register(new RunOnceScheduler(() => this.infiniteLongRunning(), ProgressBar.LONG_RUNNING_INFINITE_THRESHOLD));\n\n\t\tthis.create(container, options);\n\t}\n\n\tprivate create(container: HTMLElement, options?: IProgressBarOptions): void {\n\t\tthis.element = document.createElement('div');\n\t\tthis.element.classList.add('monaco-progress-container');\n\t\tthis.element.setAttribute('role', 'progressbar');\n\t\tthis.element.setAttribute('aria-valuemin', '0');\n\t\tcontainer.appendChild(this.element);\n\n\t\tthis.bit = document.createElement('div');\n\t\tthis.bit.classList.add('progress-bit');\n\t\tthis.bit.style.backgroundColor = options?.progressBarBackground || '#0E70C0';\n\t\tthis.element.appendChild(this.bit);\n\t}\n\n\tprivate off(): void {\n\t\tthis.bit.style.width = 'inherit';\n\t\tthis.bit.style.opacity = '1';\n\t\tthis.element.classList.remove(CSS_ACTIVE, CSS_INFINITE, CSS_INFINITE_LONG_RUNNING, CSS_DISCRETE);\n\n\t\tthis.workedVal = 0;\n\t\tthis.totalWork = undefined;\n\n\t\tthis.longRunningScheduler.cancel();\n\t\tthis.progressSignal.clear();\n\t}\n\n\t/**\n\t * Stops the progressbar from showing any progress instantly without fading out.\n\t */\n\tstop(): ProgressBar {\n\t\treturn this.doDone(false);\n\t}\n\n\tprivate doDone(delayed: boolean): ProgressBar {\n\t\tthis.element.classList.add(CSS_DONE);\n\n\t\t// discrete: let it grow to 100% width and hide afterwards\n\t\tif (!this.element.classList.contains(CSS_INFINITE)) {\n\t\t\tthis.bit.style.width = 'inherit';\n\n\t\t\tif (delayed) {\n\t\t\t\tsetTimeout(() => this.off(), 200);\n\t\t\t} else {\n\t\t\t\tthis.off();\n\t\t\t}\n\t\t}\n\n\t\t// infinite: let it fade out and hide afterwards\n\t\telse {\n\t\t\tthis.bit.style.opacity = '0';\n\t\t\tif (delayed) {\n\t\t\t\tsetTimeout(() => this.off(), 200);\n\t\t\t} else {\n\t\t\t\tthis.off();\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Use this mode to indicate progress that has no total number of work units.\n\t */\n\tinfinite(): ProgressBar {\n\t\tthis.bit.style.width = '2%';\n\t\tthis.bit.style.opacity = '1';\n\n\t\tthis.element.classList.remove(CSS_DISCRETE, CSS_DONE, CSS_INFINITE_LONG_RUNNING);\n\t\tthis.element.classList.add(CSS_ACTIVE, CSS_INFINITE);\n\n\t\tthis.longRunningScheduler.schedule();\n\n\t\treturn this;\n\t}\n\n\tprivate infiniteLongRunning(): void {\n\t\tthis.element.classList.add(CSS_INFINITE_LONG_RUNNING);\n\t}\n\n\tgetContainer(): HTMLElement {\n\t\treturn this.element;\n\t}\n}\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\nimport { $, append, createStyleSheet, EventHelper, EventLike, getWindow } from 'vs/base/browser/dom';\nimport { DomEmitter } from 'vs/base/browser/event';\nimport { EventType, Gesture } from 'vs/base/browser/touch';\nimport { Delayer } from 'vs/base/common/async';\nimport { memoize } from 'vs/base/common/decorators';\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { Disposable, DisposableStore, toDisposable } from 'vs/base/common/lifecycle';\nimport { isMacintosh } from 'vs/base/common/platform';\nimport 'vs/css!./sash';\n\n/**\n * Allow the sashes to be visible at runtime.\n * @remark Use for development purposes only.\n */\nconst DEBUG = false;\n// DEBUG = Boolean(\"true\"); // done \"weirdly\" so that a lint warning prevents you from pushing this\n\n/**\n * A vertical sash layout provider provides position and height for a sash.\n */\nexport interface IVerticalSashLayoutProvider {\n\tgetVerticalSashLeft(sash: Sash): number;\n\tgetVerticalSashTop?(sash: Sash): number;\n\tgetVerticalSashHeight?(sash: Sash): number;\n}\n\n/**\n * A vertical sash layout provider provides position and width for a sash.\n */\nexport interface IHorizontalSashLayoutProvider {\n\tgetHorizontalSashTop(sash: Sash): number;\n\tgetHorizontalSashLeft?(sash: Sash): number;\n\tgetHorizontalSashWidth?(sash: Sash): number;\n}\n\ntype ISashLayoutProvider = IVerticalSashLayoutProvider | IHorizontalSashLayoutProvider;\n\nexport interface ISashEvent {\n\treadonly startX: number;\n\treadonly currentX: number;\n\treadonly startY: number;\n\treadonly currentY: number;\n\treadonly altKey: boolean;\n}\n\nexport enum OrthogonalEdge {\n\tNorth = 'north',\n\tSouth = 'south',\n\tEast = 'east',\n\tWest = 'west'\n}\n\nexport interface IBoundarySashes {\n\treadonly bottom?: Sash;\n}\n\nexport interface ISashOptions {\n\n\t/**\n\t * Whether a sash is horizontal or vertical.\n\t */\n\treadonly orientation: Orientation;\n\n\t/**\n\t * The width or height of a vertical or horizontal sash, respectively.\n\t */\n\treadonly size?: number;\n\n\t/**\n\t * A reference to another sash, perpendicular to this one, which\n\t * aligns at the start of this one. A corner sash will be created\n\t * automatically at that location.\n\t *\n\t * The start of a horizontal sash is its left-most position.\n\t * The start of a vertical sash is its top-most position.\n\t */\n\treadonly orthogonalStartSash?: Sash;\n\n\t/**\n\t * A reference to another sash, perpendicular to this one, which\n\t * aligns at the end of this one. A corner sash will be created\n\t * automatically at that location.\n\t *\n\t * The end of a horizontal sash is its right-most position.\n\t * The end of a vertical sash is its bottom-most position.\n\t */\n\treadonly orthogonalEndSash?: Sash;\n\n\t/**\n\t * Provides a hint as to what mouse cursor to use whenever the user\n\t * hovers over a corner sash provided by this and an orthogonal sash.\n\t */\n\treadonly orthogonalEdge?: OrthogonalEdge;\n}\n\nexport interface IVerticalSashOptions extends ISashOptions {\n\treadonly orientation: Orientation.VERTICAL;\n}\n\nexport interface IHorizontalSashOptions extends ISashOptions {\n\treadonly orientation: Orientation.HORIZONTAL;\n}\n\nexport const enum Orientation {\n\tVERTICAL,\n\tHORIZONTAL\n}\n\nexport const enum SashState {\n\n\t/**\n\t * Disable any UI interaction.\n\t */\n\tDisabled,\n\n\t/**\n\t * Allow dragging down or to the right, depending on the sash orientation.\n\t *\n\t * Some OSs allow customizing the mouse cursor differently whenever\n\t * some resizable component can't be any smaller, but can be larger.\n\t */\n\tAtMinimum,\n\n\t/**\n\t * Allow dragging up or to the left, depending on the sash orientation.\n\t *\n\t * Some OSs allow customizing the mouse cursor differently whenever\n\t * some resizable component can't be any larger, but can be smaller.\n\t */\n\tAtMaximum,\n\n\t/**\n\t * Enable dragging.\n\t */\n\tEnabled\n}\n\nlet globalSize = 4;\nconst onDidChangeGlobalSize = new Emitter();\n\nlet globalHoverDelay = 300;\nconst onDidChangeHoverDelay = new Emitter();\n\ninterface PointerEvent extends EventLike {\n\treadonly pageX: number;\n\treadonly pageY: number;\n\treadonly altKey: boolean;\n\treadonly target: EventTarget | null;\n\treadonly initialTarget?: EventTarget | undefined;\n}\n\ninterface IPointerEventFactory {\n\treadonly onPointerMove: Event;\n\treadonly onPointerUp: Event;\n\tdispose(): void;\n}\n\nclass MouseEventFactory implements IPointerEventFactory {\n\n\tprivate readonly disposables = new DisposableStore();\n\n\tconstructor(private el: HTMLElement) { }\n\n\t@memoize\n\tget onPointerMove(): Event {\n\t\treturn this.disposables.add(new DomEmitter(getWindow(this.el), 'mousemove')).event;\n\t}\n\n\t@memoize\n\tget onPointerUp(): Event {\n\t\treturn this.disposables.add(new DomEmitter(getWindow(this.el), 'mouseup')).event;\n\t}\n\n\tdispose(): void {\n\t\tthis.disposables.dispose();\n\t}\n}\n\nclass GestureEventFactory implements IPointerEventFactory {\n\n\tprivate readonly disposables = new DisposableStore();\n\n\t@memoize\n\tget onPointerMove(): Event {\n\t\treturn this.disposables.add(new DomEmitter(this.el, EventType.Change)).event;\n\t}\n\n\t@memoize\n\tget onPointerUp(): Event {\n\t\treturn this.disposables.add(new DomEmitter(this.el, EventType.End)).event;\n\t}\n\n\tconstructor(private el: HTMLElement) { }\n\n\tdispose(): void {\n\t\tthis.disposables.dispose();\n\t}\n}\n\nclass OrthogonalPointerEventFactory implements IPointerEventFactory {\n\n\t@memoize\n\tget onPointerMove(): Event {\n\t\treturn this.factory.onPointerMove;\n\t}\n\n\t@memoize\n\tget onPointerUp(): Event {\n\t\treturn this.factory.onPointerUp;\n\t}\n\n\tconstructor(private factory: IPointerEventFactory) { }\n\n\tdispose(): void {\n\t\t// noop\n\t}\n}\n\nconst PointerEventsDisabledCssClass = 'pointer-events-disabled';\n\n/**\n * The {@link Sash} is the UI component which allows the user to resize other\n * components. It's usually an invisible horizontal or vertical line which, when\n * hovered, becomes highlighted and can be dragged along the perpendicular dimension\n * to its direction.\n *\n * Features:\n * - Touch event handling\n * - Corner sash support\n * - Hover with different mouse cursor support\n * - Configurable hover size\n * - Linked sash support, for 2x2 corner sashes\n */\nexport class Sash extends Disposable {\n\n\tprivate el: HTMLElement;\n\tprivate layoutProvider: ISashLayoutProvider;\n\tprivate orientation: Orientation;\n\tprivate size: number;\n\tprivate hoverDelay = globalHoverDelay;\n\tprivate hoverDelayer = this._register(new Delayer(this.hoverDelay));\n\n\tprivate _state: SashState = SashState.Enabled;\n\tprivate readonly onDidEnablementChange = this._register(new Emitter());\n\tprivate readonly _onDidStart = this._register(new Emitter());\n\tprivate readonly _onDidChange = this._register(new Emitter());\n\tprivate readonly _onDidReset = this._register(new Emitter());\n\tprivate readonly _onDidEnd = this._register(new Emitter());\n\tprivate readonly orthogonalStartSashDisposables = this._register(new DisposableStore());\n\tprivate _orthogonalStartSash: Sash | undefined;\n\tprivate readonly orthogonalStartDragHandleDisposables = this._register(new DisposableStore());\n\tprivate _orthogonalStartDragHandle: HTMLElement | undefined;\n\tprivate readonly orthogonalEndSashDisposables = this._register(new DisposableStore());\n\tprivate _orthogonalEndSash: Sash | undefined;\n\tprivate readonly orthogonalEndDragHandleDisposables = this._register(new DisposableStore());\n\tprivate _orthogonalEndDragHandle: HTMLElement | undefined;\n\n\tget state(): SashState { return this._state; }\n\tget orthogonalStartSash(): Sash | undefined { return this._orthogonalStartSash; }\n\tget orthogonalEndSash(): Sash | undefined { return this._orthogonalEndSash; }\n\n\t/**\n\t * The state of a sash defines whether it can be interacted with by the user\n\t * as well as what mouse cursor to use, when hovered.\n\t */\n\tset state(state: SashState) {\n\t\tif (this._state === state) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.el.classList.toggle('disabled', state === SashState.Disabled);\n\t\tthis.el.classList.toggle('minimum', state === SashState.AtMinimum);\n\t\tthis.el.classList.toggle('maximum', state === SashState.AtMaximum);\n\n\t\tthis._state = state;\n\t\tthis.onDidEnablementChange.fire(state);\n\t}\n\n\t/**\n\t * An event which fires whenever the user starts dragging this sash.\n\t */\n\treadonly onDidStart: Event = this._onDidStart.event;\n\n\t/**\n\t * An event which fires whenever the user moves the mouse while\n\t * dragging this sash.\n\t */\n\treadonly onDidChange: Event = this._onDidChange.event;\n\n\t/**\n\t * An event which fires whenever the user double clicks this sash.\n\t */\n\treadonly onDidReset: Event = this._onDidReset.event;\n\n\t/**\n\t * An event which fires whenever the user stops dragging this sash.\n\t */\n\treadonly onDidEnd: Event = this._onDidEnd.event;\n\n\t/**\n\t * A linked sash will be forwarded the same user interactions and events\n\t * so it moves exactly the same way as this sash.\n\t *\n\t * Useful in 2x2 grids. Not meant for widespread usage.\n\t */\n\tlinkedSash: Sash | undefined = undefined;\n\n\t/**\n\t * A reference to another sash, perpendicular to this one, which\n\t * aligns at the start of this one. A corner sash will be created\n\t * automatically at that location.\n\t *\n\t * The start of a horizontal sash is its left-most position.\n\t * The start of a vertical sash is its top-most position.\n\t */\n\tset orthogonalStartSash(sash: Sash | undefined) {\n\t\tif (this._orthogonalStartSash === sash) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.orthogonalStartDragHandleDisposables.clear();\n\t\tthis.orthogonalStartSashDisposables.clear();\n\n\t\tif (sash) {\n\t\t\tconst onChange = (state: SashState) => {\n\t\t\t\tthis.orthogonalStartDragHandleDisposables.clear();\n\n\t\t\t\tif (state !== SashState.Disabled) {\n\t\t\t\t\tthis._orthogonalStartDragHandle = append(this.el, $('.orthogonal-drag-handle.start'));\n\t\t\t\t\tthis.orthogonalStartDragHandleDisposables.add(toDisposable(() => this._orthogonalStartDragHandle!.remove()));\n\t\t\t\t\tthis.orthogonalStartDragHandleDisposables.add(new DomEmitter(this._orthogonalStartDragHandle, 'mouseenter')).event\n\t\t\t\t\t\t(() => Sash.onMouseEnter(sash), undefined, this.orthogonalStartDragHandleDisposables);\n\t\t\t\t\tthis.orthogonalStartDragHandleDisposables.add(new DomEmitter(this._orthogonalStartDragHandle, 'mouseleave')).event\n\t\t\t\t\t\t(() => Sash.onMouseLeave(sash), undefined, this.orthogonalStartDragHandleDisposables);\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tthis.orthogonalStartSashDisposables.add(sash.onDidEnablementChange.event(onChange, this));\n\t\t\tonChange(sash.state);\n\t\t}\n\n\t\tthis._orthogonalStartSash = sash;\n\t}\n\n\t/**\n\t * A reference to another sash, perpendicular to this one, which\n\t * aligns at the end of this one. A corner sash will be created\n\t * automatically at that location.\n\t *\n\t * The end of a horizontal sash is its right-most position.\n\t * The end of a vertical sash is its bottom-most position.\n\t */\n\n\tset orthogonalEndSash(sash: Sash | undefined) {\n\t\tif (this._orthogonalEndSash === sash) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.orthogonalEndDragHandleDisposables.clear();\n\t\tthis.orthogonalEndSashDisposables.clear();\n\n\t\tif (sash) {\n\t\t\tconst onChange = (state: SashState) => {\n\t\t\t\tthis.orthogonalEndDragHandleDisposables.clear();\n\n\t\t\t\tif (state !== SashState.Disabled) {\n\t\t\t\t\tthis._orthogonalEndDragHandle = append(this.el, $('.orthogonal-drag-handle.end'));\n\t\t\t\t\tthis.orthogonalEndDragHandleDisposables.add(toDisposable(() => this._orthogonalEndDragHandle!.remove()));\n\t\t\t\t\tthis.orthogonalEndDragHandleDisposables.add(new DomEmitter(this._orthogonalEndDragHandle, 'mouseenter')).event\n\t\t\t\t\t\t(() => Sash.onMouseEnter(sash), undefined, this.orthogonalEndDragHandleDisposables);\n\t\t\t\t\tthis.orthogonalEndDragHandleDisposables.add(new DomEmitter(this._orthogonalEndDragHandle, 'mouseleave')).event\n\t\t\t\t\t\t(() => Sash.onMouseLeave(sash), undefined, this.orthogonalEndDragHandleDisposables);\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tthis.orthogonalEndSashDisposables.add(sash.onDidEnablementChange.event(onChange, this));\n\t\t\tonChange(sash.state);\n\t\t}\n\n\t\tthis._orthogonalEndSash = sash;\n\t}\n\n\t/**\n\t * Create a new vertical sash.\n\t *\n\t * @param container A DOM node to append the sash to.\n\t * @param verticalLayoutProvider A vertical layout provider.\n\t * @param options The options.\n\t */\n\tconstructor(container: HTMLElement, verticalLayoutProvider: IVerticalSashLayoutProvider, options: IVerticalSashOptions);\n\n\t/**\n\t * Create a new horizontal sash.\n\t *\n\t * @param container A DOM node to append the sash to.\n\t * @param horizontalLayoutProvider A horizontal layout provider.\n\t * @param options The options.\n\t */\n\tconstructor(container: HTMLElement, horizontalLayoutProvider: IHorizontalSashLayoutProvider, options: IHorizontalSashOptions);\n\tconstructor(container: HTMLElement, layoutProvider: ISashLayoutProvider, options: ISashOptions) {\n\t\tsuper();\n\n\t\tthis.el = append(container, $('.monaco-sash'));\n\n\t\tif (options.orthogonalEdge) {\n\t\t\tthis.el.classList.add(`orthogonal-edge-${options.orthogonalEdge}`);\n\t\t}\n\n\t\tif (isMacintosh) {\n\t\t\tthis.el.classList.add('mac');\n\t\t}\n\n\t\tconst onMouseDown = this._register(new DomEmitter(this.el, 'mousedown')).event;\n\t\tthis._register(onMouseDown(e => this.onPointerStart(e, new MouseEventFactory(container)), this));\n\t\tconst onMouseDoubleClick = this._register(new DomEmitter(this.el, 'dblclick')).event;\n\t\tthis._register(onMouseDoubleClick(this.onPointerDoublePress, this));\n\t\tconst onMouseEnter = this._register(new DomEmitter(this.el, 'mouseenter')).event;\n\t\tthis._register(onMouseEnter(() => Sash.onMouseEnter(this)));\n\t\tconst onMouseLeave = this._register(new DomEmitter(this.el, 'mouseleave')).event;\n\t\tthis._register(onMouseLeave(() => Sash.onMouseLeave(this)));\n\n\t\tthis._register(Gesture.addTarget(this.el));\n\n\t\tconst onTouchStart = this._register(new DomEmitter(this.el, EventType.Start)).event;\n\t\tthis._register(onTouchStart(e => this.onPointerStart(e, new GestureEventFactory(this.el)), this));\n\t\tconst onTap = this._register(new DomEmitter(this.el, EventType.Tap)).event;\n\n\t\tlet doubleTapTimeout: any = undefined;\n\t\tthis._register(onTap(event => {\n\t\t\tif (doubleTapTimeout) {\n\t\t\t\tclearTimeout(doubleTapTimeout);\n\t\t\t\tdoubleTapTimeout = undefined;\n\t\t\t\tthis.onPointerDoublePress(event);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tclearTimeout(doubleTapTimeout);\n\t\t\tdoubleTapTimeout = setTimeout(() => doubleTapTimeout = undefined, 250);\n\t\t}, this));\n\n\t\tif (typeof options.size === 'number') {\n\t\t\tthis.size = options.size;\n\n\t\t\tif (options.orientation === Orientation.VERTICAL) {\n\t\t\t\tthis.el.style.width = `${this.size}px`;\n\t\t\t} else {\n\t\t\t\tthis.el.style.height = `${this.size}px`;\n\t\t\t}\n\t\t} else {\n\t\t\tthis.size = globalSize;\n\t\t\tthis._register(onDidChangeGlobalSize.event(size => {\n\t\t\t\tthis.size = size;\n\t\t\t\tthis.layout();\n\t\t\t}));\n\t\t}\n\n\t\tthis._register(onDidChangeHoverDelay.event(delay => this.hoverDelay = delay));\n\n\t\tthis.layoutProvider = layoutProvider;\n\n\t\tthis.orthogonalStartSash = options.orthogonalStartSash;\n\t\tthis.orthogonalEndSash = options.orthogonalEndSash;\n\n\t\tthis.orientation = options.orientation || Orientation.VERTICAL;\n\n\t\tif (this.orientation === Orientation.HORIZONTAL) {\n\t\t\tthis.el.classList.add('horizontal');\n\t\t\tthis.el.classList.remove('vertical');\n\t\t} else {\n\t\t\tthis.el.classList.remove('horizontal');\n\t\t\tthis.el.classList.add('vertical');\n\t\t}\n\n\t\tthis.el.classList.toggle('debug', DEBUG);\n\n\t\tthis.layout();\n\t}\n\n\tprivate onPointerStart(event: PointerEvent, pointerEventFactory: IPointerEventFactory): void {\n\t\tEventHelper.stop(event);\n\n\t\tlet isMultisashResize = false;\n\n\t\tif (!(event as any).__orthogonalSashEvent) {\n\t\t\tconst orthogonalSash = this.getOrthogonalSash(event);\n\n\t\t\tif (orthogonalSash) {\n\t\t\t\tisMultisashResize = true;\n\t\t\t\t(event as any).__orthogonalSashEvent = true;\n\t\t\t\torthogonalSash.onPointerStart(event, new OrthogonalPointerEventFactory(pointerEventFactory));\n\t\t\t}\n\t\t}\n\n\t\tif (this.linkedSash && !(event as any).__linkedSashEvent) {\n\t\t\t(event as any).__linkedSashEvent = true;\n\t\t\tthis.linkedSash.onPointerStart(event, new OrthogonalPointerEventFactory(pointerEventFactory));\n\t\t}\n\n\t\tif (!this.state) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst iframes = this.el.ownerDocument.getElementsByTagName('iframe');\n\t\tfor (const iframe of iframes) {\n\t\t\tiframe.classList.add(PointerEventsDisabledCssClass); // disable mouse events on iframes as long as we drag the sash\n\t\t}\n\n\t\tconst startX = event.pageX;\n\t\tconst startY = event.pageY;\n\t\tconst altKey = event.altKey;\n\t\tconst startEvent: ISashEvent = { startX, currentX: startX, startY, currentY: startY, altKey };\n\n\t\tthis.el.classList.add('active');\n\t\tthis._onDidStart.fire(startEvent);\n\n\t\t// fix https://github.com/microsoft/vscode/issues/21675\n\t\tconst style = createStyleSheet(this.el);\n\t\tconst updateStyle = () => {\n\t\t\tlet cursor = '';\n\n\t\t\tif (isMultisashResize) {\n\t\t\t\tcursor = 'all-scroll';\n\t\t\t} else if (this.orientation === Orientation.HORIZONTAL) {\n\t\t\t\tif (this.state === SashState.AtMinimum) {\n\t\t\t\t\tcursor = 's-resize';\n\t\t\t\t} else if (this.state === SashState.AtMaximum) {\n\t\t\t\t\tcursor = 'n-resize';\n\t\t\t\t} else {\n\t\t\t\t\tcursor = isMacintosh ? 'row-resize' : 'ns-resize';\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (this.state === SashState.AtMinimum) {\n\t\t\t\t\tcursor = 'e-resize';\n\t\t\t\t} else if (this.state === SashState.AtMaximum) {\n\t\t\t\t\tcursor = 'w-resize';\n\t\t\t\t} else {\n\t\t\t\t\tcursor = isMacintosh ? 'col-resize' : 'ew-resize';\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tstyle.textContent = `* { cursor: ${cursor} !important; }`;\n\t\t};\n\n\t\tconst disposables = new DisposableStore();\n\n\t\tupdateStyle();\n\n\t\tif (!isMultisashResize) {\n\t\t\tthis.onDidEnablementChange.event(updateStyle, null, disposables);\n\t\t}\n\n\t\tconst onPointerMove = (e: PointerEvent) => {\n\t\t\tEventHelper.stop(e, false);\n\t\t\tconst event: ISashEvent = { startX, currentX: e.pageX, startY, currentY: e.pageY, altKey };\n\n\t\t\tthis._onDidChange.fire(event);\n\t\t};\n\n\t\tconst onPointerUp = (e: PointerEvent) => {\n\t\t\tEventHelper.stop(e, false);\n\n\t\t\tthis.el.removeChild(style);\n\n\t\t\tthis.el.classList.remove('active');\n\t\t\tthis._onDidEnd.fire();\n\n\t\t\tdisposables.dispose();\n\n\t\t\tfor (const iframe of iframes) {\n\t\t\t\tiframe.classList.remove(PointerEventsDisabledCssClass);\n\t\t\t}\n\t\t};\n\n\t\tpointerEventFactory.onPointerMove(onPointerMove, null, disposables);\n\t\tpointerEventFactory.onPointerUp(onPointerUp, null, disposables);\n\t\tdisposables.add(pointerEventFactory);\n\t}\n\n\tprivate onPointerDoublePress(e: MouseEvent): void {\n\t\tconst orthogonalSash = this.getOrthogonalSash(e);\n\n\t\tif (orthogonalSash) {\n\t\t\torthogonalSash._onDidReset.fire();\n\t\t}\n\n\t\tif (this.linkedSash) {\n\t\t\tthis.linkedSash._onDidReset.fire();\n\t\t}\n\n\t\tthis._onDidReset.fire();\n\t}\n\n\tprivate static onMouseEnter(sash: Sash, fromLinkedSash: boolean = false): void {\n\t\tif (sash.el.classList.contains('active')) {\n\t\t\tsash.hoverDelayer.cancel();\n\t\t\tsash.el.classList.add('hover');\n\t\t} else {\n\t\t\tsash.hoverDelayer.trigger(() => sash.el.classList.add('hover'), sash.hoverDelay).then(undefined, () => { });\n\t\t}\n\n\t\tif (!fromLinkedSash && sash.linkedSash) {\n\t\t\tSash.onMouseEnter(sash.linkedSash, true);\n\t\t}\n\t}\n\n\tprivate static onMouseLeave(sash: Sash, fromLinkedSash: boolean = false): void {\n\t\tsash.hoverDelayer.cancel();\n\t\tsash.el.classList.remove('hover');\n\n\t\tif (!fromLinkedSash && sash.linkedSash) {\n\t\t\tSash.onMouseLeave(sash.linkedSash, true);\n\t\t}\n\t}\n\n\t/**\n\t * Forcefully stop any user interactions with this sash.\n\t * Useful when hiding a parent component, while the user is still\n\t * interacting with the sash.\n\t */\n\tclearSashHoverState(): void {\n\t\tSash.onMouseLeave(this);\n\t}\n\n\t/**\n\t * Layout the sash. The sash will size and position itself\n\t * based on its provided {@link ISashLayoutProvider layout provider}.\n\t */\n\tlayout(): void {\n\t\tif (this.orientation === Orientation.VERTICAL) {\n\t\t\tconst verticalProvider = (this.layoutProvider);\n\t\t\tthis.el.style.left = verticalProvider.getVerticalSashLeft(this) - (this.size / 2) + 'px';\n\n\t\t\tif (verticalProvider.getVerticalSashTop) {\n\t\t\t\tthis.el.style.top = verticalProvider.getVerticalSashTop(this) + 'px';\n\t\t\t}\n\n\t\t\tif (verticalProvider.getVerticalSashHeight) {\n\t\t\t\tthis.el.style.height = verticalProvider.getVerticalSashHeight(this) + 'px';\n\t\t\t}\n\t\t} else {\n\t\t\tconst horizontalProvider = (this.layoutProvider);\n\t\t\tthis.el.style.top = horizontalProvider.getHorizontalSashTop(this) - (this.size / 2) + 'px';\n\n\t\t\tif (horizontalProvider.getHorizontalSashLeft) {\n\t\t\t\tthis.el.style.left = horizontalProvider.getHorizontalSashLeft(this) + 'px';\n\t\t\t}\n\n\t\t\tif (horizontalProvider.getHorizontalSashWidth) {\n\t\t\t\tthis.el.style.width = horizontalProvider.getHorizontalSashWidth(this) + 'px';\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate getOrthogonalSash(e: PointerEvent): Sash | undefined {\n\t\tconst target = e.initialTarget ?? e.target;\n\n\t\tif (!target || !(target instanceof HTMLElement)) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (target.classList.contains('orthogonal-drag-handle')) {\n\t\t\treturn target.classList.contains('start') ? this.orthogonalStartSash : this.orthogonalEndSash;\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\toverride dispose(): void {\n\t\tsuper.dispose();\n\t\tthis.el.remove();\n\t}\n}\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\nimport { Dimension } from 'vs/base/browser/dom';\nimport { Orientation, OrthogonalEdge, Sash, SashState } from 'vs/base/browser/ui/sash/sash';\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { DisposableStore } from 'vs/base/common/lifecycle';\n\n\nexport interface IResizeEvent {\n\tdimension: Dimension;\n\tdone: boolean;\n\tnorth?: boolean;\n\teast?: boolean;\n\tsouth?: boolean;\n\twest?: boolean;\n}\n\nexport class ResizableHTMLElement {\n\n\treadonly domNode: HTMLElement;\n\n\tprivate readonly _onDidWillResize = new Emitter();\n\treadonly onDidWillResize: Event = this._onDidWillResize.event;\n\n\tprivate readonly _onDidResize = new Emitter();\n\treadonly onDidResize: Event = this._onDidResize.event;\n\n\tprivate readonly _northSash: Sash;\n\tprivate readonly _eastSash: Sash;\n\tprivate readonly _southSash: Sash;\n\tprivate readonly _westSash: Sash;\n\tprivate readonly _sashListener = new DisposableStore();\n\n\tprivate _size = new Dimension(0, 0);\n\tprivate _minSize = new Dimension(0, 0);\n\tprivate _maxSize = new Dimension(Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER);\n\tprivate _preferredSize?: Dimension;\n\n\tconstructor() {\n\t\tthis.domNode = document.createElement('div');\n\t\tthis._eastSash = new Sash(this.domNode, { getVerticalSashLeft: () => this._size.width }, { orientation: Orientation.VERTICAL });\n\t\tthis._westSash = new Sash(this.domNode, { getVerticalSashLeft: () => 0 }, { orientation: Orientation.VERTICAL });\n\t\tthis._northSash = new Sash(this.domNode, { getHorizontalSashTop: () => 0 }, { orientation: Orientation.HORIZONTAL, orthogonalEdge: OrthogonalEdge.North });\n\t\tthis._southSash = new Sash(this.domNode, { getHorizontalSashTop: () => this._size.height }, { orientation: Orientation.HORIZONTAL, orthogonalEdge: OrthogonalEdge.South });\n\n\t\tthis._northSash.orthogonalStartSash = this._westSash;\n\t\tthis._northSash.orthogonalEndSash = this._eastSash;\n\t\tthis._southSash.orthogonalStartSash = this._westSash;\n\t\tthis._southSash.orthogonalEndSash = this._eastSash;\n\n\t\tlet currentSize: Dimension | undefined;\n\t\tlet deltaY = 0;\n\t\tlet deltaX = 0;\n\n\t\tthis._sashListener.add(Event.any(this._northSash.onDidStart, this._eastSash.onDidStart, this._southSash.onDidStart, this._westSash.onDidStart)(() => {\n\t\t\tif (currentSize === undefined) {\n\t\t\t\tthis._onDidWillResize.fire();\n\t\t\t\tcurrentSize = this._size;\n\t\t\t\tdeltaY = 0;\n\t\t\t\tdeltaX = 0;\n\t\t\t}\n\t\t}));\n\t\tthis._sashListener.add(Event.any(this._northSash.onDidEnd, this._eastSash.onDidEnd, this._southSash.onDidEnd, this._westSash.onDidEnd)(() => {\n\t\t\tif (currentSize !== undefined) {\n\t\t\t\tcurrentSize = undefined;\n\t\t\t\tdeltaY = 0;\n\t\t\t\tdeltaX = 0;\n\t\t\t\tthis._onDidResize.fire({ dimension: this._size, done: true });\n\t\t\t}\n\t\t}));\n\n\t\tthis._sashListener.add(this._eastSash.onDidChange(e => {\n\t\t\tif (currentSize) {\n\t\t\t\tdeltaX = e.currentX - e.startX;\n\t\t\t\tthis.layout(currentSize.height + deltaY, currentSize.width + deltaX);\n\t\t\t\tthis._onDidResize.fire({ dimension: this._size, done: false, east: true });\n\t\t\t}\n\t\t}));\n\t\tthis._sashListener.add(this._westSash.onDidChange(e => {\n\t\t\tif (currentSize) {\n\t\t\t\tdeltaX = -(e.currentX - e.startX);\n\t\t\t\tthis.layout(currentSize.height + deltaY, currentSize.width + deltaX);\n\t\t\t\tthis._onDidResize.fire({ dimension: this._size, done: false, west: true });\n\t\t\t}\n\t\t}));\n\t\tthis._sashListener.add(this._northSash.onDidChange(e => {\n\t\t\tif (currentSize) {\n\t\t\t\tdeltaY = -(e.currentY - e.startY);\n\t\t\t\tthis.layout(currentSize.height + deltaY, currentSize.width + deltaX);\n\t\t\t\tthis._onDidResize.fire({ dimension: this._size, done: false, north: true });\n\t\t\t}\n\t\t}));\n\t\tthis._sashListener.add(this._southSash.onDidChange(e => {\n\t\t\tif (currentSize) {\n\t\t\t\tdeltaY = e.currentY - e.startY;\n\t\t\t\tthis.layout(currentSize.height + deltaY, currentSize.width + deltaX);\n\t\t\t\tthis._onDidResize.fire({ dimension: this._size, done: false, south: true });\n\t\t\t}\n\t\t}));\n\n\t\tthis._sashListener.add(Event.any(this._eastSash.onDidReset, this._westSash.onDidReset)(e => {\n\t\t\tif (this._preferredSize) {\n\t\t\t\tthis.layout(this._size.height, this._preferredSize.width);\n\t\t\t\tthis._onDidResize.fire({ dimension: this._size, done: true });\n\t\t\t}\n\t\t}));\n\t\tthis._sashListener.add(Event.any(this._northSash.onDidReset, this._southSash.onDidReset)(e => {\n\t\t\tif (this._preferredSize) {\n\t\t\t\tthis.layout(this._preferredSize.height, this._size.width);\n\t\t\t\tthis._onDidResize.fire({ dimension: this._size, done: true });\n\t\t\t}\n\t\t}));\n\t}\n\n\tdispose(): void {\n\t\tthis._northSash.dispose();\n\t\tthis._southSash.dispose();\n\t\tthis._eastSash.dispose();\n\t\tthis._westSash.dispose();\n\t\tthis._sashListener.dispose();\n\t\tthis._onDidResize.dispose();\n\t\tthis._onDidWillResize.dispose();\n\t\tthis.domNode.remove();\n\t}\n\n\tenableSashes(north: boolean, east: boolean, south: boolean, west: boolean): void {\n\t\tthis._northSash.state = north ? SashState.Enabled : SashState.Disabled;\n\t\tthis._eastSash.state = east ? SashState.Enabled : SashState.Disabled;\n\t\tthis._southSash.state = south ? SashState.Enabled : SashState.Disabled;\n\t\tthis._westSash.state = west ? SashState.Enabled : SashState.Disabled;\n\t}\n\n\tlayout(height: number = this.size.height, width: number = this.size.width): void {\n\n\t\tconst { height: minHeight, width: minWidth } = this._minSize;\n\t\tconst { height: maxHeight, width: maxWidth } = this._maxSize;\n\n\t\theight = Math.max(minHeight, Math.min(maxHeight, height));\n\t\twidth = Math.max(minWidth, Math.min(maxWidth, width));\n\n\t\tconst newSize = new Dimension(width, height);\n\t\tif (!Dimension.equals(newSize, this._size)) {\n\t\t\tthis.domNode.style.height = height + 'px';\n\t\t\tthis.domNode.style.width = width + 'px';\n\t\t\tthis._size = newSize;\n\t\t\tthis._northSash.layout();\n\t\t\tthis._eastSash.layout();\n\t\t\tthis._southSash.layout();\n\t\t\tthis._westSash.layout();\n\t\t}\n\t}\n\n\tclearSashHoverState(): void {\n\t\tthis._eastSash.clearSashHoverState();\n\t\tthis._westSash.clearSashHoverState();\n\t\tthis._northSash.clearSashHoverState();\n\t\tthis._southSash.clearSashHoverState();\n\t}\n\n\tget size() {\n\t\treturn this._size;\n\t}\n\n\tset maxSize(value: Dimension) {\n\t\tthis._maxSize = value;\n\t}\n\n\tget maxSize() {\n\t\treturn this._maxSize;\n\t}\n\n\tset minSize(value: Dimension) {\n\t\tthis._minSize = value;\n\t}\n\n\tget minSize() {\n\t\treturn this._minSize;\n\t}\n\n\tset preferredSize(value: Dimension | undefined) {\n\t\tthis._preferredSize = value;\n\t}\n\n\tget preferredSize() {\n\t\treturn this._preferredSize;\n\t}\n}\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\nimport * as dom from 'vs/base/browser/dom';\nimport { EventType, Gesture } from 'vs/base/browser/touch';\nimport { ISelectBoxDelegate, ISelectBoxOptions, ISelectBoxStyles, ISelectData, ISelectOptionItem } from 'vs/base/browser/ui/selectBox/selectBox';\nimport * as arrays from 'vs/base/common/arrays';\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { KeyCode } from 'vs/base/common/keyCodes';\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport { isMacintosh } from 'vs/base/common/platform';\n\nexport class SelectBoxNative extends Disposable implements ISelectBoxDelegate {\n\n\tprivate selectElement: HTMLSelectElement;\n\tprivate selectBoxOptions: ISelectBoxOptions;\n\tprivate options: ISelectOptionItem[];\n\tprivate selected = 0;\n\tprivate readonly _onDidSelect: Emitter;\n\tprivate styles: ISelectBoxStyles;\n\n\tconstructor(options: ISelectOptionItem[], selected: number, styles: ISelectBoxStyles, selectBoxOptions?: ISelectBoxOptions) {\n\t\tsuper();\n\t\tthis.selectBoxOptions = selectBoxOptions || Object.create(null);\n\n\t\tthis.options = [];\n\n\t\tthis.selectElement = document.createElement('select');\n\n\t\tthis.selectElement.className = 'monaco-select-box';\n\n\t\tif (typeof this.selectBoxOptions.ariaLabel === 'string') {\n\t\t\tthis.selectElement.setAttribute('aria-label', this.selectBoxOptions.ariaLabel);\n\t\t}\n\n\t\tif (typeof this.selectBoxOptions.ariaDescription === 'string') {\n\t\t\tthis.selectElement.setAttribute('aria-description', this.selectBoxOptions.ariaDescription);\n\t\t}\n\n\t\tthis._onDidSelect = this._register(new Emitter());\n\n\t\tthis.styles = styles;\n\n\t\tthis.registerListeners();\n\t\tthis.setOptions(options, selected);\n\t}\n\n\tprivate registerListeners() {\n\t\tthis._register(Gesture.addTarget(this.selectElement));\n\t\t[EventType.Tap].forEach(eventType => {\n\t\t\tthis._register(dom.addDisposableListener(this.selectElement, eventType, (e) => {\n\t\t\t\tthis.selectElement.focus();\n\t\t\t}));\n\t\t});\n\n\t\tthis._register(dom.addStandardDisposableListener(this.selectElement, 'click', (e) => {\n\t\t\tdom.EventHelper.stop(e, true);\n\t\t}));\n\n\t\tthis._register(dom.addStandardDisposableListener(this.selectElement, 'change', (e) => {\n\t\t\tthis.selectElement.title = e.target.value;\n\t\t\tthis._onDidSelect.fire({\n\t\t\t\tindex: e.target.selectedIndex,\n\t\t\t\tselected: e.target.value\n\t\t\t});\n\t\t}));\n\n\t\tthis._register(dom.addStandardDisposableListener(this.selectElement, 'keydown', (e) => {\n\t\t\tlet showSelect = false;\n\n\t\t\tif (isMacintosh) {\n\t\t\t\tif (e.keyCode === KeyCode.DownArrow || e.keyCode === KeyCode.UpArrow || e.keyCode === KeyCode.Space) {\n\t\t\t\t\tshowSelect = true;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (e.keyCode === KeyCode.DownArrow && e.altKey || e.keyCode === KeyCode.Space || e.keyCode === KeyCode.Enter) {\n\t\t\t\t\tshowSelect = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (showSelect) {\n\t\t\t\t// Space, Enter, is used to expand select box, do not propagate it (prevent action bar action run)\n\t\t\t\te.stopPropagation();\n\t\t\t}\n\t\t}));\n\t}\n\n\tpublic get onDidSelect(): Event {\n\t\treturn this._onDidSelect.event;\n\t}\n\n\tpublic setOptions(options: ISelectOptionItem[], selected?: number): void {\n\n\t\tif (!this.options || !arrays.equals(this.options, options)) {\n\t\t\tthis.options = options;\n\t\t\tthis.selectElement.options.length = 0;\n\n\t\t\tthis.options.forEach((option, index) => {\n\t\t\t\tthis.selectElement.add(this.createOption(option.text, index, option.isDisabled));\n\t\t\t});\n\n\t\t}\n\n\t\tif (selected !== undefined) {\n\t\t\tthis.select(selected);\n\t\t}\n\t}\n\n\tpublic select(index: number): void {\n\t\tif (this.options.length === 0) {\n\t\t\tthis.selected = 0;\n\t\t} else if (index >= 0 && index < this.options.length) {\n\t\t\tthis.selected = index;\n\t\t} else if (index > this.options.length - 1) {\n\t\t\t// Adjust index to end of list\n\t\t\t// This could make client out of sync with the select\n\t\t\tthis.select(this.options.length - 1);\n\t\t} else if (this.selected < 0) {\n\t\t\tthis.selected = 0;\n\t\t}\n\n\t\tthis.selectElement.selectedIndex = this.selected;\n\t\tif ((this.selected < this.options.length) && typeof this.options[this.selected].text === 'string') {\n\t\t\tthis.selectElement.title = this.options[this.selected].text;\n\t\t} else {\n\t\t\tthis.selectElement.title = '';\n\t\t}\n\t}\n\n\tpublic focus(): void {\n\t\tif (this.selectElement) {\n\t\t\tthis.selectElement.tabIndex = 0;\n\t\t\tthis.selectElement.focus();\n\t\t}\n\t}\n\n\tpublic blur(): void {\n\t\tif (this.selectElement) {\n\t\t\tthis.selectElement.tabIndex = -1;\n\t\t\tthis.selectElement.blur();\n\t\t}\n\t}\n\n\tpublic setFocusable(focusable: boolean): void {\n\t\tthis.selectElement.tabIndex = focusable ? 0 : -1;\n\t}\n\n\tpublic render(container: HTMLElement): void {\n\t\tcontainer.classList.add('select-container');\n\t\tcontainer.appendChild(this.selectElement);\n\t\tthis.setOptions(this.options, this.selected);\n\t\tthis.applyStyles();\n\t}\n\n\tpublic applyStyles(): void {\n\n\t\t// Style native select\n\t\tif (this.selectElement) {\n\t\t\tthis.selectElement.style.backgroundColor = this.styles.selectBackground ?? '';\n\t\t\tthis.selectElement.style.color = this.styles.selectForeground ?? '';\n\t\t\tthis.selectElement.style.borderColor = this.styles.selectBorder ?? '';\n\t\t}\n\n\t}\n\n\tprivate createOption(value: string, index: number, disabled?: boolean): HTMLOptionElement {\n\t\tconst option = document.createElement('option');\n\t\toption.value = value;\n\t\toption.text = value;\n\t\toption.disabled = !!disabled;\n\n\t\treturn option;\n\t}\n}\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\nimport * as dom from 'vs/base/browser/dom';\nimport { IKeyboardEvent, StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';\nimport { IMouseEvent, StandardMouseEvent } from 'vs/base/browser/mouseEvent';\nimport { Gesture } from 'vs/base/browser/touch';\nimport { Disposable, IDisposable } from 'vs/base/common/lifecycle';\n\nexport abstract class Widget extends Disposable {\n\n\tprotected onclick(domNode: HTMLElement, listener: (e: IMouseEvent) => void): void {\n\t\tthis._register(dom.addDisposableListener(domNode, dom.EventType.CLICK, (e: MouseEvent) => listener(new StandardMouseEvent(dom.getWindow(domNode), e))));\n\t}\n\n\tprotected onmousedown(domNode: HTMLElement, listener: (e: IMouseEvent) => void): void {\n\t\tthis._register(dom.addDisposableListener(domNode, dom.EventType.MOUSE_DOWN, (e: MouseEvent) => listener(new StandardMouseEvent(dom.getWindow(domNode), e))));\n\t}\n\n\tprotected onmouseover(domNode: HTMLElement, listener: (e: IMouseEvent) => void): void {\n\t\tthis._register(dom.addDisposableListener(domNode, dom.EventType.MOUSE_OVER, (e: MouseEvent) => listener(new StandardMouseEvent(dom.getWindow(domNode), e))));\n\t}\n\n\tprotected onmouseleave(domNode: HTMLElement, listener: (e: IMouseEvent) => void): void {\n\t\tthis._register(dom.addDisposableListener(domNode, dom.EventType.MOUSE_LEAVE, (e: MouseEvent) => listener(new StandardMouseEvent(dom.getWindow(domNode), e))));\n\t}\n\n\tprotected onkeydown(domNode: HTMLElement, listener: (e: IKeyboardEvent) => void): void {\n\t\tthis._register(dom.addDisposableListener(domNode, dom.EventType.KEY_DOWN, (e: KeyboardEvent) => listener(new StandardKeyboardEvent(e))));\n\t}\n\n\tprotected onkeyup(domNode: HTMLElement, listener: (e: IKeyboardEvent) => void): void {\n\t\tthis._register(dom.addDisposableListener(domNode, dom.EventType.KEY_UP, (e: KeyboardEvent) => listener(new StandardKeyboardEvent(e))));\n\t}\n\n\tprotected oninput(domNode: HTMLElement, listener: (e: Event) => void): void {\n\t\tthis._register(dom.addDisposableListener(domNode, dom.EventType.INPUT, listener));\n\t}\n\n\tprotected onblur(domNode: HTMLElement, listener: (e: Event) => void): void {\n\t\tthis._register(dom.addDisposableListener(domNode, dom.EventType.BLUR, listener));\n\t}\n\n\tprotected onfocus(domNode: HTMLElement, listener: (e: Event) => void): void {\n\t\tthis._register(dom.addDisposableListener(domNode, dom.EventType.FOCUS, listener));\n\t}\n\n\tprotected ignoreGesture(domNode: HTMLElement): IDisposable {\n\t\treturn Gesture.ignoreTarget(domNode);\n\t}\n}\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\nimport { GlobalPointerMoveMonitor } from 'vs/base/browser/globalPointerMoveMonitor';\nimport { Widget } from 'vs/base/browser/ui/widget';\nimport { TimeoutTimer } from 'vs/base/common/async';\nimport { ThemeIcon } from 'vs/base/common/themables';\nimport * as dom from 'vs/base/browser/dom';\n\n/**\n * The arrow image size.\n */\nexport const ARROW_IMG_SIZE = 11;\n\nexport interface ScrollbarArrowOptions {\n\tonActivate: () => void;\n\tclassName: string;\n\ticon: ThemeIcon;\n\n\tbgWidth: number;\n\tbgHeight: number;\n\n\ttop?: number;\n\tleft?: number;\n\tbottom?: number;\n\tright?: number;\n}\n\nexport class ScrollbarArrow extends Widget {\n\n\tprivate _onActivate: () => void;\n\tpublic bgDomNode: HTMLElement;\n\tpublic domNode: HTMLElement;\n\tprivate _pointerdownRepeatTimer: dom.WindowIntervalTimer;\n\tprivate _pointerdownScheduleRepeatTimer: TimeoutTimer;\n\tprivate _pointerMoveMonitor: GlobalPointerMoveMonitor;\n\n\tconstructor(opts: ScrollbarArrowOptions) {\n\t\tsuper();\n\t\tthis._onActivate = opts.onActivate;\n\n\t\tthis.bgDomNode = document.createElement('div');\n\t\tthis.bgDomNode.className = 'arrow-background';\n\t\tthis.bgDomNode.style.position = 'absolute';\n\t\tthis.bgDomNode.style.width = opts.bgWidth + 'px';\n\t\tthis.bgDomNode.style.height = opts.bgHeight + 'px';\n\t\tif (typeof opts.top !== 'undefined') {\n\t\t\tthis.bgDomNode.style.top = '0px';\n\t\t}\n\t\tif (typeof opts.left !== 'undefined') {\n\t\t\tthis.bgDomNode.style.left = '0px';\n\t\t}\n\t\tif (typeof opts.bottom !== 'undefined') {\n\t\t\tthis.bgDomNode.style.bottom = '0px';\n\t\t}\n\t\tif (typeof opts.right !== 'undefined') {\n\t\t\tthis.bgDomNode.style.right = '0px';\n\t\t}\n\n\t\tthis.domNode = document.createElement('div');\n\t\tthis.domNode.className = opts.className;\n\t\tthis.domNode.classList.add(...ThemeIcon.asClassNameArray(opts.icon));\n\n\t\tthis.domNode.style.position = 'absolute';\n\t\tthis.domNode.style.width = ARROW_IMG_SIZE + 'px';\n\t\tthis.domNode.style.height = ARROW_IMG_SIZE + 'px';\n\t\tif (typeof opts.top !== 'undefined') {\n\t\t\tthis.domNode.style.top = opts.top + 'px';\n\t\t}\n\t\tif (typeof opts.left !== 'undefined') {\n\t\t\tthis.domNode.style.left = opts.left + 'px';\n\t\t}\n\t\tif (typeof opts.bottom !== 'undefined') {\n\t\t\tthis.domNode.style.bottom = opts.bottom + 'px';\n\t\t}\n\t\tif (typeof opts.right !== 'undefined') {\n\t\t\tthis.domNode.style.right = opts.right + 'px';\n\t\t}\n\n\t\tthis._pointerMoveMonitor = this._register(new GlobalPointerMoveMonitor());\n\t\tthis._register(dom.addStandardDisposableListener(this.bgDomNode, dom.EventType.POINTER_DOWN, (e) => this._arrowPointerDown(e)));\n\t\tthis._register(dom.addStandardDisposableListener(this.domNode, dom.EventType.POINTER_DOWN, (e) => this._arrowPointerDown(e)));\n\n\t\tthis._pointerdownRepeatTimer = this._register(new dom.WindowIntervalTimer());\n\t\tthis._pointerdownScheduleRepeatTimer = this._register(new TimeoutTimer());\n\t}\n\n\tprivate _arrowPointerDown(e: PointerEvent): void {\n\t\tif (!e.target || !(e.target instanceof Element)) {\n\t\t\treturn;\n\t\t}\n\t\tconst scheduleRepeater = () => {\n\t\t\tthis._pointerdownRepeatTimer.cancelAndSet(() => this._onActivate(), 1000 / 24, dom.getWindow(e));\n\t\t};\n\n\t\tthis._onActivate();\n\t\tthis._pointerdownRepeatTimer.cancel();\n\t\tthis._pointerdownScheduleRepeatTimer.cancelAndSet(scheduleRepeater, 200);\n\n\t\tthis._pointerMoveMonitor.startMonitoring(\n\t\t\te.target,\n\t\t\te.pointerId,\n\t\t\te.buttons,\n\t\t\t(pointerMoveData) => { /* Intentional empty */ },\n\t\t\t() => {\n\t\t\t\tthis._pointerdownRepeatTimer.cancel();\n\t\t\t\tthis._pointerdownScheduleRepeatTimer.cancel();\n\t\t\t}\n\t\t);\n\n\t\te.preventDefault();\n\t}\n}\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\nimport * as dom from 'vs/base/browser/dom';\nimport { createFastDomNode, FastDomNode } from 'vs/base/browser/fastDomNode';\nimport { GlobalPointerMoveMonitor } from 'vs/base/browser/globalPointerMoveMonitor';\nimport { StandardWheelEvent } from 'vs/base/browser/mouseEvent';\nimport { ScrollbarArrow, ScrollbarArrowOptions } from 'vs/base/browser/ui/scrollbar/scrollbarArrow';\nimport { ScrollbarState } from 'vs/base/browser/ui/scrollbar/scrollbarState';\nimport { ScrollbarVisibilityController } from 'vs/base/browser/ui/scrollbar/scrollbarVisibilityController';\nimport { Widget } from 'vs/base/browser/ui/widget';\nimport * as platform from 'vs/base/common/platform';\nimport { INewScrollPosition, Scrollable, ScrollbarVisibility } from 'vs/base/common/scrollable';\n\n/**\n * The orthogonal distance to the slider at which dragging \"resets\". This implements \"snapping\"\n */\nconst POINTER_DRAG_RESET_DISTANCE = 140;\n\nexport interface ISimplifiedPointerEvent {\n\tpageX: number;\n\tpageY: number;\n}\n\nexport interface ScrollbarHost {\n\tonMouseWheel(mouseWheelEvent: StandardWheelEvent): void;\n\tonDragStart(): void;\n\tonDragEnd(): void;\n}\n\nexport interface AbstractScrollbarOptions {\n\tlazyRender: boolean;\n\thost: ScrollbarHost;\n\tscrollbarState: ScrollbarState;\n\tvisibility: ScrollbarVisibility;\n\textraScrollbarClassName: string;\n\tscrollable: Scrollable;\n\tscrollByPage: boolean;\n}\n\nexport abstract class AbstractScrollbar extends Widget {\n\n\tprotected _host: ScrollbarHost;\n\tprotected _scrollable: Scrollable;\n\tprotected _scrollByPage: boolean;\n\tprivate _lazyRender: boolean;\n\tprotected _scrollbarState: ScrollbarState;\n\tprotected _visibilityController: ScrollbarVisibilityController;\n\tprivate _pointerMoveMonitor: GlobalPointerMoveMonitor;\n\n\tpublic domNode: FastDomNode;\n\tpublic slider!: FastDomNode;\n\n\tprotected _shouldRender: boolean;\n\n\tconstructor(opts: AbstractScrollbarOptions) {\n\t\tsuper();\n\t\tthis._lazyRender = opts.lazyRender;\n\t\tthis._host = opts.host;\n\t\tthis._scrollable = opts.scrollable;\n\t\tthis._scrollByPage = opts.scrollByPage;\n\t\tthis._scrollbarState = opts.scrollbarState;\n\t\tthis._visibilityController = this._register(new ScrollbarVisibilityController(opts.visibility, 'visible scrollbar ' + opts.extraScrollbarClassName, 'invisible scrollbar ' + opts.extraScrollbarClassName));\n\t\tthis._visibilityController.setIsNeeded(this._scrollbarState.isNeeded());\n\t\tthis._pointerMoveMonitor = this._register(new GlobalPointerMoveMonitor());\n\t\tthis._shouldRender = true;\n\t\tthis.domNode = createFastDomNode(document.createElement('div'));\n\t\tthis.domNode.setAttribute('role', 'presentation');\n\t\tthis.domNode.setAttribute('aria-hidden', 'true');\n\n\t\tthis._visibilityController.setDomNode(this.domNode);\n\t\tthis.domNode.setPosition('absolute');\n\n\t\tthis._register(dom.addDisposableListener(this.domNode.domNode, dom.EventType.POINTER_DOWN, (e: PointerEvent) => this._domNodePointerDown(e)));\n\t}\n\n\t// ----------------- creation\n\n\t/**\n\t * Creates the dom node for an arrow & adds it to the container\n\t */\n\tprotected _createArrow(opts: ScrollbarArrowOptions): void {\n\t\tconst arrow = this._register(new ScrollbarArrow(opts));\n\t\tthis.domNode.domNode.appendChild(arrow.bgDomNode);\n\t\tthis.domNode.domNode.appendChild(arrow.domNode);\n\t}\n\n\t/**\n\t * Creates the slider dom node, adds it to the container & hooks up the events\n\t */\n\tprotected _createSlider(top: number, left: number, width: number | undefined, height: number | undefined): void {\n\t\tthis.slider = createFastDomNode(document.createElement('div'));\n\t\tthis.slider.setClassName('slider');\n\t\tthis.slider.setPosition('absolute');\n\t\tthis.slider.setTop(top);\n\t\tthis.slider.setLeft(left);\n\t\tif (typeof width === 'number') {\n\t\t\tthis.slider.setWidth(width);\n\t\t}\n\t\tif (typeof height === 'number') {\n\t\t\tthis.slider.setHeight(height);\n\t\t}\n\t\tthis.slider.setLayerHinting(true);\n\t\tthis.slider.setContain('strict');\n\n\t\tthis.domNode.domNode.appendChild(this.slider.domNode);\n\n\t\tthis._register(dom.addDisposableListener(\n\t\t\tthis.slider.domNode,\n\t\t\tdom.EventType.POINTER_DOWN,\n\t\t\t(e: PointerEvent) => {\n\t\t\t\tif (e.button === 0) {\n\t\t\t\t\te.preventDefault();\n\t\t\t\t\tthis._sliderPointerDown(e);\n\t\t\t\t}\n\t\t\t}\n\t\t));\n\n\t\tthis.onclick(this.slider.domNode, e => {\n\t\t\tif (e.leftButton) {\n\t\t\t\te.stopPropagation();\n\t\t\t}\n\t\t});\n\t}\n\n\t// ----------------- Update state\n\n\tprotected _onElementSize(visibleSize: number): boolean {\n\t\tif (this._scrollbarState.setVisibleSize(visibleSize)) {\n\t\t\tthis._visibilityController.setIsNeeded(this._scrollbarState.isNeeded());\n\t\t\tthis._shouldRender = true;\n\t\t\tif (!this._lazyRender) {\n\t\t\t\tthis.render();\n\t\t\t}\n\t\t}\n\t\treturn this._shouldRender;\n\t}\n\n\tprotected _onElementScrollSize(elementScrollSize: number): boolean {\n\t\tif (this._scrollbarState.setScrollSize(elementScrollSize)) {\n\t\t\tthis._visibilityController.setIsNeeded(this._scrollbarState.isNeeded());\n\t\t\tthis._shouldRender = true;\n\t\t\tif (!this._lazyRender) {\n\t\t\t\tthis.render();\n\t\t\t}\n\t\t}\n\t\treturn this._shouldRender;\n\t}\n\n\tprotected _onElementScrollPosition(elementScrollPosition: number): boolean {\n\t\tif (this._scrollbarState.setScrollPosition(elementScrollPosition)) {\n\t\t\tthis._visibilityController.setIsNeeded(this._scrollbarState.isNeeded());\n\t\t\tthis._shouldRender = true;\n\t\t\tif (!this._lazyRender) {\n\t\t\t\tthis.render();\n\t\t\t}\n\t\t}\n\t\treturn this._shouldRender;\n\t}\n\n\t// ----------------- rendering\n\n\tpublic beginReveal(): void {\n\t\tthis._visibilityController.setShouldBeVisible(true);\n\t}\n\n\tpublic beginHide(): void {\n\t\tthis._visibilityController.setShouldBeVisible(false);\n\t}\n\n\tpublic render(): void {\n\t\tif (!this._shouldRender) {\n\t\t\treturn;\n\t\t}\n\t\tthis._shouldRender = false;\n\n\t\tthis._renderDomNode(this._scrollbarState.getRectangleLargeSize(), this._scrollbarState.getRectangleSmallSize());\n\t\tthis._updateSlider(this._scrollbarState.getSliderSize(), this._scrollbarState.getArrowSize() + this._scrollbarState.getSliderPosition());\n\t}\n\t// ----------------- DOM events\n\n\tprivate _domNodePointerDown(e: PointerEvent): void {\n\t\tif (e.target !== this.domNode.domNode) {\n\t\t\treturn;\n\t\t}\n\t\tthis._onPointerDown(e);\n\t}\n\n\tpublic delegatePointerDown(e: PointerEvent): void {\n\t\tconst domTop = this.domNode.domNode.getClientRects()[0].top;\n\t\tconst sliderStart = domTop + this._scrollbarState.getSliderPosition();\n\t\tconst sliderStop = domTop + this._scrollbarState.getSliderPosition() + this._scrollbarState.getSliderSize();\n\t\tconst pointerPos = this._sliderPointerPosition(e);\n\t\tif (sliderStart <= pointerPos && pointerPos <= sliderStop) {\n\t\t\t// Act as if it was a pointer down on the slider\n\t\t\tif (e.button === 0) {\n\t\t\t\te.preventDefault();\n\t\t\t\tthis._sliderPointerDown(e);\n\t\t\t}\n\t\t} else {\n\t\t\t// Act as if it was a pointer down on the scrollbar\n\t\t\tthis._onPointerDown(e);\n\t\t}\n\t}\n\n\tprivate _onPointerDown(e: PointerEvent): void {\n\t\tlet offsetX: number;\n\t\tlet offsetY: number;\n\t\tif (e.target === this.domNode.domNode && typeof e.offsetX === 'number' && typeof e.offsetY === 'number') {\n\t\t\toffsetX = e.offsetX;\n\t\t\toffsetY = e.offsetY;\n\t\t} else {\n\t\t\tconst domNodePosition = dom.getDomNodePagePosition(this.domNode.domNode);\n\t\t\toffsetX = e.pageX - domNodePosition.left;\n\t\t\toffsetY = e.pageY - domNodePosition.top;\n\t\t}\n\n\t\tconst offset = this._pointerDownRelativePosition(offsetX, offsetY);\n\t\tthis._setDesiredScrollPositionNow(\n\t\t\tthis._scrollByPage\n\t\t\t\t? this._scrollbarState.getDesiredScrollPositionFromOffsetPaged(offset)\n\t\t\t\t: this._scrollbarState.getDesiredScrollPositionFromOffset(offset)\n\t\t);\n\n\t\tif (e.button === 0) {\n\t\t\t// left button\n\t\t\te.preventDefault();\n\t\t\tthis._sliderPointerDown(e);\n\t\t}\n\t}\n\n\tprivate _sliderPointerDown(e: PointerEvent): void {\n\t\tif (!e.target || !(e.target instanceof Element)) {\n\t\t\treturn;\n\t\t}\n\t\tconst initialPointerPosition = this._sliderPointerPosition(e);\n\t\tconst initialPointerOrthogonalPosition = this._sliderOrthogonalPointerPosition(e);\n\t\tconst initialScrollbarState = this._scrollbarState.clone();\n\t\tthis.slider.toggleClassName('active', true);\n\n\t\tthis._pointerMoveMonitor.startMonitoring(\n\t\t\te.target,\n\t\t\te.pointerId,\n\t\t\te.buttons,\n\t\t\t(pointerMoveData: PointerEvent) => {\n\t\t\t\tconst pointerOrthogonalPosition = this._sliderOrthogonalPointerPosition(pointerMoveData);\n\t\t\t\tconst pointerOrthogonalDelta = Math.abs(pointerOrthogonalPosition - initialPointerOrthogonalPosition);\n\n\t\t\t\tif (platform.isWindows && pointerOrthogonalDelta > POINTER_DRAG_RESET_DISTANCE) {\n\t\t\t\t\t// The pointer has wondered away from the scrollbar => reset dragging\n\t\t\t\t\tthis._setDesiredScrollPositionNow(initialScrollbarState.getScrollPosition());\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst pointerPosition = this._sliderPointerPosition(pointerMoveData);\n\t\t\t\tconst pointerDelta = pointerPosition - initialPointerPosition;\n\t\t\t\tthis._setDesiredScrollPositionNow(initialScrollbarState.getDesiredScrollPositionFromDelta(pointerDelta));\n\t\t\t},\n\t\t\t() => {\n\t\t\t\tthis.slider.toggleClassName('active', false);\n\t\t\t\tthis._host.onDragEnd();\n\t\t\t}\n\t\t);\n\n\t\tthis._host.onDragStart();\n\t}\n\n\tprivate _setDesiredScrollPositionNow(_desiredScrollPosition: number): void {\n\n\t\tconst desiredScrollPosition: INewScrollPosition = {};\n\t\tthis.writeScrollPosition(desiredScrollPosition, _desiredScrollPosition);\n\n\t\tthis._scrollable.setScrollPositionNow(desiredScrollPosition);\n\t}\n\n\tpublic updateScrollbarSize(scrollbarSize: number): void {\n\t\tthis._updateScrollbarSize(scrollbarSize);\n\t\tthis._scrollbarState.setScrollbarSize(scrollbarSize);\n\t\tthis._shouldRender = true;\n\t\tif (!this._lazyRender) {\n\t\t\tthis.render();\n\t\t}\n\t}\n\n\tpublic isNeeded(): boolean {\n\t\treturn this._scrollbarState.isNeeded();\n\t}\n\n\t// ----------------- Overwrite these\n\n\tprotected abstract _renderDomNode(largeSize: number, smallSize: number): void;\n\tprotected abstract _updateSlider(sliderSize: number, sliderPosition: number): void;\n\n\tprotected abstract _pointerDownRelativePosition(offsetX: number, offsetY: number): number;\n\tprotected abstract _sliderPointerPosition(e: ISimplifiedPointerEvent): number;\n\tprotected abstract _sliderOrthogonalPointerPosition(e: ISimplifiedPointerEvent): number;\n\tprotected abstract _updateScrollbarSize(size: number): void;\n\n\tpublic abstract writeScrollPosition(target: INewScrollPosition, scrollPosition: number): void;\n}\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\nimport { StandardWheelEvent } from 'vs/base/browser/mouseEvent';\nimport { AbstractScrollbar, ISimplifiedPointerEvent, ScrollbarHost } from 'vs/base/browser/ui/scrollbar/abstractScrollbar';\nimport { ScrollableElementResolvedOptions } from 'vs/base/browser/ui/scrollbar/scrollableElementOptions';\nimport { ARROW_IMG_SIZE } from 'vs/base/browser/ui/scrollbar/scrollbarArrow';\nimport { ScrollbarState } from 'vs/base/browser/ui/scrollbar/scrollbarState';\nimport { Codicon } from 'vs/base/common/codicons';\nimport { INewScrollPosition, Scrollable, ScrollbarVisibility, ScrollEvent } from 'vs/base/common/scrollable';\n\n\n\n\nexport class HorizontalScrollbar extends AbstractScrollbar {\n\n\tconstructor(scrollable: Scrollable, options: ScrollableElementResolvedOptions, host: ScrollbarHost) {\n\t\tconst scrollDimensions = scrollable.getScrollDimensions();\n\t\tconst scrollPosition = scrollable.getCurrentScrollPosition();\n\t\tsuper({\n\t\t\tlazyRender: options.lazyRender,\n\t\t\thost: host,\n\t\t\tscrollbarState: new ScrollbarState(\n\t\t\t\t(options.horizontalHasArrows ? options.arrowSize : 0),\n\t\t\t\t(options.horizontal === ScrollbarVisibility.Hidden ? 0 : options.horizontalScrollbarSize),\n\t\t\t\t(options.vertical === ScrollbarVisibility.Hidden ? 0 : options.verticalScrollbarSize),\n\t\t\t\tscrollDimensions.width,\n\t\t\t\tscrollDimensions.scrollWidth,\n\t\t\t\tscrollPosition.scrollLeft\n\t\t\t),\n\t\t\tvisibility: options.horizontal,\n\t\t\textraScrollbarClassName: 'horizontal',\n\t\t\tscrollable: scrollable,\n\t\t\tscrollByPage: options.scrollByPage\n\t\t});\n\n\t\tif (options.horizontalHasArrows) {\n\t\t\tconst arrowDelta = (options.arrowSize - ARROW_IMG_SIZE) / 2;\n\t\t\tconst scrollbarDelta = (options.horizontalScrollbarSize - ARROW_IMG_SIZE) / 2;\n\n\t\t\tthis._createArrow({\n\t\t\t\tclassName: 'scra',\n\t\t\t\ticon: Codicon.scrollbarButtonLeft,\n\t\t\t\ttop: scrollbarDelta,\n\t\t\t\tleft: arrowDelta,\n\t\t\t\tbottom: undefined,\n\t\t\t\tright: undefined,\n\t\t\t\tbgWidth: options.arrowSize,\n\t\t\t\tbgHeight: options.horizontalScrollbarSize,\n\t\t\t\tonActivate: () => this._host.onMouseWheel(new StandardWheelEvent(null, 1, 0)),\n\t\t\t});\n\n\t\t\tthis._createArrow({\n\t\t\t\tclassName: 'scra',\n\t\t\t\ticon: Codicon.scrollbarButtonRight,\n\t\t\t\ttop: scrollbarDelta,\n\t\t\t\tleft: undefined,\n\t\t\t\tbottom: undefined,\n\t\t\t\tright: arrowDelta,\n\t\t\t\tbgWidth: options.arrowSize,\n\t\t\t\tbgHeight: options.horizontalScrollbarSize,\n\t\t\t\tonActivate: () => this._host.onMouseWheel(new StandardWheelEvent(null, -1, 0)),\n\t\t\t});\n\t\t}\n\n\t\tthis._createSlider(Math.floor((options.horizontalScrollbarSize - options.horizontalSliderSize) / 2), 0, undefined, options.horizontalSliderSize);\n\t}\n\n\tprotected _updateSlider(sliderSize: number, sliderPosition: number): void {\n\t\tthis.slider.setWidth(sliderSize);\n\t\tthis.slider.setLeft(sliderPosition);\n\t}\n\n\tprotected _renderDomNode(largeSize: number, smallSize: number): void {\n\t\tthis.domNode.setWidth(largeSize);\n\t\tthis.domNode.setHeight(smallSize);\n\t\tthis.domNode.setLeft(0);\n\t\tthis.domNode.setBottom(0);\n\t}\n\n\tpublic onDidScroll(e: ScrollEvent): boolean {\n\t\tthis._shouldRender = this._onElementScrollSize(e.scrollWidth) || this._shouldRender;\n\t\tthis._shouldRender = this._onElementScrollPosition(e.scrollLeft) || this._shouldRender;\n\t\tthis._shouldRender = this._onElementSize(e.width) || this._shouldRender;\n\t\treturn this._shouldRender;\n\t}\n\n\tprotected _pointerDownRelativePosition(offsetX: number, offsetY: number): number {\n\t\treturn offsetX;\n\t}\n\n\tprotected _sliderPointerPosition(e: ISimplifiedPointerEvent): number {\n\t\treturn e.pageX;\n\t}\n\n\tprotected _sliderOrthogonalPointerPosition(e: ISimplifiedPointerEvent): number {\n\t\treturn e.pageY;\n\t}\n\n\tprotected _updateScrollbarSize(size: number): void {\n\t\tthis.slider.setHeight(size);\n\t}\n\n\tpublic writeScrollPosition(target: INewScrollPosition, scrollPosition: number): void {\n\t\ttarget.scrollLeft = scrollPosition;\n\t}\n\n\tpublic updateOptions(options: ScrollableElementResolvedOptions): void {\n\t\tthis.updateScrollbarSize(options.horizontal === ScrollbarVisibility.Hidden ? 0 : options.horizontalScrollbarSize);\n\t\tthis._scrollbarState.setOppositeScrollbarSize(options.vertical === ScrollbarVisibility.Hidden ? 0 : options.verticalScrollbarSize);\n\t\tthis._visibilityController.setVisibility(options.horizontal);\n\t\tthis._scrollByPage = options.scrollByPage;\n\t}\n}\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\nimport { StandardWheelEvent } from 'vs/base/browser/mouseEvent';\nimport { AbstractScrollbar, ISimplifiedPointerEvent, ScrollbarHost } from 'vs/base/browser/ui/scrollbar/abstractScrollbar';\nimport { ScrollableElementResolvedOptions } from 'vs/base/browser/ui/scrollbar/scrollableElementOptions';\nimport { ARROW_IMG_SIZE } from 'vs/base/browser/ui/scrollbar/scrollbarArrow';\nimport { ScrollbarState } from 'vs/base/browser/ui/scrollbar/scrollbarState';\nimport { Codicon } from 'vs/base/common/codicons';\nimport { INewScrollPosition, Scrollable, ScrollbarVisibility, ScrollEvent } from 'vs/base/common/scrollable';\n\n\n\nexport class VerticalScrollbar extends AbstractScrollbar {\n\n\tconstructor(scrollable: Scrollable, options: ScrollableElementResolvedOptions, host: ScrollbarHost) {\n\t\tconst scrollDimensions = scrollable.getScrollDimensions();\n\t\tconst scrollPosition = scrollable.getCurrentScrollPosition();\n\t\tsuper({\n\t\t\tlazyRender: options.lazyRender,\n\t\t\thost: host,\n\t\t\tscrollbarState: new ScrollbarState(\n\t\t\t\t(options.verticalHasArrows ? options.arrowSize : 0),\n\t\t\t\t(options.vertical === ScrollbarVisibility.Hidden ? 0 : options.verticalScrollbarSize),\n\t\t\t\t// give priority to vertical scroll bar over horizontal and let it scroll all the way to the bottom\n\t\t\t\t0,\n\t\t\t\tscrollDimensions.height,\n\t\t\t\tscrollDimensions.scrollHeight,\n\t\t\t\tscrollPosition.scrollTop\n\t\t\t),\n\t\t\tvisibility: options.vertical,\n\t\t\textraScrollbarClassName: 'vertical',\n\t\t\tscrollable: scrollable,\n\t\t\tscrollByPage: options.scrollByPage\n\t\t});\n\n\t\tif (options.verticalHasArrows) {\n\t\t\tconst arrowDelta = (options.arrowSize - ARROW_IMG_SIZE) / 2;\n\t\t\tconst scrollbarDelta = (options.verticalScrollbarSize - ARROW_IMG_SIZE) / 2;\n\n\t\t\tthis._createArrow({\n\t\t\t\tclassName: 'scra',\n\t\t\t\ticon: Codicon.scrollbarButtonUp,\n\t\t\t\ttop: arrowDelta,\n\t\t\t\tleft: scrollbarDelta,\n\t\t\t\tbottom: undefined,\n\t\t\t\tright: undefined,\n\t\t\t\tbgWidth: options.verticalScrollbarSize,\n\t\t\t\tbgHeight: options.arrowSize,\n\t\t\t\tonActivate: () => this._host.onMouseWheel(new StandardWheelEvent(null, 0, 1)),\n\t\t\t});\n\n\t\t\tthis._createArrow({\n\t\t\t\tclassName: 'scra',\n\t\t\t\ticon: Codicon.scrollbarButtonDown,\n\t\t\t\ttop: undefined,\n\t\t\t\tleft: scrollbarDelta,\n\t\t\t\tbottom: arrowDelta,\n\t\t\t\tright: undefined,\n\t\t\t\tbgWidth: options.verticalScrollbarSize,\n\t\t\t\tbgHeight: options.arrowSize,\n\t\t\t\tonActivate: () => this._host.onMouseWheel(new StandardWheelEvent(null, 0, -1)),\n\t\t\t});\n\t\t}\n\n\t\tthis._createSlider(0, Math.floor((options.verticalScrollbarSize - options.verticalSliderSize) / 2), options.verticalSliderSize, undefined);\n\t}\n\n\tprotected _updateSlider(sliderSize: number, sliderPosition: number): void {\n\t\tthis.slider.setHeight(sliderSize);\n\t\tthis.slider.setTop(sliderPosition);\n\t}\n\n\tprotected _renderDomNode(largeSize: number, smallSize: number): void {\n\t\tthis.domNode.setWidth(smallSize);\n\t\tthis.domNode.setHeight(largeSize);\n\t\tthis.domNode.setRight(0);\n\t\tthis.domNode.setTop(0);\n\t}\n\n\tpublic onDidScroll(e: ScrollEvent): boolean {\n\t\tthis._shouldRender = this._onElementScrollSize(e.scrollHeight) || this._shouldRender;\n\t\tthis._shouldRender = this._onElementScrollPosition(e.scrollTop) || this._shouldRender;\n\t\tthis._shouldRender = this._onElementSize(e.height) || this._shouldRender;\n\t\treturn this._shouldRender;\n\t}\n\n\tprotected _pointerDownRelativePosition(offsetX: number, offsetY: number): number {\n\t\treturn offsetY;\n\t}\n\n\tprotected _sliderPointerPosition(e: ISimplifiedPointerEvent): number {\n\t\treturn e.pageY;\n\t}\n\n\tprotected _sliderOrthogonalPointerPosition(e: ISimplifiedPointerEvent): number {\n\t\treturn e.pageX;\n\t}\n\n\tprotected _updateScrollbarSize(size: number): void {\n\t\tthis.slider.setWidth(size);\n\t}\n\n\tpublic writeScrollPosition(target: INewScrollPosition, scrollPosition: number): void {\n\t\ttarget.scrollTop = scrollPosition;\n\t}\n\n\tpublic updateOptions(options: ScrollableElementResolvedOptions): void {\n\t\tthis.updateScrollbarSize(options.vertical === ScrollbarVisibility.Hidden ? 0 : options.verticalScrollbarSize);\n\t\t// give priority to vertical scroll bar over horizontal and let it scroll all the way to the bottom\n\t\tthis._scrollbarState.setOppositeScrollbarSize(0);\n\t\tthis._visibilityController.setVisibility(options.vertical);\n\t\tthis._scrollByPage = options.scrollByPage;\n\t}\n\n}\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\nimport { getZoomFactor, isChrome } from 'vs/base/browser/browser';\nimport * as dom from 'vs/base/browser/dom';\nimport { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';\nimport { IMouseEvent, IMouseWheelEvent, StandardWheelEvent } from 'vs/base/browser/mouseEvent';\nimport { ScrollbarHost } from 'vs/base/browser/ui/scrollbar/abstractScrollbar';\nimport { HorizontalScrollbar } from 'vs/base/browser/ui/scrollbar/horizontalScrollbar';\nimport { ScrollableElementChangeOptions, ScrollableElementCreationOptions, ScrollableElementResolvedOptions } from 'vs/base/browser/ui/scrollbar/scrollableElementOptions';\nimport { VerticalScrollbar } from 'vs/base/browser/ui/scrollbar/verticalScrollbar';\nimport { Widget } from 'vs/base/browser/ui/widget';\nimport { TimeoutTimer } from 'vs/base/common/async';\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { IDisposable, dispose } from 'vs/base/common/lifecycle';\nimport * as platform from 'vs/base/common/platform';\nimport { INewScrollDimensions, INewScrollPosition, IScrollDimensions, IScrollPosition, ScrollEvent, Scrollable, ScrollbarVisibility } from 'vs/base/common/scrollable';\nimport 'vs/css!./media/scrollbars';\n\nconst HIDE_TIMEOUT = 500;\nconst SCROLL_WHEEL_SENSITIVITY = 50;\nconst SCROLL_WHEEL_SMOOTH_SCROLL_ENABLED = true;\n\nexport interface IOverviewRulerLayoutInfo {\n\tparent: HTMLElement;\n\tinsertBefore: HTMLElement;\n}\n\nclass MouseWheelClassifierItem {\n\tpublic timestamp: number;\n\tpublic deltaX: number;\n\tpublic deltaY: number;\n\tpublic score: number;\n\n\tconstructor(timestamp: number, deltaX: number, deltaY: number) {\n\t\tthis.timestamp = timestamp;\n\t\tthis.deltaX = deltaX;\n\t\tthis.deltaY = deltaY;\n\t\tthis.score = 0;\n\t}\n}\n\nexport class MouseWheelClassifier {\n\n\tpublic static readonly INSTANCE = new MouseWheelClassifier();\n\n\tprivate readonly _capacity: number;\n\tprivate _memory: MouseWheelClassifierItem[];\n\tprivate _front: number;\n\tprivate _rear: number;\n\n\tconstructor() {\n\t\tthis._capacity = 5;\n\t\tthis._memory = [];\n\t\tthis._front = -1;\n\t\tthis._rear = -1;\n\t}\n\n\tpublic isPhysicalMouseWheel(): boolean {\n\t\tif (this._front === -1 && this._rear === -1) {\n\t\t\t// no elements\n\t\t\treturn false;\n\t\t}\n\n\t\t// 0.5 * last + 0.25 * 2nd last + 0.125 * 3rd last + ...\n\t\tlet remainingInfluence = 1;\n\t\tlet score = 0;\n\t\tlet iteration = 1;\n\n\t\tlet index = this._rear;\n\t\tdo {\n\t\t\tconst influence = (index === this._front ? remainingInfluence : Math.pow(2, -iteration));\n\t\t\tremainingInfluence -= influence;\n\t\t\tscore += this._memory[index].score * influence;\n\n\t\t\tif (index === this._front) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tindex = (this._capacity + index - 1) % this._capacity;\n\t\t\titeration++;\n\t\t} while (true);\n\n\t\treturn (score <= 0.5);\n\t}\n\n\tpublic acceptStandardWheelEvent(e: StandardWheelEvent): void {\n\t\tif (isChrome) {\n\t\t\tconst targetWindow = dom.getWindow(e.browserEvent);\n\t\t\tconst pageZoomFactor = getZoomFactor(targetWindow);\n\t\t\t// On Chrome, the incoming delta events are multiplied with the OS zoom factor.\n\t\t\t// The OS zoom factor can be reverse engineered by using the device pixel ratio and the configured zoom factor into account.\n\t\t\tthis.accept(Date.now(), e.deltaX * pageZoomFactor, e.deltaY * pageZoomFactor);\n\t\t} else {\n\t\t\tthis.accept(Date.now(), e.deltaX, e.deltaY);\n\t\t}\n\t}\n\n\tpublic accept(timestamp: number, deltaX: number, deltaY: number): void {\n\t\tlet previousItem = null;\n\t\tconst item = new MouseWheelClassifierItem(timestamp, deltaX, deltaY);\n\n\t\tif (this._front === -1 && this._rear === -1) {\n\t\t\tthis._memory[0] = item;\n\t\t\tthis._front = 0;\n\t\t\tthis._rear = 0;\n\t\t} else {\n\t\t\tpreviousItem = this._memory[this._rear];\n\n\t\t\tthis._rear = (this._rear + 1) % this._capacity;\n\t\t\tif (this._rear === this._front) {\n\t\t\t\t// Drop oldest\n\t\t\t\tthis._front = (this._front + 1) % this._capacity;\n\t\t\t}\n\t\t\tthis._memory[this._rear] = item;\n\t\t}\n\n\t\titem.score = this._computeScore(item, previousItem);\n\t}\n\n\t/**\n\t * A score between 0 and 1 for `item`.\n\t * - a score towards 0 indicates that the source appears to be a physical mouse wheel\n\t * - a score towards 1 indicates that the source appears to be a touchpad or magic mouse, etc.\n\t */\n\tprivate _computeScore(item: MouseWheelClassifierItem, previousItem: MouseWheelClassifierItem | null): number {\n\n\t\tif (Math.abs(item.deltaX) > 0 && Math.abs(item.deltaY) > 0) {\n\t\t\t// both axes exercised => definitely not a physical mouse wheel\n\t\t\treturn 1;\n\t\t}\n\n\t\tlet score: number = 0.5;\n\n\t\tif (!this._isAlmostInt(item.deltaX) || !this._isAlmostInt(item.deltaY)) {\n\t\t\t// non-integer deltas => indicator that this is not a physical mouse wheel\n\t\t\tscore += 0.25;\n\t\t}\n\n\t\t// Non-accelerating scroll => indicator that this is a physical mouse wheel\n\t\t// These can be identified by seeing whether they are the module of one another.\n\t\tif (previousItem) {\n\t\t\tconst absDeltaX = Math.abs(item.deltaX);\n\t\t\tconst absDeltaY = Math.abs(item.deltaY);\n\n\t\t\tconst absPreviousDeltaX = Math.abs(previousItem.deltaX);\n\t\t\tconst absPreviousDeltaY = Math.abs(previousItem.deltaY);\n\n\t\t\t// Min 1 to avoid division by zero, module 1 will still be 0.\n\t\t\tconst minDeltaX = Math.max(Math.min(absDeltaX, absPreviousDeltaX), 1);\n\t\t\tconst minDeltaY = Math.max(Math.min(absDeltaY, absPreviousDeltaY), 1);\n\n\t\t\tconst maxDeltaX = Math.max(absDeltaX, absPreviousDeltaX);\n\t\t\tconst maxDeltaY = Math.max(absDeltaY, absPreviousDeltaY);\n\n\t\t\tconst isSameModulo = (maxDeltaX % minDeltaX === 0 && maxDeltaY % minDeltaY === 0);\n\t\t\tif (isSameModulo) {\n\t\t\t\tscore -= 0.5;\n\t\t\t}\n\t\t}\n\n\t\treturn Math.min(Math.max(score, 0), 1);\n\t}\n\n\tprivate _isAlmostInt(value: number): boolean {\n\t\tconst delta = Math.abs(Math.round(value) - value);\n\t\treturn (delta < 0.01);\n\t}\n}\n\nexport abstract class AbstractScrollableElement extends Widget {\n\n\tprivate readonly _options: ScrollableElementResolvedOptions;\n\tprotected readonly _scrollable: Scrollable;\n\tprivate readonly _verticalScrollbar: VerticalScrollbar;\n\tprivate readonly _horizontalScrollbar: HorizontalScrollbar;\n\tprivate readonly _domNode: HTMLElement;\n\n\tprivate readonly _leftShadowDomNode: FastDomNode | null;\n\tprivate readonly _topShadowDomNode: FastDomNode | null;\n\tprivate readonly _topLeftShadowDomNode: FastDomNode | null;\n\n\tprivate readonly _listenOnDomNode: HTMLElement;\n\n\tprivate _mouseWheelToDispose: IDisposable[];\n\n\tprivate _isDragging: boolean;\n\tprivate _mouseIsOver: boolean;\n\n\tprivate readonly _hideTimeout: TimeoutTimer;\n\tprivate _shouldRender: boolean;\n\n\tprivate _revealOnScroll: boolean;\n\n\tprivate readonly _onScroll = this._register(new Emitter());\n\tpublic readonly onScroll: Event = this._onScroll.event;\n\n\tprivate readonly _onWillScroll = this._register(new Emitter());\n\n\tpublic get options(): Readonly {\n\t\treturn this._options;\n\t}\n\n\tprotected constructor(element: HTMLElement, options: ScrollableElementCreationOptions, scrollable: Scrollable) {\n\t\tsuper();\n\t\telement.style.overflow = 'hidden';\n\t\tthis._options = resolveOptions(options);\n\t\tthis._scrollable = scrollable;\n\n\t\tthis._register(this._scrollable.onScroll((e) => {\n\t\t\tthis._onWillScroll.fire(e);\n\t\t\tthis._onDidScroll(e);\n\t\t\tthis._onScroll.fire(e);\n\t\t}));\n\n\t\tconst scrollbarHost: ScrollbarHost = {\n\t\t\tonMouseWheel: (mouseWheelEvent: StandardWheelEvent) => this._onMouseWheel(mouseWheelEvent),\n\t\t\tonDragStart: () => this._onDragStart(),\n\t\t\tonDragEnd: () => this._onDragEnd(),\n\t\t};\n\t\tthis._verticalScrollbar = this._register(new VerticalScrollbar(this._scrollable, this._options, scrollbarHost));\n\t\tthis._horizontalScrollbar = this._register(new HorizontalScrollbar(this._scrollable, this._options, scrollbarHost));\n\n\t\tthis._domNode = document.createElement('div');\n\t\tthis._domNode.className = 'monaco-scrollable-element ' + this._options.className;\n\t\tthis._domNode.setAttribute('role', 'presentation');\n\t\tthis._domNode.style.position = 'relative';\n\t\tthis._domNode.style.overflow = 'hidden';\n\t\tthis._domNode.appendChild(element);\n\t\tthis._domNode.appendChild(this._horizontalScrollbar.domNode.domNode);\n\t\tthis._domNode.appendChild(this._verticalScrollbar.domNode.domNode);\n\n\t\tif (this._options.useShadows) {\n\t\t\tthis._leftShadowDomNode = createFastDomNode(document.createElement('div'));\n\t\t\tthis._leftShadowDomNode.setClassName('shadow');\n\t\t\tthis._domNode.appendChild(this._leftShadowDomNode.domNode);\n\n\t\t\tthis._topShadowDomNode = createFastDomNode(document.createElement('div'));\n\t\t\tthis._topShadowDomNode.setClassName('shadow');\n\t\t\tthis._domNode.appendChild(this._topShadowDomNode.domNode);\n\n\t\t\tthis._topLeftShadowDomNode = createFastDomNode(document.createElement('div'));\n\t\t\tthis._topLeftShadowDomNode.setClassName('shadow');\n\t\t\tthis._domNode.appendChild(this._topLeftShadowDomNode.domNode);\n\t\t} else {\n\t\t\tthis._leftShadowDomNode = null;\n\t\t\tthis._topShadowDomNode = null;\n\t\t\tthis._topLeftShadowDomNode = null;\n\t\t}\n\n\t\tthis._listenOnDomNode = this._options.listenOnDomNode || this._domNode;\n\n\t\tthis._mouseWheelToDispose = [];\n\t\tthis._setListeningToMouseWheel(this._options.handleMouseWheel);\n\n\t\tthis.onmouseover(this._listenOnDomNode, (e) => this._onMouseOver(e));\n\t\tthis.onmouseleave(this._listenOnDomNode, (e) => this._onMouseLeave(e));\n\n\t\tthis._hideTimeout = this._register(new TimeoutTimer());\n\t\tthis._isDragging = false;\n\t\tthis._mouseIsOver = false;\n\n\t\tthis._shouldRender = true;\n\n\t\tthis._revealOnScroll = true;\n\t}\n\n\tpublic override dispose(): void {\n\t\tthis._mouseWheelToDispose = dispose(this._mouseWheelToDispose);\n\t\tsuper.dispose();\n\t}\n\n\t/**\n\t * Get the generated 'scrollable' dom node\n\t */\n\tpublic getDomNode(): HTMLElement {\n\t\treturn this._domNode;\n\t}\n\n\tpublic getOverviewRulerLayoutInfo(): IOverviewRulerLayoutInfo {\n\t\treturn {\n\t\t\tparent: this._domNode,\n\t\t\tinsertBefore: this._verticalScrollbar.domNode.domNode,\n\t\t};\n\t}\n\n\t/**\n\t * Delegate a pointer down event to the vertical scrollbar.\n\t * This is to help with clicking somewhere else and having the scrollbar react.\n\t */\n\tpublic delegateVerticalScrollbarPointerDown(browserEvent: PointerEvent): void {\n\t\tthis._verticalScrollbar.delegatePointerDown(browserEvent);\n\t}\n\n\tpublic getScrollDimensions(): IScrollDimensions {\n\t\treturn this._scrollable.getScrollDimensions();\n\t}\n\n\tpublic setScrollDimensions(dimensions: INewScrollDimensions): void {\n\t\tthis._scrollable.setScrollDimensions(dimensions, false);\n\t}\n\n\t/**\n\t * Update the class name of the scrollable element.\n\t */\n\tpublic updateClassName(newClassName: string): void {\n\t\tthis._options.className = newClassName;\n\t\t// Defaults are different on Macs\n\t\tif (platform.isMacintosh) {\n\t\t\tthis._options.className += ' mac';\n\t\t}\n\t\tthis._domNode.className = 'monaco-scrollable-element ' + this._options.className;\n\t}\n\n\t/**\n\t * Update configuration options for the scrollbar.\n\t */\n\tpublic updateOptions(newOptions: ScrollableElementChangeOptions): void {\n\t\tif (typeof newOptions.handleMouseWheel !== 'undefined') {\n\t\t\tthis._options.handleMouseWheel = newOptions.handleMouseWheel;\n\t\t\tthis._setListeningToMouseWheel(this._options.handleMouseWheel);\n\t\t}\n\t\tif (typeof newOptions.mouseWheelScrollSensitivity !== 'undefined') {\n\t\t\tthis._options.mouseWheelScrollSensitivity = newOptions.mouseWheelScrollSensitivity;\n\t\t}\n\t\tif (typeof newOptions.fastScrollSensitivity !== 'undefined') {\n\t\t\tthis._options.fastScrollSensitivity = newOptions.fastScrollSensitivity;\n\t\t}\n\t\tif (typeof newOptions.scrollPredominantAxis !== 'undefined') {\n\t\t\tthis._options.scrollPredominantAxis = newOptions.scrollPredominantAxis;\n\t\t}\n\t\tif (typeof newOptions.horizontal !== 'undefined') {\n\t\t\tthis._options.horizontal = newOptions.horizontal;\n\t\t}\n\t\tif (typeof newOptions.vertical !== 'undefined') {\n\t\t\tthis._options.vertical = newOptions.vertical;\n\t\t}\n\t\tif (typeof newOptions.horizontalScrollbarSize !== 'undefined') {\n\t\t\tthis._options.horizontalScrollbarSize = newOptions.horizontalScrollbarSize;\n\t\t}\n\t\tif (typeof newOptions.verticalScrollbarSize !== 'undefined') {\n\t\t\tthis._options.verticalScrollbarSize = newOptions.verticalScrollbarSize;\n\t\t}\n\t\tif (typeof newOptions.scrollByPage !== 'undefined') {\n\t\t\tthis._options.scrollByPage = newOptions.scrollByPage;\n\t\t}\n\t\tthis._horizontalScrollbar.updateOptions(this._options);\n\t\tthis._verticalScrollbar.updateOptions(this._options);\n\n\t\tif (!this._options.lazyRender) {\n\t\t\tthis._render();\n\t\t}\n\t}\n\n\tpublic delegateScrollFromMouseWheelEvent(browserEvent: IMouseWheelEvent) {\n\t\tthis._onMouseWheel(new StandardWheelEvent(browserEvent));\n\t}\n\n\t// -------------------- mouse wheel scrolling --------------------\n\n\tprivate _setListeningToMouseWheel(shouldListen: boolean): void {\n\t\tconst isListening = (this._mouseWheelToDispose.length > 0);\n\n\t\tif (isListening === shouldListen) {\n\t\t\t// No change\n\t\t\treturn;\n\t\t}\n\n\t\t// Stop listening (if necessary)\n\t\tthis._mouseWheelToDispose = dispose(this._mouseWheelToDispose);\n\n\t\t// Start listening (if necessary)\n\t\tif (shouldListen) {\n\t\t\tconst onMouseWheel = (browserEvent: IMouseWheelEvent) => {\n\t\t\t\tthis._onMouseWheel(new StandardWheelEvent(browserEvent));\n\t\t\t};\n\n\t\t\tthis._mouseWheelToDispose.push(dom.addDisposableListener(this._listenOnDomNode, dom.EventType.MOUSE_WHEEL, onMouseWheel, { passive: false }));\n\t\t}\n\t}\n\n\tprivate _onMouseWheel(e: StandardWheelEvent): void {\n\t\tif (e.browserEvent?.defaultPrevented) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst classifier = MouseWheelClassifier.INSTANCE;\n\t\tif (SCROLL_WHEEL_SMOOTH_SCROLL_ENABLED) {\n\t\t\tclassifier.acceptStandardWheelEvent(e);\n\t\t}\n\n\t\t// useful for creating unit tests:\n\t\t// console.log(`${Date.now()}, ${e.deltaY}, ${e.deltaX}`);\n\n\t\tlet didScroll = false;\n\n\t\tif (e.deltaY || e.deltaX) {\n\t\t\tlet deltaY = e.deltaY * this._options.mouseWheelScrollSensitivity;\n\t\t\tlet deltaX = e.deltaX * this._options.mouseWheelScrollSensitivity;\n\n\t\t\tif (this._options.scrollPredominantAxis) {\n\t\t\t\tif (this._options.scrollYToX && deltaX + deltaY === 0) {\n\t\t\t\t\t// when configured to map Y to X and we both see\n\t\t\t\t\t// no dominant axis and X and Y are competing with\n\t\t\t\t\t// identical values into opposite directions, we\n\t\t\t\t\t// ignore the delta as we cannot make a decision then\n\t\t\t\t\tdeltaX = deltaY = 0;\n\t\t\t\t} else if (Math.abs(deltaY) >= Math.abs(deltaX)) {\n\t\t\t\t\tdeltaX = 0;\n\t\t\t\t} else {\n\t\t\t\t\tdeltaY = 0;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (this._options.flipAxes) {\n\t\t\t\t[deltaY, deltaX] = [deltaX, deltaY];\n\t\t\t}\n\n\t\t\t// Convert vertical scrolling to horizontal if shift is held, this\n\t\t\t// is handled at a higher level on Mac\n\t\t\tconst shiftConvert = !platform.isMacintosh && e.browserEvent && e.browserEvent.shiftKey;\n\t\t\tif ((this._options.scrollYToX || shiftConvert) && !deltaX) {\n\t\t\t\tdeltaX = deltaY;\n\t\t\t\tdeltaY = 0;\n\t\t\t}\n\n\t\t\tif (e.browserEvent && e.browserEvent.altKey) {\n\t\t\t\t// fastScrolling\n\t\t\t\tdeltaX = deltaX * this._options.fastScrollSensitivity;\n\t\t\t\tdeltaY = deltaY * this._options.fastScrollSensitivity;\n\t\t\t}\n\n\t\t\tconst futureScrollPosition = this._scrollable.getFutureScrollPosition();\n\n\t\t\tlet desiredScrollPosition: INewScrollPosition = {};\n\t\t\tif (deltaY) {\n\t\t\t\tconst deltaScrollTop = SCROLL_WHEEL_SENSITIVITY * deltaY;\n\t\t\t\t// Here we convert values such as -0.3 to -1 or 0.3 to 1, otherwise low speed scrolling will never scroll\n\t\t\t\tconst desiredScrollTop = futureScrollPosition.scrollTop - (deltaScrollTop < 0 ? Math.floor(deltaScrollTop) : Math.ceil(deltaScrollTop));\n\t\t\t\tthis._verticalScrollbar.writeScrollPosition(desiredScrollPosition, desiredScrollTop);\n\t\t\t}\n\t\t\tif (deltaX) {\n\t\t\t\tconst deltaScrollLeft = SCROLL_WHEEL_SENSITIVITY * deltaX;\n\t\t\t\t// Here we convert values such as -0.3 to -1 or 0.3 to 1, otherwise low speed scrolling will never scroll\n\t\t\t\tconst desiredScrollLeft = futureScrollPosition.scrollLeft - (deltaScrollLeft < 0 ? Math.floor(deltaScrollLeft) : Math.ceil(deltaScrollLeft));\n\t\t\t\tthis._horizontalScrollbar.writeScrollPosition(desiredScrollPosition, desiredScrollLeft);\n\t\t\t}\n\n\t\t\t// Check that we are scrolling towards a location which is valid\n\t\t\tdesiredScrollPosition = this._scrollable.validateScrollPosition(desiredScrollPosition);\n\n\t\t\tif (futureScrollPosition.scrollLeft !== desiredScrollPosition.scrollLeft || futureScrollPosition.scrollTop !== desiredScrollPosition.scrollTop) {\n\n\t\t\t\tconst canPerformSmoothScroll = (\n\t\t\t\t\tSCROLL_WHEEL_SMOOTH_SCROLL_ENABLED\n\t\t\t\t\t&& this._options.mouseWheelSmoothScroll\n\t\t\t\t\t&& classifier.isPhysicalMouseWheel()\n\t\t\t\t);\n\n\t\t\t\tif (canPerformSmoothScroll) {\n\t\t\t\t\tthis._scrollable.setScrollPositionSmooth(desiredScrollPosition);\n\t\t\t\t} else {\n\t\t\t\t\tthis._scrollable.setScrollPositionNow(desiredScrollPosition);\n\t\t\t\t}\n\n\t\t\t\tdidScroll = true;\n\t\t\t}\n\t\t}\n\n\t\tlet consumeMouseWheel = didScroll;\n\t\tif (!consumeMouseWheel && this._options.alwaysConsumeMouseWheel) {\n\t\t\tconsumeMouseWheel = true;\n\t\t}\n\t\tif (!consumeMouseWheel && this._options.consumeMouseWheelIfScrollbarIsNeeded && (this._verticalScrollbar.isNeeded() || this._horizontalScrollbar.isNeeded())) {\n\t\t\tconsumeMouseWheel = true;\n\t\t}\n\n\t\tif (consumeMouseWheel) {\n\t\t\te.preventDefault();\n\t\t\te.stopPropagation();\n\t\t}\n\t}\n\n\tprivate _onDidScroll(e: ScrollEvent): void {\n\t\tthis._shouldRender = this._horizontalScrollbar.onDidScroll(e) || this._shouldRender;\n\t\tthis._shouldRender = this._verticalScrollbar.onDidScroll(e) || this._shouldRender;\n\n\t\tif (this._options.useShadows) {\n\t\t\tthis._shouldRender = true;\n\t\t}\n\n\t\tif (this._revealOnScroll) {\n\t\t\tthis._reveal();\n\t\t}\n\n\t\tif (!this._options.lazyRender) {\n\t\t\tthis._render();\n\t\t}\n\t}\n\n\t/**\n\t * Render / mutate the DOM now.\n\t * Should be used together with the ctor option `lazyRender`.\n\t */\n\tpublic renderNow(): void {\n\t\tif (!this._options.lazyRender) {\n\t\t\tthrow new Error('Please use `lazyRender` together with `renderNow`!');\n\t\t}\n\n\t\tthis._render();\n\t}\n\n\tprivate _render(): void {\n\t\tif (!this._shouldRender) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._shouldRender = false;\n\n\t\tthis._horizontalScrollbar.render();\n\t\tthis._verticalScrollbar.render();\n\n\t\tif (this._options.useShadows) {\n\t\t\tconst scrollState = this._scrollable.getCurrentScrollPosition();\n\t\t\tconst enableTop = scrollState.scrollTop > 0;\n\t\t\tconst enableLeft = scrollState.scrollLeft > 0;\n\n\t\t\tconst leftClassName = (enableLeft ? ' left' : '');\n\t\t\tconst topClassName = (enableTop ? ' top' : '');\n\t\t\tconst topLeftClassName = (enableLeft || enableTop ? ' top-left-corner' : '');\n\t\t\tthis._leftShadowDomNode!.setClassName(`shadow${leftClassName}`);\n\t\t\tthis._topShadowDomNode!.setClassName(`shadow${topClassName}`);\n\t\t\tthis._topLeftShadowDomNode!.setClassName(`shadow${topLeftClassName}${topClassName}${leftClassName}`);\n\t\t}\n\t}\n\n\t// -------------------- fade in / fade out --------------------\n\n\tprivate _onDragStart(): void {\n\t\tthis._isDragging = true;\n\t\tthis._reveal();\n\t}\n\n\tprivate _onDragEnd(): void {\n\t\tthis._isDragging = false;\n\t\tthis._hide();\n\t}\n\n\tprivate _onMouseLeave(e: IMouseEvent): void {\n\t\tthis._mouseIsOver = false;\n\t\tthis._hide();\n\t}\n\n\tprivate _onMouseOver(e: IMouseEvent): void {\n\t\tthis._mouseIsOver = true;\n\t\tthis._reveal();\n\t}\n\n\tprivate _reveal(): void {\n\t\tthis._verticalScrollbar.beginReveal();\n\t\tthis._horizontalScrollbar.beginReveal();\n\t\tthis._scheduleHide();\n\t}\n\n\tprivate _hide(): void {\n\t\tif (!this._mouseIsOver && !this._isDragging) {\n\t\t\tthis._verticalScrollbar.beginHide();\n\t\t\tthis._horizontalScrollbar.beginHide();\n\t\t}\n\t}\n\n\tprivate _scheduleHide(): void {\n\t\tif (!this._mouseIsOver && !this._isDragging) {\n\t\t\tthis._hideTimeout.cancelAndSet(() => this._hide(), HIDE_TIMEOUT);\n\t\t}\n\t}\n}\n\nexport class ScrollableElement extends AbstractScrollableElement {\n\n\tconstructor(element: HTMLElement, options: ScrollableElementCreationOptions) {\n\t\toptions = options || {};\n\t\toptions.mouseWheelSmoothScroll = false;\n\t\tconst scrollable = new Scrollable({\n\t\t\tforceIntegerValues: true,\n\t\t\tsmoothScrollDuration: 0,\n\t\t\tscheduleAtNextAnimationFrame: (callback) => dom.scheduleAtNextAnimationFrame(dom.getWindow(element), callback)\n\t\t});\n\t\tsuper(element, options, scrollable);\n\t\tthis._register(scrollable);\n\t}\n\n\tpublic setScrollPosition(update: INewScrollPosition): void {\n\t\tthis._scrollable.setScrollPositionNow(update);\n\t}\n}\n\nexport class SmoothScrollableElement extends AbstractScrollableElement {\n\n\tconstructor(element: HTMLElement, options: ScrollableElementCreationOptions, scrollable: Scrollable) {\n\t\tsuper(element, options, scrollable);\n\t}\n\n\tpublic setScrollPosition(update: INewScrollPosition & { reuseAnimation?: boolean }): void {\n\t\tif (update.reuseAnimation) {\n\t\t\tthis._scrollable.setScrollPositionSmooth(update, update.reuseAnimation);\n\t\t} else {\n\t\t\tthis._scrollable.setScrollPositionNow(update);\n\t\t}\n\t}\n\n\tpublic getScrollPosition(): IScrollPosition {\n\t\treturn this._scrollable.getCurrentScrollPosition();\n\t}\n\n}\n\nexport class DomScrollableElement extends AbstractScrollableElement {\n\n\tprivate _element: HTMLElement;\n\n\tconstructor(element: HTMLElement, options: ScrollableElementCreationOptions) {\n\t\toptions = options || {};\n\t\toptions.mouseWheelSmoothScroll = false;\n\t\tconst scrollable = new Scrollable({\n\t\t\tforceIntegerValues: false, // See https://github.com/microsoft/vscode/issues/139877\n\t\t\tsmoothScrollDuration: 0,\n\t\t\tscheduleAtNextAnimationFrame: (callback) => dom.scheduleAtNextAnimationFrame(dom.getWindow(element), callback)\n\t\t});\n\t\tsuper(element, options, scrollable);\n\t\tthis._register(scrollable);\n\t\tthis._element = element;\n\t\tthis._register(this.onScroll((e) => {\n\t\t\tif (e.scrollTopChanged) {\n\t\t\t\tthis._element.scrollTop = e.scrollTop;\n\t\t\t}\n\t\t\tif (e.scrollLeftChanged) {\n\t\t\t\tthis._element.scrollLeft = e.scrollLeft;\n\t\t\t}\n\t\t}));\n\t\tthis.scanDomNode();\n\t}\n\n\tpublic setScrollPosition(update: INewScrollPosition): void {\n\t\tthis._scrollable.setScrollPositionNow(update);\n\t}\n\n\tpublic getScrollPosition(): IScrollPosition {\n\t\treturn this._scrollable.getCurrentScrollPosition();\n\t}\n\n\tpublic scanDomNode(): void {\n\t\t// width, scrollLeft, scrollWidth, height, scrollTop, scrollHeight\n\t\tthis.setScrollDimensions({\n\t\t\twidth: this._element.clientWidth,\n\t\t\tscrollWidth: this._element.scrollWidth,\n\t\t\theight: this._element.clientHeight,\n\t\t\tscrollHeight: this._element.scrollHeight\n\t\t});\n\t\tthis.setScrollPosition({\n\t\t\tscrollLeft: this._element.scrollLeft,\n\t\t\tscrollTop: this._element.scrollTop,\n\t\t});\n\t}\n}\n\nfunction resolveOptions(opts: ScrollableElementCreationOptions): ScrollableElementResolvedOptions {\n\tconst result: ScrollableElementResolvedOptions = {\n\t\tlazyRender: (typeof opts.lazyRender !== 'undefined' ? opts.lazyRender : false),\n\t\tclassName: (typeof opts.className !== 'undefined' ? opts.className : ''),\n\t\tuseShadows: (typeof opts.useShadows !== 'undefined' ? opts.useShadows : true),\n\t\thandleMouseWheel: (typeof opts.handleMouseWheel !== 'undefined' ? opts.handleMouseWheel : true),\n\t\tflipAxes: (typeof opts.flipAxes !== 'undefined' ? opts.flipAxes : false),\n\t\tconsumeMouseWheelIfScrollbarIsNeeded: (typeof opts.consumeMouseWheelIfScrollbarIsNeeded !== 'undefined' ? opts.consumeMouseWheelIfScrollbarIsNeeded : false),\n\t\talwaysConsumeMouseWheel: (typeof opts.alwaysConsumeMouseWheel !== 'undefined' ? opts.alwaysConsumeMouseWheel : false),\n\t\tscrollYToX: (typeof opts.scrollYToX !== 'undefined' ? opts.scrollYToX : false),\n\t\tmouseWheelScrollSensitivity: (typeof opts.mouseWheelScrollSensitivity !== 'undefined' ? opts.mouseWheelScrollSensitivity : 1),\n\t\tfastScrollSensitivity: (typeof opts.fastScrollSensitivity !== 'undefined' ? opts.fastScrollSensitivity : 5),\n\t\tscrollPredominantAxis: (typeof opts.scrollPredominantAxis !== 'undefined' ? opts.scrollPredominantAxis : true),\n\t\tmouseWheelSmoothScroll: (typeof opts.mouseWheelSmoothScroll !== 'undefined' ? opts.mouseWheelSmoothScroll : true),\n\t\tarrowSize: (typeof opts.arrowSize !== 'undefined' ? opts.arrowSize : 11),\n\n\t\tlistenOnDomNode: (typeof opts.listenOnDomNode !== 'undefined' ? opts.listenOnDomNode : null),\n\n\t\thorizontal: (typeof opts.horizontal !== 'undefined' ? opts.horizontal : ScrollbarVisibility.Auto),\n\t\thorizontalScrollbarSize: (typeof opts.horizontalScrollbarSize !== 'undefined' ? opts.horizontalScrollbarSize : 10),\n\t\thorizontalSliderSize: (typeof opts.horizontalSliderSize !== 'undefined' ? opts.horizontalSliderSize : 0),\n\t\thorizontalHasArrows: (typeof opts.horizontalHasArrows !== 'undefined' ? opts.horizontalHasArrows : false),\n\n\t\tvertical: (typeof opts.vertical !== 'undefined' ? opts.vertical : ScrollbarVisibility.Auto),\n\t\tverticalScrollbarSize: (typeof opts.verticalScrollbarSize !== 'undefined' ? opts.verticalScrollbarSize : 10),\n\t\tverticalHasArrows: (typeof opts.verticalHasArrows !== 'undefined' ? opts.verticalHasArrows : false),\n\t\tverticalSliderSize: (typeof opts.verticalSliderSize !== 'undefined' ? opts.verticalSliderSize : 0),\n\n\t\tscrollByPage: (typeof opts.scrollByPage !== 'undefined' ? opts.scrollByPage : false)\n\t};\n\n\tresult.horizontalSliderSize = (typeof opts.horizontalSliderSize !== 'undefined' ? opts.horizontalSliderSize : result.horizontalScrollbarSize);\n\tresult.verticalSliderSize = (typeof opts.verticalSliderSize !== 'undefined' ? opts.verticalSliderSize : result.verticalScrollbarSize);\n\n\t// Defaults are different on Macs\n\tif (platform.isMacintosh) {\n\t\tresult.className += ' mac';\n\t}\n\n\treturn result;\n}\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\nimport * as dom from 'vs/base/browser/dom';\nimport { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';\nimport { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';\nimport { KeyCode } from 'vs/base/common/keyCodes';\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport 'vs/css!./hoverWidget';\nimport { localize } from 'vs/nls';\n\nconst $ = dom.$;\n\nexport const enum HoverPosition {\n\tLEFT, RIGHT, BELOW, ABOVE\n}\n\nexport class HoverWidget extends Disposable {\n\n\tpublic readonly containerDomNode: HTMLElement;\n\tpublic readonly contentsDomNode: HTMLElement;\n\tpublic readonly scrollbar: DomScrollableElement;\n\n\tconstructor() {\n\t\tsuper();\n\n\t\tthis.containerDomNode = document.createElement('div');\n\t\tthis.containerDomNode.className = 'monaco-hover';\n\t\tthis.containerDomNode.tabIndex = 0;\n\t\tthis.containerDomNode.setAttribute('role', 'tooltip');\n\n\t\tthis.contentsDomNode = document.createElement('div');\n\t\tthis.contentsDomNode.className = 'monaco-hover-content';\n\n\t\tthis.scrollbar = this._register(new DomScrollableElement(this.contentsDomNode, {\n\t\t\tconsumeMouseWheelIfScrollbarIsNeeded: true\n\t\t}));\n\t\tthis.containerDomNode.appendChild(this.scrollbar.getDomNode());\n\t}\n\n\tpublic onContentsChanged(): void {\n\t\tthis.scrollbar.scanDomNode();\n\t}\n}\n\nexport class HoverAction extends Disposable {\n\tpublic static render(parent: HTMLElement, actionOptions: { label: string; iconClass?: string; run: (target: HTMLElement) => void; commandId: string }, keybindingLabel: string | null) {\n\t\treturn new HoverAction(parent, actionOptions, keybindingLabel);\n\t}\n\n\tprivate readonly actionContainer: HTMLElement;\n\tprivate readonly action: HTMLElement;\n\n\tprivate constructor(parent: HTMLElement, actionOptions: { label: string; iconClass?: string; run: (target: HTMLElement) => void; commandId: string }, keybindingLabel: string | null) {\n\t\tsuper();\n\n\t\tthis.actionContainer = dom.append(parent, $('div.action-container'));\n\t\tthis.actionContainer.setAttribute('tabindex', '0');\n\n\t\tthis.action = dom.append(this.actionContainer, $('a.action'));\n\t\tthis.action.setAttribute('role', 'button');\n\t\tif (actionOptions.iconClass) {\n\t\t\tdom.append(this.action, $(`span.icon.${actionOptions.iconClass}`));\n\t\t}\n\t\tconst label = dom.append(this.action, $('span'));\n\t\tlabel.textContent = keybindingLabel ? `${actionOptions.label} (${keybindingLabel})` : actionOptions.label;\n\n\t\tthis._store.add(new ClickAction(this.actionContainer, actionOptions.run));\n\t\tthis._store.add(new KeyDownAction(this.actionContainer, actionOptions.run, [KeyCode.Enter, KeyCode.Space]));\n\t\tthis.setEnabled(true);\n\t}\n\n\tpublic setEnabled(enabled: boolean): void {\n\t\tif (enabled) {\n\t\t\tthis.actionContainer.classList.remove('disabled');\n\t\t\tthis.actionContainer.removeAttribute('aria-disabled');\n\t\t} else {\n\t\t\tthis.actionContainer.classList.add('disabled');\n\t\t\tthis.actionContainer.setAttribute('aria-disabled', 'true');\n\t\t}\n\t}\n}\n\nexport function getHoverAccessibleViewHint(shouldHaveHint?: boolean, keybinding?: string | null): string | undefined {\n\treturn shouldHaveHint && keybinding ? localize('acessibleViewHint', \"Inspect this in the accessible view with {0}.\", keybinding) : shouldHaveHint ? localize('acessibleViewHintNoKbOpen', \"Inspect this in the accessible view via the command Open Accessible View which is currently not triggerable via keybinding.\") : '';\n}\n\nexport class ClickAction extends Disposable {\n\tconstructor(container: HTMLElement, run: (container: HTMLElement) => void) {\n\t\tsuper();\n\t\tthis._register(dom.addDisposableListener(container, dom.EventType.CLICK, e => {\n\t\t\te.stopPropagation();\n\t\t\te.preventDefault();\n\t\t\trun(container);\n\t\t}));\n\t}\n}\n\nexport class KeyDownAction extends Disposable {\n\tconstructor(container: HTMLElement, run: (container: HTMLElement) => void, keyCodes: KeyCode[]) {\n\t\tsuper();\n\t\tthis._register(dom.addDisposableListener(container, dom.EventType.KEY_DOWN, e => {\n\t\t\tconst event = new StandardKeyboardEvent(e);\n\t\t\tif (keyCodes.some(keyCode => event.equals(keyCode))) {\n\t\t\t\te.stopPropagation();\n\t\t\t\te.preventDefault();\n\t\t\t\trun(container);\n\t\t\t}\n\t\t}));\n\t}\n}\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\nimport { DataTransfers, IDragAndDropData } from 'vs/base/browser/dnd';\nimport { $, addDisposableListener, animate, Dimension, getContentHeight, getContentWidth, getTopLeftOffset, getWindow, isAncestor, scheduleAtNextAnimationFrame } from 'vs/base/browser/dom';\nimport { DomEmitter } from 'vs/base/browser/event';\nimport { EventType as TouchEventType, Gesture, GestureEvent } from 'vs/base/browser/touch';\nimport { SmoothScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';\nimport { distinct, equals } from 'vs/base/common/arrays';\nimport { Delayer, disposableTimeout } from 'vs/base/common/async';\nimport { memoize } from 'vs/base/common/decorators';\nimport { Emitter, Event, IValueWithChangeEvent } from 'vs/base/common/event';\nimport { Disposable, DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle';\nimport { IRange, Range } from 'vs/base/common/range';\nimport { INewScrollDimensions, Scrollable, ScrollbarVisibility, ScrollEvent } from 'vs/base/common/scrollable';\nimport { ISpliceable } from 'vs/base/common/sequence';\nimport { IListDragAndDrop, IListDragEvent, IListGestureEvent, IListMouseEvent, IListRenderer, IListTouchEvent, IListVirtualDelegate, ListDragOverEffectPosition, ListDragOverEffectType } from 'vs/base/browser/ui/list/list';\nimport { IRangeMap, RangeMap, shift } from 'vs/base/browser/ui/list/rangeMap';\nimport { IRow, RowCache } from 'vs/base/browser/ui/list/rowCache';\nimport { BugIndicatingError } from 'vs/base/common/errors';\nimport { AriaRole } from 'vs/base/browser/ui/aria/aria';\nimport { ScrollableElementChangeOptions } from 'vs/base/browser/ui/scrollbar/scrollableElementOptions';\nimport { clamp } from 'vs/base/common/numbers';\n\ninterface IItem {\n\treadonly id: string;\n\treadonly element: T;\n\treadonly templateId: string;\n\trow: IRow | null;\n\tsize: number;\n\twidth: number | undefined;\n\thasDynamicHeight: boolean;\n\tlastDynamicHeightWidth: number | undefined;\n\turi: string | undefined;\n\tdropTarget: boolean;\n\tdragStartDisposable: IDisposable;\n\tcheckedDisposable: IDisposable;\n\tstale: boolean;\n}\n\nconst StaticDND = {\n\tCurrentDragAndDropData: undefined as IDragAndDropData | undefined\n};\n\nexport interface IListViewDragAndDrop extends IListDragAndDrop {\n\tgetDragElements(element: T): T[];\n}\n\nexport const enum ListViewTargetSector {\n\t// drop position relative to the top of the item\n\tTOP = 0, \t\t\t\t// [0%-25%)\n\tCENTER_TOP = 1, \t\t// [25%-50%)\n\tCENTER_BOTTOM = 2, \t\t// [50%-75%)\n\tBOTTOM = 3\t\t\t\t// [75%-100%)\n}\n\nexport interface IListViewAccessibilityProvider {\n\tgetSetSize?(element: T, index: number, listLength: number): number;\n\tgetPosInSet?(element: T, index: number): number;\n\tgetRole?(element: T): AriaRole | undefined;\n\tisChecked?(element: T): boolean | IValueWithChangeEvent | undefined;\n}\n\nexport interface IListViewOptionsUpdate {\n\treadonly smoothScrolling?: boolean;\n\treadonly horizontalScrolling?: boolean;\n\treadonly scrollByPage?: boolean;\n\treadonly mouseWheelScrollSensitivity?: number;\n\treadonly fastScrollSensitivity?: number;\n\treadonly paddingTop?: number;\n\treadonly paddingBottom?: number;\n}\n\nexport interface IListViewOptions extends IListViewOptionsUpdate {\n\treadonly dnd?: IListViewDragAndDrop;\n\treadonly useShadows?: boolean;\n\treadonly verticalScrollMode?: ScrollbarVisibility;\n\treadonly setRowLineHeight?: boolean;\n\treadonly setRowHeight?: boolean;\n\treadonly supportDynamicHeights?: boolean;\n\treadonly mouseSupport?: boolean;\n\treadonly accessibilityProvider?: IListViewAccessibilityProvider;\n\treadonly transformOptimization?: boolean;\n\treadonly alwaysConsumeMouseWheel?: boolean;\n\treadonly initialSize?: Dimension;\n}\n\nconst DefaultOptions = {\n\tuseShadows: true,\n\tverticalScrollMode: ScrollbarVisibility.Auto,\n\tsetRowLineHeight: true,\n\tsetRowHeight: true,\n\tsupportDynamicHeights: false,\n\tdnd: {\n\t\tgetDragElements(e: T) { return [e]; },\n\t\tgetDragURI() { return null; },\n\t\tonDragStart(): void { },\n\t\tonDragOver() { return false; },\n\t\tdrop() { },\n\t\tdispose() { }\n\t},\n\thorizontalScrolling: false,\n\ttransformOptimization: true,\n\talwaysConsumeMouseWheel: true,\n};\n\nexport class ElementsDragAndDropData implements IDragAndDropData {\n\n\treadonly elements: T[];\n\n\tconstructor(elements: T[]) {\n\t\tthis.elements = elements;\n\t}\n\n\tupdate(): void { }\n\n\tgetData(): T[] {\n\t\treturn this.elements;\n\t}\n}\n\nexport class ExternalElementsDragAndDropData implements IDragAndDropData {\n\n\treadonly elements: T[];\n\n\tconstructor(elements: T[]) {\n\t\tthis.elements = elements;\n\t}\n\n\tupdate(): void { }\n\n\tgetData(): T[] {\n\t\treturn this.elements;\n\t}\n}\n\nexport class NativeDragAndDropData implements IDragAndDropData {\n\n\treadonly types: any[];\n\treadonly files: any[];\n\n\tconstructor() {\n\t\tthis.types = [];\n\t\tthis.files = [];\n\t}\n\n\tupdate(dataTransfer: DataTransfer): void {\n\t\tif (dataTransfer.types) {\n\t\t\tthis.types.splice(0, this.types.length, ...dataTransfer.types);\n\t\t}\n\n\t\tif (dataTransfer.files) {\n\t\t\tthis.files.splice(0, this.files.length);\n\n\t\t\tfor (let i = 0; i < dataTransfer.files.length; i++) {\n\t\t\t\tconst file = dataTransfer.files.item(i);\n\n\t\t\t\tif (file && (file.size || file.type)) {\n\t\t\t\t\tthis.files.push(file);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tgetData(): any {\n\t\treturn {\n\t\t\ttypes: this.types,\n\t\t\tfiles: this.files\n\t\t};\n\t}\n}\n\nfunction equalsDragFeedback(f1: number[] | undefined, f2: number[] | undefined): boolean {\n\tif (Array.isArray(f1) && Array.isArray(f2)) {\n\t\treturn equals(f1, f2);\n\t}\n\n\treturn f1 === f2;\n}\n\nclass ListViewAccessibilityProvider implements Required> {\n\n\treadonly getSetSize: (element: any, index: number, listLength: number) => number;\n\treadonly getPosInSet: (element: any, index: number) => number;\n\treadonly getRole: (element: T) => AriaRole | undefined;\n\treadonly isChecked: (element: T) => boolean | IValueWithChangeEvent | undefined;\n\n\tconstructor(accessibilityProvider?: IListViewAccessibilityProvider) {\n\t\tif (accessibilityProvider?.getSetSize) {\n\t\t\tthis.getSetSize = accessibilityProvider.getSetSize.bind(accessibilityProvider);\n\t\t} else {\n\t\t\tthis.getSetSize = (e, i, l) => l;\n\t\t}\n\n\t\tif (accessibilityProvider?.getPosInSet) {\n\t\t\tthis.getPosInSet = accessibilityProvider.getPosInSet.bind(accessibilityProvider);\n\t\t} else {\n\t\t\tthis.getPosInSet = (e, i) => i + 1;\n\t\t}\n\n\t\tif (accessibilityProvider?.getRole) {\n\t\t\tthis.getRole = accessibilityProvider.getRole.bind(accessibilityProvider);\n\t\t} else {\n\t\t\tthis.getRole = _ => 'listitem';\n\t\t}\n\n\t\tif (accessibilityProvider?.isChecked) {\n\t\t\tthis.isChecked = accessibilityProvider.isChecked.bind(accessibilityProvider);\n\t\t} else {\n\t\t\tthis.isChecked = _ => undefined;\n\t\t}\n\t}\n}\n\nexport interface IListView extends ISpliceable, IDisposable {\n\treadonly domId: string;\n\treadonly domNode: HTMLElement;\n\treadonly scrollableElementDomNode: HTMLElement;\n\treadonly length: number;\n\treadonly contentHeight: number;\n\treadonly onDidChangeContentHeight: Event;\n\treadonly renderHeight: number;\n\treadonly scrollHeight: number;\n\treadonly firstVisibleIndex: number;\n\tonDidScroll: Event;\n\tonMouseClick: Event>;\n\tonMouseDblClick: Event>;\n\tonMouseMiddleClick: Event>;\n\tonMouseDown: Event>;\n\tonMouseOver: Event>;\n\tonMouseOut: Event>;\n\tonContextMenu: Event>;\n\tonTouchStart: Event>;\n\tonTap: Event>;\n\telement(index: number): T;\n\tdomElement(index: number): HTMLElement | null;\n\tgetElementDomId(index: number): string;\n\telementHeight(index: number): number;\n\telementTop(index: number): number;\n\tindexOf(element: T): number;\n\tindexAt(position: number): number;\n\tindexAfter(position: number): number;\n\tupdateOptions(options: IListViewOptionsUpdate): void;\n\tgetScrollTop(): number;\n\tsetScrollTop(scrollTop: number, reuseAnimation?: boolean): void;\n\trerender(): void;\n\tlayout(height?: number, width?: number): void;\n}\n\n/**\n * The {@link ListView} is a virtual scrolling engine.\n *\n * Given that it only renders elements within its viewport, it can hold large\n * collections of elements and stay very performant. The performance bottleneck\n * usually lies within the user's rendering code for each element.\n *\n * @remarks It is a low-level widget, not meant to be used directly. Refer to the\n * List widget instead.\n */\nexport class ListView implements IListView {\n\n\tprivate static InstanceCount = 0;\n\treadonly domId = `list_id_${++ListView.InstanceCount}`;\n\n\treadonly domNode: HTMLElement;\n\n\tprivate items: IItem[];\n\tprivate itemId: number;\n\tprotected rangeMap: IRangeMap;\n\tprivate cache: RowCache;\n\tprivate renderers = new Map>();\n\tprotected lastRenderTop: number;\n\tprotected lastRenderHeight: number;\n\tprivate renderWidth = 0;\n\tprivate rowsContainer: HTMLElement;\n\tprivate scrollable: Scrollable;\n\tprivate scrollableElement: SmoothScrollableElement;\n\tprivate _scrollHeight: number = 0;\n\tprivate scrollableElementUpdateDisposable: IDisposable | null = null;\n\tprivate scrollableElementWidthDelayer = new Delayer(50);\n\tprivate splicing = false;\n\tprivate dragOverAnimationDisposable: IDisposable | undefined;\n\tprivate dragOverAnimationStopDisposable: IDisposable = Disposable.None;\n\tprivate dragOverMouseY: number = 0;\n\tprivate setRowLineHeight: boolean;\n\tprivate setRowHeight: boolean;\n\tprivate supportDynamicHeights: boolean;\n\tprivate paddingBottom: number;\n\tprivate accessibilityProvider: ListViewAccessibilityProvider;\n\tprivate scrollWidth: number | undefined;\n\n\tprivate dnd: IListViewDragAndDrop;\n\tprivate canDrop: boolean = false;\n\tprivate currentDragData: IDragAndDropData | undefined;\n\tprivate currentDragFeedback: number[] | undefined;\n\tprivate currentDragFeedbackPosition: ListDragOverEffectPosition | undefined;\n\tprivate currentDragFeedbackDisposable: IDisposable = Disposable.None;\n\tprivate onDragLeaveTimeout: IDisposable = Disposable.None;\n\n\tprivate readonly disposables: DisposableStore = new DisposableStore();\n\n\tprivate readonly _onDidChangeContentHeight = new Emitter();\n\tprivate readonly _onDidChangeContentWidth = new Emitter();\n\treadonly onDidChangeContentHeight: Event = Event.latch(this._onDidChangeContentHeight.event, undefined, this.disposables);\n\tget contentHeight(): number { return this.rangeMap.size; }\n\n\tget onDidScroll(): Event { return this.scrollableElement.onScroll; }\n\tget scrollableElementDomNode(): HTMLElement { return this.scrollableElement.getDomNode(); }\n\n\tprivate _horizontalScrolling: boolean = false;\n\tprivate get horizontalScrolling(): boolean { return this._horizontalScrolling; }\n\tprivate set horizontalScrolling(value: boolean) {\n\t\tif (value === this._horizontalScrolling) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (value && this.supportDynamicHeights) {\n\t\t\tthrow new Error('Horizontal scrolling and dynamic heights not supported simultaneously');\n\t\t}\n\n\t\tthis._horizontalScrolling = value;\n\t\tthis.domNode.classList.toggle('horizontal-scrolling', this._horizontalScrolling);\n\n\t\tif (this._horizontalScrolling) {\n\t\t\tfor (const item of this.items) {\n\t\t\t\tthis.measureItemWidth(item);\n\t\t\t}\n\n\t\t\tthis.updateScrollWidth();\n\t\t\tthis.scrollableElement.setScrollDimensions({ width: getContentWidth(this.domNode) });\n\t\t\tthis.rowsContainer.style.width = `${Math.max(this.scrollWidth || 0, this.renderWidth)}px`;\n\t\t} else {\n\t\t\tthis.scrollableElementWidthDelayer.cancel();\n\t\t\tthis.scrollableElement.setScrollDimensions({ width: this.renderWidth, scrollWidth: this.renderWidth });\n\t\t\tthis.rowsContainer.style.width = '';\n\t\t}\n\t}\n\n\tconstructor(\n\t\tcontainer: HTMLElement,\n\t\tprivate virtualDelegate: IListVirtualDelegate,\n\t\trenderers: IListRenderer[],\n\t\toptions: IListViewOptions = DefaultOptions as IListViewOptions\n\t) {\n\t\tif (options.horizontalScrolling && options.supportDynamicHeights) {\n\t\t\tthrow new Error('Horizontal scrolling and dynamic heights not supported simultaneously');\n\t\t}\n\n\t\tthis.items = [];\n\t\tthis.itemId = 0;\n\t\tthis.rangeMap = this.createRangeMap(options.paddingTop ?? 0);\n\n\t\tfor (const renderer of renderers) {\n\t\t\tthis.renderers.set(renderer.templateId, renderer);\n\t\t}\n\n\t\tthis.cache = this.disposables.add(new RowCache(this.renderers));\n\n\t\tthis.lastRenderTop = 0;\n\t\tthis.lastRenderHeight = 0;\n\n\t\tthis.domNode = document.createElement('div');\n\t\tthis.domNode.className = 'monaco-list';\n\n\t\tthis.domNode.classList.add(this.domId);\n\t\tthis.domNode.tabIndex = 0;\n\n\t\tthis.domNode.classList.toggle('mouse-support', typeof options.mouseSupport === 'boolean' ? options.mouseSupport : true);\n\n\t\tthis._horizontalScrolling = options.horizontalScrolling ?? DefaultOptions.horizontalScrolling;\n\t\tthis.domNode.classList.toggle('horizontal-scrolling', this._horizontalScrolling);\n\n\t\tthis.paddingBottom = typeof options.paddingBottom === 'undefined' ? 0 : options.paddingBottom;\n\n\t\tthis.accessibilityProvider = new ListViewAccessibilityProvider(options.accessibilityProvider);\n\n\t\tthis.rowsContainer = document.createElement('div');\n\t\tthis.rowsContainer.className = 'monaco-list-rows';\n\n\t\tconst transformOptimization = options.transformOptimization ?? DefaultOptions.transformOptimization;\n\t\tif (transformOptimization) {\n\t\t\tthis.rowsContainer.style.transform = 'translate3d(0px, 0px, 0px)';\n\t\t\tthis.rowsContainer.style.overflow = 'hidden';\n\t\t\tthis.rowsContainer.style.contain = 'strict';\n\t\t}\n\n\t\tthis.disposables.add(Gesture.addTarget(this.rowsContainer));\n\n\t\tthis.scrollable = this.disposables.add(new Scrollable({\n\t\t\tforceIntegerValues: true,\n\t\t\tsmoothScrollDuration: (options.smoothScrolling ?? false) ? 125 : 0,\n\t\t\tscheduleAtNextAnimationFrame: cb => scheduleAtNextAnimationFrame(getWindow(this.domNode), cb)\n\t\t}));\n\t\tthis.scrollableElement = this.disposables.add(new SmoothScrollableElement(this.rowsContainer, {\n\t\t\talwaysConsumeMouseWheel: options.alwaysConsumeMouseWheel ?? DefaultOptions.alwaysConsumeMouseWheel,\n\t\t\thorizontal: ScrollbarVisibility.Auto,\n\t\t\tvertical: options.verticalScrollMode ?? DefaultOptions.verticalScrollMode,\n\t\t\tuseShadows: options.useShadows ?? DefaultOptions.useShadows,\n\t\t\tmouseWheelScrollSensitivity: options.mouseWheelScrollSensitivity,\n\t\t\tfastScrollSensitivity: options.fastScrollSensitivity,\n\t\t\tscrollByPage: options.scrollByPage\n\t\t}, this.scrollable));\n\n\t\tthis.domNode.appendChild(this.scrollableElement.getDomNode());\n\t\tcontainer.appendChild(this.domNode);\n\n\t\tthis.scrollableElement.onScroll(this.onScroll, this, this.disposables);\n\t\tthis.disposables.add(addDisposableListener(this.rowsContainer, TouchEventType.Change, e => this.onTouchChange(e as GestureEvent)));\n\n\t\t// Prevent the monaco-scrollable-element from scrolling\n\t\t// https://github.com/microsoft/vscode/issues/44181\n\t\tthis.disposables.add(addDisposableListener(this.scrollableElement.getDomNode(), 'scroll', e => (e.target as HTMLElement).scrollTop = 0));\n\n\t\tthis.disposables.add(addDisposableListener(this.domNode, 'dragover', e => this.onDragOver(this.toDragEvent(e))));\n\t\tthis.disposables.add(addDisposableListener(this.domNode, 'drop', e => this.onDrop(this.toDragEvent(e))));\n\t\tthis.disposables.add(addDisposableListener(this.domNode, 'dragleave', e => this.onDragLeave(this.toDragEvent(e))));\n\t\tthis.disposables.add(addDisposableListener(this.domNode, 'dragend', e => this.onDragEnd(e)));\n\n\t\tthis.setRowLineHeight = options.setRowLineHeight ?? DefaultOptions.setRowLineHeight;\n\t\tthis.setRowHeight = options.setRowHeight ?? DefaultOptions.setRowHeight;\n\t\tthis.supportDynamicHeights = options.supportDynamicHeights ?? DefaultOptions.supportDynamicHeights;\n\t\tthis.dnd = options.dnd ?? this.disposables.add(DefaultOptions.dnd);\n\n\t\tthis.layout(options.initialSize?.height, options.initialSize?.width);\n\t}\n\n\tupdateOptions(options: IListViewOptionsUpdate) {\n\t\tif (options.paddingBottom !== undefined) {\n\t\t\tthis.paddingBottom = options.paddingBottom;\n\t\t\tthis.scrollableElement.setScrollDimensions({ scrollHeight: this.scrollHeight });\n\t\t}\n\n\t\tif (options.smoothScrolling !== undefined) {\n\t\t\tthis.scrollable.setSmoothScrollDuration(options.smoothScrolling ? 125 : 0);\n\t\t}\n\n\t\tif (options.horizontalScrolling !== undefined) {\n\t\t\tthis.horizontalScrolling = options.horizontalScrolling;\n\t\t}\n\n\t\tlet scrollableOptions: ScrollableElementChangeOptions | undefined;\n\n\t\tif (options.scrollByPage !== undefined) {\n\t\t\tscrollableOptions = { ...(scrollableOptions ?? {}), scrollByPage: options.scrollByPage };\n\t\t}\n\n\t\tif (options.mouseWheelScrollSensitivity !== undefined) {\n\t\t\tscrollableOptions = { ...(scrollableOptions ?? {}), mouseWheelScrollSensitivity: options.mouseWheelScrollSensitivity };\n\t\t}\n\n\t\tif (options.fastScrollSensitivity !== undefined) {\n\t\t\tscrollableOptions = { ...(scrollableOptions ?? {}), fastScrollSensitivity: options.fastScrollSensitivity };\n\t\t}\n\n\t\tif (scrollableOptions) {\n\t\t\tthis.scrollableElement.updateOptions(scrollableOptions);\n\t\t}\n\n\t\tif (options.paddingTop !== undefined && options.paddingTop !== this.rangeMap.paddingTop) {\n\t\t\t// trigger a rerender\n\t\t\tconst lastRenderRange = this.getRenderRange(this.lastRenderTop, this.lastRenderHeight);\n\t\t\tconst offset = options.paddingTop - this.rangeMap.paddingTop;\n\t\t\tthis.rangeMap.paddingTop = options.paddingTop;\n\n\t\t\tthis.render(lastRenderRange, Math.max(0, this.lastRenderTop + offset), this.lastRenderHeight, undefined, undefined, true);\n\t\t\tthis.setScrollTop(this.lastRenderTop);\n\n\t\t\tthis.eventuallyUpdateScrollDimensions();\n\n\t\t\tif (this.supportDynamicHeights) {\n\t\t\t\tthis._rerender(this.lastRenderTop, this.lastRenderHeight);\n\t\t\t}\n\t\t}\n\t}\n\n\tprotected createRangeMap(paddingTop: number): IRangeMap {\n\t\treturn new RangeMap(paddingTop);\n\t}\n\n\tsplice(start: number, deleteCount: number, elements: readonly T[] = []): T[] {\n\t\tif (this.splicing) {\n\t\t\tthrow new Error('Can\\'t run recursive splices.');\n\t\t}\n\n\t\tthis.splicing = true;\n\n\t\ttry {\n\t\t\treturn this._splice(start, deleteCount, elements);\n\t\t} finally {\n\t\t\tthis.splicing = false;\n\t\t\tthis._onDidChangeContentHeight.fire(this.contentHeight);\n\t\t}\n\t}\n\n\tprivate _splice(start: number, deleteCount: number, elements: readonly T[] = []): T[] {\n\t\tconst previousRenderRange = this.getRenderRange(this.lastRenderTop, this.lastRenderHeight);\n\t\tconst deleteRange = { start, end: start + deleteCount };\n\t\tconst removeRange = Range.intersect(previousRenderRange, deleteRange);\n\n\t\t// try to reuse rows, avoid removing them from DOM\n\t\tconst rowsToDispose = new Map();\n\t\tfor (let i = removeRange.end - 1; i >= removeRange.start; i--) {\n\t\t\tconst item = this.items[i];\n\t\t\titem.dragStartDisposable.dispose();\n\t\t\titem.checkedDisposable.dispose();\n\n\t\t\tif (item.row) {\n\t\t\t\tlet rows = rowsToDispose.get(item.templateId);\n\n\t\t\t\tif (!rows) {\n\t\t\t\t\trows = [];\n\t\t\t\t\trowsToDispose.set(item.templateId, rows);\n\t\t\t\t}\n\n\t\t\t\tconst renderer = this.renderers.get(item.templateId);\n\n\t\t\t\tif (renderer && renderer.disposeElement) {\n\t\t\t\t\trenderer.disposeElement(item.element, i, item.row.templateData, item.size);\n\t\t\t\t}\n\n\t\t\t\trows.unshift(item.row);\n\t\t\t}\n\n\t\t\titem.row = null;\n\t\t\titem.stale = true;\n\t\t}\n\n\t\tconst previousRestRange: IRange = { start: start + deleteCount, end: this.items.length };\n\t\tconst previousRenderedRestRange = Range.intersect(previousRestRange, previousRenderRange);\n\t\tconst previousUnrenderedRestRanges = Range.relativeComplement(previousRestRange, previousRenderRange);\n\n\t\tconst inserted = elements.map>(element => ({\n\t\t\tid: String(this.itemId++),\n\t\t\telement,\n\t\t\ttemplateId: this.virtualDelegate.getTemplateId(element),\n\t\t\tsize: this.virtualDelegate.getHeight(element),\n\t\t\twidth: undefined,\n\t\t\thasDynamicHeight: !!this.virtualDelegate.hasDynamicHeight && this.virtualDelegate.hasDynamicHeight(element),\n\t\t\tlastDynamicHeightWidth: undefined,\n\t\t\trow: null,\n\t\t\turi: undefined,\n\t\t\tdropTarget: false,\n\t\t\tdragStartDisposable: Disposable.None,\n\t\t\tcheckedDisposable: Disposable.None,\n\t\t\tstale: false\n\t\t}));\n\n\t\tlet deleted: IItem[];\n\n\t\t// TODO@joao: improve this optimization to catch even more cases\n\t\tif (start === 0 && deleteCount >= this.items.length) {\n\t\t\tthis.rangeMap = this.createRangeMap(this.rangeMap.paddingTop);\n\t\t\tthis.rangeMap.splice(0, 0, inserted);\n\t\t\tdeleted = this.items;\n\t\t\tthis.items = inserted;\n\t\t} else {\n\t\t\tthis.rangeMap.splice(start, deleteCount, inserted);\n\t\t\tdeleted = this.items.splice(start, deleteCount, ...inserted);\n\t\t}\n\n\t\tconst delta = elements.length - deleteCount;\n\t\tconst renderRange = this.getRenderRange(this.lastRenderTop, this.lastRenderHeight);\n\t\tconst renderedRestRange = shift(previousRenderedRestRange, delta);\n\t\tconst updateRange = Range.intersect(renderRange, renderedRestRange);\n\n\t\tfor (let i = updateRange.start; i < updateRange.end; i++) {\n\t\t\tthis.updateItemInDOM(this.items[i], i);\n\t\t}\n\n\t\tconst removeRanges = Range.relativeComplement(renderedRestRange, renderRange);\n\n\t\tfor (const range of removeRanges) {\n\t\t\tfor (let i = range.start; i < range.end; i++) {\n\t\t\t\tthis.removeItemFromDOM(i);\n\t\t\t}\n\t\t}\n\n\t\tconst unrenderedRestRanges = previousUnrenderedRestRanges.map(r => shift(r, delta));\n\t\tconst elementsRange = { start, end: start + elements.length };\n\t\tconst insertRanges = [elementsRange, ...unrenderedRestRanges].map(r => Range.intersect(renderRange, r)).reverse();\n\n\t\tfor (const range of insertRanges) {\n\t\t\tfor (let i = range.end - 1; i >= range.start; i--) {\n\t\t\t\tconst item = this.items[i];\n\t\t\t\tconst rows = rowsToDispose.get(item.templateId);\n\t\t\t\tconst row = rows?.pop();\n\t\t\t\tthis.insertItemInDOM(i, row);\n\t\t\t}\n\t\t}\n\n\t\tfor (const rows of rowsToDispose.values()) {\n\t\t\tfor (const row of rows) {\n\t\t\t\tthis.cache.release(row);\n\t\t\t}\n\t\t}\n\n\t\tthis.eventuallyUpdateScrollDimensions();\n\n\t\tif (this.supportDynamicHeights) {\n\t\t\tthis._rerender(this.scrollTop, this.renderHeight);\n\t\t}\n\n\t\treturn deleted.map(i => i.element);\n\t}\n\n\tprotected eventuallyUpdateScrollDimensions(): void {\n\t\tthis._scrollHeight = this.contentHeight;\n\t\tthis.rowsContainer.style.height = `${this._scrollHeight}px`;\n\n\t\tif (!this.scrollableElementUpdateDisposable) {\n\t\t\tthis.scrollableElementUpdateDisposable = scheduleAtNextAnimationFrame(getWindow(this.domNode), () => {\n\t\t\t\tthis.scrollableElement.setScrollDimensions({ scrollHeight: this.scrollHeight });\n\t\t\t\tthis.updateScrollWidth();\n\t\t\t\tthis.scrollableElementUpdateDisposable = null;\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate eventuallyUpdateScrollWidth(): void {\n\t\tif (!this.horizontalScrolling) {\n\t\t\tthis.scrollableElementWidthDelayer.cancel();\n\t\t\treturn;\n\t\t}\n\n\t\tthis.scrollableElementWidthDelayer.trigger(() => this.updateScrollWidth());\n\t}\n\n\tprivate updateScrollWidth(): void {\n\t\tif (!this.horizontalScrolling) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet scrollWidth = 0;\n\n\t\tfor (const item of this.items) {\n\t\t\tif (typeof item.width !== 'undefined') {\n\t\t\t\tscrollWidth = Math.max(scrollWidth, item.width);\n\t\t\t}\n\t\t}\n\n\t\tthis.scrollWidth = scrollWidth;\n\t\tthis.scrollableElement.setScrollDimensions({ scrollWidth: scrollWidth === 0 ? 0 : (scrollWidth + 10) });\n\t\tthis._onDidChangeContentWidth.fire(this.scrollWidth);\n\t}\n\n\trerender(): void {\n\t\tif (!this.supportDynamicHeights) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor (const item of this.items) {\n\t\t\titem.lastDynamicHeightWidth = undefined;\n\t\t}\n\n\t\tthis._rerender(this.lastRenderTop, this.lastRenderHeight);\n\t}\n\n\tget length(): number {\n\t\treturn this.items.length;\n\t}\n\n\tget renderHeight(): number {\n\t\tconst scrollDimensions = this.scrollableElement.getScrollDimensions();\n\t\treturn scrollDimensions.height;\n\t}\n\n\tget firstVisibleIndex(): number {\n\t\tconst range = this.getRenderRange(this.lastRenderTop, this.lastRenderHeight);\n\t\treturn range.start;\n\t}\n\n\telement(index: number): T {\n\t\treturn this.items[index].element;\n\t}\n\n\tindexOf(element: T): number {\n\t\treturn this.items.findIndex(item => item.element === element);\n\t}\n\n\tdomElement(index: number): HTMLElement | null {\n\t\tconst row = this.items[index].row;\n\t\treturn row && row.domNode;\n\t}\n\n\telementHeight(index: number): number {\n\t\treturn this.items[index].size;\n\t}\n\n\telementTop(index: number): number {\n\t\treturn this.rangeMap.positionAt(index);\n\t}\n\n\tindexAt(position: number): number {\n\t\treturn this.rangeMap.indexAt(position);\n\t}\n\n\tindexAfter(position: number): number {\n\t\treturn this.rangeMap.indexAfter(position);\n\t}\n\n\tlayout(height?: number, width?: number): void {\n\t\tconst scrollDimensions: INewScrollDimensions = {\n\t\t\theight: typeof height === 'number' ? height : getContentHeight(this.domNode)\n\t\t};\n\n\t\tif (this.scrollableElementUpdateDisposable) {\n\t\t\tthis.scrollableElementUpdateDisposable.dispose();\n\t\t\tthis.scrollableElementUpdateDisposable = null;\n\t\t\tscrollDimensions.scrollHeight = this.scrollHeight;\n\t\t}\n\n\t\tthis.scrollableElement.setScrollDimensions(scrollDimensions);\n\n\t\tif (typeof width !== 'undefined') {\n\t\t\tthis.renderWidth = width;\n\n\t\t\tif (this.supportDynamicHeights) {\n\t\t\t\tthis._rerender(this.scrollTop, this.renderHeight);\n\t\t\t}\n\t\t}\n\n\t\tif (this.horizontalScrolling) {\n\t\t\tthis.scrollableElement.setScrollDimensions({\n\t\t\t\twidth: typeof width === 'number' ? width : getContentWidth(this.domNode)\n\t\t\t});\n\t\t}\n\t}\n\n\t// Render\n\n\tprotected render(previousRenderRange: IRange, renderTop: number, renderHeight: number, renderLeft: number | undefined, scrollWidth: number | undefined, updateItemsInDOM: boolean = false): void {\n\t\tconst renderRange = this.getRenderRange(renderTop, renderHeight);\n\n\t\tconst rangesToInsert = Range.relativeComplement(renderRange, previousRenderRange).reverse();\n\t\tconst rangesToRemove = Range.relativeComplement(previousRenderRange, renderRange);\n\n\t\tif (updateItemsInDOM) {\n\t\t\tconst rangesToUpdate = Range.intersect(previousRenderRange, renderRange);\n\n\t\t\tfor (let i = rangesToUpdate.start; i < rangesToUpdate.end; i++) {\n\t\t\t\tthis.updateItemInDOM(this.items[i], i);\n\t\t\t}\n\t\t}\n\n\t\tthis.cache.transact(() => {\n\t\t\tfor (const range of rangesToRemove) {\n\t\t\t\tfor (let i = range.start; i < range.end; i++) {\n\t\t\t\t\tthis.removeItemFromDOM(i);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (const range of rangesToInsert) {\n\t\t\t\tfor (let i = range.end - 1; i >= range.start; i--) {\n\t\t\t\t\tthis.insertItemInDOM(i);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\tif (renderLeft !== undefined) {\n\t\t\tthis.rowsContainer.style.left = `-${renderLeft}px`;\n\t\t}\n\n\t\tthis.rowsContainer.style.top = `-${renderTop}px`;\n\n\t\tif (this.horizontalScrolling && scrollWidth !== undefined) {\n\t\t\tthis.rowsContainer.style.width = `${Math.max(scrollWidth, this.renderWidth)}px`;\n\t\t}\n\n\t\tthis.lastRenderTop = renderTop;\n\t\tthis.lastRenderHeight = renderHeight;\n\t}\n\n\t// DOM operations\n\n\tprivate insertItemInDOM(index: number, row?: IRow): void {\n\t\tconst item = this.items[index];\n\n\t\tif (!item.row) {\n\t\t\tif (row) {\n\t\t\t\titem.row = row;\n\t\t\t\titem.stale = true;\n\t\t\t} else {\n\t\t\t\tconst result = this.cache.alloc(item.templateId);\n\t\t\t\titem.row = result.row;\n\t\t\t\titem.stale ||= result.isReusingConnectedDomNode;\n\t\t\t}\n\t\t}\n\n\t\tconst role = this.accessibilityProvider.getRole(item.element) || 'listitem';\n\t\titem.row.domNode.setAttribute('role', role);\n\n\t\tconst checked = this.accessibilityProvider.isChecked(item.element);\n\n\t\tif (typeof checked === 'boolean') {\n\t\t\titem.row.domNode.setAttribute('aria-checked', String(!!checked));\n\t\t} else if (checked) {\n\t\t\tconst update = (checked: boolean) => item.row!.domNode.setAttribute('aria-checked', String(!!checked));\n\t\t\tupdate(checked.value);\n\t\t\titem.checkedDisposable = checked.onDidChange(() => update(checked.value));\n\t\t}\n\n\t\tif (item.stale || !item.row.domNode.parentElement) {\n\t\t\tconst referenceNode = this.items.at(index + 1)?.row?.domNode ?? null;\n\t\t\tif (item.row.domNode.parentElement !== this.rowsContainer || item.row.domNode.nextElementSibling !== referenceNode) {\n\t\t\t\tthis.rowsContainer.insertBefore(item.row.domNode, referenceNode);\n\t\t\t}\n\t\t\titem.stale = false;\n\t\t}\n\n\t\tthis.updateItemInDOM(item, index);\n\n\t\tconst renderer = this.renderers.get(item.templateId);\n\n\t\tif (!renderer) {\n\t\t\tthrow new Error(`No renderer found for template id ${item.templateId}`);\n\t\t}\n\n\t\trenderer?.renderElement(item.element, index, item.row.templateData, item.size);\n\n\t\tconst uri = this.dnd.getDragURI(item.element);\n\t\titem.dragStartDisposable.dispose();\n\t\titem.row.domNode.draggable = !!uri;\n\n\t\tif (uri) {\n\t\t\titem.dragStartDisposable = addDisposableListener(item.row.domNode, 'dragstart', event => this.onDragStart(item.element, uri, event));\n\t\t}\n\n\t\tif (this.horizontalScrolling) {\n\t\t\tthis.measureItemWidth(item);\n\t\t\tthis.eventuallyUpdateScrollWidth();\n\t\t}\n\t}\n\n\tprivate measureItemWidth(item: IItem): void {\n\t\tif (!item.row || !item.row.domNode) {\n\t\t\treturn;\n\t\t}\n\n\t\titem.row.domNode.style.width = 'fit-content';\n\t\titem.width = getContentWidth(item.row.domNode);\n\t\tconst style = getWindow(item.row.domNode).getComputedStyle(item.row.domNode);\n\n\t\tif (style.paddingLeft) {\n\t\t\titem.width += parseFloat(style.paddingLeft);\n\t\t}\n\n\t\tif (style.paddingRight) {\n\t\t\titem.width += parseFloat(style.paddingRight);\n\t\t}\n\n\t\titem.row.domNode.style.width = '';\n\t}\n\n\tprivate updateItemInDOM(item: IItem, index: number): void {\n\t\titem.row!.domNode.style.top = `${this.elementTop(index)}px`;\n\n\t\tif (this.setRowHeight) {\n\t\t\titem.row!.domNode.style.height = `${item.size}px`;\n\t\t}\n\n\t\tif (this.setRowLineHeight) {\n\t\t\titem.row!.domNode.style.lineHeight = `${item.size}px`;\n\t\t}\n\n\t\titem.row!.domNode.setAttribute('data-index', `${index}`);\n\t\titem.row!.domNode.setAttribute('data-last-element', index === this.length - 1 ? 'true' : 'false');\n\t\titem.row!.domNode.setAttribute('data-parity', index % 2 === 0 ? 'even' : 'odd');\n\t\titem.row!.domNode.setAttribute('aria-setsize', String(this.accessibilityProvider.getSetSize(item.element, index, this.length)));\n\t\titem.row!.domNode.setAttribute('aria-posinset', String(this.accessibilityProvider.getPosInSet(item.element, index)));\n\t\titem.row!.domNode.setAttribute('id', this.getElementDomId(index));\n\n\t\titem.row!.domNode.classList.toggle('drop-target', item.dropTarget);\n\t}\n\n\tprivate removeItemFromDOM(index: number): void {\n\t\tconst item = this.items[index];\n\t\titem.dragStartDisposable.dispose();\n\t\titem.checkedDisposable.dispose();\n\n\t\tif (item.row) {\n\t\t\tconst renderer = this.renderers.get(item.templateId);\n\n\t\t\tif (renderer && renderer.disposeElement) {\n\t\t\t\trenderer.disposeElement(item.element, index, item.row.templateData, item.size);\n\t\t\t}\n\n\t\t\tthis.cache.release(item.row);\n\t\t\titem.row = null;\n\t\t}\n\n\t\tif (this.horizontalScrolling) {\n\t\t\tthis.eventuallyUpdateScrollWidth();\n\t\t}\n\t}\n\n\tgetScrollTop(): number {\n\t\tconst scrollPosition = this.scrollableElement.getScrollPosition();\n\t\treturn scrollPosition.scrollTop;\n\t}\n\n\tsetScrollTop(scrollTop: number, reuseAnimation?: boolean): void {\n\t\tif (this.scrollableElementUpdateDisposable) {\n\t\t\tthis.scrollableElementUpdateDisposable.dispose();\n\t\t\tthis.scrollableElementUpdateDisposable = null;\n\t\t\tthis.scrollableElement.setScrollDimensions({ scrollHeight: this.scrollHeight });\n\t\t}\n\n\t\tthis.scrollableElement.setScrollPosition({ scrollTop, reuseAnimation });\n\t}\n\n\n\tget scrollTop(): number {\n\t\treturn this.getScrollTop();\n\t}\n\n\tset scrollTop(scrollTop: number) {\n\t\tthis.setScrollTop(scrollTop);\n\t}\n\n\tget scrollHeight(): number {\n\t\treturn this._scrollHeight + (this.horizontalScrolling ? 10 : 0) + this.paddingBottom;\n\t}\n\n\t// Events\n\n\t@memoize get onMouseClick(): Event> { return Event.map(this.disposables.add(new DomEmitter(this.domNode, 'click')).event, e => this.toMouseEvent(e), this.disposables); }\n\t@memoize get onMouseDblClick(): Event> { return Event.map(this.disposables.add(new DomEmitter(this.domNode, 'dblclick')).event, e => this.toMouseEvent(e), this.disposables); }\n\t@memoize get onMouseMiddleClick(): Event> { return Event.filter(Event.map(this.disposables.add(new DomEmitter(this.domNode, 'auxclick')).event, e => this.toMouseEvent(e as MouseEvent), this.disposables), e => e.browserEvent.button === 1, this.disposables); }\n\t@memoize get onMouseDown(): Event> { return Event.map(this.disposables.add(new DomEmitter(this.domNode, 'mousedown')).event, e => this.toMouseEvent(e), this.disposables); }\n\t@memoize get onMouseOver(): Event> { return Event.map(this.disposables.add(new DomEmitter(this.domNode, 'mouseover')).event, e => this.toMouseEvent(e), this.disposables); }\n\t@memoize get onMouseOut(): Event> { return Event.map(this.disposables.add(new DomEmitter(this.domNode, 'mouseout')).event, e => this.toMouseEvent(e), this.disposables); }\n\t@memoize get onContextMenu(): Event | IListGestureEvent> { return Event.any | IListGestureEvent>(Event.map(this.disposables.add(new DomEmitter(this.domNode, 'contextmenu')).event, e => this.toMouseEvent(e), this.disposables), Event.map(this.disposables.add(new DomEmitter(this.domNode, TouchEventType.Contextmenu)).event as Event, e => this.toGestureEvent(e), this.disposables)); }\n\t@memoize get onTouchStart(): Event> { return Event.map(this.disposables.add(new DomEmitter(this.domNode, 'touchstart')).event, e => this.toTouchEvent(e), this.disposables); }\n\t@memoize get onTap(): Event> { return Event.map(this.disposables.add(new DomEmitter(this.rowsContainer, TouchEventType.Tap)).event, e => this.toGestureEvent(e as GestureEvent), this.disposables); }\n\n\tprivate toMouseEvent(browserEvent: MouseEvent): IListMouseEvent {\n\t\tconst index = this.getItemIndexFromEventTarget(browserEvent.target || null);\n\t\tconst item = typeof index === 'undefined' ? undefined : this.items[index];\n\t\tconst element = item && item.element;\n\t\treturn { browserEvent, index, element };\n\t}\n\n\tprivate toTouchEvent(browserEvent: TouchEvent): IListTouchEvent {\n\t\tconst index = this.getItemIndexFromEventTarget(browserEvent.target || null);\n\t\tconst item = typeof index === 'undefined' ? undefined : this.items[index];\n\t\tconst element = item && item.element;\n\t\treturn { browserEvent, index, element };\n\t}\n\n\tprivate toGestureEvent(browserEvent: GestureEvent): IListGestureEvent {\n\t\tconst index = this.getItemIndexFromEventTarget(browserEvent.initialTarget || null);\n\t\tconst item = typeof index === 'undefined' ? undefined : this.items[index];\n\t\tconst element = item && item.element;\n\t\treturn { browserEvent, index, element };\n\t}\n\n\tprivate toDragEvent(browserEvent: DragEvent): IListDragEvent {\n\t\tconst index = this.getItemIndexFromEventTarget(browserEvent.target || null);\n\t\tconst item = typeof index === 'undefined' ? undefined : this.items[index];\n\t\tconst element = item && item.element;\n\t\tconst sector = this.getTargetSector(browserEvent, index);\n\t\treturn { browserEvent, index, element, sector };\n\t}\n\n\tprivate onScroll(e: ScrollEvent): void {\n\t\ttry {\n\t\t\tconst previousRenderRange = this.getRenderRange(this.lastRenderTop, this.lastRenderHeight);\n\t\t\tthis.render(previousRenderRange, e.scrollTop, e.height, e.scrollLeft, e.scrollWidth);\n\n\t\t\tif (this.supportDynamicHeights) {\n\t\t\t\tthis._rerender(e.scrollTop, e.height, e.inSmoothScrolling);\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tconsole.error('Got bad scroll event:', e);\n\t\t\tthrow err;\n\t\t}\n\t}\n\n\tprivate onTouchChange(event: GestureEvent): void {\n\t\tevent.preventDefault();\n\t\tevent.stopPropagation();\n\n\t\tthis.scrollTop -= event.translationY;\n\t}\n\n\t// DND\n\n\tprivate onDragStart(element: T, uri: string, event: DragEvent): void {\n\t\tif (!event.dataTransfer) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst elements = this.dnd.getDragElements(element);\n\n\t\tevent.dataTransfer.effectAllowed = 'copyMove';\n\t\tevent.dataTransfer.setData(DataTransfers.TEXT, uri);\n\n\t\tif (event.dataTransfer.setDragImage) {\n\t\t\tlet label: string | undefined;\n\n\t\t\tif (this.dnd.getDragLabel) {\n\t\t\t\tlabel = this.dnd.getDragLabel(elements, event);\n\t\t\t}\n\n\t\t\tif (typeof label === 'undefined') {\n\t\t\t\tlabel = String(elements.length);\n\t\t\t}\n\n\t\t\tconst dragImage = $('.monaco-drag-image');\n\t\t\tdragImage.textContent = label;\n\n\t\t\tconst getDragImageContainer = (e: HTMLElement | null) => {\n\t\t\t\twhile (e && !e.classList.contains('monaco-workbench')) {\n\t\t\t\t\te = e.parentElement;\n\t\t\t\t}\n\t\t\t\treturn e || this.domNode.ownerDocument;\n\t\t\t};\n\n\t\t\tconst container = getDragImageContainer(this.domNode);\n\t\t\tcontainer.appendChild(dragImage);\n\t\t\tevent.dataTransfer.setDragImage(dragImage, -10, -10);\n\t\t\tsetTimeout(() => container.removeChild(dragImage), 0);\n\t\t}\n\n\t\tthis.domNode.classList.add('dragging');\n\t\tthis.currentDragData = new ElementsDragAndDropData(elements);\n\t\tStaticDND.CurrentDragAndDropData = new ExternalElementsDragAndDropData(elements);\n\n\t\tthis.dnd.onDragStart?.(this.currentDragData, event);\n\t}\n\n\tprivate onDragOver(event: IListDragEvent): boolean {\n\t\tevent.browserEvent.preventDefault(); // needed so that the drop event fires (https://stackoverflow.com/questions/21339924/drop-event-not-firing-in-chrome)\n\n\t\tthis.onDragLeaveTimeout.dispose();\n\n\t\tif (StaticDND.CurrentDragAndDropData && StaticDND.CurrentDragAndDropData.getData() === 'vscode-ui') {\n\t\t\treturn false;\n\t\t}\n\n\t\tthis.setupDragAndDropScrollTopAnimation(event.browserEvent);\n\n\t\tif (!event.browserEvent.dataTransfer) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Drag over from outside\n\t\tif (!this.currentDragData) {\n\t\t\tif (StaticDND.CurrentDragAndDropData) {\n\t\t\t\t// Drag over from another list\n\t\t\t\tthis.currentDragData = StaticDND.CurrentDragAndDropData;\n\n\t\t\t} else {\n\t\t\t\t// Drag over from the desktop\n\t\t\t\tif (!event.browserEvent.dataTransfer.types) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tthis.currentDragData = new NativeDragAndDropData();\n\t\t\t}\n\t\t}\n\n\t\tconst result = this.dnd.onDragOver(this.currentDragData, event.element, event.index, event.sector, event.browserEvent);\n\t\tthis.canDrop = typeof result === 'boolean' ? result : result.accept;\n\n\t\tif (!this.canDrop) {\n\t\t\tthis.currentDragFeedback = undefined;\n\t\t\tthis.currentDragFeedbackDisposable.dispose();\n\t\t\treturn false;\n\t\t}\n\n\t\tevent.browserEvent.dataTransfer.dropEffect = (typeof result !== 'boolean' && result.effect?.type === ListDragOverEffectType.Copy) ? 'copy' : 'move';\n\n\t\tlet feedback: number[];\n\n\t\tif (typeof result !== 'boolean' && result.feedback) {\n\t\t\tfeedback = result.feedback;\n\t\t} else {\n\t\t\tif (typeof event.index === 'undefined') {\n\t\t\t\tfeedback = [-1];\n\t\t\t} else {\n\t\t\t\tfeedback = [event.index];\n\t\t\t}\n\t\t}\n\n\t\t// sanitize feedback list\n\t\tfeedback = distinct(feedback).filter(i => i >= -1 && i < this.length).sort((a, b) => a - b);\n\t\tfeedback = feedback[0] === -1 ? [-1] : feedback;\n\n\t\tlet dragOverEffectPosition = typeof result !== 'boolean' && result.effect && result.effect.position ? result.effect.position : ListDragOverEffectPosition.Over;\n\n\t\tif (equalsDragFeedback(this.currentDragFeedback, feedback) && this.currentDragFeedbackPosition === dragOverEffectPosition) {\n\t\t\treturn true;\n\t\t}\n\n\t\tthis.currentDragFeedback = feedback;\n\t\tthis.currentDragFeedbackPosition = dragOverEffectPosition;\n\t\tthis.currentDragFeedbackDisposable.dispose();\n\n\t\tif (feedback[0] === -1) { // entire list feedback\n\t\t\tthis.domNode.classList.add(dragOverEffectPosition);\n\t\t\tthis.rowsContainer.classList.add(dragOverEffectPosition);\n\t\t\tthis.currentDragFeedbackDisposable = toDisposable(() => {\n\t\t\t\tthis.domNode.classList.remove(dragOverEffectPosition);\n\t\t\t\tthis.rowsContainer.classList.remove(dragOverEffectPosition);\n\t\t\t});\n\t\t} else {\n\n\t\t\tif (feedback.length > 1 && dragOverEffectPosition !== ListDragOverEffectPosition.Over) {\n\t\t\t\tthrow new Error('Can\\'t use multiple feedbacks with position different than \\'over\\'');\n\t\t\t}\n\n\t\t\t// Make sure there is no flicker when moving between two items\n\t\t\t// Always use the before feedback if possible\n\t\t\tif (dragOverEffectPosition === ListDragOverEffectPosition.After) {\n\t\t\t\tif (feedback[0] < this.length - 1) {\n\t\t\t\t\tfeedback[0] += 1;\n\t\t\t\t\tdragOverEffectPosition = ListDragOverEffectPosition.Before;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (const index of feedback) {\n\t\t\t\tconst item = this.items[index]!;\n\t\t\t\titem.dropTarget = true;\n\n\t\t\t\titem.row?.domNode.classList.add(dragOverEffectPosition);\n\t\t\t}\n\n\t\t\tthis.currentDragFeedbackDisposable = toDisposable(() => {\n\t\t\t\tfor (const index of feedback) {\n\t\t\t\t\tconst item = this.items[index]!;\n\t\t\t\t\titem.dropTarget = false;\n\n\t\t\t\t\titem.row?.domNode.classList.remove(dragOverEffectPosition);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tprivate onDragLeave(event: IListDragEvent): void {\n\t\tthis.onDragLeaveTimeout.dispose();\n\t\tthis.onDragLeaveTimeout = disposableTimeout(() => this.clearDragOverFeedback(), 100, this.disposables);\n\t\tif (this.currentDragData) {\n\t\t\tthis.dnd.onDragLeave?.(this.currentDragData, event.element, event.index, event.browserEvent);\n\t\t}\n\t}\n\n\tprivate onDrop(event: IListDragEvent): void {\n\t\tif (!this.canDrop) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst dragData = this.currentDragData;\n\t\tthis.teardownDragAndDropScrollTopAnimation();\n\t\tthis.clearDragOverFeedback();\n\t\tthis.domNode.classList.remove('dragging');\n\t\tthis.currentDragData = undefined;\n\t\tStaticDND.CurrentDragAndDropData = undefined;\n\n\t\tif (!dragData || !event.browserEvent.dataTransfer) {\n\t\t\treturn;\n\t\t}\n\n\t\tevent.browserEvent.preventDefault();\n\t\tdragData.update(event.browserEvent.dataTransfer);\n\t\tthis.dnd.drop(dragData, event.element, event.index, event.sector, event.browserEvent);\n\t}\n\n\tprivate onDragEnd(event: DragEvent): void {\n\t\tthis.canDrop = false;\n\t\tthis.teardownDragAndDropScrollTopAnimation();\n\t\tthis.clearDragOverFeedback();\n\t\tthis.domNode.classList.remove('dragging');\n\t\tthis.currentDragData = undefined;\n\t\tStaticDND.CurrentDragAndDropData = undefined;\n\n\t\tthis.dnd.onDragEnd?.(event);\n\t}\n\n\tprivate clearDragOverFeedback(): void {\n\t\tthis.currentDragFeedback = undefined;\n\t\tthis.currentDragFeedbackPosition = undefined;\n\t\tthis.currentDragFeedbackDisposable.dispose();\n\t\tthis.currentDragFeedbackDisposable = Disposable.None;\n\t}\n\n\t// DND scroll top animation\n\n\tprivate setupDragAndDropScrollTopAnimation(event: DragEvent): void {\n\t\tif (!this.dragOverAnimationDisposable) {\n\t\t\tconst viewTop = getTopLeftOffset(this.domNode).top;\n\t\t\tthis.dragOverAnimationDisposable = animate(getWindow(this.domNode), this.animateDragAndDropScrollTop.bind(this, viewTop));\n\t\t}\n\n\t\tthis.dragOverAnimationStopDisposable.dispose();\n\t\tthis.dragOverAnimationStopDisposable = disposableTimeout(() => {\n\t\t\tif (this.dragOverAnimationDisposable) {\n\t\t\t\tthis.dragOverAnimationDisposable.dispose();\n\t\t\t\tthis.dragOverAnimationDisposable = undefined;\n\t\t\t}\n\t\t}, 1000, this.disposables);\n\n\t\tthis.dragOverMouseY = event.pageY;\n\t}\n\n\tprivate animateDragAndDropScrollTop(viewTop: number): void {\n\t\tif (this.dragOverMouseY === undefined) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst diff = this.dragOverMouseY - viewTop;\n\t\tconst upperLimit = this.renderHeight - 35;\n\n\t\tif (diff < 35) {\n\t\t\tthis.scrollTop += Math.max(-14, Math.floor(0.3 * (diff - 35)));\n\t\t} else if (diff > upperLimit) {\n\t\t\tthis.scrollTop += Math.min(14, Math.floor(0.3 * (diff - upperLimit)));\n\t\t}\n\t}\n\n\tprivate teardownDragAndDropScrollTopAnimation(): void {\n\t\tthis.dragOverAnimationStopDisposable.dispose();\n\n\t\tif (this.dragOverAnimationDisposable) {\n\t\t\tthis.dragOverAnimationDisposable.dispose();\n\t\t\tthis.dragOverAnimationDisposable = undefined;\n\t\t}\n\t}\n\n\t// Util\n\n\tprivate getTargetSector(browserEvent: DragEvent, targetIndex: number | undefined): ListViewTargetSector | undefined {\n\t\tif (targetIndex === undefined) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst relativePosition = browserEvent.offsetY / this.items[targetIndex].size;\n\t\tconst sector = Math.floor(relativePosition / 0.25);\n\t\treturn clamp(sector, 0, 3);\n\t}\n\n\tprivate getItemIndexFromEventTarget(target: EventTarget | null): number | undefined {\n\t\tconst scrollableElement = this.scrollableElement.getDomNode();\n\t\tlet element: HTMLElement | null = target as (HTMLElement | null);\n\n\t\twhile (element instanceof HTMLElement && element !== this.rowsContainer && scrollableElement.contains(element)) {\n\t\t\tconst rawIndex = element.getAttribute('data-index');\n\n\t\t\tif (rawIndex) {\n\t\t\t\tconst index = Number(rawIndex);\n\n\t\t\t\tif (!isNaN(index)) {\n\t\t\t\t\treturn index;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\telement = element.parentElement;\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\tprotected getRenderRange(renderTop: number, renderHeight: number): IRange {\n\t\treturn {\n\t\t\tstart: this.rangeMap.indexAt(renderTop),\n\t\t\tend: this.rangeMap.indexAfter(renderTop + renderHeight - 1)\n\t\t};\n\t}\n\n\t/**\n\t * Given a stable rendered state, checks every rendered element whether it needs\n\t * to be probed for dynamic height. Adjusts scroll height and top if necessary.\n\t */\n\tprotected _rerender(renderTop: number, renderHeight: number, inSmoothScrolling?: boolean): void {\n\t\tconst previousRenderRange = this.getRenderRange(renderTop, renderHeight);\n\n\t\t// Let's remember the second element's position, this helps in scrolling up\n\t\t// and preserving a linear upwards scroll movement\n\t\tlet anchorElementIndex: number | undefined;\n\t\tlet anchorElementTopDelta: number | undefined;\n\n\t\tif (renderTop === this.elementTop(previousRenderRange.start)) {\n\t\t\tanchorElementIndex = previousRenderRange.start;\n\t\t\tanchorElementTopDelta = 0;\n\t\t} else if (previousRenderRange.end - previousRenderRange.start > 1) {\n\t\t\tanchorElementIndex = previousRenderRange.start + 1;\n\t\t\tanchorElementTopDelta = this.elementTop(anchorElementIndex) - renderTop;\n\t\t}\n\n\t\tlet heightDiff = 0;\n\n\t\twhile (true) {\n\t\t\tconst renderRange = this.getRenderRange(renderTop, renderHeight);\n\n\t\t\tlet didChange = false;\n\n\t\t\tfor (let i = renderRange.start; i < renderRange.end; i++) {\n\t\t\t\tconst diff = this.probeDynamicHeight(i);\n\n\t\t\t\tif (diff !== 0) {\n\t\t\t\t\tthis.rangeMap.splice(i, 1, [this.items[i]]);\n\t\t\t\t}\n\n\t\t\t\theightDiff += diff;\n\t\t\t\tdidChange = didChange || diff !== 0;\n\t\t\t}\n\n\t\t\tif (!didChange) {\n\t\t\t\tif (heightDiff !== 0) {\n\t\t\t\t\tthis.eventuallyUpdateScrollDimensions();\n\t\t\t\t}\n\n\t\t\t\tconst unrenderRanges = Range.relativeComplement(previousRenderRange, renderRange);\n\n\t\t\t\tfor (const range of unrenderRanges) {\n\t\t\t\t\tfor (let i = range.start; i < range.end; i++) {\n\t\t\t\t\t\tif (this.items[i].row) {\n\t\t\t\t\t\t\tthis.removeItemFromDOM(i);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst renderRanges = Range.relativeComplement(renderRange, previousRenderRange).reverse();\n\n\t\t\t\tfor (const range of renderRanges) {\n\t\t\t\t\tfor (let i = range.end - 1; i >= range.start; i--) {\n\t\t\t\t\t\tthis.insertItemInDOM(i);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfor (let i = renderRange.start; i < renderRange.end; i++) {\n\t\t\t\t\tif (this.items[i].row) {\n\t\t\t\t\t\tthis.updateItemInDOM(this.items[i], i);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (typeof anchorElementIndex === 'number') {\n\t\t\t\t\t// To compute a destination scroll top, we need to take into account the current smooth scrolling\n\t\t\t\t\t// animation, and then reuse it with a new target (to avoid prolonging the scroll)\n\t\t\t\t\t// See https://github.com/microsoft/vscode/issues/104144\n\t\t\t\t\t// See https://github.com/microsoft/vscode/pull/104284\n\t\t\t\t\t// See https://github.com/microsoft/vscode/issues/107704\n\t\t\t\t\tconst deltaScrollTop = this.scrollable.getFutureScrollPosition().scrollTop - renderTop;\n\t\t\t\t\tconst newScrollTop = this.elementTop(anchorElementIndex) - anchorElementTopDelta! + deltaScrollTop;\n\t\t\t\t\tthis.setScrollTop(newScrollTop, inSmoothScrolling);\n\t\t\t\t}\n\n\t\t\t\tthis._onDidChangeContentHeight.fire(this.contentHeight);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate probeDynamicHeight(index: number): number {\n\t\tconst item = this.items[index];\n\n\t\tif (!!this.virtualDelegate.getDynamicHeight) {\n\t\t\tconst newSize = this.virtualDelegate.getDynamicHeight(item.element);\n\t\t\tif (newSize !== null) {\n\t\t\t\tconst size = item.size;\n\t\t\t\titem.size = newSize;\n\t\t\t\titem.lastDynamicHeightWidth = this.renderWidth;\n\t\t\t\treturn newSize - size;\n\t\t\t}\n\t\t}\n\n\t\tif (!item.hasDynamicHeight || item.lastDynamicHeightWidth === this.renderWidth) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tif (!!this.virtualDelegate.hasDynamicHeight && !this.virtualDelegate.hasDynamicHeight(item.element)) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tconst size = item.size;\n\n\t\tif (item.row) {\n\t\t\titem.row.domNode.style.height = '';\n\t\t\titem.size = item.row.domNode.offsetHeight;\n\t\t\tif (item.size === 0 && !isAncestor(item.row.domNode, getWindow(item.row.domNode).document.body)) {\n\t\t\t\tconsole.warn('Measuring item node that is not in DOM! Add ListView to the DOM before measuring row height!');\n\t\t\t}\n\t\t\titem.lastDynamicHeightWidth = this.renderWidth;\n\t\t\treturn item.size - size;\n\t\t}\n\n\t\tconst { row } = this.cache.alloc(item.templateId);\n\t\trow.domNode.style.height = '';\n\t\tthis.rowsContainer.appendChild(row.domNode);\n\n\t\tconst renderer = this.renderers.get(item.templateId);\n\n\t\tif (!renderer) {\n\t\t\tthrow new BugIndicatingError('Missing renderer for templateId: ' + item.templateId);\n\t\t}\n\n\t\trenderer.renderElement(item.element, index, row.templateData, undefined);\n\t\titem.size = row.domNode.offsetHeight;\n\t\trenderer.disposeElement?.(item.element, index, row.templateData, undefined);\n\n\t\tthis.virtualDelegate.setDynamicHeight?.(item.element, item.size);\n\n\t\titem.lastDynamicHeightWidth = this.renderWidth;\n\t\tthis.rowsContainer.removeChild(row.domNode);\n\t\tthis.cache.release(row);\n\n\t\treturn item.size - size;\n\t}\n\n\tgetElementDomId(index: number): string {\n\t\treturn `${this.domId}_${index}`;\n\t}\n\n\t// Dispose\n\n\tdispose() {\n\t\tfor (const item of this.items) {\n\t\t\titem.dragStartDisposable.dispose();\n\t\t\titem.checkedDisposable.dispose();\n\n\t\t\tif (item.row) {\n\t\t\t\tconst renderer = this.renderers.get(item.row.templateId);\n\t\t\t\tif (renderer) {\n\t\t\t\t\trenderer.disposeElement?.(item.element, -1, item.row.templateData, undefined);\n\t\t\t\t\trenderer.disposeTemplate(item.row.templateData);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthis.items = [];\n\n\t\tif (this.domNode && this.domNode.parentNode) {\n\t\t\tthis.domNode.parentNode.removeChild(this.domNode);\n\t\t}\n\n\t\tthis.dragOverAnimationDisposable?.dispose();\n\t\tthis.disposables.dispose();\n\t}\n}\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\nimport { IDragAndDropData } from 'vs/base/browser/dnd';\nimport { asCssValueWithDefault, createStyleSheet, EventHelper, getActiveElement, getWindow, isMouseEvent } from 'vs/base/browser/dom';\nimport { DomEmitter } from 'vs/base/browser/event';\nimport { IKeyboardEvent, StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';\nimport { Gesture } from 'vs/base/browser/touch';\nimport { alert, AriaRole } from 'vs/base/browser/ui/aria/aria';\nimport { CombinedSpliceable } from 'vs/base/browser/ui/list/splice';\nimport { binarySearch, firstOrDefault, range } from 'vs/base/common/arrays';\nimport { timeout } from 'vs/base/common/async';\nimport { Color } from 'vs/base/common/color';\nimport { memoize } from 'vs/base/common/decorators';\nimport { Emitter, Event, EventBufferer } from 'vs/base/common/event';\nimport { matchesFuzzy2, matchesPrefix } from 'vs/base/common/filters';\nimport { KeyCode } from 'vs/base/common/keyCodes';\nimport { DisposableStore, dispose, IDisposable } from 'vs/base/common/lifecycle';\nimport { clamp } from 'vs/base/common/numbers';\nimport * as platform from 'vs/base/common/platform';\nimport { ScrollbarVisibility, ScrollEvent } from 'vs/base/common/scrollable';\nimport { ISpliceable } from 'vs/base/common/sequence';\nimport { isNumber } from 'vs/base/common/types';\nimport 'vs/css!./list';\nimport { IIdentityProvider, IKeyboardNavigationDelegate, IKeyboardNavigationLabelProvider, IListContextMenuEvent, IListDragAndDrop, IListDragOverReaction, IListEvent, IListGestureEvent, IListMouseEvent, IListRenderer, IListTouchEvent, IListVirtualDelegate, ListError } from './list';\nimport { IListView, IListViewAccessibilityProvider, IListViewDragAndDrop, IListViewOptions, IListViewOptionsUpdate, ListViewTargetSector, ListView } from './listView';\nimport { StandardMouseEvent } from 'vs/base/browser/mouseEvent';\nimport { autorun, constObservable, IObservable } from 'vs/base/common/observable';\n\ninterface ITraitChangeEvent {\n\tindexes: number[];\n\tbrowserEvent?: UIEvent;\n}\n\ntype ITraitTemplateData = HTMLElement;\n\ntype IAccessibilityTemplateData = {\n\tcontainer: HTMLElement;\n\tdisposables: DisposableStore;\n};\n\ninterface IRenderedContainer {\n\ttemplateData: ITraitTemplateData;\n\tindex: number;\n}\n\nclass TraitRenderer implements IListRenderer {\n\tprivate renderedElements: IRenderedContainer[] = [];\n\n\tconstructor(private trait: Trait) { }\n\n\tget templateId(): string {\n\t\treturn `template:${this.trait.name}`;\n\t}\n\n\trenderTemplate(container: HTMLElement): ITraitTemplateData {\n\t\treturn container;\n\t}\n\n\trenderElement(element: T, index: number, templateData: ITraitTemplateData): void {\n\t\tconst renderedElementIndex = this.renderedElements.findIndex(el => el.templateData === templateData);\n\n\t\tif (renderedElementIndex >= 0) {\n\t\t\tconst rendered = this.renderedElements[renderedElementIndex];\n\t\t\tthis.trait.unrender(templateData);\n\t\t\trendered.index = index;\n\t\t} else {\n\t\t\tconst rendered = { index, templateData };\n\t\t\tthis.renderedElements.push(rendered);\n\t\t}\n\n\t\tthis.trait.renderIndex(index, templateData);\n\t}\n\n\tsplice(start: number, deleteCount: number, insertCount: number): void {\n\t\tconst rendered: IRenderedContainer[] = [];\n\n\t\tfor (const renderedElement of this.renderedElements) {\n\n\t\t\tif (renderedElement.index < start) {\n\t\t\t\trendered.push(renderedElement);\n\t\t\t} else if (renderedElement.index >= start + deleteCount) {\n\t\t\t\trendered.push({\n\t\t\t\t\tindex: renderedElement.index + insertCount - deleteCount,\n\t\t\t\t\ttemplateData: renderedElement.templateData\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tthis.renderedElements = rendered;\n\t}\n\n\trenderIndexes(indexes: number[]): void {\n\t\tfor (const { index, templateData } of this.renderedElements) {\n\t\t\tif (indexes.indexOf(index) > -1) {\n\t\t\t\tthis.trait.renderIndex(index, templateData);\n\t\t\t}\n\t\t}\n\t}\n\n\tdisposeTemplate(templateData: ITraitTemplateData): void {\n\t\tconst index = this.renderedElements.findIndex(el => el.templateData === templateData);\n\n\t\tif (index < 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.renderedElements.splice(index, 1);\n\t}\n}\n\nclass Trait implements ISpliceable, IDisposable {\n\n\tprotected indexes: number[] = [];\n\tprotected sortedIndexes: number[] = [];\n\n\tprivate readonly _onChange = new Emitter();\n\treadonly onChange: Event = this._onChange.event;\n\n\tget name(): string { return this._trait; }\n\n\t@memoize\n\tget renderer(): TraitRenderer {\n\t\treturn new TraitRenderer(this);\n\t}\n\n\tconstructor(private _trait: string) { }\n\n\tsplice(start: number, deleteCount: number, elements: boolean[]): void {\n\t\tconst diff = elements.length - deleteCount;\n\t\tconst end = start + deleteCount;\n\t\tconst sortedIndexes: number[] = [];\n\t\tlet i = 0;\n\n\t\twhile (i < this.sortedIndexes.length && this.sortedIndexes[i] < start) {\n\t\t\tsortedIndexes.push(this.sortedIndexes[i++]);\n\t\t}\n\n\t\tfor (let j = 0; j < elements.length; j++) {\n\t\t\tif (elements[j]) {\n\t\t\t\tsortedIndexes.push(j + start);\n\t\t\t}\n\t\t}\n\n\t\twhile (i < this.sortedIndexes.length && this.sortedIndexes[i] >= end) {\n\t\t\tsortedIndexes.push(this.sortedIndexes[i++] + diff);\n\t\t}\n\n\t\tthis.renderer.splice(start, deleteCount, elements.length);\n\t\tthis._set(sortedIndexes, sortedIndexes);\n\t}\n\n\trenderIndex(index: number, container: HTMLElement): void {\n\t\tcontainer.classList.toggle(this._trait, this.contains(index));\n\t}\n\n\tunrender(container: HTMLElement): void {\n\t\tcontainer.classList.remove(this._trait);\n\t}\n\n\t/**\n\t * Sets the indexes which should have this trait.\n\t *\n\t * @param indexes Indexes which should have this trait.\n\t * @return The old indexes which had this trait.\n\t */\n\tset(indexes: number[], browserEvent?: UIEvent): number[] {\n\t\treturn this._set(indexes, [...indexes].sort(numericSort), browserEvent);\n\t}\n\n\tprivate _set(indexes: number[], sortedIndexes: number[], browserEvent?: UIEvent): number[] {\n\t\tconst result = this.indexes;\n\t\tconst sortedResult = this.sortedIndexes;\n\n\t\tthis.indexes = indexes;\n\t\tthis.sortedIndexes = sortedIndexes;\n\n\t\tconst toRender = disjunction(sortedResult, indexes);\n\t\tthis.renderer.renderIndexes(toRender);\n\n\t\tthis._onChange.fire({ indexes, browserEvent });\n\t\treturn result;\n\t}\n\n\tget(): number[] {\n\t\treturn this.indexes;\n\t}\n\n\tcontains(index: number): boolean {\n\t\treturn binarySearch(this.sortedIndexes, index, numericSort) >= 0;\n\t}\n\n\tdispose() {\n\t\tdispose(this._onChange);\n\t}\n}\n\nclass SelectionTrait extends Trait {\n\n\tconstructor(private setAriaSelected: boolean) {\n\t\tsuper('selected');\n\t}\n\n\toverride renderIndex(index: number, container: HTMLElement): void {\n\t\tsuper.renderIndex(index, container);\n\n\t\tif (this.setAriaSelected) {\n\t\t\tif (this.contains(index)) {\n\t\t\t\tcontainer.setAttribute('aria-selected', 'true');\n\t\t\t} else {\n\t\t\t\tcontainer.setAttribute('aria-selected', 'false');\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * The TraitSpliceable is used as a util class to be able\n * to preserve traits across splice calls, given an identity\n * provider.\n */\nclass TraitSpliceable implements ISpliceable {\n\n\tconstructor(\n\t\tprivate trait: Trait,\n\t\tprivate view: IListView,\n\t\tprivate identityProvider?: IIdentityProvider\n\t) { }\n\n\tsplice(start: number, deleteCount: number, elements: T[]): void {\n\t\tif (!this.identityProvider) {\n\t\t\treturn this.trait.splice(start, deleteCount, new Array(elements.length).fill(false));\n\t\t}\n\n\t\tconst pastElementsWithTrait = this.trait.get().map(i => this.identityProvider!.getId(this.view.element(i)).toString());\n\t\tif (pastElementsWithTrait.length === 0) {\n\t\t\treturn this.trait.splice(start, deleteCount, new Array(elements.length).fill(false));\n\t\t}\n\n\t\tconst pastElementsWithTraitSet = new Set(pastElementsWithTrait);\n\t\tconst elementsWithTrait = elements.map(e => pastElementsWithTraitSet.has(this.identityProvider!.getId(e).toString()));\n\t\tthis.trait.splice(start, deleteCount, elementsWithTrait);\n\t}\n}\n\nexport function isInputElement(e: HTMLElement): boolean {\n\treturn e.tagName === 'INPUT' || e.tagName === 'TEXTAREA';\n}\n\nfunction isListElementDescendantOfClass(e: HTMLElement, className: string): boolean {\n\tif (e.classList.contains(className)) {\n\t\treturn true;\n\t}\n\n\tif (e.classList.contains('monaco-list')) {\n\t\treturn false;\n\t}\n\n\tif (!e.parentElement) {\n\t\treturn false;\n\t}\n\n\treturn isListElementDescendantOfClass(e.parentElement, className);\n}\n\nexport function isMonacoEditor(e: HTMLElement): boolean {\n\treturn isListElementDescendantOfClass(e, 'monaco-editor');\n}\n\nexport function isMonacoCustomToggle(e: HTMLElement): boolean {\n\treturn isListElementDescendantOfClass(e, 'monaco-custom-toggle');\n}\n\nexport function isActionItem(e: HTMLElement): boolean {\n\treturn isListElementDescendantOfClass(e, 'action-item');\n}\n\nexport function isStickyScrollElement(e: HTMLElement): boolean {\n\treturn isListElementDescendantOfClass(e, 'monaco-tree-sticky-row');\n}\n\nexport function isStickyScrollContainer(e: HTMLElement): boolean {\n\treturn e.classList.contains('monaco-tree-sticky-container');\n}\n\nexport function isButton(e: HTMLElement): boolean {\n\tif ((e.tagName === 'A' && e.classList.contains('monaco-button')) ||\n\t\t(e.tagName === 'DIV' && e.classList.contains('monaco-button-dropdown'))) {\n\t\treturn true;\n\t}\n\n\tif (e.classList.contains('monaco-list')) {\n\t\treturn false;\n\t}\n\n\tif (!e.parentElement) {\n\t\treturn false;\n\t}\n\n\treturn isButton(e.parentElement);\n}\n\nclass KeyboardController implements IDisposable {\n\n\tprivate readonly disposables = new DisposableStore();\n\tprivate readonly multipleSelectionDisposables = new DisposableStore();\n\tprivate multipleSelectionSupport: boolean | undefined;\n\n\t@memoize\n\tprivate get onKeyDown(): Event {\n\t\treturn Event.chain(\n\t\t\tthis.disposables.add(new DomEmitter(this.view.domNode, 'keydown')).event, $ =>\n\t\t\t$.filter(e => !isInputElement(e.target as HTMLElement))\n\t\t\t\t.map(e => new StandardKeyboardEvent(e))\n\t\t);\n\t}\n\n\tconstructor(\n\t\tprivate list: List,\n\t\tprivate view: IListView,\n\t\toptions: IListOptions\n\t) {\n\t\tthis.multipleSelectionSupport = options.multipleSelectionSupport;\n\t\tthis.disposables.add(this.onKeyDown(e => {\n\t\t\tswitch (e.keyCode) {\n\t\t\t\tcase KeyCode.Enter:\n\t\t\t\t\treturn this.onEnter(e);\n\t\t\t\tcase KeyCode.UpArrow:\n\t\t\t\t\treturn this.onUpArrow(e);\n\t\t\t\tcase KeyCode.DownArrow:\n\t\t\t\t\treturn this.onDownArrow(e);\n\t\t\t\tcase KeyCode.PageUp:\n\t\t\t\t\treturn this.onPageUpArrow(e);\n\t\t\t\tcase KeyCode.PageDown:\n\t\t\t\t\treturn this.onPageDownArrow(e);\n\t\t\t\tcase KeyCode.Escape:\n\t\t\t\t\treturn this.onEscape(e);\n\t\t\t\tcase KeyCode.KeyA:\n\t\t\t\t\tif (this.multipleSelectionSupport && (platform.isMacintosh ? e.metaKey : e.ctrlKey)) {\n\t\t\t\t\t\tthis.onCtrlA(e);\n\t\t\t\t\t}\n\t\t\t}\n\t\t}));\n\t}\n\n\tupdateOptions(optionsUpdate: IListOptionsUpdate): void {\n\t\tif (optionsUpdate.multipleSelectionSupport !== undefined) {\n\t\t\tthis.multipleSelectionSupport = optionsUpdate.multipleSelectionSupport;\n\t\t}\n\t}\n\n\tprivate onEnter(e: StandardKeyboardEvent): void {\n\t\te.preventDefault();\n\t\te.stopPropagation();\n\t\tthis.list.setSelection(this.list.getFocus(), e.browserEvent);\n\t}\n\n\tprivate onUpArrow(e: StandardKeyboardEvent): void {\n\t\te.preventDefault();\n\t\te.stopPropagation();\n\t\tthis.list.focusPrevious(1, false, e.browserEvent);\n\t\tconst el = this.list.getFocus()[0];\n\t\tthis.list.setAnchor(el);\n\t\tthis.list.reveal(el);\n\t\tthis.view.domNode.focus();\n\t}\n\n\tprivate onDownArrow(e: StandardKeyboardEvent): void {\n\t\te.preventDefault();\n\t\te.stopPropagation();\n\t\tthis.list.focusNext(1, false, e.browserEvent);\n\t\tconst el = this.list.getFocus()[0];\n\t\tthis.list.setAnchor(el);\n\t\tthis.list.reveal(el);\n\t\tthis.view.domNode.focus();\n\t}\n\n\tprivate onPageUpArrow(e: StandardKeyboardEvent): void {\n\t\te.preventDefault();\n\t\te.stopPropagation();\n\t\tthis.list.focusPreviousPage(e.browserEvent);\n\t\tconst el = this.list.getFocus()[0];\n\t\tthis.list.setAnchor(el);\n\t\tthis.list.reveal(el);\n\t\tthis.view.domNode.focus();\n\t}\n\n\tprivate onPageDownArrow(e: StandardKeyboardEvent): void {\n\t\te.preventDefault();\n\t\te.stopPropagation();\n\t\tthis.list.focusNextPage(e.browserEvent);\n\t\tconst el = this.list.getFocus()[0];\n\t\tthis.list.setAnchor(el);\n\t\tthis.list.reveal(el);\n\t\tthis.view.domNode.focus();\n\t}\n\n\tprivate onCtrlA(e: StandardKeyboardEvent): void {\n\t\te.preventDefault();\n\t\te.stopPropagation();\n\t\tthis.list.setSelection(range(this.list.length), e.browserEvent);\n\t\tthis.list.setAnchor(undefined);\n\t\tthis.view.domNode.focus();\n\t}\n\n\tprivate onEscape(e: StandardKeyboardEvent): void {\n\t\tif (this.list.getSelection().length) {\n\t\t\te.preventDefault();\n\t\t\te.stopPropagation();\n\t\t\tthis.list.setSelection([], e.browserEvent);\n\t\t\tthis.list.setAnchor(undefined);\n\t\t\tthis.view.domNode.focus();\n\t\t}\n\t}\n\n\tdispose() {\n\t\tthis.disposables.dispose();\n\t\tthis.multipleSelectionDisposables.dispose();\n\t}\n}\n\nexport enum TypeNavigationMode {\n\tAutomatic,\n\tTrigger\n}\n\nenum TypeNavigationControllerState {\n\tIdle,\n\tTyping\n}\n\nexport const DefaultKeyboardNavigationDelegate = new class implements IKeyboardNavigationDelegate {\n\tmightProducePrintableCharacter(event: IKeyboardEvent): boolean {\n\t\tif (event.ctrlKey || event.metaKey || event.altKey) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn (event.keyCode >= KeyCode.KeyA && event.keyCode <= KeyCode.KeyZ)\n\t\t\t|| (event.keyCode >= KeyCode.Digit0 && event.keyCode <= KeyCode.Digit9)\n\t\t\t|| (event.keyCode >= KeyCode.Numpad0 && event.keyCode <= KeyCode.Numpad9)\n\t\t\t|| (event.keyCode >= KeyCode.Semicolon && event.keyCode <= KeyCode.Quote);\n\t}\n};\n\nclass TypeNavigationController implements IDisposable {\n\n\tprivate enabled = false;\n\tprivate state: TypeNavigationControllerState = TypeNavigationControllerState.Idle;\n\n\tprivate mode = TypeNavigationMode.Automatic;\n\tprivate triggered = false;\n\tprivate previouslyFocused = -1;\n\n\tprivate readonly enabledDisposables = new DisposableStore();\n\tprivate readonly disposables = new DisposableStore();\n\n\tconstructor(\n\t\tprivate list: List,\n\t\tprivate view: IListView,\n\t\tprivate keyboardNavigationLabelProvider: IKeyboardNavigationLabelProvider,\n\t\tprivate keyboardNavigationEventFilter: IKeyboardNavigationEventFilter,\n\t\tprivate delegate: IKeyboardNavigationDelegate\n\t) {\n\t\tthis.updateOptions(list.options);\n\t}\n\n\tupdateOptions(options: IListOptions): void {\n\t\tif (options.typeNavigationEnabled ?? true) {\n\t\t\tthis.enable();\n\t\t} else {\n\t\t\tthis.disable();\n\t\t}\n\n\t\tthis.mode = options.typeNavigationMode ?? TypeNavigationMode.Automatic;\n\t}\n\n\tprivate enable(): void {\n\t\tif (this.enabled) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet typing = false;\n\n\t\tconst onChar = Event.chain(this.enabledDisposables.add(new DomEmitter(this.view.domNode, 'keydown')).event, $ =>\n\t\t\t$.filter(e => !isInputElement(e.target as HTMLElement))\n\t\t\t\t.filter(() => this.mode === TypeNavigationMode.Automatic || this.triggered)\n\t\t\t\t.map(event => new StandardKeyboardEvent(event))\n\t\t\t\t.filter(e => typing || this.keyboardNavigationEventFilter(e))\n\t\t\t\t.filter(e => this.delegate.mightProducePrintableCharacter(e))\n\t\t\t\t.forEach(e => EventHelper.stop(e, true))\n\t\t\t\t.map(event => event.browserEvent.key)\n\t\t);\n\n\t\tconst onClear = Event.debounce(onChar, () => null, 800, undefined, undefined, undefined, this.enabledDisposables);\n\t\tconst onInput = Event.reduce(Event.any(onChar, onClear), (r, i) => i === null ? null : ((r || '') + i), undefined, this.enabledDisposables);\n\n\t\tonInput(this.onInput, this, this.enabledDisposables);\n\t\tonClear(this.onClear, this, this.enabledDisposables);\n\n\t\tonChar(() => typing = true, undefined, this.enabledDisposables);\n\t\tonClear(() => typing = false, undefined, this.enabledDisposables);\n\n\t\tthis.enabled = true;\n\t\tthis.triggered = false;\n\t}\n\n\tprivate disable(): void {\n\t\tif (!this.enabled) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.enabledDisposables.clear();\n\t\tthis.enabled = false;\n\t\tthis.triggered = false;\n\t}\n\n\tprivate onClear(): void {\n\t\tconst focus = this.list.getFocus();\n\t\tif (focus.length > 0 && focus[0] === this.previouslyFocused) {\n\t\t\t// List: re-announce element on typing end since typed keys will interrupt aria label of focused element\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\n\t\t\tconst ariaLabel = this.list.options.accessibilityProvider?.getAriaLabel(this.list.element(focus[0]));\n\n\t\t\tif (typeof ariaLabel === 'string') {\n\t\t\t\talert(ariaLabel);\n\t\t\t} else if (ariaLabel) {\n\t\t\t\talert(ariaLabel.get());\n\t\t\t}\n\t\t}\n\t\tthis.previouslyFocused = -1;\n\t}\n\n\tprivate onInput(word: string | null): void {\n\t\tif (!word) {\n\t\t\tthis.state = TypeNavigationControllerState.Idle;\n\t\t\tthis.triggered = false;\n\t\t\treturn;\n\t\t}\n\n\t\tconst focus = this.list.getFocus();\n\t\tconst start = focus.length > 0 ? focus[0] : 0;\n\t\tconst delta = this.state === TypeNavigationControllerState.Idle ? 1 : 0;\n\t\tthis.state = TypeNavigationControllerState.Typing;\n\n\t\tfor (let i = 0; i < this.list.length; i++) {\n\t\t\tconst index = (start + i + delta) % this.list.length;\n\t\t\tconst label = this.keyboardNavigationLabelProvider.getKeyboardNavigationLabel(this.view.element(index));\n\t\t\tconst labelStr = label && label.toString();\n\n\t\t\tif (this.list.options.typeNavigationEnabled) {\n\t\t\t\tif (typeof labelStr !== 'undefined') {\n\n\t\t\t\t\t// If prefix is found, focus and return early\n\t\t\t\t\tif (matchesPrefix(word, labelStr)) {\n\t\t\t\t\t\tthis.previouslyFocused = start;\n\t\t\t\t\t\tthis.list.setFocus([index]);\n\t\t\t\t\t\tthis.list.reveal(index);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst fuzzy = matchesFuzzy2(word, labelStr);\n\n\t\t\t\t\tif (fuzzy) {\n\t\t\t\t\t\tconst fuzzyScore = fuzzy[0].end - fuzzy[0].start;\n\t\t\t\t\t\t// ensures that when fuzzy matching, doesn't clash with prefix matching (1 input vs 1+ should be prefix and fuzzy respecitvely). Also makes sure that exact matches are prioritized.\n\t\t\t\t\t\tif (fuzzyScore > 1 && fuzzy.length === 1) {\n\t\t\t\t\t\t\tthis.previouslyFocused = start;\n\t\t\t\t\t\t\tthis.list.setFocus([index]);\n\t\t\t\t\t\t\tthis.list.reveal(index);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (typeof labelStr === 'undefined' || matchesPrefix(word, labelStr)) {\n\t\t\t\tthis.previouslyFocused = start;\n\t\t\t\tthis.list.setFocus([index]);\n\t\t\t\tthis.list.reveal(index);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\tdispose() {\n\t\tthis.disable();\n\t\tthis.enabledDisposables.dispose();\n\t\tthis.disposables.dispose();\n\t}\n}\n\nclass DOMFocusController implements IDisposable {\n\n\tprivate readonly disposables = new DisposableStore();\n\n\tconstructor(\n\t\tprivate list: List,\n\t\tprivate view: IListView\n\t) {\n\t\tconst onKeyDown = Event.chain(this.disposables.add(new DomEmitter(view.domNode, 'keydown')).event, $ => $\n\t\t\t.filter(e => !isInputElement(e.target as HTMLElement))\n\t\t\t.map(e => new StandardKeyboardEvent(e))\n\t\t);\n\n\t\tconst onTab = Event.chain(onKeyDown, $ => $.filter(e => e.keyCode === KeyCode.Tab && !e.ctrlKey && !e.metaKey && !e.shiftKey && !e.altKey));\n\n\t\tonTab(this.onTab, this, this.disposables);\n\t}\n\n\tprivate onTab(e: StandardKeyboardEvent): void {\n\t\tif (e.target !== this.view.domNode) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst focus = this.list.getFocus();\n\n\t\tif (focus.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst focusedDomElement = this.view.domElement(focus[0]);\n\n\t\tif (!focusedDomElement) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst tabIndexElement = focusedDomElement.querySelector('[tabIndex]');\n\n\t\tif (!tabIndexElement || !(tabIndexElement instanceof HTMLElement) || tabIndexElement.tabIndex === -1) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst style = getWindow(tabIndexElement).getComputedStyle(tabIndexElement);\n\t\tif (style.visibility === 'hidden' || style.display === 'none') {\n\t\t\treturn;\n\t\t}\n\n\t\te.preventDefault();\n\t\te.stopPropagation();\n\t\ttabIndexElement.focus();\n\t}\n\n\tdispose() {\n\t\tthis.disposables.dispose();\n\t}\n}\n\nexport function isSelectionSingleChangeEvent(event: IListMouseEvent | IListTouchEvent): boolean {\n\treturn platform.isMacintosh ? event.browserEvent.metaKey : event.browserEvent.ctrlKey;\n}\n\nexport function isSelectionRangeChangeEvent(event: IListMouseEvent | IListTouchEvent): boolean {\n\treturn event.browserEvent.shiftKey;\n}\n\nfunction isMouseRightClick(event: UIEvent): boolean {\n\treturn isMouseEvent(event) && event.button === 2;\n}\n\nconst DefaultMultipleSelectionController = {\n\tisSelectionSingleChangeEvent,\n\tisSelectionRangeChangeEvent\n};\n\nexport class MouseController implements IDisposable {\n\n\tprivate multipleSelectionController: IMultipleSelectionController | undefined;\n\tprivate mouseSupport: boolean;\n\tprivate readonly disposables = new DisposableStore();\n\n\tprivate _onPointer = new Emitter>();\n\treadonly onPointer: Event> = this._onPointer.event;\n\n\tconstructor(protected list: List) {\n\t\tif (list.options.multipleSelectionSupport !== false) {\n\t\t\tthis.multipleSelectionController = this.list.options.multipleSelectionController || DefaultMultipleSelectionController;\n\t\t}\n\n\t\tthis.mouseSupport = typeof list.options.mouseSupport === 'undefined' || !!list.options.mouseSupport;\n\n\t\tif (this.mouseSupport) {\n\t\t\tlist.onMouseDown(this.onMouseDown, this, this.disposables);\n\t\t\tlist.onContextMenu(this.onContextMenu, this, this.disposables);\n\t\t\tlist.onMouseDblClick(this.onDoubleClick, this, this.disposables);\n\t\t\tlist.onTouchStart(this.onMouseDown, this, this.disposables);\n\t\t\tthis.disposables.add(Gesture.addTarget(list.getHTMLElement()));\n\t\t}\n\n\t\tEvent.any | IListGestureEvent>(list.onMouseClick, list.onMouseMiddleClick, list.onTap)(this.onViewPointer, this, this.disposables);\n\t}\n\n\tupdateOptions(optionsUpdate: IListOptionsUpdate): void {\n\t\tif (optionsUpdate.multipleSelectionSupport !== undefined) {\n\t\t\tthis.multipleSelectionController = undefined;\n\n\t\t\tif (optionsUpdate.multipleSelectionSupport) {\n\t\t\t\tthis.multipleSelectionController = this.list.options.multipleSelectionController || DefaultMultipleSelectionController;\n\t\t\t}\n\t\t}\n\t}\n\n\tprotected isSelectionSingleChangeEvent(event: IListMouseEvent | IListTouchEvent): boolean {\n\t\tif (!this.multipleSelectionController) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn this.multipleSelectionController.isSelectionSingleChangeEvent(event);\n\t}\n\n\tprotected isSelectionRangeChangeEvent(event: IListMouseEvent | IListTouchEvent): boolean {\n\t\tif (!this.multipleSelectionController) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn this.multipleSelectionController.isSelectionRangeChangeEvent(event);\n\t}\n\n\tprivate isSelectionChangeEvent(event: IListMouseEvent | IListTouchEvent): boolean {\n\t\treturn this.isSelectionSingleChangeEvent(event) || this.isSelectionRangeChangeEvent(event);\n\t}\n\n\tprotected onMouseDown(e: IListMouseEvent | IListTouchEvent): void {\n\t\tif (isMonacoEditor(e.browserEvent.target as HTMLElement)) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (getActiveElement() !== e.browserEvent.target) {\n\t\t\tthis.list.domFocus();\n\t\t}\n\t}\n\n\tprotected onContextMenu(e: IListContextMenuEvent): void {\n\t\tif (isInputElement(e.browserEvent.target as HTMLElement) || isMonacoEditor(e.browserEvent.target as HTMLElement)) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst focus = typeof e.index === 'undefined' ? [] : [e.index];\n\t\tthis.list.setFocus(focus, e.browserEvent);\n\t}\n\n\tprotected onViewPointer(e: IListMouseEvent): void {\n\t\tif (!this.mouseSupport) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (isInputElement(e.browserEvent.target as HTMLElement) || isMonacoEditor(e.browserEvent.target as HTMLElement)) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (e.browserEvent.isHandledByList) {\n\t\t\treturn;\n\t\t}\n\n\t\te.browserEvent.isHandledByList = true;\n\t\tconst focus = e.index;\n\n\t\tif (typeof focus === 'undefined') {\n\t\t\tthis.list.setFocus([], e.browserEvent);\n\t\t\tthis.list.setSelection([], e.browserEvent);\n\t\t\tthis.list.setAnchor(undefined);\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.isSelectionChangeEvent(e)) {\n\t\t\treturn this.changeSelection(e);\n\t\t}\n\n\t\tthis.list.setFocus([focus], e.browserEvent);\n\t\tthis.list.setAnchor(focus);\n\n\t\tif (!isMouseRightClick(e.browserEvent)) {\n\t\t\tthis.list.setSelection([focus], e.browserEvent);\n\t\t}\n\n\t\tthis._onPointer.fire(e);\n\t}\n\n\tprotected onDoubleClick(e: IListMouseEvent): void {\n\t\tif (isInputElement(e.browserEvent.target as HTMLElement) || isMonacoEditor(e.browserEvent.target as HTMLElement)) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.isSelectionChangeEvent(e)) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (e.browserEvent.isHandledByList) {\n\t\t\treturn;\n\t\t}\n\n\t\te.browserEvent.isHandledByList = true;\n\t\tconst focus = this.list.getFocus();\n\t\tthis.list.setSelection(focus, e.browserEvent);\n\t}\n\n\tprivate changeSelection(e: IListMouseEvent | IListTouchEvent): void {\n\t\tconst focus = e.index!;\n\t\tlet anchor = this.list.getAnchor();\n\n\t\tif (this.isSelectionRangeChangeEvent(e)) {\n\t\t\tif (typeof anchor === 'undefined') {\n\t\t\t\tconst currentFocus = this.list.getFocus()[0];\n\t\t\t\tanchor = currentFocus ?? focus;\n\t\t\t\tthis.list.setAnchor(anchor);\n\t\t\t}\n\n\t\t\tconst min = Math.min(anchor, focus);\n\t\t\tconst max = Math.max(anchor, focus);\n\t\t\tconst rangeSelection = range(min, max + 1);\n\t\t\tconst selection = this.list.getSelection();\n\t\t\tconst contiguousRange = getContiguousRangeContaining(disjunction(selection, [anchor]), anchor);\n\n\t\t\tif (contiguousRange.length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst newSelection = disjunction(rangeSelection, relativeComplement(selection, contiguousRange));\n\t\t\tthis.list.setSelection(newSelection, e.browserEvent);\n\t\t\tthis.list.setFocus([focus], e.browserEvent);\n\n\t\t} else if (this.isSelectionSingleChangeEvent(e)) {\n\t\t\tconst selection = this.list.getSelection();\n\t\t\tconst newSelection = selection.filter(i => i !== focus);\n\n\t\t\tthis.list.setFocus([focus]);\n\t\t\tthis.list.setAnchor(focus);\n\n\t\t\tif (selection.length === newSelection.length) {\n\t\t\t\tthis.list.setSelection([...newSelection, focus], e.browserEvent);\n\t\t\t} else {\n\t\t\t\tthis.list.setSelection(newSelection, e.browserEvent);\n\t\t\t}\n\t\t}\n\t}\n\n\tdispose() {\n\t\tthis.disposables.dispose();\n\t}\n}\n\nexport interface IMultipleSelectionController {\n\tisSelectionSingleChangeEvent(event: IListMouseEvent | IListTouchEvent): boolean;\n\tisSelectionRangeChangeEvent(event: IListMouseEvent | IListTouchEvent): boolean;\n}\n\nexport interface IStyleController {\n\tstyle(styles: IListStyles): void;\n}\n\nexport interface IListAccessibilityProvider extends IListViewAccessibilityProvider {\n\tgetAriaLabel(element: T): string | IObservable | null;\n\tgetWidgetAriaLabel(): string;\n\tgetWidgetRole?(): AriaRole;\n\tgetAriaLevel?(element: T): number | undefined;\n\tonDidChangeActiveDescendant?: Event;\n\tgetActiveDescendantId?(element: T): string | undefined;\n}\n\nexport class DefaultStyleController implements IStyleController {\n\n\tconstructor(private styleElement: HTMLStyleElement, private selectorSuffix: string) { }\n\n\tstyle(styles: IListStyles): void {\n\t\tconst suffix = this.selectorSuffix && `.${this.selectorSuffix}`;\n\t\tconst content: string[] = [];\n\n\t\tif (styles.listBackground) {\n\t\t\tcontent.push(`.monaco-list${suffix} .monaco-list-rows { background: ${styles.listBackground}; }`);\n\t\t}\n\n\t\tif (styles.listFocusBackground) {\n\t\t\tcontent.push(`.monaco-list${suffix}:focus .monaco-list-row.focused { background-color: ${styles.listFocusBackground}; }`);\n\t\t\tcontent.push(`.monaco-list${suffix}:focus .monaco-list-row.focused:hover { background-color: ${styles.listFocusBackground}; }`); // overwrite :hover style in this case!\n\t\t}\n\n\t\tif (styles.listFocusForeground) {\n\t\t\tcontent.push(`.monaco-list${suffix}:focus .monaco-list-row.focused { color: ${styles.listFocusForeground}; }`);\n\t\t}\n\n\t\tif (styles.listActiveSelectionBackground) {\n\t\t\tcontent.push(`.monaco-list${suffix}:focus .monaco-list-row.selected { background-color: ${styles.listActiveSelectionBackground}; }`);\n\t\t\tcontent.push(`.monaco-list${suffix}:focus .monaco-list-row.selected:hover { background-color: ${styles.listActiveSelectionBackground}; }`); // overwrite :hover style in this case!\n\t\t}\n\n\t\tif (styles.listActiveSelectionForeground) {\n\t\t\tcontent.push(`.monaco-list${suffix}:focus .monaco-list-row.selected { color: ${styles.listActiveSelectionForeground}; }`);\n\t\t}\n\n\t\tif (styles.listActiveSelectionIconForeground) {\n\t\t\tcontent.push(`.monaco-list${suffix}:focus .monaco-list-row.selected .codicon { color: ${styles.listActiveSelectionIconForeground}; }`);\n\t\t}\n\n\t\tif (styles.listFocusAndSelectionBackground) {\n\t\t\tcontent.push(`\n\t\t\t\t.monaco-drag-image,\n\t\t\t\t.monaco-list${suffix}:focus .monaco-list-row.selected.focused { background-color: ${styles.listFocusAndSelectionBackground}; }\n\t\t\t`);\n\t\t}\n\n\t\tif (styles.listFocusAndSelectionForeground) {\n\t\t\tcontent.push(`\n\t\t\t\t.monaco-drag-image,\n\t\t\t\t.monaco-list${suffix}:focus .monaco-list-row.selected.focused { color: ${styles.listFocusAndSelectionForeground}; }\n\t\t\t`);\n\t\t}\n\n\t\tif (styles.listInactiveFocusForeground) {\n\t\t\tcontent.push(`.monaco-list${suffix} .monaco-list-row.focused { color: ${styles.listInactiveFocusForeground}; }`);\n\t\t\tcontent.push(`.monaco-list${suffix} .monaco-list-row.focused:hover { color: ${styles.listInactiveFocusForeground}; }`); // overwrite :hover style in this case!\n\t\t}\n\n\t\tif (styles.listInactiveSelectionIconForeground) {\n\t\t\tcontent.push(`.monaco-list${suffix} .monaco-list-row.focused .codicon { color: ${styles.listInactiveSelectionIconForeground}; }`);\n\t\t}\n\n\t\tif (styles.listInactiveFocusBackground) {\n\t\t\tcontent.push(`.monaco-list${suffix} .monaco-list-row.focused { background-color: ${styles.listInactiveFocusBackground}; }`);\n\t\t\tcontent.push(`.monaco-list${suffix} .monaco-list-row.focused:hover { background-color: ${styles.listInactiveFocusBackground}; }`); // overwrite :hover style in this case!\n\t\t}\n\n\t\tif (styles.listInactiveSelectionBackground) {\n\t\t\tcontent.push(`.monaco-list${suffix} .monaco-list-row.selected { background-color: ${styles.listInactiveSelectionBackground}; }`);\n\t\t\tcontent.push(`.monaco-list${suffix} .monaco-list-row.selected:hover { background-color: ${styles.listInactiveSelectionBackground}; }`); // overwrite :hover style in this case!\n\t\t}\n\n\t\tif (styles.listInactiveSelectionForeground) {\n\t\t\tcontent.push(`.monaco-list${suffix} .monaco-list-row.selected { color: ${styles.listInactiveSelectionForeground}; }`);\n\t\t}\n\n\t\tif (styles.listHoverBackground) {\n\t\t\tcontent.push(`.monaco-list${suffix}:not(.drop-target):not(.dragging) .monaco-list-row:hover:not(.selected):not(.focused) { background-color: ${styles.listHoverBackground}; }`);\n\t\t}\n\n\t\tif (styles.listHoverForeground) {\n\t\t\tcontent.push(`.monaco-list${suffix}:not(.drop-target):not(.dragging) .monaco-list-row:hover:not(.selected):not(.focused) { color: ${styles.listHoverForeground}; }`);\n\t\t}\n\n\t\t/**\n\t\t * Outlines\n\t\t */\n\t\tconst focusAndSelectionOutline = asCssValueWithDefault(styles.listFocusAndSelectionOutline, asCssValueWithDefault(styles.listSelectionOutline, styles.listFocusOutline ?? ''));\n\t\tif (focusAndSelectionOutline) { // default: listFocusOutline\n\t\t\tcontent.push(`.monaco-list${suffix}:focus .monaco-list-row.focused.selected { outline: 1px solid ${focusAndSelectionOutline}; outline-offset: -1px;}`);\n\t\t}\n\n\t\tif (styles.listFocusOutline) { // default: set\n\t\t\tcontent.push(`\n\t\t\t\t.monaco-drag-image,\n\t\t\t\t.monaco-list${suffix}:focus .monaco-list-row.focused { outline: 1px solid ${styles.listFocusOutline}; outline-offset: -1px; }\n\t\t\t\t.monaco-workbench.context-menu-visible .monaco-list${suffix}.last-focused .monaco-list-row.focused { outline: 1px solid ${styles.listFocusOutline}; outline-offset: -1px; }\n\t\t\t`);\n\t\t}\n\n\t\tconst inactiveFocusAndSelectionOutline = asCssValueWithDefault(styles.listSelectionOutline, styles.listInactiveFocusOutline ?? '');\n\t\tif (inactiveFocusAndSelectionOutline) {\n\t\t\tcontent.push(`.monaco-list${suffix} .monaco-list-row.focused.selected { outline: 1px dotted ${inactiveFocusAndSelectionOutline}; outline-offset: -1px; }`);\n\t\t}\n\n\t\tif (styles.listSelectionOutline) { // default: activeContrastBorder\n\t\t\tcontent.push(`.monaco-list${suffix} .monaco-list-row.selected { outline: 1px dotted ${styles.listSelectionOutline}; outline-offset: -1px; }`);\n\t\t}\n\n\t\tif (styles.listInactiveFocusOutline) { // default: null\n\t\t\tcontent.push(`.monaco-list${suffix} .monaco-list-row.focused { outline: 1px dotted ${styles.listInactiveFocusOutline}; outline-offset: -1px; }`);\n\t\t}\n\n\t\tif (styles.listHoverOutline) { // default: activeContrastBorder\n\t\t\tcontent.push(`.monaco-list${suffix} .monaco-list-row:hover { outline: 1px dashed ${styles.listHoverOutline}; outline-offset: -1px; }`);\n\t\t}\n\n\t\tif (styles.listDropOverBackground) {\n\t\t\tcontent.push(`\n\t\t\t\t.monaco-list${suffix}.drop-target,\n\t\t\t\t.monaco-list${suffix} .monaco-list-rows.drop-target,\n\t\t\t\t.monaco-list${suffix} .monaco-list-row.drop-target { background-color: ${styles.listDropOverBackground} !important; color: inherit !important; }\n\t\t\t`);\n\t\t}\n\n\t\tif (styles.listDropBetweenBackground) {\n\t\t\tcontent.push(`\n\t\t\t.monaco-list${suffix} .monaco-list-rows.drop-target-before .monaco-list-row:first-child::before,\n\t\t\t.monaco-list${suffix} .monaco-list-row.drop-target-before::before {\n\t\t\t\tcontent: \"\"; position: absolute; top: 0px; left: 0px; width: 100%; height: 1px;\n\t\t\t\tbackground-color: ${styles.listDropBetweenBackground};\n\t\t\t}`);\n\t\t\tcontent.push(`\n\t\t\t.monaco-list${suffix} .monaco-list-rows.drop-target-after .monaco-list-row:last-child::after,\n\t\t\t.monaco-list${suffix} .monaco-list-row.drop-target-after::after {\n\t\t\t\tcontent: \"\"; position: absolute; bottom: 0px; left: 0px; width: 100%; height: 1px;\n\t\t\t\tbackground-color: ${styles.listDropBetweenBackground};\n\t\t\t}`);\n\t\t}\n\n\t\tif (styles.tableColumnsBorder) {\n\t\t\tcontent.push(`\n\t\t\t\t.monaco-table > .monaco-split-view2,\n\t\t\t\t.monaco-table > .monaco-split-view2 .monaco-sash.vertical::before,\n\t\t\t\t.monaco-workbench:not(.reduce-motion) .monaco-table:hover > .monaco-split-view2,\n\t\t\t\t.monaco-workbench:not(.reduce-motion) .monaco-table:hover > .monaco-split-view2 .monaco-sash.vertical::before {\n\t\t\t\t\tborder-color: ${styles.tableColumnsBorder};\n\t\t\t\t}\n\n\t\t\t\t.monaco-workbench:not(.reduce-motion) .monaco-table > .monaco-split-view2,\n\t\t\t\t.monaco-workbench:not(.reduce-motion) .monaco-table > .monaco-split-view2 .monaco-sash.vertical::before {\n\t\t\t\t\tborder-color: transparent;\n\t\t\t\t}\n\t\t\t`);\n\t\t}\n\n\t\tif (styles.tableOddRowsBackgroundColor) {\n\t\t\tcontent.push(`\n\t\t\t\t.monaco-table .monaco-list-row[data-parity=odd]:not(.focused):not(.selected):not(:hover) .monaco-table-tr,\n\t\t\t\t.monaco-table .monaco-list:not(:focus) .monaco-list-row[data-parity=odd].focused:not(.selected):not(:hover) .monaco-table-tr,\n\t\t\t\t.monaco-table .monaco-list:not(.focused) .monaco-list-row[data-parity=odd].focused:not(.selected):not(:hover) .monaco-table-tr {\n\t\t\t\t\tbackground-color: ${styles.tableOddRowsBackgroundColor};\n\t\t\t\t}\n\t\t\t`);\n\t\t}\n\n\t\tthis.styleElement.textContent = content.join('\\n');\n\t}\n}\n\nexport interface IKeyboardNavigationEventFilter {\n\t(e: StandardKeyboardEvent): boolean;\n}\n\nexport interface IListOptionsUpdate extends IListViewOptionsUpdate {\n\treadonly typeNavigationEnabled?: boolean;\n\treadonly typeNavigationMode?: TypeNavigationMode;\n\treadonly multipleSelectionSupport?: boolean;\n}\n\nexport interface IListOptions extends IListOptionsUpdate {\n\treadonly identityProvider?: IIdentityProvider;\n\treadonly dnd?: IListDragAndDrop;\n\treadonly keyboardNavigationLabelProvider?: IKeyboardNavigationLabelProvider;\n\treadonly keyboardNavigationDelegate?: IKeyboardNavigationDelegate;\n\treadonly keyboardSupport?: boolean;\n\treadonly multipleSelectionController?: IMultipleSelectionController;\n\treadonly styleController?: (suffix: string) => IStyleController;\n\treadonly accessibilityProvider?: IListAccessibilityProvider;\n\treadonly keyboardNavigationEventFilter?: IKeyboardNavigationEventFilter;\n\n\t// list view options\n\treadonly useShadows?: boolean;\n\treadonly verticalScrollMode?: ScrollbarVisibility;\n\treadonly setRowLineHeight?: boolean;\n\treadonly setRowHeight?: boolean;\n\treadonly mouseSupport?: boolean;\n\treadonly horizontalScrolling?: boolean;\n\treadonly scrollByPage?: boolean;\n\treadonly smoothScrolling?: boolean;\n\treadonly alwaysConsumeMouseWheel?: boolean;\n}\n\nexport interface IListStyles {\n\tlistBackground: string | undefined;\n\tlistFocusBackground: string | undefined;\n\tlistFocusForeground: string | undefined;\n\tlistActiveSelectionBackground: string | undefined;\n\tlistActiveSelectionForeground: string | undefined;\n\tlistActiveSelectionIconForeground: string | undefined;\n\tlistFocusAndSelectionOutline: string | undefined;\n\tlistFocusAndSelectionBackground: string | undefined;\n\tlistFocusAndSelectionForeground: string | undefined;\n\tlistInactiveSelectionBackground: string | undefined;\n\tlistInactiveSelectionIconForeground: string | undefined;\n\tlistInactiveSelectionForeground: string | undefined;\n\tlistInactiveFocusForeground: string | undefined;\n\tlistInactiveFocusBackground: string | undefined;\n\tlistHoverBackground: string | undefined;\n\tlistHoverForeground: string | undefined;\n\tlistDropOverBackground: string | undefined;\n\tlistDropBetweenBackground: string | undefined;\n\tlistFocusOutline: string | undefined;\n\tlistInactiveFocusOutline: string | undefined;\n\tlistSelectionOutline: string | undefined;\n\tlistHoverOutline: string | undefined;\n\ttreeIndentGuidesStroke: string | undefined;\n\ttreeInactiveIndentGuidesStroke: string | undefined;\n\ttreeStickyScrollBackground: string | undefined;\n\ttreeStickyScrollBorder: string | undefined;\n\ttreeStickyScrollShadow: string | undefined;\n\ttableColumnsBorder: string | undefined;\n\ttableOddRowsBackgroundColor: string | undefined;\n}\n\nexport const unthemedListStyles: IListStyles = {\n\tlistFocusBackground: '#7FB0D0',\n\tlistActiveSelectionBackground: '#0E639C',\n\tlistActiveSelectionForeground: '#FFFFFF',\n\tlistActiveSelectionIconForeground: '#FFFFFF',\n\tlistFocusAndSelectionOutline: '#90C2F9',\n\tlistFocusAndSelectionBackground: '#094771',\n\tlistFocusAndSelectionForeground: '#FFFFFF',\n\tlistInactiveSelectionBackground: '#3F3F46',\n\tlistInactiveSelectionIconForeground: '#FFFFFF',\n\tlistHoverBackground: '#2A2D2E',\n\tlistDropOverBackground: '#383B3D',\n\tlistDropBetweenBackground: '#EEEEEE',\n\ttreeIndentGuidesStroke: '#a9a9a9',\n\ttreeInactiveIndentGuidesStroke: Color.fromHex('#a9a9a9').transparent(0.4).toString(),\n\ttableColumnsBorder: Color.fromHex('#cccccc').transparent(0.2).toString(),\n\ttableOddRowsBackgroundColor: Color.fromHex('#cccccc').transparent(0.04).toString(),\n\tlistBackground: undefined,\n\tlistFocusForeground: undefined,\n\tlistInactiveSelectionForeground: undefined,\n\tlistInactiveFocusForeground: undefined,\n\tlistInactiveFocusBackground: undefined,\n\tlistHoverForeground: undefined,\n\tlistFocusOutline: undefined,\n\tlistInactiveFocusOutline: undefined,\n\tlistSelectionOutline: undefined,\n\tlistHoverOutline: undefined,\n\ttreeStickyScrollBackground: undefined,\n\ttreeStickyScrollBorder: undefined,\n\ttreeStickyScrollShadow: undefined\n};\n\nconst DefaultOptions: IListOptions = {\n\tkeyboardSupport: true,\n\tmouseSupport: true,\n\tmultipleSelectionSupport: true,\n\tdnd: {\n\t\tgetDragURI() { return null; },\n\t\tonDragStart(): void { },\n\t\tonDragOver() { return false; },\n\t\tdrop() { },\n\t\tdispose() { }\n\t}\n};\n\n// TODO@Joao: move these utils into a SortedArray class\n\nfunction getContiguousRangeContaining(range: number[], value: number): number[] {\n\tconst index = range.indexOf(value);\n\n\tif (index === -1) {\n\t\treturn [];\n\t}\n\n\tconst result: number[] = [];\n\tlet i = index - 1;\n\twhile (i >= 0 && range[i] === value - (index - i)) {\n\t\tresult.push(range[i--]);\n\t}\n\n\tresult.reverse();\n\ti = index;\n\twhile (i < range.length && range[i] === value + (i - index)) {\n\t\tresult.push(range[i++]);\n\t}\n\n\treturn result;\n}\n\n/**\n * Given two sorted collections of numbers, returns the intersection\n * between them (OR).\n */\nfunction disjunction(one: number[], other: number[]): number[] {\n\tconst result: number[] = [];\n\tlet i = 0, j = 0;\n\n\twhile (i < one.length || j < other.length) {\n\t\tif (i >= one.length) {\n\t\t\tresult.push(other[j++]);\n\t\t} else if (j >= other.length) {\n\t\t\tresult.push(one[i++]);\n\t\t} else if (one[i] === other[j]) {\n\t\t\tresult.push(one[i]);\n\t\t\ti++;\n\t\t\tj++;\n\t\t\tcontinue;\n\t\t} else if (one[i] < other[j]) {\n\t\t\tresult.push(one[i++]);\n\t\t} else {\n\t\t\tresult.push(other[j++]);\n\t\t}\n\t}\n\n\treturn result;\n}\n\n/**\n * Given two sorted collections of numbers, returns the relative\n * complement between them (XOR).\n */\nfunction relativeComplement(one: number[], other: number[]): number[] {\n\tconst result: number[] = [];\n\tlet i = 0, j = 0;\n\n\twhile (i < one.length || j < other.length) {\n\t\tif (i >= one.length) {\n\t\t\tresult.push(other[j++]);\n\t\t} else if (j >= other.length) {\n\t\t\tresult.push(one[i++]);\n\t\t} else if (one[i] === other[j]) {\n\t\t\ti++;\n\t\t\tj++;\n\t\t\tcontinue;\n\t\t} else if (one[i] < other[j]) {\n\t\t\tresult.push(one[i++]);\n\t\t} else {\n\t\t\tj++;\n\t\t}\n\t}\n\n\treturn result;\n}\n\nconst numericSort = (a: number, b: number) => a - b;\n\nclass PipelineRenderer implements IListRenderer {\n\n\tconstructor(\n\t\tprivate _templateId: string,\n\t\tprivate renderers: IListRenderer[]\n\t) { }\n\n\tget templateId(): string {\n\t\treturn this._templateId;\n\t}\n\n\trenderTemplate(container: HTMLElement): any[] {\n\t\treturn this.renderers.map(r => r.renderTemplate(container));\n\t}\n\n\trenderElement(element: T, index: number, templateData: any[], height: number | undefined): void {\n\t\tlet i = 0;\n\n\t\tfor (const renderer of this.renderers) {\n\t\t\trenderer.renderElement(element, index, templateData[i++], height);\n\t\t}\n\t}\n\n\tdisposeElement(element: T, index: number, templateData: any[], height: number | undefined): void {\n\t\tlet i = 0;\n\n\t\tfor (const renderer of this.renderers) {\n\t\t\trenderer.disposeElement?.(element, index, templateData[i], height);\n\n\t\t\ti += 1;\n\t\t}\n\t}\n\n\tdisposeTemplate(templateData: any[]): void {\n\t\tlet i = 0;\n\n\t\tfor (const renderer of this.renderers) {\n\t\t\trenderer.disposeTemplate(templateData[i++]);\n\t\t}\n\t}\n}\n\nclass AccessibiltyRenderer implements IListRenderer {\n\n\ttemplateId: string = 'a18n';\n\n\tconstructor(private accessibilityProvider: IListAccessibilityProvider) { }\n\n\trenderTemplate(container: HTMLElement): IAccessibilityTemplateData {\n\t\treturn { container, disposables: new DisposableStore() };\n\t}\n\n\trenderElement(element: T, index: number, data: IAccessibilityTemplateData): void {\n\t\tconst ariaLabel = this.accessibilityProvider.getAriaLabel(element);\n\t\tconst observable = (ariaLabel && typeof ariaLabel !== 'string') ? ariaLabel : constObservable(ariaLabel);\n\n\t\tdata.disposables.add(autorun(reader => {\n\t\t\tthis.setAriaLabel(reader.readObservable(observable), data.container);\n\t\t}));\n\n\t\tconst ariaLevel = this.accessibilityProvider.getAriaLevel && this.accessibilityProvider.getAriaLevel(element);\n\n\t\tif (typeof ariaLevel === 'number') {\n\t\t\tdata.container.setAttribute('aria-level', `${ariaLevel}`);\n\t\t} else {\n\t\t\tdata.container.removeAttribute('aria-level');\n\t\t}\n\t}\n\n\tprivate setAriaLabel(ariaLabel: string | null, element: HTMLElement): void {\n\t\tif (ariaLabel) {\n\t\t\telement.setAttribute('aria-label', ariaLabel);\n\t\t} else {\n\t\t\telement.removeAttribute('aria-label');\n\t\t}\n\t}\n\n\tdisposeElement(element: T, index: number, templateData: IAccessibilityTemplateData, height: number | undefined): void {\n\t\ttemplateData.disposables.clear();\n\t}\n\n\tdisposeTemplate(templateData: any): void {\n\t\ttemplateData.disposables.dispose();\n\t}\n}\n\nclass ListViewDragAndDrop implements IListViewDragAndDrop {\n\n\tconstructor(private list: List, private dnd: IListDragAndDrop) { }\n\n\tgetDragElements(element: T): T[] {\n\t\tconst selection = this.list.getSelectedElements();\n\t\tconst elements = selection.indexOf(element) > -1 ? selection : [element];\n\t\treturn elements;\n\t}\n\n\tgetDragURI(element: T): string | null {\n\t\treturn this.dnd.getDragURI(element);\n\t}\n\n\tgetDragLabel?(elements: T[], originalEvent: DragEvent): string | undefined {\n\t\tif (this.dnd.getDragLabel) {\n\t\t\treturn this.dnd.getDragLabel(elements, originalEvent);\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\tonDragStart(data: IDragAndDropData, originalEvent: DragEvent): void {\n\t\tthis.dnd.onDragStart?.(data, originalEvent);\n\t}\n\n\tonDragOver(data: IDragAndDropData, targetElement: T, targetIndex: number, targetSector: ListViewTargetSector | undefined, originalEvent: DragEvent): boolean | IListDragOverReaction {\n\t\treturn this.dnd.onDragOver(data, targetElement, targetIndex, targetSector, originalEvent);\n\t}\n\n\tonDragLeave(data: IDragAndDropData, targetElement: T, targetIndex: number, originalEvent: DragEvent): void {\n\t\tthis.dnd.onDragLeave?.(data, targetElement, targetIndex, originalEvent);\n\t}\n\n\tonDragEnd(originalEvent: DragEvent): void {\n\t\tthis.dnd.onDragEnd?.(originalEvent);\n\t}\n\n\tdrop(data: IDragAndDropData, targetElement: T, targetIndex: number, targetSector: ListViewTargetSector | undefined, originalEvent: DragEvent): void {\n\t\tthis.dnd.drop(data, targetElement, targetIndex, targetSector, originalEvent);\n\t}\n\n\tdispose(): void {\n\t\tthis.dnd.dispose();\n\t}\n}\n\n/**\n * The {@link List} is a virtual scrolling widget, built on top of the {@link ListView}\n * widget.\n *\n * Features:\n * - Customizable keyboard and mouse support\n * - Element traits: focus, selection, achor\n * - Accessibility support\n * - Touch support\n * - Performant template-based rendering\n * - Horizontal scrolling\n * - Variable element height support\n * - Dynamic element height support\n * - Drag-and-drop support\n */\nexport class List implements ISpliceable, IDisposable {\n\n\tprivate focus = new Trait('focused');\n\tprivate selection: Trait;\n\tprivate anchor = new Trait('anchor');\n\tprivate eventBufferer = new EventBufferer();\n\tprotected view: IListView;\n\tprivate spliceable: ISpliceable;\n\tprivate styleController: IStyleController;\n\tprivate typeNavigationController?: TypeNavigationController;\n\tprivate accessibilityProvider?: IListAccessibilityProvider;\n\tprivate keyboardController: KeyboardController | undefined;\n\tprivate mouseController: MouseController;\n\tprivate _ariaLabel: string = '';\n\n\tprotected readonly disposables = new DisposableStore();\n\n\t@memoize get onDidChangeFocus(): Event> {\n\t\treturn Event.map(this.eventBufferer.wrapEvent(this.focus.onChange), e => this.toListEvent(e), this.disposables);\n\t}\n\n\t@memoize get onDidChangeSelection(): Event> {\n\t\treturn Event.map(this.eventBufferer.wrapEvent(this.selection.onChange), e => this.toListEvent(e), this.disposables);\n\t}\n\n\tget domId(): string { return this.view.domId; }\n\tget onDidScroll(): Event { return this.view.onDidScroll; }\n\tget onMouseClick(): Event> { return this.view.onMouseClick; }\n\tget onMouseDblClick(): Event> { return this.view.onMouseDblClick; }\n\tget onMouseMiddleClick(): Event> { return this.view.onMouseMiddleClick; }\n\tget onPointer(): Event> { return this.mouseController.onPointer; }\n\tget onMouseDown(): Event> { return this.view.onMouseDown; }\n\tget onMouseOver(): Event> { return this.view.onMouseOver; }\n\tget onMouseOut(): Event> { return this.view.onMouseOut; }\n\tget onTouchStart(): Event> { return this.view.onTouchStart; }\n\tget onTap(): Event> { return this.view.onTap; }\n\n\t/**\n\t * Possible context menu trigger events:\n\t * - ContextMenu key\n\t * - Shift F10\n\t * - Ctrl Option Shift M (macOS with VoiceOver)\n\t * - Mouse right click\n\t */\n\t@memoize get onContextMenu(): Event> {\n\t\tlet didJustPressContextMenuKey = false;\n\n\t\tconst fromKeyDown: Event = Event.chain(this.disposables.add(new DomEmitter(this.view.domNode, 'keydown')).event, $ =>\n\t\t\t$.map(e => new StandardKeyboardEvent(e))\n\t\t\t\t.filter(e => didJustPressContextMenuKey = e.keyCode === KeyCode.ContextMenu || (e.shiftKey && e.keyCode === KeyCode.F10))\n\t\t\t\t.map(e => EventHelper.stop(e, true))\n\t\t\t\t.filter(() => false));\n\n\t\tconst fromKeyUp = Event.chain(this.disposables.add(new DomEmitter(this.view.domNode, 'keyup')).event, $ =>\n\t\t\t$.forEach(() => didJustPressContextMenuKey = false)\n\t\t\t\t.map(e => new StandardKeyboardEvent(e))\n\t\t\t\t.filter(e => e.keyCode === KeyCode.ContextMenu || (e.shiftKey && e.keyCode === KeyCode.F10))\n\t\t\t\t.map(e => EventHelper.stop(e, true))\n\t\t\t\t.map(({ browserEvent }) => {\n\t\t\t\t\tconst focus = this.getFocus();\n\t\t\t\t\tconst index = focus.length ? focus[0] : undefined;\n\t\t\t\t\tconst element = typeof index !== 'undefined' ? this.view.element(index) : undefined;\n\t\t\t\t\tconst anchor = typeof index !== 'undefined' ? this.view.domElement(index) as HTMLElement : this.view.domNode;\n\t\t\t\t\treturn { index, element, anchor, browserEvent };\n\t\t\t\t}));\n\n\t\tconst fromMouse = Event.chain(this.view.onContextMenu, $ =>\n\t\t\t$.filter(_ => !didJustPressContextMenuKey)\n\t\t\t\t.map(({ element, index, browserEvent }) => ({ element, index, anchor: new StandardMouseEvent(getWindow(this.view.domNode), browserEvent), browserEvent }))\n\t\t);\n\n\t\treturn Event.any>(fromKeyDown, fromKeyUp, fromMouse);\n\t}\n\n\t@memoize get onKeyDown(): Event { return this.disposables.add(new DomEmitter(this.view.domNode, 'keydown')).event; }\n\n\t@memoize get onDidFocus(): Event { return Event.signal(this.disposables.add(new DomEmitter(this.view.domNode, 'focus', true)).event); }\n\t@memoize get onDidBlur(): Event { return Event.signal(this.disposables.add(new DomEmitter(this.view.domNode, 'blur', true)).event); }\n\n\tprivate readonly _onDidDispose = new Emitter();\n\treadonly onDidDispose: Event = this._onDidDispose.event;\n\n\tconstructor(\n\t\tprivate user: string,\n\t\tcontainer: HTMLElement,\n\t\tvirtualDelegate: IListVirtualDelegate,\n\t\trenderers: IListRenderer[],\n\t\tprivate _options: IListOptions = DefaultOptions\n\t) {\n\t\tconst role = this._options.accessibilityProvider && this._options.accessibilityProvider.getWidgetRole ? this._options.accessibilityProvider?.getWidgetRole() : 'list';\n\t\tthis.selection = new SelectionTrait(role !== 'listbox');\n\n\t\tconst baseRenderers: IListRenderer[] = [this.focus.renderer, this.selection.renderer];\n\n\t\tthis.accessibilityProvider = _options.accessibilityProvider;\n\n\t\tif (this.accessibilityProvider) {\n\t\t\tbaseRenderers.push(new AccessibiltyRenderer(this.accessibilityProvider));\n\n\t\t\tthis.accessibilityProvider.onDidChangeActiveDescendant?.(this.onDidChangeActiveDescendant, this, this.disposables);\n\t\t}\n\n\t\trenderers = renderers.map(r => new PipelineRenderer(r.templateId, [...baseRenderers, r]));\n\n\t\tconst viewOptions: IListViewOptions = {\n\t\t\t..._options,\n\t\t\tdnd: _options.dnd && new ListViewDragAndDrop(this, _options.dnd)\n\t\t};\n\n\t\tthis.view = this.createListView(container, virtualDelegate, renderers, viewOptions);\n\t\tthis.view.domNode.setAttribute('role', role);\n\n\t\tif (_options.styleController) {\n\t\t\tthis.styleController = _options.styleController(this.view.domId);\n\t\t} else {\n\t\t\tconst styleElement = createStyleSheet(this.view.domNode);\n\t\t\tthis.styleController = new DefaultStyleController(styleElement, this.view.domId);\n\t\t}\n\n\t\tthis.spliceable = new CombinedSpliceable([\n\t\t\tnew TraitSpliceable(this.focus, this.view, _options.identityProvider),\n\t\t\tnew TraitSpliceable(this.selection, this.view, _options.identityProvider),\n\t\t\tnew TraitSpliceable(this.anchor, this.view, _options.identityProvider),\n\t\t\tthis.view\n\t\t]);\n\n\t\tthis.disposables.add(this.focus);\n\t\tthis.disposables.add(this.selection);\n\t\tthis.disposables.add(this.anchor);\n\t\tthis.disposables.add(this.view);\n\t\tthis.disposables.add(this._onDidDispose);\n\n\t\tthis.disposables.add(new DOMFocusController(this, this.view));\n\n\t\tif (typeof _options.keyboardSupport !== 'boolean' || _options.keyboardSupport) {\n\t\t\tthis.keyboardController = new KeyboardController(this, this.view, _options);\n\t\t\tthis.disposables.add(this.keyboardController);\n\t\t}\n\n\t\tif (_options.keyboardNavigationLabelProvider) {\n\t\t\tconst delegate = _options.keyboardNavigationDelegate || DefaultKeyboardNavigationDelegate;\n\t\t\tthis.typeNavigationController = new TypeNavigationController(this, this.view, _options.keyboardNavigationLabelProvider, _options.keyboardNavigationEventFilter ?? (() => true), delegate);\n\t\t\tthis.disposables.add(this.typeNavigationController);\n\t\t}\n\n\t\tthis.mouseController = this.createMouseController(_options);\n\t\tthis.disposables.add(this.mouseController);\n\n\t\tthis.onDidChangeFocus(this._onFocusChange, this, this.disposables);\n\t\tthis.onDidChangeSelection(this._onSelectionChange, this, this.disposables);\n\n\t\tif (this.accessibilityProvider) {\n\t\t\tthis.ariaLabel = this.accessibilityProvider.getWidgetAriaLabel();\n\t\t}\n\n\t\tif (this._options.multipleSelectionSupport !== false) {\n\t\t\tthis.view.domNode.setAttribute('aria-multiselectable', 'true');\n\t\t}\n\t}\n\n\tprotected createListView(container: HTMLElement, virtualDelegate: IListVirtualDelegate, renderers: IListRenderer[], viewOptions: IListViewOptions): IListView {\n\t\treturn new ListView(container, virtualDelegate, renderers, viewOptions);\n\t}\n\n\tprotected createMouseController(options: IListOptions): MouseController {\n\t\treturn new MouseController(this);\n\t}\n\n\tupdateOptions(optionsUpdate: IListOptionsUpdate = {}): void {\n\t\tthis._options = { ...this._options, ...optionsUpdate };\n\n\t\tthis.typeNavigationController?.updateOptions(this._options);\n\n\t\tif (this._options.multipleSelectionController !== undefined) {\n\t\t\tif (this._options.multipleSelectionSupport) {\n\t\t\t\tthis.view.domNode.setAttribute('aria-multiselectable', 'true');\n\t\t\t} else {\n\t\t\t\tthis.view.domNode.removeAttribute('aria-multiselectable');\n\t\t\t}\n\t\t}\n\n\t\tthis.mouseController.updateOptions(optionsUpdate);\n\t\tthis.keyboardController?.updateOptions(optionsUpdate);\n\t\tthis.view.updateOptions(optionsUpdate);\n\t}\n\n\tget options(): IListOptions {\n\t\treturn this._options;\n\t}\n\n\tsplice(start: number, deleteCount: number, elements: readonly T[] = []): void {\n\t\tif (start < 0 || start > this.view.length) {\n\t\t\tthrow new ListError(this.user, `Invalid start index: ${start}`);\n\t\t}\n\n\t\tif (deleteCount < 0) {\n\t\t\tthrow new ListError(this.user, `Invalid delete count: ${deleteCount}`);\n\t\t}\n\n\t\tif (deleteCount === 0 && elements.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.eventBufferer.bufferEvents(() => this.spliceable.splice(start, deleteCount, elements));\n\t}\n\n\trerender(): void {\n\t\tthis.view.rerender();\n\t}\n\n\telement(index: number): T {\n\t\treturn this.view.element(index);\n\t}\n\n\tindexOf(element: T): number {\n\t\treturn this.view.indexOf(element);\n\t}\n\n\tindexAt(position: number): number {\n\t\treturn this.view.indexAt(position);\n\t}\n\n\tget length(): number {\n\t\treturn this.view.length;\n\t}\n\n\tget contentHeight(): number {\n\t\treturn this.view.contentHeight;\n\t}\n\n\tget onDidChangeContentHeight(): Event {\n\t\treturn this.view.onDidChangeContentHeight;\n\t}\n\n\tget scrollTop(): number {\n\t\treturn this.view.getScrollTop();\n\t}\n\n\tset scrollTop(scrollTop: number) {\n\t\tthis.view.setScrollTop(scrollTop);\n\t}\n\n\tget scrollHeight(): number {\n\t\treturn this.view.scrollHeight;\n\t}\n\n\tget renderHeight(): number {\n\t\treturn this.view.renderHeight;\n\t}\n\n\tget firstVisibleIndex(): number {\n\t\treturn this.view.firstVisibleIndex;\n\t}\n\n\tget ariaLabel(): string {\n\t\treturn this._ariaLabel;\n\t}\n\n\tset ariaLabel(value: string) {\n\t\tthis._ariaLabel = value;\n\t\tthis.view.domNode.setAttribute('aria-label', value);\n\t}\n\n\tdomFocus(): void {\n\t\tthis.view.domNode.focus({ preventScroll: true });\n\t}\n\n\tlayout(height?: number, width?: number): void {\n\t\tthis.view.layout(height, width);\n\t}\n\n\tsetSelection(indexes: number[], browserEvent?: UIEvent): void {\n\t\tfor (const index of indexes) {\n\t\t\tif (index < 0 || index >= this.length) {\n\t\t\t\tthrow new ListError(this.user, `Invalid index ${index}`);\n\t\t\t}\n\t\t}\n\n\t\tthis.selection.set(indexes, browserEvent);\n\t}\n\n\tgetSelection(): number[] {\n\t\treturn this.selection.get();\n\t}\n\n\tgetSelectedElements(): T[] {\n\t\treturn this.getSelection().map(i => this.view.element(i));\n\t}\n\n\tsetAnchor(index: number | undefined): void {\n\t\tif (typeof index === 'undefined') {\n\t\t\tthis.anchor.set([]);\n\t\t\treturn;\n\t\t}\n\n\t\tif (index < 0 || index >= this.length) {\n\t\t\tthrow new ListError(this.user, `Invalid index ${index}`);\n\t\t}\n\n\t\tthis.anchor.set([index]);\n\t}\n\n\tgetAnchor(): number | undefined {\n\t\treturn firstOrDefault(this.anchor.get(), undefined);\n\t}\n\n\tgetAnchorElement(): T | undefined {\n\t\tconst anchor = this.getAnchor();\n\t\treturn typeof anchor === 'undefined' ? undefined : this.element(anchor);\n\t}\n\n\tsetFocus(indexes: number[], browserEvent?: UIEvent): void {\n\t\tfor (const index of indexes) {\n\t\t\tif (index < 0 || index >= this.length) {\n\t\t\t\tthrow new ListError(this.user, `Invalid index ${index}`);\n\t\t\t}\n\t\t}\n\n\t\tthis.focus.set(indexes, browserEvent);\n\t}\n\n\tfocusNext(n = 1, loop = false, browserEvent?: UIEvent, filter?: (element: T) => boolean): void {\n\t\tif (this.length === 0) { return; }\n\n\t\tconst focus = this.focus.get();\n\t\tconst index = this.findNextIndex(focus.length > 0 ? focus[0] + n : 0, loop, filter);\n\n\t\tif (index > -1) {\n\t\t\tthis.setFocus([index], browserEvent);\n\t\t}\n\t}\n\n\tfocusPrevious(n = 1, loop = false, browserEvent?: UIEvent, filter?: (element: T) => boolean): void {\n\t\tif (this.length === 0) { return; }\n\n\t\tconst focus = this.focus.get();\n\t\tconst index = this.findPreviousIndex(focus.length > 0 ? focus[0] - n : 0, loop, filter);\n\n\t\tif (index > -1) {\n\t\t\tthis.setFocus([index], browserEvent);\n\t\t}\n\t}\n\n\tasync focusNextPage(browserEvent?: UIEvent, filter?: (element: T) => boolean): Promise {\n\t\tlet lastPageIndex = this.view.indexAt(this.view.getScrollTop() + this.view.renderHeight);\n\t\tlastPageIndex = lastPageIndex === 0 ? 0 : lastPageIndex - 1;\n\t\tconst currentlyFocusedElementIndex = this.getFocus()[0];\n\n\t\tif (currentlyFocusedElementIndex !== lastPageIndex && (currentlyFocusedElementIndex === undefined || lastPageIndex > currentlyFocusedElementIndex)) {\n\t\t\tconst lastGoodPageIndex = this.findPreviousIndex(lastPageIndex, false, filter);\n\n\t\t\tif (lastGoodPageIndex > -1 && currentlyFocusedElementIndex !== lastGoodPageIndex) {\n\t\t\t\tthis.setFocus([lastGoodPageIndex], browserEvent);\n\t\t\t} else {\n\t\t\t\tthis.setFocus([lastPageIndex], browserEvent);\n\t\t\t}\n\t\t} else {\n\t\t\tconst previousScrollTop = this.view.getScrollTop();\n\t\t\tlet nextpageScrollTop = previousScrollTop + this.view.renderHeight;\n\t\t\tif (lastPageIndex > currentlyFocusedElementIndex) {\n\t\t\t\t// scroll last page element to the top only if the last page element is below the focused element\n\t\t\t\tnextpageScrollTop -= this.view.elementHeight(lastPageIndex);\n\t\t\t}\n\n\t\t\tthis.view.setScrollTop(nextpageScrollTop);\n\n\t\t\tif (this.view.getScrollTop() !== previousScrollTop) {\n\t\t\t\tthis.setFocus([]);\n\n\t\t\t\t// Let the scroll event listener run\n\t\t\t\tawait timeout(0);\n\t\t\t\tawait this.focusNextPage(browserEvent, filter);\n\t\t\t}\n\t\t}\n\t}\n\n\tasync focusPreviousPage(browserEvent?: UIEvent, filter?: (element: T) => boolean, getPaddingTop: () => number = () => 0): Promise {\n\t\tlet firstPageIndex: number;\n\t\tconst paddingTop = getPaddingTop();\n\t\tconst scrollTop = this.view.getScrollTop() + paddingTop;\n\n\t\tif (scrollTop === 0) {\n\t\t\tfirstPageIndex = this.view.indexAt(scrollTop);\n\t\t} else {\n\t\t\tfirstPageIndex = this.view.indexAfter(scrollTop - 1);\n\t\t}\n\n\t\tconst currentlyFocusedElementIndex = this.getFocus()[0];\n\n\t\tif (currentlyFocusedElementIndex !== firstPageIndex && (currentlyFocusedElementIndex === undefined || currentlyFocusedElementIndex >= firstPageIndex)) {\n\t\t\tconst firstGoodPageIndex = this.findNextIndex(firstPageIndex, false, filter);\n\n\t\t\tif (firstGoodPageIndex > -1 && currentlyFocusedElementIndex !== firstGoodPageIndex) {\n\t\t\t\tthis.setFocus([firstGoodPageIndex], browserEvent);\n\t\t\t} else {\n\t\t\t\tthis.setFocus([firstPageIndex], browserEvent);\n\t\t\t}\n\t\t} else {\n\t\t\tconst previousScrollTop = scrollTop;\n\t\t\tthis.view.setScrollTop(scrollTop - this.view.renderHeight - paddingTop);\n\n\t\t\tif (this.view.getScrollTop() + getPaddingTop() !== previousScrollTop) {\n\t\t\t\tthis.setFocus([]);\n\n\t\t\t\t// Let the scroll event listener run\n\t\t\t\tawait timeout(0);\n\t\t\t\tawait this.focusPreviousPage(browserEvent, filter, getPaddingTop);\n\t\t\t}\n\t\t}\n\t}\n\n\tfocusLast(browserEvent?: UIEvent, filter?: (element: T) => boolean): void {\n\t\tif (this.length === 0) { return; }\n\n\t\tconst index = this.findPreviousIndex(this.length - 1, false, filter);\n\n\t\tif (index > -1) {\n\t\t\tthis.setFocus([index], browserEvent);\n\t\t}\n\t}\n\n\tfocusFirst(browserEvent?: UIEvent, filter?: (element: T) => boolean): void {\n\t\tthis.focusNth(0, browserEvent, filter);\n\t}\n\n\tfocusNth(n: number, browserEvent?: UIEvent, filter?: (element: T) => boolean): void {\n\t\tif (this.length === 0) { return; }\n\n\t\tconst index = this.findNextIndex(n, false, filter);\n\n\t\tif (index > -1) {\n\t\t\tthis.setFocus([index], browserEvent);\n\t\t}\n\t}\n\n\tprivate findNextIndex(index: number, loop = false, filter?: (element: T) => boolean): number {\n\t\tfor (let i = 0; i < this.length; i++) {\n\t\t\tif (index >= this.length && !loop) {\n\t\t\t\treturn -1;\n\t\t\t}\n\n\t\t\tindex = index % this.length;\n\n\t\t\tif (!filter || filter(this.element(index))) {\n\t\t\t\treturn index;\n\t\t\t}\n\n\t\t\tindex++;\n\t\t}\n\n\t\treturn -1;\n\t}\n\n\tprivate findPreviousIndex(index: number, loop = false, filter?: (element: T) => boolean): number {\n\t\tfor (let i = 0; i < this.length; i++) {\n\t\t\tif (index < 0 && !loop) {\n\t\t\t\treturn -1;\n\t\t\t}\n\n\t\t\tindex = (this.length + (index % this.length)) % this.length;\n\n\t\t\tif (!filter || filter(this.element(index))) {\n\t\t\t\treturn index;\n\t\t\t}\n\n\t\t\tindex--;\n\t\t}\n\n\t\treturn -1;\n\t}\n\n\tgetFocus(): number[] {\n\t\treturn this.focus.get();\n\t}\n\n\tgetFocusedElements(): T[] {\n\t\treturn this.getFocus().map(i => this.view.element(i));\n\t}\n\n\treveal(index: number, relativeTop?: number, paddingTop: number = 0): void {\n\t\tif (index < 0 || index >= this.length) {\n\t\t\tthrow new ListError(this.user, `Invalid index ${index}`);\n\t\t}\n\n\t\tconst scrollTop = this.view.getScrollTop();\n\t\tconst elementTop = this.view.elementTop(index);\n\t\tconst elementHeight = this.view.elementHeight(index);\n\n\t\tif (isNumber(relativeTop)) {\n\t\t\t// y = mx + b\n\t\t\tconst m = elementHeight - this.view.renderHeight + paddingTop;\n\t\t\tthis.view.setScrollTop(m * clamp(relativeTop, 0, 1) + elementTop - paddingTop);\n\t\t} else {\n\t\t\tconst viewItemBottom = elementTop + elementHeight;\n\t\t\tconst scrollBottom = scrollTop + this.view.renderHeight;\n\n\t\t\tif (elementTop < scrollTop + paddingTop && viewItemBottom >= scrollBottom) {\n\t\t\t\t// The element is already overflowing the viewport, no-op\n\t\t\t} else if (elementTop < scrollTop + paddingTop || (viewItemBottom >= scrollBottom && elementHeight >= this.view.renderHeight)) {\n\t\t\t\tthis.view.setScrollTop(elementTop - paddingTop);\n\t\t\t} else if (viewItemBottom >= scrollBottom) {\n\t\t\t\tthis.view.setScrollTop(viewItemBottom - this.view.renderHeight);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Returns the relative position of an element rendered in the list.\n\t * Returns `null` if the element isn't *entirely* in the visible viewport.\n\t */\n\tgetRelativeTop(index: number, paddingTop: number = 0): number | null {\n\t\tif (index < 0 || index >= this.length) {\n\t\t\tthrow new ListError(this.user, `Invalid index ${index}`);\n\t\t}\n\n\t\tconst scrollTop = this.view.getScrollTop();\n\t\tconst elementTop = this.view.elementTop(index);\n\t\tconst elementHeight = this.view.elementHeight(index);\n\n\t\tif (elementTop < scrollTop + paddingTop || elementTop + elementHeight > scrollTop + this.view.renderHeight) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// y = mx + b\n\t\tconst m = elementHeight - this.view.renderHeight + paddingTop;\n\t\treturn Math.abs((scrollTop + paddingTop - elementTop) / m);\n\t}\n\n\tgetHTMLElement(): HTMLElement {\n\t\treturn this.view.domNode;\n\t}\n\n\tgetScrollableElement(): HTMLElement {\n\t\treturn this.view.scrollableElementDomNode;\n\t}\n\n\tgetElementID(index: number): string {\n\t\treturn this.view.getElementDomId(index);\n\t}\n\n\tgetElementTop(index: number): number {\n\t\treturn this.view.elementTop(index);\n\t}\n\n\tstyle(styles: IListStyles): void {\n\t\tthis.styleController.style(styles);\n\t}\n\n\tprivate toListEvent({ indexes, browserEvent }: ITraitChangeEvent) {\n\t\treturn { indexes, elements: indexes.map(i => this.view.element(i)), browserEvent };\n\t}\n\n\tprivate _onFocusChange(): void {\n\t\tconst focus = this.focus.get();\n\t\tthis.view.domNode.classList.toggle('element-focused', focus.length > 0);\n\t\tthis.onDidChangeActiveDescendant();\n\t}\n\n\tprivate onDidChangeActiveDescendant(): void {\n\t\tconst focus = this.focus.get();\n\n\t\tif (focus.length > 0) {\n\t\t\tlet id: string | undefined;\n\n\t\t\tif (this.accessibilityProvider?.getActiveDescendantId) {\n\t\t\t\tid = this.accessibilityProvider.getActiveDescendantId(this.view.element(focus[0]));\n\t\t\t}\n\n\t\t\tthis.view.domNode.setAttribute('aria-activedescendant', id || this.view.getElementDomId(focus[0]));\n\t\t} else {\n\t\t\tthis.view.domNode.removeAttribute('aria-activedescendant');\n\t\t}\n\t}\n\n\tprivate _onSelectionChange(): void {\n\t\tconst selection = this.selection.get();\n\n\t\tthis.view.domNode.classList.toggle('selection-none', selection.length === 0);\n\t\tthis.view.domNode.classList.toggle('selection-single', selection.length === 1);\n\t\tthis.view.domNode.classList.toggle('selection-multiple', selection.length > 1);\n\t}\n\n\tdispose(): void {\n\t\tthis._onDidDispose.fire();\n\t\tthis.disposables.dispose();\n\n\t\tthis._onDidDispose.dispose();\n\t}\n}\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\nimport { range } from 'vs/base/common/arrays';\nimport { CancellationTokenSource } from 'vs/base/common/cancellation';\nimport { Event } from 'vs/base/common/event';\nimport { Disposable, IDisposable } from 'vs/base/common/lifecycle';\nimport { IPagedModel } from 'vs/base/common/paging';\nimport 'vs/css!./list';\nimport { IListEvent, IListMouseEvent, IListRenderer, IListVirtualDelegate } from './list';\nimport { IListAccessibilityProvider, IListOptions, IListOptionsUpdate, IListStyles, List } from './listWidget';\n\nexport interface IPagedRenderer extends IListRenderer {\n\trenderPlaceholder(index: number, templateData: TTemplateData): void;\n}\n\nexport interface ITemplateData {\n\tdata?: T;\n\tdisposable?: IDisposable;\n}\n\nclass PagedRenderer implements IListRenderer> {\n\n\tget templateId(): string { return this.renderer.templateId; }\n\n\tconstructor(\n\t\tprivate renderer: IPagedRenderer,\n\t\tprivate modelProvider: () => IPagedModel\n\t) { }\n\n\trenderTemplate(container: HTMLElement): ITemplateData {\n\t\tconst data = this.renderer.renderTemplate(container);\n\t\treturn { data, disposable: Disposable.None };\n\t}\n\n\trenderElement(index: number, _: number, data: ITemplateData, height: number | undefined): void {\n\t\tdata.disposable?.dispose();\n\n\t\tif (!data.data) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst model = this.modelProvider();\n\n\t\tif (model.isResolved(index)) {\n\t\t\treturn this.renderer.renderElement(model.get(index), index, data.data, height);\n\t\t}\n\n\t\tconst cts = new CancellationTokenSource();\n\t\tconst promise = model.resolve(index, cts.token);\n\t\tdata.disposable = { dispose: () => cts.cancel() };\n\n\t\tthis.renderer.renderPlaceholder(index, data.data);\n\t\tpromise.then(entry => this.renderer.renderElement(entry, index, data.data!, height));\n\t}\n\n\tdisposeTemplate(data: ITemplateData): void {\n\t\tif (data.disposable) {\n\t\t\tdata.disposable.dispose();\n\t\t\tdata.disposable = undefined;\n\t\t}\n\t\tif (data.data) {\n\t\t\tthis.renderer.disposeTemplate(data.data);\n\t\t\tdata.data = undefined;\n\t\t}\n\t}\n}\n\nclass PagedAccessibilityProvider implements IListAccessibilityProvider {\n\n\tconstructor(\n\t\tprivate modelProvider: () => IPagedModel,\n\t\tprivate accessibilityProvider: IListAccessibilityProvider\n\t) { }\n\n\tgetWidgetAriaLabel(): string {\n\t\treturn this.accessibilityProvider.getWidgetAriaLabel();\n\t}\n\n\tgetAriaLabel(index: number) {\n\t\tconst model = this.modelProvider();\n\n\t\tif (!model.isResolved(index)) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn this.accessibilityProvider.getAriaLabel(model.get(index));\n\t}\n}\n\nexport interface IPagedListOptions {\n\treadonly keyboardSupport?: boolean;\n\treadonly accessibilityProvider?: IListAccessibilityProvider;\n\treadonly horizontalScrolling?: boolean;\n}\n\nfunction fromPagedListOptions(modelProvider: () => IPagedModel, options: IPagedListOptions): IListOptions {\n\treturn {\n\t\t...options,\n\t\taccessibilityProvider: options.accessibilityProvider && new PagedAccessibilityProvider(modelProvider, options.accessibilityProvider)\n\t};\n}\n\nexport class PagedList implements IDisposable {\n\n\tprivate list: List;\n\tprivate _model!: IPagedModel;\n\n\tconstructor(\n\t\tuser: string,\n\t\tcontainer: HTMLElement,\n\t\tvirtualDelegate: IListVirtualDelegate,\n\t\trenderers: IPagedRenderer[],\n\t\toptions: IPagedListOptions = {}\n\t) {\n\t\tconst modelProvider = () => this.model;\n\t\tconst pagedRenderers = renderers.map(r => new PagedRenderer>(r, modelProvider));\n\t\tthis.list = new List(user, container, virtualDelegate, pagedRenderers, fromPagedListOptions(modelProvider, options));\n\t}\n\n\tupdateOptions(options: IListOptionsUpdate) {\n\t\tthis.list.updateOptions(options);\n\t}\n\n\tgetHTMLElement(): HTMLElement {\n\t\treturn this.list.getHTMLElement();\n\t}\n\n\tget onDidFocus(): Event {\n\t\treturn this.list.onDidFocus;\n\t}\n\n\tget widget(): List {\n\t\treturn this.list;\n\t}\n\n\tget onDidDispose(): Event {\n\t\treturn this.list.onDidDispose;\n\t}\n\n\tget onMouseDblClick(): Event> {\n\t\treturn Event.map(this.list.onMouseDblClick, ({ element, index, browserEvent }) => ({ element: element === undefined ? undefined : this._model.get(element), index, browserEvent }));\n\t}\n\n\tget onPointer(): Event> {\n\t\treturn Event.map(this.list.onPointer, ({ element, index, browserEvent }) => ({ element: element === undefined ? undefined : this._model.get(element), index, browserEvent }));\n\t}\n\n\tget onDidChangeSelection(): Event> {\n\t\treturn Event.map(this.list.onDidChangeSelection, ({ elements, indexes, browserEvent }) => ({ elements: elements.map(e => this._model.get(e)), indexes, browserEvent }));\n\t}\n\n\tget model(): IPagedModel {\n\t\treturn this._model;\n\t}\n\n\tset model(model: IPagedModel) {\n\t\tthis._model = model;\n\t\tthis.list.splice(0, this.list.length, range(model.length));\n\t}\n\n\tgetFocus(): number[] {\n\t\treturn this.list.getFocus();\n\t}\n\n\tgetSelection(): number[] {\n\t\treturn this.list.getSelection();\n\t}\n\n\tgetSelectedElements(): T[] {\n\t\treturn this.getSelection().map(i => this.model.get(i));\n\t}\n\n\tstyle(styles: IListStyles): void {\n\t\tthis.list.style(styles);\n\t}\n\n\tdispose(): void {\n\t\tthis.list.dispose();\n\t}\n}\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\nimport { $, addDisposableListener, append, getWindow, scheduleAtNextAnimationFrame } from 'vs/base/browser/dom';\nimport { DomEmitter } from 'vs/base/browser/event';\nimport { ISashEvent as IBaseSashEvent, Orientation, Sash, SashState } from 'vs/base/browser/ui/sash/sash';\nimport { SmoothScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';\nimport { pushToEnd, pushToStart, range } from 'vs/base/common/arrays';\nimport { Color } from 'vs/base/common/color';\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { combinedDisposable, Disposable, dispose, IDisposable, toDisposable } from 'vs/base/common/lifecycle';\nimport { clamp } from 'vs/base/common/numbers';\nimport { Scrollable, ScrollbarVisibility, ScrollEvent } from 'vs/base/common/scrollable';\nimport * as types from 'vs/base/common/types';\nimport 'vs/css!./splitview';\nexport { Orientation } from 'vs/base/browser/ui/sash/sash';\n\nexport interface ISplitViewStyles {\n\treadonly separatorBorder: Color;\n}\n\nconst defaultStyles: ISplitViewStyles = {\n\tseparatorBorder: Color.transparent\n};\n\nexport const enum LayoutPriority {\n\tNormal,\n\tLow,\n\tHigh\n}\n\n/**\n * The interface to implement for views within a {@link SplitView}.\n *\n * An optional {@link TLayoutContext layout context type} may be used in order to\n * pass along layout contextual data from the {@link SplitView.layout} method down\n * to each view's {@link IView.layout} calls.\n */\nexport interface IView {\n\n\t/**\n\t * The DOM element for this view.\n\t */\n\treadonly element: HTMLElement;\n\n\t/**\n\t * A minimum size for this view.\n\t *\n\t * @remarks If none, set it to `0`.\n\t */\n\treadonly minimumSize: number;\n\n\t/**\n\t * A maximum size for this view.\n\t *\n\t * @remarks If none, set it to `Number.POSITIVE_INFINITY`.\n\t */\n\treadonly maximumSize: number;\n\n\t/**\n\t * The priority of the view when the {@link SplitView.resize layout} algorithm\n\t * runs. Views with higher priority will be resized first.\n\t *\n\t * @remarks Only used when `proportionalLayout` is false.\n\t */\n\treadonly priority?: LayoutPriority;\n\n\t/**\n\t * If the {@link SplitView} supports {@link ISplitViewOptions.proportionalLayout proportional layout},\n\t * this property allows for finer control over the proportional layout algorithm, per view.\n\t *\n\t * @defaultValue `true`\n\t */\n\treadonly proportionalLayout?: boolean;\n\n\t/**\n\t * Whether the view will snap whenever the user reaches its minimum size or\n\t * attempts to grow it beyond the minimum size.\n\t *\n\t * @defaultValue `false`\n\t */\n\treadonly snap?: boolean;\n\n\t/**\n\t * View instances are supposed to fire the {@link IView.onDidChange} event whenever\n\t * any of the constraint properties have changed:\n\t *\n\t * - {@link IView.minimumSize}\n\t * - {@link IView.maximumSize}\n\t * - {@link IView.priority}\n\t * - {@link IView.snap}\n\t *\n\t * The SplitView will relayout whenever that happens. The event can optionally emit\n\t * the view's preferred size for that relayout.\n\t */\n\treadonly onDidChange: Event;\n\n\t/**\n\t * This will be called by the {@link SplitView} during layout. A view meant to\n\t * pass along the layout information down to its descendants.\n\t *\n\t * @param size The size of this view, in pixels.\n\t * @param offset The offset of this view, relative to the start of the {@link SplitView}.\n\t * @param context The optional {@link IView layout context} passed to {@link SplitView.layout}.\n\t */\n\tlayout(size: number, offset: number, context: TLayoutContext | undefined): void;\n\n\t/**\n\t * This will be called by the {@link SplitView} whenever this view is made\n\t * visible or hidden.\n\t *\n\t * @param visible Whether the view becomes visible.\n\t */\n\tsetVisible?(visible: boolean): void;\n}\n\n/**\n * A descriptor for a {@link SplitView} instance.\n */\nexport interface ISplitViewDescriptor = IView> {\n\n\t/**\n\t * The layout size of the {@link SplitView}.\n\t */\n\treadonly size: number;\n\n\t/**\n\t * Descriptors for each {@link IView view}.\n\t */\n\treadonly views: {\n\n\t\t/**\n\t\t * Whether the {@link IView view} is visible.\n\t\t *\n\t\t * @defaultValue `true`\n\t\t */\n\t\treadonly visible?: boolean;\n\n\t\t/**\n\t\t * The size of the {@link IView view}.\n\t\t *\n\t\t * @defaultValue `true`\n\t\t */\n\t\treadonly size: number;\n\n\t\t/**\n\t\t * The size of the {@link IView view}.\n\t\t *\n\t\t * @defaultValue `true`\n\t\t */\n\t\treadonly view: TView;\n\t}[];\n}\n\nexport interface ISplitViewOptions = IView> {\n\n\t/**\n\t * Which axis the views align on.\n\t *\n\t * @defaultValue `Orientation.VERTICAL`\n\t */\n\treadonly orientation?: Orientation;\n\n\t/**\n\t * Styles overriding the {@link defaultStyles default ones}.\n\t */\n\treadonly styles?: ISplitViewStyles;\n\n\t/**\n\t * Make Alt-drag the default drag operation.\n\t */\n\treadonly inverseAltBehavior?: boolean;\n\n\t/**\n\t * Resize each view proportionally when resizing the SplitView.\n\t *\n\t * @defaultValue `true`\n\t */\n\treadonly proportionalLayout?: boolean;\n\n\t/**\n\t * An initial description of this {@link SplitView} instance, allowing\n\t * to initialze all views within the ctor.\n\t */\n\treadonly descriptor?: ISplitViewDescriptor;\n\n\t/**\n\t * The scrollbar visibility setting for whenever the views within\n\t * the {@link SplitView} overflow.\n\t */\n\treadonly scrollbarVisibility?: ScrollbarVisibility;\n\n\t/**\n\t * Override the orthogonal size of sashes.\n\t */\n\treadonly getSashOrthogonalSize?: () => number;\n}\n\ninterface ISashEvent {\n\treadonly sash: Sash;\n\treadonly start: number;\n\treadonly current: number;\n\treadonly alt: boolean;\n}\n\ntype ViewItemSize = number | { cachedVisibleSize: number };\n\nabstract class ViewItem> {\n\n\tprivate _size: number;\n\tset size(size: number) {\n\t\tthis._size = size;\n\t}\n\n\tget size(): number {\n\t\treturn this._size;\n\t}\n\n\tprivate _cachedVisibleSize: number | undefined = undefined;\n\n\tget visible(): boolean {\n\t\treturn typeof this._cachedVisibleSize === 'undefined';\n\t}\n\n\tsetVisible(visible: boolean, size?: number): void {\n\t\tif (visible === this.visible) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (visible) {\n\t\t\tthis.size = clamp(this._cachedVisibleSize!, this.viewMinimumSize, this.viewMaximumSize);\n\t\t\tthis._cachedVisibleSize = undefined;\n\t\t} else {\n\t\t\tthis._cachedVisibleSize = typeof size === 'number' ? size : this.size;\n\t\t\tthis.size = 0;\n\t\t}\n\n\t\tthis.container.classList.toggle('visible', visible);\n\n\t\ttry {\n\t\t\tthis.view.setVisible?.(visible);\n\t\t} catch (e) {\n\t\t\tconsole.error('Splitview: Failed to set visible view');\n\t\t\tconsole.error(e);\n\t\t}\n\t}\n\n\tget minimumSize(): number { return this.visible ? this.view.minimumSize : 0; }\n\tget viewMinimumSize(): number { return this.view.minimumSize; }\n\n\tget maximumSize(): number { return this.visible ? this.view.maximumSize : 0; }\n\tget viewMaximumSize(): number { return this.view.maximumSize; }\n\n\tget priority(): LayoutPriority | undefined { return this.view.priority; }\n\tget proportionalLayout(): boolean { return this.view.proportionalLayout ?? true; }\n\tget snap(): boolean { return !!this.view.snap; }\n\n\tset enabled(enabled: boolean) {\n\t\tthis.container.style.pointerEvents = enabled ? '' : 'none';\n\t}\n\n\tconstructor(\n\t\tprotected container: HTMLElement,\n\t\treadonly view: TView,\n\t\tsize: ViewItemSize,\n\t\tprivate disposable: IDisposable\n\t) {\n\t\tif (typeof size === 'number') {\n\t\t\tthis._size = size;\n\t\t\tthis._cachedVisibleSize = undefined;\n\t\t\tcontainer.classList.add('visible');\n\t\t} else {\n\t\t\tthis._size = 0;\n\t\t\tthis._cachedVisibleSize = size.cachedVisibleSize;\n\t\t}\n\t}\n\n\tlayout(offset: number, layoutContext: TLayoutContext | undefined): void {\n\t\tthis.layoutContainer(offset);\n\n\t\ttry {\n\t\t\tthis.view.layout(this.size, offset, layoutContext);\n\t\t} catch (e) {\n\t\t\tconsole.error('Splitview: Failed to layout view');\n\t\t\tconsole.error(e);\n\t\t}\n\t}\n\n\tabstract layoutContainer(offset: number): void;\n\n\tdispose(): void {\n\t\tthis.disposable.dispose();\n\t}\n}\n\nclass VerticalViewItem> extends ViewItem {\n\n\tlayoutContainer(offset: number): void {\n\t\tthis.container.style.top = `${offset}px`;\n\t\tthis.container.style.height = `${this.size}px`;\n\t}\n}\n\nclass HorizontalViewItem> extends ViewItem {\n\n\tlayoutContainer(offset: number): void {\n\t\tthis.container.style.left = `${offset}px`;\n\t\tthis.container.style.width = `${this.size}px`;\n\t}\n}\n\ninterface ISashItem {\n\tsash: Sash;\n\tdisposable: IDisposable;\n}\n\ninterface ISashDragSnapState {\n\treadonly index: number;\n\treadonly limitDelta: number;\n\treadonly size: number;\n}\n\ninterface ISashDragState {\n\tindex: number;\n\tstart: number;\n\tcurrent: number;\n\tsizes: number[];\n\tminDelta: number;\n\tmaxDelta: number;\n\talt: boolean;\n\tsnapBefore: ISashDragSnapState | undefined;\n\tsnapAfter: ISashDragSnapState | undefined;\n\tdisposable: IDisposable;\n}\n\nenum State {\n\tIdle,\n\tBusy\n}\n\n/**\n * When adding or removing views, uniformly distribute the entire split view space among\n * all views.\n */\nexport type DistributeSizing = { type: 'distribute' };\n\n/**\n * When adding a view, make space for it by reducing the size of another view,\n * indexed by the provided `index`.\n */\nexport type SplitSizing = { type: 'split'; index: number };\n\n/**\n * When adding a view, use DistributeSizing when all pre-existing views are\n * distributed evenly, otherwise use SplitSizing.\n */\nexport type AutoSizing = { type: 'auto'; index: number };\n\n/**\n * When adding or removing views, assume the view is invisible.\n */\nexport type InvisibleSizing = { type: 'invisible'; cachedVisibleSize: number };\n\n/**\n * When adding or removing views, the sizing provides fine grained\n * control over how other views get resized.\n */\nexport type Sizing = DistributeSizing | SplitSizing | AutoSizing | InvisibleSizing;\n\nexport namespace Sizing {\n\n\t/**\n\t * When adding or removing views, distribute the delta space among\n\t * all other views.\n\t */\n\texport const Distribute: DistributeSizing = { type: 'distribute' };\n\n\t/**\n\t * When adding or removing views, split the delta space with another\n\t * specific view, indexed by the provided `index`.\n\t */\n\texport function Split(index: number): SplitSizing { return { type: 'split', index }; }\n\n\t/**\n\t * When adding a view, use DistributeSizing when all pre-existing views are\n\t * distributed evenly, otherwise use SplitSizing.\n\t */\n\texport function Auto(index: number): AutoSizing { return { type: 'auto', index }; }\n\n\t/**\n\t * When adding or removing views, assume the view is invisible.\n\t */\n\texport function Invisible(cachedVisibleSize: number): InvisibleSizing { return { type: 'invisible', cachedVisibleSize }; }\n}\n\n/**\n * The {@link SplitView} is the UI component which implements a one dimensional\n * flex-like layout algorithm for a collection of {@link IView} instances, which\n * are essentially HTMLElement instances with the following size constraints:\n *\n * - {@link IView.minimumSize}\n * - {@link IView.maximumSize}\n * - {@link IView.priority}\n * - {@link IView.snap}\n *\n * In case the SplitView doesn't have enough size to fit all views, it will overflow\n * its content with a scrollbar.\n *\n * In between each pair of views there will be a {@link Sash} allowing the user\n * to resize the views, making sure the constraints are respected.\n *\n * An optional {@link TLayoutContext layout context type} may be used in order to\n * pass along layout contextual data from the {@link SplitView.layout} method down\n * to each view's {@link IView.layout} calls.\n *\n * Features:\n * - Flex-like layout algorithm\n * - Snap support\n * - Orthogonal sash support, for corner sashes\n * - View hide/show support\n * - View swap/move support\n * - Alt key modifier behavior, macOS style\n */\nexport class SplitView = IView> extends Disposable {\n\n\t/**\n\t * This {@link SplitView}'s orientation.\n\t */\n\treadonly orientation: Orientation;\n\n\t/**\n\t * The DOM element representing this {@link SplitView}.\n\t */\n\treadonly el: HTMLElement;\n\n\tprivate sashContainer: HTMLElement;\n\tprivate viewContainer: HTMLElement;\n\tprivate scrollable: Scrollable;\n\tprivate scrollableElement: SmoothScrollableElement;\n\tprivate size = 0;\n\tprivate layoutContext: TLayoutContext | undefined;\n\tprivate _contentSize = 0;\n\tprivate proportions: (number | undefined)[] | undefined = undefined;\n\tprivate viewItems: ViewItem[] = [];\n\tsashItems: ISashItem[] = []; // used in tests\n\tprivate sashDragState: ISashDragState | undefined;\n\tprivate state: State = State.Idle;\n\tprivate inverseAltBehavior: boolean;\n\tprivate proportionalLayout: boolean;\n\tprivate readonly getSashOrthogonalSize: { (): number } | undefined;\n\n\tprivate _onDidSashChange = this._register(new Emitter());\n\tprivate _onDidSashReset = this._register(new Emitter());\n\tprivate _orthogonalStartSash: Sash | undefined;\n\tprivate _orthogonalEndSash: Sash | undefined;\n\tprivate _startSnappingEnabled = true;\n\tprivate _endSnappingEnabled = true;\n\n\t/**\n\t * Fires whenever the user resizes a {@link Sash sash}.\n\t */\n\treadonly onDidSashChange = this._onDidSashChange.event;\n\n\t/**\n\t * Fires whenever the user double clicks a {@link Sash sash}.\n\t */\n\treadonly onDidSashReset = this._onDidSashReset.event;\n\n\t/**\n\t * Fires whenever the split view is scrolled.\n\t */\n\treadonly onDidScroll: Event;\n\n\tget orthogonalStartSash(): Sash | undefined { return this._orthogonalStartSash; }\n\tget orthogonalEndSash(): Sash | undefined { return this._orthogonalEndSash; }\n\tget startSnappingEnabled(): boolean { return this._startSnappingEnabled; }\n\tget endSnappingEnabled(): boolean { return this._endSnappingEnabled; }\n\n\t/**\n\t * A reference to a sash, perpendicular to all sashes in this {@link SplitView},\n\t * located at the left- or top-most side of the SplitView.\n\t * Corner sashes will be created automatically at the intersections.\n\t */\n\tset orthogonalStartSash(sash: Sash | undefined) {\n\t\tfor (const sashItem of this.sashItems) {\n\t\t\tsashItem.sash.orthogonalStartSash = sash;\n\t\t}\n\n\t\tthis._orthogonalStartSash = sash;\n\t}\n\n\t/**\n\t * A reference to a sash, perpendicular to all sashes in this {@link SplitView},\n\t * located at the right- or bottom-most side of the SplitView.\n\t * Corner sashes will be created automatically at the intersections.\n\t */\n\tset orthogonalEndSash(sash: Sash | undefined) {\n\t\tfor (const sashItem of this.sashItems) {\n\t\t\tsashItem.sash.orthogonalEndSash = sash;\n\t\t}\n\n\t\tthis._orthogonalEndSash = sash;\n\t}\n\n\t/**\n\t * Enable/disable snapping at the beginning of this {@link SplitView}.\n\t */\n\tset startSnappingEnabled(startSnappingEnabled: boolean) {\n\t\tif (this._startSnappingEnabled === startSnappingEnabled) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._startSnappingEnabled = startSnappingEnabled;\n\t\tthis.updateSashEnablement();\n\t}\n\n\t/**\n\t * Enable/disable snapping at the end of this {@link SplitView}.\n\t */\n\tset endSnappingEnabled(endSnappingEnabled: boolean) {\n\t\tif (this._endSnappingEnabled === endSnappingEnabled) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._endSnappingEnabled = endSnappingEnabled;\n\t\tthis.updateSashEnablement();\n\t}\n\n\t/**\n\t * Create a new {@link SplitView} instance.\n\t */\n\tconstructor(container: HTMLElement, options: ISplitViewOptions = {}) {\n\t\tsuper();\n\n\t\tthis.orientation = options.orientation ?? Orientation.VERTICAL;\n\t\tthis.inverseAltBehavior = options.inverseAltBehavior ?? false;\n\t\tthis.proportionalLayout = options.proportionalLayout ?? true;\n\t\tthis.getSashOrthogonalSize = options.getSashOrthogonalSize;\n\n\t\tthis.el = document.createElement('div');\n\t\tthis.el.classList.add('monaco-split-view2');\n\t\tthis.el.classList.add(this.orientation === Orientation.VERTICAL ? 'vertical' : 'horizontal');\n\t\tcontainer.appendChild(this.el);\n\n\t\tthis.sashContainer = append(this.el, $('.sash-container'));\n\t\tthis.viewContainer = $('.split-view-container');\n\n\t\tthis.scrollable = this._register(new Scrollable({\n\t\t\tforceIntegerValues: true,\n\t\t\tsmoothScrollDuration: 125,\n\t\t\tscheduleAtNextAnimationFrame: callback => scheduleAtNextAnimationFrame(getWindow(this.el), callback),\n\t\t}));\n\t\tthis.scrollableElement = this._register(new SmoothScrollableElement(this.viewContainer, {\n\t\t\tvertical: this.orientation === Orientation.VERTICAL ? (options.scrollbarVisibility ?? ScrollbarVisibility.Auto) : ScrollbarVisibility.Hidden,\n\t\t\thorizontal: this.orientation === Orientation.HORIZONTAL ? (options.scrollbarVisibility ?? ScrollbarVisibility.Auto) : ScrollbarVisibility.Hidden\n\t\t}, this.scrollable));\n\n\t\t// https://github.com/microsoft/vscode/issues/157737\n\t\tconst onDidScrollViewContainer = this._register(new DomEmitter(this.viewContainer, 'scroll')).event;\n\t\tthis._register(onDidScrollViewContainer(_ => {\n\t\t\tconst position = this.scrollableElement.getScrollPosition();\n\t\t\tconst scrollLeft = Math.abs(this.viewContainer.scrollLeft - position.scrollLeft) <= 1 ? undefined : this.viewContainer.scrollLeft;\n\t\t\tconst scrollTop = Math.abs(this.viewContainer.scrollTop - position.scrollTop) <= 1 ? undefined : this.viewContainer.scrollTop;\n\n\t\t\tif (scrollLeft !== undefined || scrollTop !== undefined) {\n\t\t\t\tthis.scrollableElement.setScrollPosition({ scrollLeft, scrollTop });\n\t\t\t}\n\t\t}));\n\n\t\tthis.onDidScroll = this.scrollableElement.onScroll;\n\t\tthis._register(this.onDidScroll(e => {\n\t\t\tif (e.scrollTopChanged) {\n\t\t\t\tthis.viewContainer.scrollTop = e.scrollTop;\n\t\t\t}\n\n\t\t\tif (e.scrollLeftChanged) {\n\t\t\t\tthis.viewContainer.scrollLeft = e.scrollLeft;\n\t\t\t}\n\t\t}));\n\n\t\tappend(this.el, this.scrollableElement.getDomNode());\n\n\t\tthis.style(options.styles || defaultStyles);\n\n\t\t// We have an existing set of view, add them now\n\t\tif (options.descriptor) {\n\t\t\tthis.size = options.descriptor.size;\n\t\t\toptions.descriptor.views.forEach((viewDescriptor, index) => {\n\t\t\t\tconst sizing = types.isUndefined(viewDescriptor.visible) || viewDescriptor.visible ? viewDescriptor.size : { type: 'invisible', cachedVisibleSize: viewDescriptor.size } satisfies InvisibleSizing;\n\n\t\t\t\tconst view = viewDescriptor.view;\n\t\t\t\tthis.doAddView(view, sizing, index, true);\n\t\t\t});\n\n\t\t\t// Initialize content size and proportions for first layout\n\t\t\tthis._contentSize = this.viewItems.reduce((r, i) => r + i.size, 0);\n\t\t\tthis.saveProportions();\n\t\t}\n\t}\n\n\tstyle(styles: ISplitViewStyles): void {\n\t\tif (styles.separatorBorder.isTransparent()) {\n\t\t\tthis.el.classList.remove('separator-border');\n\t\t\tthis.el.style.removeProperty('--separator-border');\n\t\t} else {\n\t\t\tthis.el.classList.add('separator-border');\n\t\t\tthis.el.style.setProperty('--separator-border', styles.separatorBorder.toString());\n\t\t}\n\t}\n\n\t/**\n\t * Add a {@link IView view} to this {@link SplitView}.\n\t *\n\t * @param view The view to add.\n\t * @param size Either a fixed size, or a dynamic {@link Sizing} strategy.\n\t * @param index The index to insert the view on.\n\t * @param skipLayout Whether layout should be skipped.\n\t */\n\taddView(view: TView, size: number | Sizing, index = this.viewItems.length, skipLayout?: boolean): void {\n\t\tthis.doAddView(view, size, index, skipLayout);\n\t}\n\n\t/**\n\t * Layout the {@link SplitView}.\n\t *\n\t * @param size The entire size of the {@link SplitView}.\n\t * @param layoutContext An optional layout context to pass along to {@link IView views}.\n\t */\n\tlayout(size: number, layoutContext?: TLayoutContext): void {\n\t\tconst previousSize = Math.max(this.size, this._contentSize);\n\t\tthis.size = size;\n\t\tthis.layoutContext = layoutContext;\n\n\t\tif (!this.proportions) {\n\t\t\tconst indexes = range(this.viewItems.length);\n\t\t\tconst lowPriorityIndexes = indexes.filter(i => this.viewItems[i].priority === LayoutPriority.Low);\n\t\t\tconst highPriorityIndexes = indexes.filter(i => this.viewItems[i].priority === LayoutPriority.High);\n\n\t\t\tthis.resize(this.viewItems.length - 1, size - previousSize, undefined, lowPriorityIndexes, highPriorityIndexes);\n\t\t} else {\n\t\t\tlet total = 0;\n\n\t\t\tfor (let i = 0; i < this.viewItems.length; i++) {\n\t\t\t\tconst item = this.viewItems[i];\n\t\t\t\tconst proportion = this.proportions[i];\n\n\t\t\t\tif (typeof proportion === 'number') {\n\t\t\t\t\ttotal += proportion;\n\t\t\t\t} else {\n\t\t\t\t\tsize -= item.size;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (let i = 0; i < this.viewItems.length; i++) {\n\t\t\t\tconst item = this.viewItems[i];\n\t\t\t\tconst proportion = this.proportions[i];\n\n\t\t\t\tif (typeof proportion === 'number' && total > 0) {\n\t\t\t\t\titem.size = clamp(Math.round(proportion * size / total), item.minimumSize, item.maximumSize);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthis.distributeEmptySpace();\n\t\tthis.layoutViews();\n\t}\n\n\tprivate saveProportions(): void {\n\t\tif (this.proportionalLayout && this._contentSize > 0) {\n\t\t\tthis.proportions = this.viewItems.map(v => v.proportionalLayout && v.visible ? v.size / this._contentSize : undefined);\n\t\t}\n\t}\n\n\tprivate onSashStart({ sash, start, alt }: ISashEvent): void {\n\t\tfor (const item of this.viewItems) {\n\t\t\titem.enabled = false;\n\t\t}\n\n\t\tconst index = this.sashItems.findIndex(item => item.sash === sash);\n\n\t\t// This way, we can press Alt while we resize a sash, macOS style!\n\t\tconst disposable = combinedDisposable(\n\t\t\taddDisposableListener(this.el.ownerDocument.body, 'keydown', e => resetSashDragState(this.sashDragState!.current, e.altKey)),\n\t\t\taddDisposableListener(this.el.ownerDocument.body, 'keyup', () => resetSashDragState(this.sashDragState!.current, false))\n\t\t);\n\n\t\tconst resetSashDragState = (start: number, alt: boolean) => {\n\t\t\tconst sizes = this.viewItems.map(i => i.size);\n\t\t\tlet minDelta = Number.NEGATIVE_INFINITY;\n\t\t\tlet maxDelta = Number.POSITIVE_INFINITY;\n\n\t\t\tif (this.inverseAltBehavior) {\n\t\t\t\talt = !alt;\n\t\t\t}\n\n\t\t\tif (alt) {\n\t\t\t\t// When we're using the last sash with Alt, we're resizing\n\t\t\t\t// the view to the left/up, instead of right/down as usual\n\t\t\t\t// Thus, we must do the inverse of the usual\n\t\t\t\tconst isLastSash = index === this.sashItems.length - 1;\n\n\t\t\t\tif (isLastSash) {\n\t\t\t\t\tconst viewItem = this.viewItems[index];\n\t\t\t\t\tminDelta = (viewItem.minimumSize - viewItem.size) / 2;\n\t\t\t\t\tmaxDelta = (viewItem.maximumSize - viewItem.size) / 2;\n\t\t\t\t} else {\n\t\t\t\t\tconst viewItem = this.viewItems[index + 1];\n\t\t\t\t\tminDelta = (viewItem.size - viewItem.maximumSize) / 2;\n\t\t\t\t\tmaxDelta = (viewItem.size - viewItem.minimumSize) / 2;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet snapBefore: ISashDragSnapState | undefined;\n\t\t\tlet snapAfter: ISashDragSnapState | undefined;\n\n\t\t\tif (!alt) {\n\t\t\t\tconst upIndexes = range(index, -1);\n\t\t\t\tconst downIndexes = range(index + 1, this.viewItems.length);\n\t\t\t\tconst minDeltaUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].minimumSize - sizes[i]), 0);\n\t\t\t\tconst maxDeltaUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].viewMaximumSize - sizes[i]), 0);\n\t\t\t\tconst maxDeltaDown = downIndexes.length === 0 ? Number.POSITIVE_INFINITY : downIndexes.reduce((r, i) => r + (sizes[i] - this.viewItems[i].minimumSize), 0);\n\t\t\t\tconst minDeltaDown = downIndexes.length === 0 ? Number.NEGATIVE_INFINITY : downIndexes.reduce((r, i) => r + (sizes[i] - this.viewItems[i].viewMaximumSize), 0);\n\t\t\t\tconst minDelta = Math.max(minDeltaUp, minDeltaDown);\n\t\t\t\tconst maxDelta = Math.min(maxDeltaDown, maxDeltaUp);\n\t\t\t\tconst snapBeforeIndex = this.findFirstSnapIndex(upIndexes);\n\t\t\t\tconst snapAfterIndex = this.findFirstSnapIndex(downIndexes);\n\n\t\t\t\tif (typeof snapBeforeIndex === 'number') {\n\t\t\t\t\tconst viewItem = this.viewItems[snapBeforeIndex];\n\t\t\t\t\tconst halfSize = Math.floor(viewItem.viewMinimumSize / 2);\n\n\t\t\t\t\tsnapBefore = {\n\t\t\t\t\t\tindex: snapBeforeIndex,\n\t\t\t\t\t\tlimitDelta: viewItem.visible ? minDelta - halfSize : minDelta + halfSize,\n\t\t\t\t\t\tsize: viewItem.size\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tif (typeof snapAfterIndex === 'number') {\n\t\t\t\t\tconst viewItem = this.viewItems[snapAfterIndex];\n\t\t\t\t\tconst halfSize = Math.floor(viewItem.viewMinimumSize / 2);\n\n\t\t\t\t\tsnapAfter = {\n\t\t\t\t\t\tindex: snapAfterIndex,\n\t\t\t\t\t\tlimitDelta: viewItem.visible ? maxDelta + halfSize : maxDelta - halfSize,\n\t\t\t\t\t\tsize: viewItem.size\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.sashDragState = { start, current: start, index, sizes, minDelta, maxDelta, alt, snapBefore, snapAfter, disposable };\n\t\t};\n\n\t\tresetSashDragState(start, alt);\n\t}\n\n\tprivate onSashChange({ current }: ISashEvent): void {\n\t\tconst { index, start, sizes, alt, minDelta, maxDelta, snapBefore, snapAfter } = this.sashDragState!;\n\t\tthis.sashDragState!.current = current;\n\n\t\tconst delta = current - start;\n\t\tconst newDelta = this.resize(index, delta, sizes, undefined, undefined, minDelta, maxDelta, snapBefore, snapAfter);\n\n\t\tif (alt) {\n\t\t\tconst isLastSash = index === this.sashItems.length - 1;\n\t\t\tconst newSizes = this.viewItems.map(i => i.size);\n\t\t\tconst viewItemIndex = isLastSash ? index : index + 1;\n\t\t\tconst viewItem = this.viewItems[viewItemIndex];\n\t\t\tconst newMinDelta = viewItem.size - viewItem.maximumSize;\n\t\t\tconst newMaxDelta = viewItem.size - viewItem.minimumSize;\n\t\t\tconst resizeIndex = isLastSash ? index - 1 : index + 1;\n\n\t\t\tthis.resize(resizeIndex, -newDelta, newSizes, undefined, undefined, newMinDelta, newMaxDelta);\n\t\t}\n\n\t\tthis.distributeEmptySpace();\n\t\tthis.layoutViews();\n\t}\n\n\tprivate onSashEnd(index: number): void {\n\t\tthis._onDidSashChange.fire(index);\n\t\tthis.sashDragState!.disposable.dispose();\n\t\tthis.saveProportions();\n\n\t\tfor (const item of this.viewItems) {\n\t\t\titem.enabled = true;\n\t\t}\n\t}\n\n\tprivate onViewChange(item: ViewItem, size: number | undefined): void {\n\t\tconst index = this.viewItems.indexOf(item);\n\n\t\tif (index < 0 || index >= this.viewItems.length) {\n\t\t\treturn;\n\t\t}\n\n\t\tsize = typeof size === 'number' ? size : item.size;\n\t\tsize = clamp(size, item.minimumSize, item.maximumSize);\n\n\t\tif (this.inverseAltBehavior && index > 0) {\n\t\t\t// In this case, we want the view to grow or shrink both sides equally\n\t\t\t// so we just resize the \"left\" side by half and let `resize` do the clamping magic\n\t\t\tthis.resize(index - 1, Math.floor((item.size - size) / 2));\n\t\t\tthis.distributeEmptySpace();\n\t\t\tthis.layoutViews();\n\t\t} else {\n\t\t\titem.size = size;\n\t\t\tthis.relayout([index], undefined);\n\t\t}\n\t}\n\n\t/**\n\t * Resize a {@link IView view} within the {@link SplitView}.\n\t *\n\t * @param index The {@link IView view} index.\n\t * @param size The {@link IView view} size.\n\t */\n\tresizeView(index: number, size: number): void {\n\t\tif (index < 0 || index >= this.viewItems.length) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.state !== State.Idle) {\n\t\t\tthrow new Error('Cant modify splitview');\n\t\t}\n\n\t\tthis.state = State.Busy;\n\n\t\ttry {\n\t\t\tconst indexes = range(this.viewItems.length).filter(i => i !== index);\n\t\t\tconst lowPriorityIndexes = [...indexes.filter(i => this.viewItems[i].priority === LayoutPriority.Low), index];\n\t\t\tconst highPriorityIndexes = indexes.filter(i => this.viewItems[i].priority === LayoutPriority.High);\n\n\t\t\tconst item = this.viewItems[index];\n\t\t\tsize = Math.round(size);\n\t\t\tsize = clamp(size, item.minimumSize, Math.min(item.maximumSize, this.size));\n\n\t\t\titem.size = size;\n\t\t\tthis.relayout(lowPriorityIndexes, highPriorityIndexes);\n\t\t} finally {\n\t\t\tthis.state = State.Idle;\n\t\t}\n\t}\n\n\t/**\n\t * Distribute the entire {@link SplitView} size among all {@link IView views}.\n\t */\n\tdistributeViewSizes(): void {\n\t\tconst flexibleViewItems: ViewItem[] = [];\n\t\tlet flexibleSize = 0;\n\n\t\tfor (const item of this.viewItems) {\n\t\t\tif (item.maximumSize - item.minimumSize > 0) {\n\t\t\t\tflexibleViewItems.push(item);\n\t\t\t\tflexibleSize += item.size;\n\t\t\t}\n\t\t}\n\n\t\tconst size = Math.floor(flexibleSize / flexibleViewItems.length);\n\n\t\tfor (const item of flexibleViewItems) {\n\t\t\titem.size = clamp(size, item.minimumSize, item.maximumSize);\n\t\t}\n\n\t\tconst indexes = range(this.viewItems.length);\n\t\tconst lowPriorityIndexes = indexes.filter(i => this.viewItems[i].priority === LayoutPriority.Low);\n\t\tconst highPriorityIndexes = indexes.filter(i => this.viewItems[i].priority === LayoutPriority.High);\n\n\t\tthis.relayout(lowPriorityIndexes, highPriorityIndexes);\n\t}\n\n\t/**\n\t * Returns the size of a {@link IView view}.\n\t */\n\tgetViewSize(index: number): number {\n\t\tif (index < 0 || index >= this.viewItems.length) {\n\t\t\treturn -1;\n\t\t}\n\n\t\treturn this.viewItems[index].size;\n\t}\n\n\tprivate doAddView(view: TView, size: number | Sizing, index = this.viewItems.length, skipLayout?: boolean): void {\n\t\tif (this.state !== State.Idle) {\n\t\t\tthrow new Error('Cant modify splitview');\n\t\t}\n\n\t\tthis.state = State.Busy;\n\n\t\ttry {\n\t\t\t// Add view\n\t\t\tconst container = $('.split-view-view');\n\n\t\t\tif (index === this.viewItems.length) {\n\t\t\t\tthis.viewContainer.appendChild(container);\n\t\t\t} else {\n\t\t\t\tthis.viewContainer.insertBefore(container, this.viewContainer.children.item(index));\n\t\t\t}\n\n\t\t\tconst onChangeDisposable = view.onDidChange(size => this.onViewChange(item, size));\n\t\t\tconst containerDisposable = toDisposable(() => this.viewContainer.removeChild(container));\n\t\t\tconst disposable = combinedDisposable(onChangeDisposable, containerDisposable);\n\n\t\t\tlet viewSize: ViewItemSize;\n\n\t\t\tif (typeof size === 'number') {\n\t\t\t\tviewSize = size;\n\t\t\t} else {\n\t\t\t\tif (size.type === 'auto') {\n\t\t\t\t\tif (this.areViewsDistributed()) {\n\t\t\t\t\t\tsize = { type: 'distribute' };\n\t\t\t\t\t} else {\n\t\t\t\t\t\tsize = { type: 'split', index: size.index };\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (size.type === 'split') {\n\t\t\t\t\tviewSize = this.getViewSize(size.index) / 2;\n\t\t\t\t} else if (size.type === 'invisible') {\n\t\t\t\t\tviewSize = { cachedVisibleSize: size.cachedVisibleSize };\n\t\t\t\t} else {\n\t\t\t\t\tviewSize = view.minimumSize;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst item = this.orientation === Orientation.VERTICAL\n\t\t\t\t? new VerticalViewItem(container, view, viewSize, disposable)\n\t\t\t\t: new HorizontalViewItem(container, view, viewSize, disposable);\n\n\t\t\tthis.viewItems.splice(index, 0, item);\n\n\t\t\t// Add sash\n\t\t\tif (this.viewItems.length > 1) {\n\t\t\t\tconst opts = { orthogonalStartSash: this.orthogonalStartSash, orthogonalEndSash: this.orthogonalEndSash };\n\n\t\t\t\tconst sash = this.orientation === Orientation.VERTICAL\n\t\t\t\t\t? new Sash(this.sashContainer, { getHorizontalSashTop: s => this.getSashPosition(s), getHorizontalSashWidth: this.getSashOrthogonalSize }, { ...opts, orientation: Orientation.HORIZONTAL })\n\t\t\t\t\t: new Sash(this.sashContainer, { getVerticalSashLeft: s => this.getSashPosition(s), getVerticalSashHeight: this.getSashOrthogonalSize }, { ...opts, orientation: Orientation.VERTICAL });\n\n\t\t\t\tconst sashEventMapper = this.orientation === Orientation.VERTICAL\n\t\t\t\t\t? (e: IBaseSashEvent) => ({ sash, start: e.startY, current: e.currentY, alt: e.altKey })\n\t\t\t\t\t: (e: IBaseSashEvent) => ({ sash, start: e.startX, current: e.currentX, alt: e.altKey });\n\n\t\t\t\tconst onStart = Event.map(sash.onDidStart, sashEventMapper);\n\t\t\t\tconst onStartDisposable = onStart(this.onSashStart, this);\n\t\t\t\tconst onChange = Event.map(sash.onDidChange, sashEventMapper);\n\t\t\t\tconst onChangeDisposable = onChange(this.onSashChange, this);\n\t\t\t\tconst onEnd = Event.map(sash.onDidEnd, () => this.sashItems.findIndex(item => item.sash === sash));\n\t\t\t\tconst onEndDisposable = onEnd(this.onSashEnd, this);\n\n\t\t\t\tconst onDidResetDisposable = sash.onDidReset(() => {\n\t\t\t\t\tconst index = this.sashItems.findIndex(item => item.sash === sash);\n\t\t\t\t\tconst upIndexes = range(index, -1);\n\t\t\t\t\tconst downIndexes = range(index + 1, this.viewItems.length);\n\t\t\t\t\tconst snapBeforeIndex = this.findFirstSnapIndex(upIndexes);\n\t\t\t\t\tconst snapAfterIndex = this.findFirstSnapIndex(downIndexes);\n\n\t\t\t\t\tif (typeof snapBeforeIndex === 'number' && !this.viewItems[snapBeforeIndex].visible) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (typeof snapAfterIndex === 'number' && !this.viewItems[snapAfterIndex].visible) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tthis._onDidSashReset.fire(index);\n\t\t\t\t});\n\n\t\t\t\tconst disposable = combinedDisposable(onStartDisposable, onChangeDisposable, onEndDisposable, onDidResetDisposable, sash);\n\t\t\t\tconst sashItem: ISashItem = { sash, disposable };\n\n\t\t\t\tthis.sashItems.splice(index - 1, 0, sashItem);\n\t\t\t}\n\n\t\t\tcontainer.appendChild(view.element);\n\n\t\t\tlet highPriorityIndexes: number[] | undefined;\n\n\t\t\tif (typeof size !== 'number' && size.type === 'split') {\n\t\t\t\thighPriorityIndexes = [size.index];\n\t\t\t}\n\n\t\t\tif (!skipLayout) {\n\t\t\t\tthis.relayout([index], highPriorityIndexes);\n\t\t\t}\n\n\n\t\t\tif (!skipLayout && typeof size !== 'number' && size.type === 'distribute') {\n\t\t\t\tthis.distributeViewSizes();\n\t\t\t}\n\n\t\t} finally {\n\t\t\tthis.state = State.Idle;\n\t\t}\n\t}\n\n\tprivate relayout(lowPriorityIndexes?: number[], highPriorityIndexes?: number[]): void {\n\t\tconst contentSize = this.viewItems.reduce((r, i) => r + i.size, 0);\n\n\t\tthis.resize(this.viewItems.length - 1, this.size - contentSize, undefined, lowPriorityIndexes, highPriorityIndexes);\n\t\tthis.distributeEmptySpace();\n\t\tthis.layoutViews();\n\t\tthis.saveProportions();\n\t}\n\n\tprivate resize(\n\t\tindex: number,\n\t\tdelta: number,\n\t\tsizes = this.viewItems.map(i => i.size),\n\t\tlowPriorityIndexes?: number[],\n\t\thighPriorityIndexes?: number[],\n\t\toverloadMinDelta: number = Number.NEGATIVE_INFINITY,\n\t\toverloadMaxDelta: number = Number.POSITIVE_INFINITY,\n\t\tsnapBefore?: ISashDragSnapState,\n\t\tsnapAfter?: ISashDragSnapState\n\t): number {\n\t\tif (index < 0 || index >= this.viewItems.length) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tconst upIndexes = range(index, -1);\n\t\tconst downIndexes = range(index + 1, this.viewItems.length);\n\n\t\tif (highPriorityIndexes) {\n\t\t\tfor (const index of highPriorityIndexes) {\n\t\t\t\tpushToStart(upIndexes, index);\n\t\t\t\tpushToStart(downIndexes, index);\n\t\t\t}\n\t\t}\n\n\t\tif (lowPriorityIndexes) {\n\t\t\tfor (const index of lowPriorityIndexes) {\n\t\t\t\tpushToEnd(upIndexes, index);\n\t\t\t\tpushToEnd(downIndexes, index);\n\t\t\t}\n\t\t}\n\n\t\tconst upItems = upIndexes.map(i => this.viewItems[i]);\n\t\tconst upSizes = upIndexes.map(i => sizes[i]);\n\n\t\tconst downItems = downIndexes.map(i => this.viewItems[i]);\n\t\tconst downSizes = downIndexes.map(i => sizes[i]);\n\n\t\tconst minDeltaUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].minimumSize - sizes[i]), 0);\n\t\tconst maxDeltaUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].maximumSize - sizes[i]), 0);\n\t\tconst maxDeltaDown = downIndexes.length === 0 ? Number.POSITIVE_INFINITY : downIndexes.reduce((r, i) => r + (sizes[i] - this.viewItems[i].minimumSize), 0);\n\t\tconst minDeltaDown = downIndexes.length === 0 ? Number.NEGATIVE_INFINITY : downIndexes.reduce((r, i) => r + (sizes[i] - this.viewItems[i].maximumSize), 0);\n\t\tconst minDelta = Math.max(minDeltaUp, minDeltaDown, overloadMinDelta);\n\t\tconst maxDelta = Math.min(maxDeltaDown, maxDeltaUp, overloadMaxDelta);\n\n\t\tlet snapped = false;\n\n\t\tif (snapBefore) {\n\t\t\tconst snapView = this.viewItems[snapBefore.index];\n\t\t\tconst visible = delta >= snapBefore.limitDelta;\n\t\t\tsnapped = visible !== snapView.visible;\n\t\t\tsnapView.setVisible(visible, snapBefore.size);\n\t\t}\n\n\t\tif (!snapped && snapAfter) {\n\t\t\tconst snapView = this.viewItems[snapAfter.index];\n\t\t\tconst visible = delta < snapAfter.limitDelta;\n\t\t\tsnapped = visible !== snapView.visible;\n\t\t\tsnapView.setVisible(visible, snapAfter.size);\n\t\t}\n\n\t\tif (snapped) {\n\t\t\treturn this.resize(index, delta, sizes, lowPriorityIndexes, highPriorityIndexes, overloadMinDelta, overloadMaxDelta);\n\t\t}\n\n\t\tdelta = clamp(delta, minDelta, maxDelta);\n\n\t\tfor (let i = 0, deltaUp = delta; i < upItems.length; i++) {\n\t\t\tconst item = upItems[i];\n\t\t\tconst size = clamp(upSizes[i] + deltaUp, item.minimumSize, item.maximumSize);\n\t\t\tconst viewDelta = size - upSizes[i];\n\n\t\t\tdeltaUp -= viewDelta;\n\t\t\titem.size = size;\n\t\t}\n\n\t\tfor (let i = 0, deltaDown = delta; i < downItems.length; i++) {\n\t\t\tconst item = downItems[i];\n\t\t\tconst size = clamp(downSizes[i] - deltaDown, item.minimumSize, item.maximumSize);\n\t\t\tconst viewDelta = size - downSizes[i];\n\n\t\t\tdeltaDown += viewDelta;\n\t\t\titem.size = size;\n\t\t}\n\n\t\treturn delta;\n\t}\n\n\tprivate distributeEmptySpace(lowPriorityIndex?: number): void {\n\t\tconst contentSize = this.viewItems.reduce((r, i) => r + i.size, 0);\n\t\tlet emptyDelta = this.size - contentSize;\n\n\t\tconst indexes = range(this.viewItems.length - 1, -1);\n\t\tconst lowPriorityIndexes = indexes.filter(i => this.viewItems[i].priority === LayoutPriority.Low);\n\t\tconst highPriorityIndexes = indexes.filter(i => this.viewItems[i].priority === LayoutPriority.High);\n\n\t\tfor (const index of highPriorityIndexes) {\n\t\t\tpushToStart(indexes, index);\n\t\t}\n\n\t\tfor (const index of lowPriorityIndexes) {\n\t\t\tpushToEnd(indexes, index);\n\t\t}\n\n\t\tif (typeof lowPriorityIndex === 'number') {\n\t\t\tpushToEnd(indexes, lowPriorityIndex);\n\t\t}\n\n\t\tfor (let i = 0; emptyDelta !== 0 && i < indexes.length; i++) {\n\t\t\tconst item = this.viewItems[indexes[i]];\n\t\t\tconst size = clamp(item.size + emptyDelta, item.minimumSize, item.maximumSize);\n\t\t\tconst viewDelta = size - item.size;\n\n\t\t\temptyDelta -= viewDelta;\n\t\t\titem.size = size;\n\t\t}\n\t}\n\n\tprivate layoutViews(): void {\n\t\t// Save new content size\n\t\tthis._contentSize = this.viewItems.reduce((r, i) => r + i.size, 0);\n\n\t\t// Layout views\n\t\tlet offset = 0;\n\n\t\tfor (const viewItem of this.viewItems) {\n\t\t\tviewItem.layout(offset, this.layoutContext);\n\t\t\toffset += viewItem.size;\n\t\t}\n\n\t\t// Layout sashes\n\t\tthis.sashItems.forEach(item => item.sash.layout());\n\t\tthis.updateSashEnablement();\n\t\tthis.updateScrollableElement();\n\t}\n\n\tprivate updateScrollableElement(): void {\n\t\tif (this.orientation === Orientation.VERTICAL) {\n\t\t\tthis.scrollableElement.setScrollDimensions({\n\t\t\t\theight: this.size,\n\t\t\t\tscrollHeight: this._contentSize\n\t\t\t});\n\t\t} else {\n\t\t\tthis.scrollableElement.setScrollDimensions({\n\t\t\t\twidth: this.size,\n\t\t\t\tscrollWidth: this._contentSize\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate updateSashEnablement(): void {\n\t\tlet previous = false;\n\t\tconst collapsesDown = this.viewItems.map(i => previous = (i.size - i.minimumSize > 0) || previous);\n\n\t\tprevious = false;\n\t\tconst expandsDown = this.viewItems.map(i => previous = (i.maximumSize - i.size > 0) || previous);\n\n\t\tconst reverseViews = [...this.viewItems].reverse();\n\t\tprevious = false;\n\t\tconst collapsesUp = reverseViews.map(i => previous = (i.size - i.minimumSize > 0) || previous).reverse();\n\n\t\tprevious = false;\n\t\tconst expandsUp = reverseViews.map(i => previous = (i.maximumSize - i.size > 0) || previous).reverse();\n\n\t\tlet position = 0;\n\t\tfor (let index = 0; index < this.sashItems.length; index++) {\n\t\t\tconst { sash } = this.sashItems[index];\n\t\t\tconst viewItem = this.viewItems[index];\n\t\t\tposition += viewItem.size;\n\n\t\t\tconst min = !(collapsesDown[index] && expandsUp[index + 1]);\n\t\t\tconst max = !(expandsDown[index] && collapsesUp[index + 1]);\n\n\t\t\tif (min && max) {\n\t\t\t\tconst upIndexes = range(index, -1);\n\t\t\t\tconst downIndexes = range(index + 1, this.viewItems.length);\n\t\t\t\tconst snapBeforeIndex = this.findFirstSnapIndex(upIndexes);\n\t\t\t\tconst snapAfterIndex = this.findFirstSnapIndex(downIndexes);\n\n\t\t\t\tconst snappedBefore = typeof snapBeforeIndex === 'number' && !this.viewItems[snapBeforeIndex].visible;\n\t\t\t\tconst snappedAfter = typeof snapAfterIndex === 'number' && !this.viewItems[snapAfterIndex].visible;\n\n\t\t\t\tif (snappedBefore && collapsesUp[index] && (position > 0 || this.startSnappingEnabled)) {\n\t\t\t\t\tsash.state = SashState.AtMinimum;\n\t\t\t\t} else if (snappedAfter && collapsesDown[index] && (position < this._contentSize || this.endSnappingEnabled)) {\n\t\t\t\t\tsash.state = SashState.AtMaximum;\n\t\t\t\t} else {\n\t\t\t\t\tsash.state = SashState.Disabled;\n\t\t\t\t}\n\t\t\t} else if (min && !max) {\n\t\t\t\tsash.state = SashState.AtMinimum;\n\t\t\t} else if (!min && max) {\n\t\t\t\tsash.state = SashState.AtMaximum;\n\t\t\t} else {\n\t\t\t\tsash.state = SashState.Enabled;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate getSashPosition(sash: Sash): number {\n\t\tlet position = 0;\n\n\t\tfor (let i = 0; i < this.sashItems.length; i++) {\n\t\t\tposition += this.viewItems[i].size;\n\n\t\t\tif (this.sashItems[i].sash === sash) {\n\t\t\t\treturn position;\n\t\t\t}\n\t\t}\n\n\t\treturn 0;\n\t}\n\n\tprivate findFirstSnapIndex(indexes: number[]): number | undefined {\n\t\t// visible views first\n\t\tfor (const index of indexes) {\n\t\t\tconst viewItem = this.viewItems[index];\n\n\t\t\tif (!viewItem.visible) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (viewItem.snap) {\n\t\t\t\treturn index;\n\t\t\t}\n\t\t}\n\n\t\t// then, hidden views\n\t\tfor (const index of indexes) {\n\t\t\tconst viewItem = this.viewItems[index];\n\n\t\t\tif (viewItem.visible && viewItem.maximumSize - viewItem.minimumSize > 0) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\n\t\t\tif (!viewItem.visible && viewItem.snap) {\n\t\t\t\treturn index;\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\tprivate areViewsDistributed() {\n\t\tlet min = undefined, max = undefined;\n\n\t\tfor (const view of this.viewItems) {\n\t\t\tmin = min === undefined ? view.size : Math.min(min, view.size);\n\t\t\tmax = max === undefined ? view.size : Math.max(max, view.size);\n\n\t\t\tif (max - min > 2) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\toverride dispose(): void {\n\t\tthis.sashDragState?.disposable.dispose();\n\n\t\tdispose(this.viewItems);\n\t\tthis.viewItems = [];\n\n\t\tthis.sashItems.forEach(i => i.disposable.dispose());\n\t\tthis.sashItems = [];\n\n\t\tsuper.dispose();\n\t}\n}\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\nimport { $, append, clearNode, createStyleSheet } from 'vs/base/browser/dom';\nimport { getBaseLayerHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate2';\nimport { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegateFactory';\nimport { IListRenderer, IListVirtualDelegate } from 'vs/base/browser/ui/list/list';\nimport { IListOptions, IListOptionsUpdate, IListStyles, List, unthemedListStyles } from 'vs/base/browser/ui/list/listWidget';\nimport { ISplitViewDescriptor, IView, Orientation, SplitView } from 'vs/base/browser/ui/splitview/splitview';\nimport { ITableColumn, ITableEvent, ITableMouseEvent, ITableRenderer, ITableVirtualDelegate } from 'vs/base/browser/ui/table/table';\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle';\nimport { ScrollbarVisibility, ScrollEvent } from 'vs/base/common/scrollable';\nimport { ISpliceable } from 'vs/base/common/sequence';\nimport 'vs/css!./table';\n\n// TODO@joao\ntype TCell = any;\n\ninterface RowTemplateData {\n\treadonly container: HTMLElement;\n\treadonly cellContainers: HTMLElement[];\n\treadonly cellTemplateData: unknown[];\n}\n\nclass TableListRenderer implements IListRenderer {\n\n\tstatic TemplateId = 'row';\n\treadonly templateId = TableListRenderer.TemplateId;\n\tprivate renderers: ITableRenderer[];\n\tprivate renderedTemplates = new Set();\n\n\tconstructor(\n\t\tprivate columns: ITableColumn[],\n\t\trenderers: ITableRenderer[],\n\t\tprivate getColumnSize: (index: number) => number\n\t) {\n\t\tconst rendererMap = new Map(renderers.map(r => [r.templateId, r]));\n\t\tthis.renderers = [];\n\n\t\tfor (const column of columns) {\n\t\t\tconst renderer = rendererMap.get(column.templateId);\n\n\t\t\tif (!renderer) {\n\t\t\t\tthrow new Error(`Table cell renderer for template id ${column.templateId} not found.`);\n\t\t\t}\n\n\t\t\tthis.renderers.push(renderer);\n\t\t}\n\t}\n\n\trenderTemplate(container: HTMLElement) {\n\t\tconst rowContainer = append(container, $('.monaco-table-tr'));\n\t\tconst cellContainers: HTMLElement[] = [];\n\t\tconst cellTemplateData: unknown[] = [];\n\n\t\tfor (let i = 0; i < this.columns.length; i++) {\n\t\t\tconst renderer = this.renderers[i];\n\t\t\tconst cellContainer = append(rowContainer, $('.monaco-table-td', { 'data-col-index': i }));\n\n\t\t\tcellContainer.style.width = `${this.getColumnSize(i)}px`;\n\t\t\tcellContainers.push(cellContainer);\n\t\t\tcellTemplateData.push(renderer.renderTemplate(cellContainer));\n\t\t}\n\n\t\tconst result = { container, cellContainers, cellTemplateData };\n\t\tthis.renderedTemplates.add(result);\n\n\t\treturn result;\n\t}\n\n\trenderElement(element: TRow, index: number, templateData: RowTemplateData, height: number | undefined): void {\n\t\tfor (let i = 0; i < this.columns.length; i++) {\n\t\t\tconst column = this.columns[i];\n\t\t\tconst cell = column.project(element);\n\t\t\tconst renderer = this.renderers[i];\n\t\t\trenderer.renderElement(cell, index, templateData.cellTemplateData[i], height);\n\t\t}\n\t}\n\n\tdisposeElement(element: TRow, index: number, templateData: RowTemplateData, height: number | undefined): void {\n\t\tfor (let i = 0; i < this.columns.length; i++) {\n\t\t\tconst renderer = this.renderers[i];\n\n\t\t\tif (renderer.disposeElement) {\n\t\t\t\tconst column = this.columns[i];\n\t\t\t\tconst cell = column.project(element);\n\n\t\t\t\trenderer.disposeElement(cell, index, templateData.cellTemplateData[i], height);\n\t\t\t}\n\t\t}\n\t}\n\n\tdisposeTemplate(templateData: RowTemplateData): void {\n\t\tfor (let i = 0; i < this.columns.length; i++) {\n\t\t\tconst renderer = this.renderers[i];\n\t\t\trenderer.disposeTemplate(templateData.cellTemplateData[i]);\n\t\t}\n\n\t\tclearNode(templateData.container);\n\t\tthis.renderedTemplates.delete(templateData);\n\t}\n\n\tlayoutColumn(index: number, size: number): void {\n\t\tfor (const { cellContainers } of this.renderedTemplates) {\n\t\t\tcellContainers[index].style.width = `${size}px`;\n\t\t}\n\t}\n}\n\nfunction asListVirtualDelegate(delegate: ITableVirtualDelegate): IListVirtualDelegate {\n\treturn {\n\t\tgetHeight(row) { return delegate.getHeight(row); },\n\t\tgetTemplateId() { return TableListRenderer.TemplateId; },\n\t};\n}\n\nclass ColumnHeader extends Disposable implements IView {\n\n\treadonly element: HTMLElement;\n\n\tget minimumSize() { return this.column.minimumWidth ?? 120; }\n\tget maximumSize() { return this.column.maximumWidth ?? Number.POSITIVE_INFINITY; }\n\tget onDidChange() { return this.column.onDidChangeWidthConstraints ?? Event.None; }\n\n\tprivate _onDidLayout = new Emitter<[number, number]>();\n\treadonly onDidLayout = this._onDidLayout.event;\n\n\tconstructor(readonly column: ITableColumn, private index: number) {\n\t\tsuper();\n\n\t\tthis.element = $('.monaco-table-th', { 'data-col-index': index }, column.label);\n\n\t\tif (column.tooltip) {\n\t\t\tthis._register(getBaseLayerHoverDelegate().setupUpdatableHover(getDefaultHoverDelegate('mouse'), this.element, column.tooltip));\n\t\t}\n\t}\n\n\tlayout(size: number): void {\n\t\tthis._onDidLayout.fire([this.index, size]);\n\t}\n}\n\nexport interface ITableOptions extends IListOptions { }\nexport interface ITableOptionsUpdate extends IListOptionsUpdate { }\nexport interface ITableStyles extends IListStyles { }\n\nexport class Table implements ISpliceable, IDisposable {\n\n\tprivate static InstanceCount = 0;\n\treadonly domId = `table_id_${++Table.InstanceCount}`;\n\n\treadonly domNode: HTMLElement;\n\tprivate splitview: SplitView;\n\tprivate list: List;\n\tprivate styleElement: HTMLStyleElement;\n\tprotected readonly disposables = new DisposableStore();\n\n\tprivate cachedWidth: number = 0;\n\tprivate cachedHeight: number = 0;\n\n\tget onDidChangeFocus(): Event> { return this.list.onDidChangeFocus; }\n\tget onDidChangeSelection(): Event> { return this.list.onDidChangeSelection; }\n\n\tget onDidScroll(): Event { return this.list.onDidScroll; }\n\tget onMouseDblClick(): Event> { return this.list.onMouseDblClick; }\n\tget onPointer(): Event> { return this.list.onPointer; }\n\n\tget onDidFocus(): Event { return this.list.onDidFocus; }\n\n\tget scrollTop(): number { return this.list.scrollTop; }\n\tset scrollTop(scrollTop: number) { this.list.scrollTop = scrollTop; }\n\tget scrollHeight(): number { return this.list.scrollHeight; }\n\tget renderHeight(): number { return this.list.renderHeight; }\n\tget onDidDispose(): Event { return this.list.onDidDispose; }\n\n\tconstructor(\n\t\tuser: string,\n\t\tcontainer: HTMLElement,\n\t\tprivate virtualDelegate: ITableVirtualDelegate,\n\t\tcolumns: ITableColumn[],\n\t\trenderers: ITableRenderer[],\n\t\t_options?: ITableOptions\n\t) {\n\t\tthis.domNode = append(container, $(`.monaco-table.${this.domId}`));\n\n\t\tconst headers = columns.map((c, i) => this.disposables.add(new ColumnHeader(c, i)));\n\t\tconst descriptor: ISplitViewDescriptor = {\n\t\t\tsize: headers.reduce((a, b) => a + b.column.weight, 0),\n\t\t\tviews: headers.map(view => ({ size: view.column.weight, view }))\n\t\t};\n\n\t\tthis.splitview = this.disposables.add(new SplitView(this.domNode, {\n\t\t\torientation: Orientation.HORIZONTAL,\n\t\t\tscrollbarVisibility: ScrollbarVisibility.Hidden,\n\t\t\tgetSashOrthogonalSize: () => this.cachedHeight,\n\t\t\tdescriptor\n\t\t}));\n\n\t\tthis.splitview.el.style.height = `${virtualDelegate.headerRowHeight}px`;\n\t\tthis.splitview.el.style.lineHeight = `${virtualDelegate.headerRowHeight}px`;\n\n\t\tconst renderer = new TableListRenderer(columns, renderers, i => this.splitview.getViewSize(i));\n\t\tthis.list = this.disposables.add(new List(user, this.domNode, asListVirtualDelegate(virtualDelegate), [renderer], _options));\n\n\t\tEvent.any(...headers.map(h => h.onDidLayout))\n\t\t\t(([index, size]) => renderer.layoutColumn(index, size), null, this.disposables);\n\n\t\tthis.splitview.onDidSashReset(index => {\n\t\t\tconst totalWeight = columns.reduce((r, c) => r + c.weight, 0);\n\t\t\tconst size = columns[index].weight / totalWeight * this.cachedWidth;\n\t\t\tthis.splitview.resizeView(index, size);\n\t\t}, null, this.disposables);\n\n\t\tthis.styleElement = createStyleSheet(this.domNode);\n\t\tthis.style(unthemedListStyles);\n\t}\n\n\tupdateOptions(options: ITableOptionsUpdate): void {\n\t\tthis.list.updateOptions(options);\n\t}\n\n\tsplice(start: number, deleteCount: number, elements: readonly TRow[] = []): void {\n\t\tthis.list.splice(start, deleteCount, elements);\n\t}\n\n\tgetHTMLElement(): HTMLElement {\n\t\treturn this.domNode;\n\t}\n\n\tstyle(styles: ITableStyles): void {\n\t\tconst content: string[] = [];\n\n\t\tcontent.push(`.monaco-table.${this.domId} > .monaco-split-view2 .monaco-sash.vertical::before {\n\t\t\ttop: ${this.virtualDelegate.headerRowHeight + 1}px;\n\t\t\theight: calc(100% - ${this.virtualDelegate.headerRowHeight}px);\n\t\t}`);\n\n\t\tthis.styleElement.textContent = content.join('\\n');\n\t\tthis.list.style(styles);\n\t}\n\n\tgetSelectedElements(): TRow[] {\n\t\treturn this.list.getSelectedElements();\n\t}\n\n\tgetSelection(): number[] {\n\t\treturn this.list.getSelection();\n\t}\n\n\tgetFocus(): number[] {\n\t\treturn this.list.getFocus();\n\t}\n\n\tdispose(): void {\n\t\tthis.disposables.dispose();\n\t}\n}\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\nimport { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';\nimport { Widget } from 'vs/base/browser/ui/widget';\nimport { ThemeIcon } from 'vs/base/common/themables';\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { KeyCode } from 'vs/base/common/keyCodes';\nimport 'vs/css!./toggle';\nimport { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegateFactory';\nimport { IHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate';\nimport { IUpdatableHover } from 'vs/base/browser/ui/hover/hover';\nimport { getBaseLayerHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate2';\n\nexport interface IToggleOpts extends IToggleStyles {\n\treadonly actionClassName?: string;\n\treadonly icon?: ThemeIcon;\n\treadonly title: string;\n\treadonly isChecked: boolean;\n\treadonly notFocusable?: boolean;\n\treadonly hoverDelegate?: IHoverDelegate;\n}\n\nexport interface IToggleStyles {\n\treadonly inputActiveOptionBorder: string | undefined;\n\treadonly inputActiveOptionForeground: string | undefined;\n\treadonly inputActiveOptionBackground: string | undefined;\n}\n\nexport interface ICheckboxStyles {\n\treadonly checkboxBackground: string | undefined;\n\treadonly checkboxBorder: string | undefined;\n\treadonly checkboxForeground: string | undefined;\n}\n\nexport const unthemedToggleStyles = {\n\tinputActiveOptionBorder: '#007ACC00',\n\tinputActiveOptionForeground: '#FFFFFF',\n\tinputActiveOptionBackground: '#0E639C50'\n};\n\nexport class Toggle extends Widget {\n\n\tprivate readonly _onChange = this._register(new Emitter());\n\treadonly onChange: Event = this._onChange.event;\n\n\tprivate readonly _onKeyDown = this._register(new Emitter());\n\treadonly onKeyDown: Event = this._onKeyDown.event;\n\n\tprivate readonly _opts: IToggleOpts;\n\tprivate _icon: ThemeIcon | undefined;\n\treadonly domNode: HTMLElement;\n\n\tprivate _checked: boolean;\n\tprivate _hover: IUpdatableHover;\n\n\tconstructor(opts: IToggleOpts) {\n\t\tsuper();\n\n\t\tthis._opts = opts;\n\t\tthis._checked = this._opts.isChecked;\n\n\t\tconst classes = ['monaco-custom-toggle'];\n\t\tif (this._opts.icon) {\n\t\t\tthis._icon = this._opts.icon;\n\t\t\tclasses.push(...ThemeIcon.asClassNameArray(this._icon));\n\t\t}\n\t\tif (this._opts.actionClassName) {\n\t\t\tclasses.push(...this._opts.actionClassName.split(' '));\n\t\t}\n\t\tif (this._checked) {\n\t\t\tclasses.push('checked');\n\t\t}\n\n\t\tthis.domNode = document.createElement('div');\n\t\tthis._hover = this._register(getBaseLayerHoverDelegate().setupUpdatableHover(opts.hoverDelegate ?? getDefaultHoverDelegate('mouse'), this.domNode, this._opts.title));\n\t\tthis.domNode.classList.add(...classes);\n\t\tif (!this._opts.notFocusable) {\n\t\t\tthis.domNode.tabIndex = 0;\n\t\t}\n\t\tthis.domNode.setAttribute('role', 'checkbox');\n\t\tthis.domNode.setAttribute('aria-checked', String(this._checked));\n\t\tthis.domNode.setAttribute('aria-label', this._opts.title);\n\n\t\tthis.applyStyles();\n\n\t\tthis.onclick(this.domNode, (ev) => {\n\t\t\tif (this.enabled) {\n\t\t\t\tthis.checked = !this._checked;\n\t\t\t\tthis._onChange.fire(false);\n\t\t\t\tev.preventDefault();\n\t\t\t}\n\t\t});\n\n\t\tthis._register(this.ignoreGesture(this.domNode));\n\n\t\tthis.onkeydown(this.domNode, (keyboardEvent) => {\n\t\t\tif (keyboardEvent.keyCode === KeyCode.Space || keyboardEvent.keyCode === KeyCode.Enter) {\n\t\t\t\tthis.checked = !this._checked;\n\t\t\t\tthis._onChange.fire(true);\n\t\t\t\tkeyboardEvent.preventDefault();\n\t\t\t\tkeyboardEvent.stopPropagation();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis._onKeyDown.fire(keyboardEvent);\n\t\t});\n\t}\n\n\tget enabled(): boolean {\n\t\treturn this.domNode.getAttribute('aria-disabled') !== 'true';\n\t}\n\n\tfocus(): void {\n\t\tthis.domNode.focus();\n\t}\n\n\tget checked(): boolean {\n\t\treturn this._checked;\n\t}\n\n\tset checked(newIsChecked: boolean) {\n\t\tthis._checked = newIsChecked;\n\n\t\tthis.domNode.setAttribute('aria-checked', String(this._checked));\n\t\tthis.domNode.classList.toggle('checked', this._checked);\n\n\t\tthis.applyStyles();\n\t}\n\n\twidth(): number {\n\t\treturn 2 /*margin left*/ + 2 /*border*/ + 2 /*padding*/ + 16 /* icon width */;\n\t}\n\n\tprotected applyStyles(): void {\n\t\tif (this.domNode) {\n\t\t\tthis.domNode.style.borderColor = (this._checked && this._opts.inputActiveOptionBorder) || '';\n\t\t\tthis.domNode.style.color = (this._checked && this._opts.inputActiveOptionForeground) || 'inherit';\n\t\t\tthis.domNode.style.backgroundColor = (this._checked && this._opts.inputActiveOptionBackground) || '';\n\t\t}\n\t}\n\n\tenable(): void {\n\t\tthis.domNode.setAttribute('aria-disabled', String(false));\n\t}\n\n\tdisable(): void {\n\t\tthis.domNode.setAttribute('aria-disabled', String(true));\n\t}\n}\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\nimport { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegateFactory';\nimport { IHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate';\nimport { Toggle } from 'vs/base/browser/ui/toggle/toggle';\nimport { Codicon } from 'vs/base/common/codicons';\nimport * as nls from 'vs/nls';\n\nexport interface IFindInputToggleOpts {\n\treadonly appendTitle: string;\n\treadonly isChecked: boolean;\n\treadonly inputActiveOptionBorder: string | undefined;\n\treadonly inputActiveOptionForeground: string | undefined;\n\treadonly inputActiveOptionBackground: string | undefined;\n\treadonly hoverDelegate?: IHoverDelegate;\n}\n\nconst NLS_CASE_SENSITIVE_TOGGLE_LABEL = nls.localize('caseDescription', \"Match Case\");\nconst NLS_WHOLE_WORD_TOGGLE_LABEL = nls.localize('wordsDescription', \"Match Whole Word\");\nconst NLS_REGEX_TOGGLE_LABEL = nls.localize('regexDescription', \"Use Regular Expression\");\n\nexport class CaseSensitiveToggle extends Toggle {\n\tconstructor(opts: IFindInputToggleOpts) {\n\t\tsuper({\n\t\t\ticon: Codicon.caseSensitive,\n\t\t\ttitle: NLS_CASE_SENSITIVE_TOGGLE_LABEL + opts.appendTitle,\n\t\t\tisChecked: opts.isChecked,\n\t\t\thoverDelegate: opts.hoverDelegate ?? getDefaultHoverDelegate('element'),\n\t\t\tinputActiveOptionBorder: opts.inputActiveOptionBorder,\n\t\t\tinputActiveOptionForeground: opts.inputActiveOptionForeground,\n\t\t\tinputActiveOptionBackground: opts.inputActiveOptionBackground\n\t\t});\n\t}\n}\n\nexport class WholeWordsToggle extends Toggle {\n\tconstructor(opts: IFindInputToggleOpts) {\n\t\tsuper({\n\t\t\ticon: Codicon.wholeWord,\n\t\t\ttitle: NLS_WHOLE_WORD_TOGGLE_LABEL + opts.appendTitle,\n\t\t\tisChecked: opts.isChecked,\n\t\t\thoverDelegate: opts.hoverDelegate ?? getDefaultHoverDelegate('element'),\n\t\t\tinputActiveOptionBorder: opts.inputActiveOptionBorder,\n\t\t\tinputActiveOptionForeground: opts.inputActiveOptionForeground,\n\t\t\tinputActiveOptionBackground: opts.inputActiveOptionBackground\n\t\t});\n\t}\n}\n\nexport class RegexToggle extends Toggle {\n\tconstructor(opts: IFindInputToggleOpts) {\n\t\tsuper({\n\t\t\ticon: Codicon.regex,\n\t\t\ttitle: NLS_REGEX_TOGGLE_LABEL + opts.appendTitle,\n\t\t\tisChecked: opts.isChecked,\n\t\t\thoverDelegate: opts.hoverDelegate ?? getDefaultHoverDelegate('element'),\n\t\t\tinputActiveOptionBorder: opts.inputActiveOptionBorder,\n\t\t\tinputActiveOptionForeground: opts.inputActiveOptionForeground,\n\t\t\tinputActiveOptionBackground: opts.inputActiveOptionBackground\n\t\t});\n\t}\n}\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\nimport { CharCode } from 'vs/base/common/charCode';\nimport * as extpath from 'vs/base/common/extpath';\nimport { Schemas } from 'vs/base/common/network';\nimport * as paths from 'vs/base/common/path';\nimport { isLinux, isWindows } from 'vs/base/common/platform';\nimport { compare as strCompare, equalsIgnoreCase } from 'vs/base/common/strings';\nimport { URI, uriToFsPath } from 'vs/base/common/uri';\n\nexport function originalFSPath(uri: URI): string {\n\treturn uriToFsPath(uri, true);\n}\n\n//#region IExtUri\n\nexport interface IExtUri {\n}\n\nexport class ExtUri implements IExtUri {\n\n\tconstructor(private _ignorePathCasing: (uri: URI) => boolean) { }\n\n\tcompare(uri1: URI, uri2: URI, ignoreFragment: boolean = false): number {\n\t\tif (uri1 === uri2) {\n\t\t\treturn 0;\n\t\t}\n\t\treturn strCompare(this.getComparisonKey(uri1, ignoreFragment), this.getComparisonKey(uri2, ignoreFragment));\n\t}\n\n\tisEqual(uri1: URI | undefined, uri2: URI | undefined, ignoreFragment: boolean = false): boolean {\n\t\tif (uri1 === uri2) {\n\t\t\treturn true;\n\t\t}\n\t\tif (!uri1 || !uri2) {\n\t\t\treturn false;\n\t\t}\n\t\treturn this.getComparisonKey(uri1, ignoreFragment) === this.getComparisonKey(uri2, ignoreFragment);\n\t}\n\n\tgetComparisonKey(uri: URI, ignoreFragment: boolean = false): string {\n\t\treturn uri.with({\n\t\t\tpath: this._ignorePathCasing(uri) ? uri.path.toLowerCase() : undefined,\n\t\t\tfragment: ignoreFragment ? null : undefined\n\t\t}).toString();\n\t}\n\n\tisEqualOrParent(base: URI, parentCandidate: URI, ignoreFragment: boolean = false): boolean {\n\t\tif (base.scheme === parentCandidate.scheme) {\n\t\t\tif (base.scheme === Schemas.file) {\n\t\t\t\treturn extpath.isEqualOrParent(originalFSPath(base), originalFSPath(parentCandidate), this._ignorePathCasing(base)) && base.query === parentCandidate.query && (ignoreFragment || base.fragment === parentCandidate.fragment);\n\t\t\t}\n\t\t\tif (isEqualAuthority(base.authority, parentCandidate.authority)) {\n\t\t\t\treturn extpath.isEqualOrParent(base.path, parentCandidate.path, this._ignorePathCasing(base), '/') && base.query === parentCandidate.query && (ignoreFragment || base.fragment === parentCandidate.fragment);\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\t// --- path math\n\n\tjoinPath(resource: URI, ...pathFragment: string[]): URI {\n\t\treturn URI.joinPath(resource, ...pathFragment);\n\t}\n\n\tbasenameOrAuthority(resource: URI): string {\n\t\treturn basename(resource) || resource.authority;\n\t}\n\n\tbasename(resource: URI): string {\n\t\treturn paths.posix.basename(resource.path);\n\t}\n\n\textname(resource: URI): string {\n\t\treturn paths.posix.extname(resource.path);\n\t}\n\n\tdirname(resource: URI): URI {\n\t\tif (resource.path.length === 0) {\n\t\t\treturn resource;\n\t\t}\n\t\tlet dirname;\n\t\tif (resource.scheme === Schemas.file) {\n\t\t\tdirname = URI.file(paths.dirname(originalFSPath(resource))).path;\n\t\t} else {\n\t\t\tdirname = paths.posix.dirname(resource.path);\n\t\t\tif (resource.authority && dirname.length && dirname.charCodeAt(0) !== CharCode.Slash) {\n\t\t\t\tconsole.error(`dirname(\"${resource.toString})) resulted in a relative path`);\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\n\t\t\t}\n\t\t}\n\t\treturn resource.with({\n\t\t\tpath: dirname\n\t\t});\n\t}\n\n\tnormalizePath(resource: URI): URI {\n\t\tif (!resource.path.length) {\n\t\t\treturn resource;\n\t\t}\n\t\tlet normalizedPath: string;\n\t\tif (resource.scheme === Schemas.file) {\n\t\t\tnormalizedPath = URI.file(paths.normalize(originalFSPath(resource))).path;\n\t\t} else {\n\t\t\tnormalizedPath = paths.posix.normalize(resource.path);\n\t\t}\n\t\treturn resource.with({\n\t\t\tpath: normalizedPath\n\t\t});\n\t}\n\n\trelativePath(from: URI, to: URI): string | undefined {\n\t\tif (from.scheme !== to.scheme || !isEqualAuthority(from.authority, to.authority)) {\n\t\t\treturn undefined;\n\t\t}\n\t\tif (from.scheme === Schemas.file) {\n\t\t\tconst relativePath = paths.relative(originalFSPath(from), originalFSPath(to));\n\t\t\treturn isWindows ? extpath.toSlashes(relativePath) : relativePath;\n\t\t}\n\t\tlet fromPath = from.path || '/';\n\t\tconst toPath = to.path || '/';\n\t\tif (this._ignorePathCasing(from)) {\n\t\t\t// make casing of fromPath match toPath\n\t\t\tlet i = 0;\n\t\t\tfor (const len = Math.min(fromPath.length, toPath.length); i < len; i++) {\n\t\t\t\tif (fromPath.charCodeAt(i) !== toPath.charCodeAt(i)) {\n\t\t\t\t\tif (fromPath.charAt(i).toLowerCase() !== toPath.charAt(i).toLowerCase()) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tfromPath = toPath.substr(0, i) + fromPath.substr(i);\n\t\t}\n\t\treturn paths.posix.relative(fromPath, toPath);\n\t}\n\n\tresolvePath(base: URI, path: string): URI {\n\t\tif (base.scheme === Schemas.file) {\n\t\t\tconst newURI = URI.file(paths.resolve(originalFSPath(base), path));\n\t\t\treturn base.with({\n\t\t\t\tauthority: newURI.authority,\n\t\t\t\tpath: newURI.path\n\t\t\t});\n\t\t}\n\t\tpath = extpath.toPosixPath(path); // we allow path to be a windows path\n\t\treturn base.with({\n\t\t\tpath: paths.posix.resolve(base.path, path)\n\t\t});\n\t}\n\n\t// --- misc\n\n\tisAbsolutePath(resource: URI): boolean {\n\t\treturn !!resource.path && resource.path[0] === '/';\n\t}\n\n\tisEqualAuthority(a1: string | undefined, a2: string | undefined) {\n\t\treturn a1 === a2 || (a1 !== undefined && a2 !== undefined && equalsIgnoreCase(a1, a2));\n\t}\n\n\thasTrailingPathSeparator(resource: URI, sep: string = paths.sep): boolean {\n\t\tif (resource.scheme === Schemas.file) {\n\t\t\tconst fsp = originalFSPath(resource);\n\t\t\treturn fsp.length > extpath.getRoot(fsp).length && fsp[fsp.length - 1] === sep;\n\t\t} else {\n\t\t\tconst p = resource.path;\n\t\t\treturn (p.length > 1 && p.charCodeAt(p.length - 1) === CharCode.Slash) && !(/^[a-zA-Z]:(\\/$|\\\\$)/.test(resource.fsPath)); // ignore the slash at offset 0\n\t\t}\n\t}\n\n\tremoveTrailingPathSeparator(resource: URI, sep: string = paths.sep): URI {\n\t\t// Make sure that the path isn't a drive letter. A trailing separator there is not removable.\n\t\tif (hasTrailingPathSeparator(resource, sep)) {\n\t\t\treturn resource.with({ path: resource.path.substr(0, resource.path.length - 1) });\n\t\t}\n\t\treturn resource;\n\t}\n\n\taddTrailingPathSeparator(resource: URI, sep: string = paths.sep): URI {\n\t\tlet isRootSep: boolean = false;\n\t\tif (resource.scheme === Schemas.file) {\n\t\t\tconst fsp = originalFSPath(resource);\n\t\t\tisRootSep = ((fsp !== undefined) && (fsp.length === extpath.getRoot(fsp).length) && (fsp[fsp.length - 1] === sep));\n\t\t} else {\n\t\t\tsep = '/';\n\t\t\tconst p = resource.path;\n\t\t\tisRootSep = p.length === 1 && p.charCodeAt(p.length - 1) === CharCode.Slash;\n\t\t}\n\t\tif (!isRootSep && !hasTrailingPathSeparator(resource, sep)) {\n\t\t\treturn resource.with({ path: resource.path + '/' });\n\t\t}\n\t\treturn resource;\n\t}\n}\n\n\n/**\n * Unbiased utility that takes uris \"as they are\". This means it can be interchanged with\n * uri#toString() usages. The following is true\n * ```\n * assertEqual(aUri.toString() === bUri.toString(), exturi.isEqual(aUri, bUri))\n * ```\n */\nexport const extUri = new ExtUri(() => false);\n\n/**\n * BIASED utility that _mostly_ ignored the case of urs paths. ONLY use this util if you\n * understand what you are doing.\n *\n * This utility is INCOMPATIBLE with `uri.toString()`-usages and both CANNOT be used interchanged.\n *\n * When dealing with uris from files or documents, `extUri` (the unbiased friend)is sufficient\n * because those uris come from a \"trustworthy source\". When creating unknown uris it's always\n * better to use `IUriIdentityService` which exposes an `IExtUri`-instance which knows when path\n * casing matters.\n */\nexport const extUriBiasedIgnorePathCase = new ExtUri(uri => {\n\t// A file scheme resource is in the same platform as code, so ignore case for non linux platforms\n\t// Resource can be from another platform. Lowering the case as an hack. Should come from File system provider\n\treturn uri.scheme === Schemas.file ? !isLinux : true;\n});\n\n\n/**\n * BIASED utility that always ignores the casing of uris paths. ONLY use this util if you\n * understand what you are doing.\n *\n * This utility is INCOMPATIBLE with `uri.toString()`-usages and both CANNOT be used interchanged.\n *\n * When dealing with uris from files or documents, `extUri` (the unbiased friend)is sufficient\n * because those uris come from a \"trustworthy source\". When creating unknown uris it's always\n * better to use `IUriIdentityService` which exposes an `IExtUri`-instance which knows when path\n * casing matters.\n */\nexport const extUriIgnorePathCase = new ExtUri(_ => true);\n\nexport const isEqual = extUri.isEqual.bind(extUri);\nexport const isEqualOrParent = extUri.isEqualOrParent.bind(extUri);\nexport const getComparisonKey = extUri.getComparisonKey.bind(extUri);\nexport const basenameOrAuthority = extUri.basenameOrAuthority.bind(extUri);\nexport const basename = extUri.basename.bind(extUri);\nexport const extname = extUri.extname.bind(extUri);\nexport const dirname = extUri.dirname.bind(extUri);\nexport const joinPath = extUri.joinPath.bind(extUri);\nexport const normalizePath = extUri.normalizePath.bind(extUri);\nexport const relativePath = extUri.relativePath.bind(extUri);\nexport const resolvePath = extUri.resolvePath.bind(extUri);\nexport const isAbsolutePath = extUri.isAbsolutePath.bind(extUri);\nexport const isEqualAuthority = extUri.isEqualAuthority.bind(extUri);\nexport const hasTrailingPathSeparator = extUri.hasTrailingPathSeparator.bind(extUri);\nexport const removeTrailingPathSeparator = extUri.removeTrailingPathSeparator.bind(extUri);\nexport const addTrailingPathSeparator = extUri.addTrailingPathSeparator.bind(extUri);\n\n/**\n * Data URI related helpers.\n */\nexport namespace DataUri {\n\n\texport const META_DATA_LABEL = 'label';\n\texport const META_DATA_DESCRIPTION = 'description';\n\texport const META_DATA_SIZE = 'size';\n\texport const META_DATA_MIME = 'mime';\n\n\texport function parseMetaData(dataUri: URI): Map {\n\t\tconst metadata = new Map();\n\n\t\t// Given a URI of: data:image/png;size:2313;label:SomeLabel;description:SomeDescription;base64,77+9UE5...\n\t\t// the metadata is: size:2313;label:SomeLabel;description:SomeDescription\n\t\tconst meta = dataUri.path.substring(dataUri.path.indexOf(';') + 1, dataUri.path.lastIndexOf(';'));\n\t\tmeta.split(';').forEach(property => {\n\t\t\tconst [key, value] = property.split(':');\n\t\t\tif (key && value) {\n\t\t\t\tmetadata.set(key, value);\n\t\t\t}\n\t\t});\n\n\t\t// Given a URI of: data:image/png;size:2313;label:SomeLabel;description:SomeDescription;base64,77+9UE5...\n\t\t// the mime is: image/png\n\t\tconst mime = dataUri.path.substring(0, dataUri.path.indexOf(';'));\n\t\tif (mime) {\n\t\t\tmetadata.set(META_DATA_MIME, mime);\n\t\t}\n\n\t\treturn metadata;\n\t}\n}\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\nimport { illegalArgument } from 'vs/base/common/errors';\nimport { escapeIcons } from 'vs/base/common/iconLabels';\nimport { isEqual } from 'vs/base/common/resources';\nimport { escapeRegExpCharacters } from 'vs/base/common/strings';\nimport { URI, UriComponents } from 'vs/base/common/uri';\n\nexport interface MarkdownStringTrustedOptions {\n\treadonly enabledCommands: readonly string[];\n}\n\nexport interface IMarkdownString {\n\treadonly value: string;\n\treadonly isTrusted?: boolean | MarkdownStringTrustedOptions;\n\treadonly supportThemeIcons?: boolean;\n\treadonly supportHtml?: boolean;\n\treadonly baseUri?: UriComponents;\n\turis?: { [href: string]: UriComponents };\n}\n\nexport const enum MarkdownStringTextNewlineStyle {\n\tParagraph = 0,\n\tBreak = 1,\n}\n\nexport class MarkdownString implements IMarkdownString {\n\n\tpublic value: string;\n\tpublic isTrusted?: boolean | MarkdownStringTrustedOptions;\n\tpublic supportThemeIcons?: boolean;\n\tpublic supportHtml?: boolean;\n\tpublic baseUri?: URI;\n\n\tconstructor(\n\t\tvalue: string = '',\n\t\tisTrustedOrOptions: boolean | { isTrusted?: boolean | MarkdownStringTrustedOptions; supportThemeIcons?: boolean; supportHtml?: boolean } = false,\n\t) {\n\t\tthis.value = value;\n\t\tif (typeof this.value !== 'string') {\n\t\t\tthrow illegalArgument('value');\n\t\t}\n\n\t\tif (typeof isTrustedOrOptions === 'boolean') {\n\t\t\tthis.isTrusted = isTrustedOrOptions;\n\t\t\tthis.supportThemeIcons = false;\n\t\t\tthis.supportHtml = false;\n\t\t}\n\t\telse {\n\t\t\tthis.isTrusted = isTrustedOrOptions.isTrusted ?? undefined;\n\t\t\tthis.supportThemeIcons = isTrustedOrOptions.supportThemeIcons ?? false;\n\t\t\tthis.supportHtml = isTrustedOrOptions.supportHtml ?? false;\n\t\t}\n\t}\n\n\tappendText(value: string, newlineStyle: MarkdownStringTextNewlineStyle = MarkdownStringTextNewlineStyle.Paragraph): MarkdownString {\n\t\tthis.value += escapeMarkdownSyntaxTokens(this.supportThemeIcons ? escapeIcons(value) : value) // CodeQL [SM02383] The Markdown is fully sanitized after being rendered.\n\t\t\t.replace(/([ \\t]+)/g, (_match, g1) => ' '.repeat(g1.length)) // CodeQL [SM02383] The Markdown is fully sanitized after being rendered.\n\t\t\t.replace(/\\>/gm, '\\\\>') // CodeQL [SM02383] The Markdown is fully sanitized after being rendered.\n\t\t\t.replace(/\\n/g, newlineStyle === MarkdownStringTextNewlineStyle.Break ? '\\\\\\n' : '\\n\\n'); // CodeQL [SM02383] The Markdown is fully sanitized after being rendered.\n\n\t\treturn this;\n\t}\n\n\tappendMarkdown(value: string): MarkdownString {\n\t\tthis.value += value;\n\t\treturn this;\n\t}\n\n\tappendCodeblock(langId: string, code: string): MarkdownString {\n\t\tthis.value += `\\n${appendEscapedMarkdownCodeBlockFence(code, langId)}\\n`;\n\t\treturn this;\n\t}\n\n\tappendLink(target: URI | string, label: string, title?: string): MarkdownString {\n\t\tthis.value += '[';\n\t\tthis.value += this._escape(label, ']');\n\t\tthis.value += '](';\n\t\tthis.value += this._escape(String(target), ')');\n\t\tif (title) {\n\t\t\tthis.value += ` \"${this._escape(this._escape(title, '\"'), ')')}\"`;\n\t\t}\n\t\tthis.value += ')';\n\t\treturn this;\n\t}\n\n\tprivate _escape(value: string, ch: string): string {\n\t\tconst r = new RegExp(escapeRegExpCharacters(ch), 'g');\n\t\treturn value.replace(r, (match, offset) => {\n\t\t\tif (value.charAt(offset - 1) !== '\\\\') {\n\t\t\t\treturn `\\\\${match}`;\n\t\t\t} else {\n\t\t\t\treturn match;\n\t\t\t}\n\t\t});\n\t}\n}\n\nexport function isEmptyMarkdownString(oneOrMany: IMarkdownString | IMarkdownString[] | null | undefined): boolean {\n\tif (isMarkdownString(oneOrMany)) {\n\t\treturn !oneOrMany.value;\n\t} else if (Array.isArray(oneOrMany)) {\n\t\treturn oneOrMany.every(isEmptyMarkdownString);\n\t} else {\n\t\treturn true;\n\t}\n}\n\nexport function isMarkdownString(thing: any): thing is IMarkdownString {\n\tif (thing instanceof MarkdownString) {\n\t\treturn true;\n\t} else if (thing && typeof thing === 'object') {\n\t\treturn typeof (thing).value === 'string'\n\t\t\t&& (typeof (thing).isTrusted === 'boolean' || typeof (thing).isTrusted === 'object' || (thing).isTrusted === undefined)\n\t\t\t&& (typeof (thing).supportThemeIcons === 'boolean' || (thing).supportThemeIcons === undefined);\n\t}\n\treturn false;\n}\n\nexport function markdownStringEqual(a: IMarkdownString, b: IMarkdownString): boolean {\n\tif (a === b) {\n\t\treturn true;\n\t} else if (!a || !b) {\n\t\treturn false;\n\t} else {\n\t\treturn a.value === b.value\n\t\t\t&& a.isTrusted === b.isTrusted\n\t\t\t&& a.supportThemeIcons === b.supportThemeIcons\n\t\t\t&& a.supportHtml === b.supportHtml\n\t\t\t&& (a.baseUri === b.baseUri || !!a.baseUri && !!b.baseUri && isEqual(URI.from(a.baseUri), URI.from(b.baseUri)));\n\t}\n}\n\nexport function escapeMarkdownSyntaxTokens(text: string): string {\n\t// escape markdown syntax tokens: http://daringfireball.net/projects/markdown/syntax#backslash\n\treturn text.replace(/[\\\\`*_{}[\\]()#+\\-!~]/g, '\\\\$&'); // CodeQL [SM02383] Backslash is escaped in the character class\n}\n\n/**\n * @see https://github.com/microsoft/vscode/issues/193746\n */\nexport function appendEscapedMarkdownCodeBlockFence(code: string, langId: string) {\n\tconst longestFenceLength =\n\t\tcode.match(/^`+/gm)?.reduce((a, b) => (a.length > b.length ? a : b)).length ??\n\t\t0;\n\tconst desiredFenceLength =\n\t\tlongestFenceLength >= 3 ? longestFenceLength + 1 : 3;\n\n\t// the markdown result\n\treturn [\n\t\t`${'`'.repeat(desiredFenceLength)}${langId}`,\n\t\tcode,\n\t\t`${'`'.repeat(desiredFenceLength)}`,\n\t].join('\\n');\n}\n\nexport function escapeDoubleQuotes(input: string) {\n\treturn input.replace(/\"/g, '"');\n}\n\nexport function removeMarkdownEscapes(text: string): string {\n\tif (!text) {\n\t\treturn text;\n\t}\n\treturn text.replace(/\\\\([\\\\`*_{}[\\]()#+\\-.!~])/g, '$1');\n}\n\nexport function parseHrefAndDimensions(href: string): { href: string; dimensions: string[] } {\n\tconst dimensions: string[] = [];\n\tconst splitted = href.split('|').map(s => s.trim());\n\thref = splitted[0];\n\tconst parameters = splitted[1];\n\tif (parameters) {\n\t\tconst heightFromParams = /height=(\\d+)/.exec(parameters);\n\t\tconst widthFromParams = /width=(\\d+)/.exec(parameters);\n\t\tconst height = heightFromParams ? heightFromParams[1] : '';\n\t\tconst width = widthFromParams ? widthFromParams[1] : '';\n\t\tconst widthIsFinite = isFinite(parseInt(width));\n\t\tconst heightIsFinite = isFinite(parseInt(height));\n\t\tif (widthIsFinite) {\n\t\t\tdimensions.push(`width=\"${width}\"`);\n\t\t}\n\t\tif (heightIsFinite) {\n\t\t\tdimensions.push(`height=\"${height}\"`);\n\t\t}\n\t}\n\treturn { href, dimensions };\n}\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\nimport * as DOM from 'vs/base/browser/dom';\nimport * as dompurify from 'vs/base/browser/dompurify/dompurify';\nimport { DomEmitter } from 'vs/base/browser/event';\nimport { createElement, FormattedTextRenderOptions } from 'vs/base/browser/formattedTextRenderer';\nimport { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';\nimport { StandardMouseEvent } from 'vs/base/browser/mouseEvent';\nimport { renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels';\nimport { onUnexpectedError } from 'vs/base/common/errors';\nimport { Event } from 'vs/base/common/event';\nimport { escapeDoubleQuotes, IMarkdownString, MarkdownStringTrustedOptions, parseHrefAndDimensions, removeMarkdownEscapes } from 'vs/base/common/htmlContent';\nimport { markdownEscapeEscapedIcons } from 'vs/base/common/iconLabels';\nimport { defaultGenerator } from 'vs/base/common/idGenerator';\nimport { KeyCode } from 'vs/base/common/keyCodes';\nimport { Lazy } from 'vs/base/common/lazy';\nimport { DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle';\nimport { marked } from 'vs/base/common/marked/marked';\nimport { parse } from 'vs/base/common/marshalling';\nimport { FileAccess, Schemas } from 'vs/base/common/network';\nimport { cloneAndChange } from 'vs/base/common/objects';\nimport { dirname, resolvePath } from 'vs/base/common/resources';\nimport { escape } from 'vs/base/common/strings';\nimport { URI } from 'vs/base/common/uri';\n\nexport interface MarkedOptions extends marked.MarkedOptions {\n}\n\nexport interface MarkdownRenderOptions extends FormattedTextRenderOptions {\n\treadonly codeBlockRenderer?: (languageId: string, value: string) => Promise;\n\treadonly codeBlockRendererSync?: (languageId: string, value: string) => HTMLElement;\n\treadonly asyncRenderCallback?: () => void;\n\treadonly fillInIncompleteTokens?: boolean;\n\treadonly remoteImageIsAllowed?: (uri: URI) => boolean;\n\treadonly sanitizerOptions?: ISanitizerOptions;\n}\n\nexport interface ISanitizerOptions {\n\treplaceWithPlaintext?: boolean;\n\tallowedTags?: string[];\n}\n\nconst defaultMarkedRenderers = Object.freeze({\n\timage: (href: string | null, title: string | null, text: string): string => {\n\t\tlet dimensions: string[] = [];\n\t\tlet attributes: string[] = [];\n\t\tif (href) {\n\t\t\t({ href, dimensions } = parseHrefAndDimensions(href));\n\t\t\tattributes.push(`src=\"${escapeDoubleQuotes(href)}\"`);\n\t\t}\n\t\tif (text) {\n\t\t\tattributes.push(`alt=\"${escapeDoubleQuotes(text)}\"`);\n\t\t}\n\t\tif (title) {\n\t\t\tattributes.push(`title=\"${escapeDoubleQuotes(title)}\"`);\n\t\t}\n\t\tif (dimensions.length) {\n\t\t\tattributes = attributes.concat(dimensions);\n\t\t}\n\t\treturn '';\n\t},\n\n\tparagraph: (text: string): string => {\n\t\treturn `

    ${text}

    `;\n\t},\n\n\tlink: (href: string | null, title: string | null, text: string): string => {\n\t\tif (typeof href !== 'string') {\n\t\t\treturn '';\n\t\t}\n\n\t\t// Remove markdown escapes. Workaround for https://github.com/chjj/marked/issues/829\n\t\tif (href === text) { // raw link case\n\t\t\ttext = removeMarkdownEscapes(text);\n\t\t}\n\n\t\ttitle = typeof title === 'string' ? escapeDoubleQuotes(removeMarkdownEscapes(title)) : '';\n\t\thref = removeMarkdownEscapes(href);\n\n\t\t// HTML Encode href\n\t\thref = href.replace(/&/g, '&')\n\t\t\t.replace(//g, '>')\n\t\t\t.replace(/\"/g, '"')\n\t\t\t.replace(/'/g, ''');\n\n\t\treturn `
    ${text}`;\n\t},\n});\n\n/**\n * Low-level way create a html element from a markdown string.\n *\n * **Note** that for most cases you should be using [`MarkdownRenderer`](./src/vs/editor/contrib/markdownRenderer/browser/markdownRenderer.ts)\n * which comes with support for pretty code block rendering and which uses the default way of handling links.\n */\nexport function renderMarkdown(markdown: IMarkdownString, options: MarkdownRenderOptions = {}, markedOptions: MarkedOptions = {}): { element: HTMLElement; dispose: () => void } {\n\tconst disposables = new DisposableStore();\n\tlet isDisposed = false;\n\n\tconst element = createElement(options);\n\n\tconst _uriMassage = function (part: string): string {\n\t\tlet data: any;\n\t\ttry {\n\t\t\tdata = parse(decodeURIComponent(part));\n\t\t} catch (e) {\n\t\t\t// ignore\n\t\t}\n\t\tif (!data) {\n\t\t\treturn part;\n\t\t}\n\t\tdata = cloneAndChange(data, value => {\n\t\t\tif (markdown.uris && markdown.uris[value]) {\n\t\t\t\treturn URI.revive(markdown.uris[value]);\n\t\t\t} else {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t});\n\t\treturn encodeURIComponent(JSON.stringify(data));\n\t};\n\n\tconst _href = function (href: string, isDomUri: boolean): string {\n\t\tconst data = markdown.uris && markdown.uris[href];\n\t\tlet uri = URI.revive(data);\n\t\tif (isDomUri) {\n\t\t\tif (href.startsWith(Schemas.data + ':')) {\n\t\t\t\treturn href;\n\t\t\t}\n\t\t\tif (!uri) {\n\t\t\t\turi = URI.parse(href);\n\t\t\t}\n\t\t\t// this URI will end up as \"src\"-attribute of a dom node\n\t\t\t// and because of that special rewriting needs to be done\n\t\t\t// so that the URI uses a protocol that's understood by\n\t\t\t// browsers (like http or https)\n\t\t\treturn FileAccess.uriToBrowserUri(uri).toString(true);\n\t\t}\n\t\tif (!uri) {\n\t\t\treturn href;\n\t\t}\n\t\tif (URI.parse(href).toString() === uri.toString()) {\n\t\t\treturn href; // no transformation performed\n\t\t}\n\t\tif (uri.query) {\n\t\t\turi = uri.with({ query: _uriMassage(uri.query) });\n\t\t}\n\t\treturn uri.toString();\n\t};\n\n\tconst renderer = new marked.Renderer();\n\trenderer.image = defaultMarkedRenderers.image;\n\trenderer.link = defaultMarkedRenderers.link;\n\trenderer.paragraph = defaultMarkedRenderers.paragraph;\n\n\t// Will collect [id, renderedElement] tuples\n\tconst codeBlocks: Promise<[string, HTMLElement]>[] = [];\n\tconst syncCodeBlocks: [string, HTMLElement][] = [];\n\n\tif (options.codeBlockRendererSync) {\n\t\trenderer.code = (code, lang) => {\n\t\t\tconst id = defaultGenerator.nextId();\n\t\t\tconst value = options.codeBlockRendererSync!(postProcessCodeBlockLanguageId(lang), code);\n\t\t\tsyncCodeBlocks.push([id, value]);\n\t\t\treturn `
    ${escape(code)}
    `;\n\t\t};\n\t} else if (options.codeBlockRenderer) {\n\t\trenderer.code = (code, lang) => {\n\t\t\tconst id = defaultGenerator.nextId();\n\t\t\tconst value = options.codeBlockRenderer!(postProcessCodeBlockLanguageId(lang), code);\n\t\t\tcodeBlocks.push(value.then(element => [id, element]));\n\t\t\treturn `
    ${escape(code)}
    `;\n\t\t};\n\t}\n\n\tif (options.actionHandler) {\n\t\tconst _activateLink = function (event: StandardMouseEvent | StandardKeyboardEvent): void {\n\t\t\tlet target: HTMLElement | null = event.target;\n\t\t\tif (target.tagName !== 'A') {\n\t\t\t\ttarget = target.parentElement;\n\t\t\t\tif (!target || target.tagName !== 'A') {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tlet href = target.dataset['href'];\n\t\t\t\tif (href) {\n\t\t\t\t\tif (markdown.baseUri) {\n\t\t\t\t\t\thref = resolveWithBaseUri(URI.from(markdown.baseUri), href);\n\t\t\t\t\t}\n\t\t\t\t\toptions.actionHandler!.callback(href, event);\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tonUnexpectedError(err);\n\t\t\t} finally {\n\t\t\t\tevent.preventDefault();\n\t\t\t}\n\t\t};\n\t\tconst onClick = options.actionHandler.disposables.add(new DomEmitter(element, 'click'));\n\t\tconst onAuxClick = options.actionHandler.disposables.add(new DomEmitter(element, 'auxclick'));\n\t\toptions.actionHandler.disposables.add(Event.any(onClick.event, onAuxClick.event)(e => {\n\t\t\tconst mouseEvent = new StandardMouseEvent(DOM.getWindow(element), e);\n\t\t\tif (!mouseEvent.leftButton && !mouseEvent.middleButton) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t_activateLink(mouseEvent);\n\t\t}));\n\t\toptions.actionHandler.disposables.add(DOM.addDisposableListener(element, 'keydown', (e) => {\n\t\t\tconst keyboardEvent = new StandardKeyboardEvent(e);\n\t\t\tif (!keyboardEvent.equals(KeyCode.Space) && !keyboardEvent.equals(KeyCode.Enter)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t_activateLink(keyboardEvent);\n\t\t}));\n\t}\n\n\tif (!markdown.supportHtml) {\n\t\t// TODO: Can we deprecated this in favor of 'supportHtml'?\n\n\t\t// Use our own sanitizer so that we can let through only spans.\n\t\t// Otherwise, we'd be letting all html be rendered.\n\t\t// If we want to allow markdown permitted tags, then we can delete sanitizer and sanitize.\n\t\t// We always pass the output through dompurify after this so that we don't rely on\n\t\t// marked for sanitization.\n\t\tmarkedOptions.sanitizer = (html: string): string => {\n\t\t\tif (options.sanitizerOptions?.replaceWithPlaintext) {\n\t\t\t\treturn escape(html);\n\t\t\t}\n\n\t\t\tconst match = markdown.isTrusted ? html.match(/^(]+>)|(<\\/\\s*span>)$/) : undefined;\n\t\t\treturn match ? html : '';\n\t\t};\n\t\tmarkedOptions.sanitize = true;\n\t\tmarkedOptions.silent = true;\n\t}\n\n\tmarkedOptions.renderer = renderer;\n\n\t// values that are too long will freeze the UI\n\tlet value = markdown.value ?? '';\n\tif (value.length > 100_000) {\n\t\tvalue = `${value.substr(0, 100_000)}…`;\n\t}\n\t// escape theme icons\n\tif (markdown.supportThemeIcons) {\n\t\tvalue = markdownEscapeEscapedIcons(value);\n\t}\n\n\tlet renderedMarkdown: string;\n\tif (options.fillInIncompleteTokens) {\n\t\t// The defaults are applied by parse but not lexer()/parser(), and they need to be present\n\t\tconst opts = {\n\t\t\t...marked.defaults,\n\t\t\t...markedOptions\n\t\t};\n\t\tconst tokens = marked.lexer(value, opts);\n\t\tconst newTokens = fillInIncompleteTokens(tokens);\n\t\trenderedMarkdown = marked.parser(newTokens, opts);\n\t} else {\n\t\trenderedMarkdown = marked.parse(value, markedOptions);\n\t}\n\n\t// Rewrite theme icons\n\tif (markdown.supportThemeIcons) {\n\t\tconst elements = renderLabelWithIcons(renderedMarkdown);\n\t\trenderedMarkdown = elements.map(e => typeof e === 'string' ? e : e.outerHTML).join('');\n\t}\n\n\tconst htmlParser = new DOMParser();\n\tconst markdownHtmlDoc = htmlParser.parseFromString(sanitizeRenderedMarkdown({ isTrusted: markdown.isTrusted, ...options.sanitizerOptions }, renderedMarkdown) as unknown as string, 'text/html');\n\n\tmarkdownHtmlDoc.body.querySelectorAll('img, audio, video, source')\n\t\t.forEach(img => {\n\t\t\tconst src = img.getAttribute('src'); // Get the raw 'src' attribute value as text, not the resolved 'src'\n\t\t\tif (src) {\n\t\t\t\tlet href = src;\n\t\t\t\ttry {\n\t\t\t\t\tif (markdown.baseUri) { // absolute or relative local path, or file: uri\n\t\t\t\t\t\thref = resolveWithBaseUri(URI.from(markdown.baseUri), href);\n\t\t\t\t\t}\n\t\t\t\t} catch (err) { }\n\n\t\t\t\timg.setAttribute('src', _href(href, true));\n\n\t\t\t\tif (options.remoteImageIsAllowed) {\n\t\t\t\t\tconst uri = URI.parse(href);\n\t\t\t\t\tif (uri.scheme !== Schemas.file && uri.scheme !== Schemas.data && !options.remoteImageIsAllowed(uri)) {\n\t\t\t\t\t\timg.replaceWith(DOM.$('', undefined, img.outerHTML));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\tmarkdownHtmlDoc.body.querySelectorAll('a')\n\t\t.forEach(a => {\n\t\t\tconst href = a.getAttribute('href'); // Get the raw 'href' attribute value as text, not the resolved 'href'\n\t\t\ta.setAttribute('href', ''); // Clear out href. We use the `data-href` for handling clicks instead\n\t\t\tif (\n\t\t\t\t!href\n\t\t\t\t|| /^data:|javascript:/i.test(href)\n\t\t\t\t|| (/^command:/i.test(href) && !markdown.isTrusted)\n\t\t\t\t|| /^command:(\\/\\/\\/)?_workbench\\.downloadResource/i.test(href)\n\t\t\t) {\n\t\t\t\t// drop the link\n\t\t\t\ta.replaceWith(...a.childNodes);\n\t\t\t} else {\n\t\t\t\tlet resolvedHref = _href(href, false);\n\t\t\t\tif (markdown.baseUri) {\n\t\t\t\t\tresolvedHref = resolveWithBaseUri(URI.from(markdown.baseUri), href);\n\t\t\t\t}\n\t\t\t\ta.dataset.href = resolvedHref;\n\t\t\t}\n\t\t});\n\n\telement.innerHTML = sanitizeRenderedMarkdown({ isTrusted: markdown.isTrusted, ...options.sanitizerOptions }, markdownHtmlDoc.body.innerHTML) as unknown as string;\n\n\tif (codeBlocks.length > 0) {\n\t\tPromise.all(codeBlocks).then((tuples) => {\n\t\t\tif (isDisposed) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst renderedElements = new Map(tuples);\n\t\t\tconst placeholderElements = element.querySelectorAll(`div[data-code]`);\n\t\t\tfor (const placeholderElement of placeholderElements) {\n\t\t\t\tconst renderedElement = renderedElements.get(placeholderElement.dataset['code'] ?? '');\n\t\t\t\tif (renderedElement) {\n\t\t\t\t\tDOM.reset(placeholderElement, renderedElement);\n\t\t\t\t}\n\t\t\t}\n\t\t\toptions.asyncRenderCallback?.();\n\t\t});\n\t} else if (syncCodeBlocks.length > 0) {\n\t\tconst renderedElements = new Map(syncCodeBlocks);\n\t\tconst placeholderElements = element.querySelectorAll(`div[data-code]`);\n\t\tfor (const placeholderElement of placeholderElements) {\n\t\t\tconst renderedElement = renderedElements.get(placeholderElement.dataset['code'] ?? '');\n\t\t\tif (renderedElement) {\n\t\t\t\tDOM.reset(placeholderElement, renderedElement);\n\t\t\t}\n\t\t}\n\t}\n\n\t// signal size changes for image tags\n\tif (options.asyncRenderCallback) {\n\t\tfor (const img of element.getElementsByTagName('img')) {\n\t\t\tconst listener = disposables.add(DOM.addDisposableListener(img, 'load', () => {\n\t\t\t\tlistener.dispose();\n\t\t\t\toptions.asyncRenderCallback!();\n\t\t\t}));\n\t\t}\n\t}\n\n\treturn {\n\t\telement,\n\t\tdispose: () => {\n\t\t\tisDisposed = true;\n\t\t\tdisposables.dispose();\n\t\t}\n\t};\n}\n\nfunction postProcessCodeBlockLanguageId(lang: string | undefined): string {\n\tif (!lang) {\n\t\treturn '';\n\t}\n\n\tconst parts = lang.split(/[\\s+|:|,|\\{|\\?]/, 1);\n\tif (parts.length) {\n\t\treturn parts[0];\n\t}\n\treturn lang;\n}\n\nfunction resolveWithBaseUri(baseUri: URI, href: string): string {\n\tconst hasScheme = /^\\w[\\w\\d+.-]*:/.test(href);\n\tif (hasScheme) {\n\t\treturn href;\n\t}\n\n\tif (baseUri.path.endsWith('/')) {\n\t\treturn resolvePath(baseUri, href).toString();\n\t} else {\n\t\treturn resolvePath(dirname(baseUri), href).toString();\n\t}\n}\n\ninterface IInternalSanitizerOptions extends ISanitizerOptions {\n\tisTrusted?: boolean | MarkdownStringTrustedOptions;\n}\n\nconst selfClosingTags = ['area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr'];\n\nfunction sanitizeRenderedMarkdown(\n\toptions: IInternalSanitizerOptions,\n\trenderedMarkdown: string,\n): TrustedHTML {\n\tconst { config, allowedSchemes } = getSanitizerOptions(options);\n\tconst store = new DisposableStore();\n\tstore.add(addDompurifyHook('uponSanitizeAttribute', (element, e) => {\n\t\tif (e.attrName === 'style' || e.attrName === 'class') {\n\t\t\tif (element.tagName === 'SPAN') {\n\t\t\t\tif (e.attrName === 'style') {\n\t\t\t\t\te.keepAttr = /^(color\\:(#[0-9a-fA-F]+|var\\(--vscode(-[a-zA-Z]+)+\\));)?(background-color\\:(#[0-9a-fA-F]+|var\\(--vscode(-[a-zA-Z]+)+\\));)?$/.test(e.attrValue);\n\t\t\t\t\treturn;\n\t\t\t\t} else if (e.attrName === 'class') {\n\t\t\t\t\te.keepAttr = /^codicon codicon-[a-z\\-]+( codicon-modifier-[a-z\\-]+)?$/.test(e.attrValue);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\te.keepAttr = false;\n\t\t\treturn;\n\t\t} else if (element.tagName === 'INPUT' && element.attributes.getNamedItem('type')?.value === 'checkbox') {\n\t\t\tif ((e.attrName === 'type' && e.attrValue === 'checkbox') || e.attrName === 'disabled' || e.attrName === 'checked') {\n\t\t\t\te.keepAttr = true;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\te.keepAttr = false;\n\t\t}\n\t}));\n\n\tstore.add(addDompurifyHook('uponSanitizeElement', (element, e) => {\n\t\tif (e.tagName === 'input') {\n\t\t\tif (element.attributes.getNamedItem('type')?.value === 'checkbox') {\n\t\t\t\telement.setAttribute('disabled', '');\n\t\t\t} else if (!options.replaceWithPlaintext) {\n\t\t\t\telement.parentElement?.removeChild(element);\n\t\t\t}\n\t\t}\n\n\t\tif (options.replaceWithPlaintext && !e.allowedTags[e.tagName] && e.tagName !== 'body') {\n\t\t\tif (element.parentElement) {\n\t\t\t\tlet startTagText: string;\n\t\t\t\tlet endTagText: string | undefined;\n\t\t\t\tif (e.tagName === '#comment') {\n\t\t\t\t\tstartTagText = ``;\n\t\t\t\t} else {\n\t\t\t\t\tconst isSelfClosing = selfClosingTags.includes(e.tagName);\n\t\t\t\t\tconst attrString = element.attributes.length ?\n\t\t\t\t\t\t' ' + Array.from(element.attributes)\n\t\t\t\t\t\t\t.map(attr => `${attr.name}=\"${attr.value}\"`)\n\t\t\t\t\t\t\t.join(' ')\n\t\t\t\t\t\t: '';\n\t\t\t\t\tstartTagText = `<${e.tagName}${attrString}>`;\n\t\t\t\t\tif (!isSelfClosing) {\n\t\t\t\t\t\tendTagText = ``;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst fragment = document.createDocumentFragment();\n\t\t\t\tconst textNode = element.parentElement.ownerDocument.createTextNode(startTagText);\n\t\t\t\tfragment.appendChild(textNode);\n\t\t\t\tconst endTagTextNode = endTagText ? element.parentElement.ownerDocument.createTextNode(endTagText) : undefined;\n\t\t\t\twhile (element.firstChild) {\n\t\t\t\t\tfragment.appendChild(element.firstChild);\n\t\t\t\t}\n\n\t\t\t\tif (endTagTextNode) {\n\t\t\t\t\tfragment.appendChild(endTagTextNode);\n\t\t\t\t}\n\n\t\t\t\telement.parentElement.replaceChild(fragment, element);\n\t\t\t}\n\t\t}\n\t}));\n\n\tstore.add(DOM.hookDomPurifyHrefAndSrcSanitizer(allowedSchemes));\n\n\ttry {\n\t\treturn dompurify.sanitize(renderedMarkdown, { ...config, RETURN_TRUSTED_TYPE: true });\n\t} finally {\n\t\tstore.dispose();\n\t}\n}\n\nexport const allowedMarkdownAttr = [\n\t'align',\n\t'autoplay',\n\t'alt',\n\t'checked',\n\t'class',\n\t'controls',\n\t'data-code',\n\t'data-href',\n\t'disabled',\n\t'draggable',\n\t'height',\n\t'href',\n\t'loop',\n\t'muted',\n\t'playsinline',\n\t'poster',\n\t'src',\n\t'style',\n\t'target',\n\t'title',\n\t'type',\n\t'width',\n\t'start',\n];\n\nfunction getSanitizerOptions(options: IInternalSanitizerOptions): { config: dompurify.Config; allowedSchemes: string[] } {\n\tconst allowedSchemes = [\n\t\tSchemas.http,\n\t\tSchemas.https,\n\t\tSchemas.mailto,\n\t\tSchemas.data,\n\t\tSchemas.file,\n\t\tSchemas.vscodeFileResource,\n\t\tSchemas.vscodeRemote,\n\t\tSchemas.vscodeRemoteResource,\n\t];\n\n\tif (options.isTrusted) {\n\t\tallowedSchemes.push(Schemas.command);\n\t}\n\n\treturn {\n\t\tconfig: {\n\t\t\t// allowedTags should included everything that markdown renders to.\n\t\t\t// Since we have our own sanitize function for marked, it's possible we missed some tag so let dompurify make sure.\n\t\t\t// HTML tags that can result from markdown are from reading https://spec.commonmark.org/0.29/\n\t\t\t// HTML table tags that can result from markdown are from https://github.github.com/gfm/#tables-extension-\n\t\t\tALLOWED_TAGS: options.allowedTags ?? [...DOM.basicMarkupHtmlTags],\n\t\t\tALLOWED_ATTR: allowedMarkdownAttr,\n\t\t\tALLOW_UNKNOWN_PROTOCOLS: true,\n\t\t},\n\t\tallowedSchemes\n\t};\n}\n\n/**\n * Strips all markdown from `string`, if it's an IMarkdownString. For example\n * `# Header` would be output as `Header`. If it's not, the string is returned.\n */\nexport function renderStringAsPlaintext(string: IMarkdownString | string) {\n\treturn typeof string === 'string' ? string : renderMarkdownAsPlaintext(string);\n}\n\n/**\n * Strips all markdown from `markdown`. For example `# Header` would be output as `Header`.\n * provide @param withCodeBlocks to retain code blocks\n */\nexport function renderMarkdownAsPlaintext(markdown: IMarkdownString, withCodeBlocks?: boolean) {\n\t// values that are too long will freeze the UI\n\tlet value = markdown.value ?? '';\n\tif (value.length > 100_000) {\n\t\tvalue = `${value.substr(0, 100_000)}…`;\n\t}\n\n\tconst html = marked.parse(value, { renderer: withCodeBlocks ? plainTextWithCodeBlocksRenderer.value : plainTextRenderer.value }).replace(/&(#\\d+|[a-zA-Z]+);/g, m => unescapeInfo.get(m) ?? m);\n\n\treturn sanitizeRenderedMarkdown({ isTrusted: false }, html).toString();\n}\n\nconst unescapeInfo = new Map([\n\t['"', '\"'],\n\t[' ', ' '],\n\t['&', '&'],\n\t[''', '\\''],\n\t['<', '<'],\n\t['>', '>'],\n]);\n\nfunction createRenderer(): marked.Renderer {\n\tconst renderer = new marked.Renderer();\n\n\trenderer.code = (code: string): string => {\n\t\treturn code;\n\t};\n\trenderer.blockquote = (quote: string): string => {\n\t\treturn quote;\n\t};\n\trenderer.html = (_html: string): string => {\n\t\treturn '';\n\t};\n\trenderer.heading = (text: string, _level: 1 | 2 | 3 | 4 | 5 | 6, _raw: string): string => {\n\t\treturn text + '\\n';\n\t};\n\trenderer.hr = (): string => {\n\t\treturn '';\n\t};\n\trenderer.list = (body: string, _ordered: boolean): string => {\n\t\treturn body;\n\t};\n\trenderer.listitem = (text: string): string => {\n\t\treturn text + '\\n';\n\t};\n\trenderer.paragraph = (text: string): string => {\n\t\treturn text + '\\n';\n\t};\n\trenderer.table = (header: string, body: string): string => {\n\t\treturn header + body + '\\n';\n\t};\n\trenderer.tablerow = (content: string): string => {\n\t\treturn content;\n\t};\n\trenderer.tablecell = (content: string, _flags: {\n\t\theader: boolean;\n\t\talign: 'center' | 'left' | 'right' | null;\n\t}): string => {\n\t\treturn content + ' ';\n\t};\n\trenderer.strong = (text: string): string => {\n\t\treturn text;\n\t};\n\trenderer.em = (text: string): string => {\n\t\treturn text;\n\t};\n\trenderer.codespan = (code: string): string => {\n\t\treturn code;\n\t};\n\trenderer.br = (): string => {\n\t\treturn '\\n';\n\t};\n\trenderer.del = (text: string): string => {\n\t\treturn text;\n\t};\n\trenderer.image = (_href: string, _title: string, _text: string): string => {\n\t\treturn '';\n\t};\n\trenderer.text = (text: string): string => {\n\t\treturn text;\n\t};\n\trenderer.link = (_href: string, _title: string, text: string): string => {\n\t\treturn text;\n\t};\n\treturn renderer;\n}\nconst plainTextRenderer = new Lazy((withCodeBlocks?: boolean) => createRenderer());\nconst plainTextWithCodeBlocksRenderer = new Lazy(() => {\n\tconst renderer = createRenderer();\n\trenderer.code = (code: string): string => {\n\t\treturn '\\n' + '```' + code + '```' + '\\n';\n\t};\n\treturn renderer;\n});\n\nfunction mergeRawTokenText(tokens: marked.Token[]): string {\n\tlet mergedTokenText = '';\n\ttokens.forEach(token => {\n\t\tmergedTokenText += token.raw;\n\t});\n\treturn mergedTokenText;\n}\n\nfunction completeSingleLinePattern(token: marked.Tokens.Text | marked.Tokens.Paragraph): marked.Token | undefined {\n\tif (!token.tokens) {\n\t\treturn undefined;\n\t}\n\n\tfor (let i = token.tokens.length - 1; i >= 0; i--) {\n\t\tconst subtoken = token.tokens[i];\n\t\tif (subtoken.type === 'text') {\n\t\t\tconst lines = subtoken.raw.split('\\n');\n\t\t\tconst lastLine = lines[lines.length - 1];\n\t\t\tif (lastLine.includes('`')) {\n\t\t\t\treturn completeCodespan(token);\n\t\t\t}\n\n\t\t\telse if (lastLine.includes('**')) {\n\t\t\t\treturn completeDoublestar(token);\n\t\t\t}\n\n\t\t\telse if (lastLine.match(/\\*\\w/)) {\n\t\t\t\treturn completeStar(token);\n\t\t\t}\n\n\t\t\telse if (lastLine.match(/(^|\\s)__\\w/)) {\n\t\t\t\treturn completeDoubleUnderscore(token);\n\t\t\t}\n\n\t\t\telse if (lastLine.match(/(^|\\s)_\\w/)) {\n\t\t\t\treturn completeUnderscore(token);\n\t\t\t}\n\n\t\t\telse if (\n\t\t\t\t// Text with start of link target\n\t\t\t\thasLinkTextAndStartOfLinkTarget(lastLine) ||\n\t\t\t\t// This token doesn't have the link text, eg if it contains other markdown constructs that are in other subtokens.\n\t\t\t\t// But some preceding token does have an unbalanced [ at least\n\t\t\t\thasStartOfLinkTargetAndNoLinkText(lastLine) && token.tokens.slice(0, i).some(t => t.type === 'text' && t.raw.match(/\\[[^\\]]*$/))\n\t\t\t) {\n\t\t\t\tconst nextTwoSubTokens = token.tokens.slice(i + 1);\n\n\t\t\t\t// A markdown link can look like\n\t\t\t\t// [link text](https://microsoft.com \"more text\")\n\t\t\t\t// Where \"more text\" is a title for the link or an argument to a vscode command link\n\t\t\t\tif (\n\t\t\t\t\t// If the link was parsed as a link, then look for a link token and a text token with a quote\n\t\t\t\t\tnextTwoSubTokens[0]?.type === 'link' && nextTwoSubTokens[1]?.type === 'text' && nextTwoSubTokens[1].raw.match(/^ *\"[^\"]*$/) ||\n\t\t\t\t\t// And if the link was not parsed as a link (eg command link), just look for a single quote in this token\n\t\t\t\t\tlastLine.match(/^[^\"]* +\"[^\"]*$/)\n\t\t\t\t) {\n\n\t\t\t\t\treturn completeLinkTargetArg(token);\n\t\t\t\t}\n\t\t\t\treturn completeLinkTarget(token);\n\t\t\t}\n\n\t\t\t// Contains the start of link text, and no following tokens contain the link target\n\t\t\telse if (lastLine.match(/(^|\\s)\\[\\w*/)) {\n\t\t\t\treturn completeLinkText(token);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn undefined;\n}\n\nfunction hasLinkTextAndStartOfLinkTarget(str: string): boolean {\n\treturn !!str.match(/(^|\\s)\\[.*\\]\\(\\w*/);\n}\n\nfunction hasStartOfLinkTargetAndNoLinkText(str: string): boolean {\n\treturn !!str.match(/^[^\\[]*\\]\\([^\\)]*$/);\n}\n\nfunction completeListItemPattern(list: marked.Tokens.List): marked.Tokens.List | undefined {\n\t// Patch up this one list item\n\tconst lastListItem = list.items[list.items.length - 1];\n\tconst lastListSubToken = lastListItem.tokens ? lastListItem.tokens[lastListItem.tokens.length - 1] : undefined;\n\n\t/*\n\tExample list token structures:\n\n\tlist\n\t\tlist_item\n\t\t\ttext\n\t\t\t\ttext\n\t\t\t\tcodespan\n\t\t\t\tlink\n\t\tlist_item\n\t\t\ttext\n\t\t\tcode // Complete indented codeblock\n\t\tlist_item\n\t\t\ttext\n\t\t\tspace\n\t\t\ttext\n\t\t\t\ttext // Incomplete indented codeblock\n\t\tlist_item\n\t\t\ttext\n\t\t\tlist // Nested list\n\t\t\t\tlist_item\n\t\t\t\t\ttext\n\t\t\t\t\t\ttext\n\n\tContrast with paragraph:\n\tparagraph\n\t\ttext\n\t\tcodespan\n\t*/\n\n\tlet newToken: marked.Token | undefined;\n\tif (lastListSubToken?.type === 'text' && !('inRawBlock' in lastListItem)) { // Why does Tag have a type of 'text'\n\t\tnewToken = completeSingleLinePattern(lastListSubToken as marked.Tokens.Text);\n\t}\n\n\tif (!newToken || newToken.type !== 'paragraph') { // 'text' item inside the list item turns into paragraph\n\t\t// Nothing to fix, or not a pattern we were expecting\n\t\treturn;\n\t}\n\n\tconst previousListItemsText = mergeRawTokenText(list.items.slice(0, -1));\n\n\t// Grabbing the `- ` or `1. ` off the list item because I can't find a better way to do this\n\tconst lastListItemLead = lastListItem.raw.match(/^(\\s*(-|\\d+\\.) +)/)?.[0];\n\tif (!lastListItemLead) {\n\t\t// Is badly formatted\n\t\treturn;\n\t}\n\n\tconst newListItemText = lastListItemLead +\n\t\tmergeRawTokenText(lastListItem.tokens.slice(0, -1)) +\n\t\tnewToken.raw;\n\n\tconst newList = marked.lexer(previousListItemsText + newListItemText)[0] as marked.Tokens.List;\n\tif (newList.type !== 'list') {\n\t\t// Something went wrong\n\t\treturn;\n\t}\n\n\treturn newList;\n}\n\nconst maxIncompleteTokensFixRounds = 3;\nexport function fillInIncompleteTokens(tokens: marked.TokensList): marked.TokensList {\n\tfor (let i = 0; i < maxIncompleteTokensFixRounds; i++) {\n\t\tconst newTokens = fillInIncompleteTokensOnce(tokens);\n\t\tif (newTokens) {\n\t\t\ttokens = newTokens;\n\t\t} else {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn tokens;\n}\n\nfunction fillInIncompleteTokensOnce(tokens: marked.TokensList): marked.TokensList | null {\n\tlet i: number;\n\tlet newTokens: marked.Token[] | undefined;\n\tfor (i = 0; i < tokens.length; i++) {\n\t\tconst token = tokens[i];\n\t\tlet codeblockStart: RegExpMatchArray | null;\n\t\tif (token.type === 'paragraph' && (codeblockStart = token.raw.match(/(\\n|^)(````*)/))) {\n\t\t\tconst codeblockLead = codeblockStart[2];\n\t\t\t// If the code block was complete, it would be in a type='code'\n\t\t\tnewTokens = completeCodeBlock(tokens.slice(i), codeblockLead);\n\t\t\tbreak;\n\t\t}\n\n\t\tif (token.type === 'paragraph' && token.raw.match(/(\\n|^)\\|/)) {\n\t\t\tnewTokens = completeTable(tokens.slice(i));\n\t\t\tbreak;\n\t\t}\n\n\t\tif (i === tokens.length - 1 && token.type === 'list') {\n\t\t\tconst newListToken = completeListItemPattern(token);\n\t\t\tif (newListToken) {\n\t\t\t\tnewTokens = [newListToken];\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (i === tokens.length - 1 && token.type === 'paragraph') {\n\t\t\t// Only operates on a single token, because any newline that follows this should break these patterns\n\t\t\tconst newToken = completeSingleLinePattern(token);\n\t\t\tif (newToken) {\n\t\t\t\tnewTokens = [newToken];\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (newTokens) {\n\t\tconst newTokensList = [\n\t\t\t...tokens.slice(0, i),\n\t\t\t...newTokens\n\t\t];\n\t\t(newTokensList as marked.TokensList).links = tokens.links;\n\t\treturn newTokensList as marked.TokensList;\n\t}\n\n\treturn null;\n}\n\nfunction completeCodeBlock(tokens: marked.Token[], leader: string): marked.Token[] {\n\tconst mergedRawText = mergeRawTokenText(tokens);\n\treturn marked.lexer(mergedRawText + `\\n${leader}`);\n}\n\nfunction completeCodespan(token: marked.Token): marked.Token {\n\treturn completeWithString(token, '`');\n}\n\nfunction completeStar(tokens: marked.Token): marked.Token {\n\treturn completeWithString(tokens, '*');\n}\n\nfunction completeUnderscore(tokens: marked.Token): marked.Token {\n\treturn completeWithString(tokens, '_');\n}\n\nfunction completeLinkTarget(tokens: marked.Token): marked.Token {\n\treturn completeWithString(tokens, ')');\n}\n\nfunction completeLinkTargetArg(tokens: marked.Token): marked.Token {\n\treturn completeWithString(tokens, '\")');\n}\n\nfunction completeLinkText(tokens: marked.Token): marked.Token {\n\treturn completeWithString(tokens, '](https://microsoft.com)');\n}\n\nfunction completeDoublestar(tokens: marked.Token): marked.Token {\n\treturn completeWithString(tokens, '**');\n}\n\nfunction completeDoubleUnderscore(tokens: marked.Token): marked.Token {\n\treturn completeWithString(tokens, '__');\n}\n\nfunction completeWithString(tokens: marked.Token[] | marked.Token, closingString: string): marked.Token {\n\tconst mergedRawText = mergeRawTokenText(Array.isArray(tokens) ? tokens : [tokens]);\n\n\t// If it was completed correctly, this should be a single token.\n\t// Expecting either a Paragraph or a List\n\treturn marked.lexer(mergedRawText + closingString)[0] as marked.Token;\n}\n\nfunction completeTable(tokens: marked.Token[]): marked.Token[] | undefined {\n\tconst mergedRawText = mergeRawTokenText(tokens);\n\tconst lines = mergedRawText.split('\\n');\n\n\tlet numCols: number | undefined; // The number of line1 col headers\n\tlet hasSeparatorRow = false;\n\tfor (let i = 0; i < lines.length; i++) {\n\t\tconst line = lines[i].trim();\n\t\tif (typeof numCols === 'undefined' && line.match(/^\\s*\\|/)) {\n\t\t\tconst line1Matches = line.match(/(\\|[^\\|]+)(?=\\||$)/g);\n\t\t\tif (line1Matches) {\n\t\t\t\tnumCols = line1Matches.length;\n\t\t\t}\n\t\t} else if (typeof numCols === 'number') {\n\t\t\tif (line.match(/^\\s*\\|/)) {\n\t\t\t\tif (i !== lines.length - 1) {\n\t\t\t\t\t// We got the line1 header row, and the line2 separator row, but there are more lines, and it wasn't parsed as a table!\n\t\t\t\t\t// That's strange and means that the table is probably malformed in the source, so I won't try to patch it up.\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\n\t\t\t\t// Got a line2 separator row- partial or complete, doesn't matter, we'll replace it with a correct one\n\t\t\t\thasSeparatorRow = true;\n\t\t\t} else {\n\t\t\t\t// The line after the header row isn't a valid separator row, so the table is malformed, don't fix it up\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (typeof numCols === 'number' && numCols > 0) {\n\t\tconst prefixText = hasSeparatorRow ? lines.slice(0, -1).join('\\n') : mergedRawText;\n\t\tconst line1EndsInPipe = !!prefixText.match(/\\|\\s*$/);\n\t\tconst newRawText = prefixText + (line1EndsInPipe ? '' : '|') + `\\n|${' --- |'.repeat(numCols)}`;\n\t\treturn marked.lexer(newRawText);\n\t}\n\n\treturn undefined;\n}\n\nfunction addDompurifyHook(\n\thook: 'uponSanitizeElement',\n\tcb: (currentNode: Element, data: dompurify.SanitizeElementHookEvent, config: dompurify.Config) => void,\n): IDisposable;\nfunction addDompurifyHook(\n\thook: 'uponSanitizeAttribute',\n\tcb: (currentNode: Element, data: dompurify.SanitizeAttributeHookEvent, config: dompurify.Config) => void,\n): IDisposable;\nfunction addDompurifyHook(hook: 'uponSanitizeElement' | 'uponSanitizeAttribute', cb: any): IDisposable {\n\tdompurify.addHook(hook, cb);\n\treturn toDisposable(() => dompurify.removeHook(hook));\n}\n","\nimport { addDisposableListener, EventHelper, EventType, IFocusTracker, reset, trackFocus } from 'vs/base/browser/dom';\nimport { sanitize } from 'vs/base/browser/dompurify/dompurify';\nimport { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';\nimport { renderMarkdown, renderStringAsPlaintext } from 'vs/base/browser/markdownRenderer';\nimport { Gesture, EventType as TouchEventType } from 'vs/base/browser/touch';\nimport { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegateFactory';\nimport { IHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate';\nimport { renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels';\nimport { Color } from 'vs/base/common/color';\nimport { Event as BaseEvent, Emitter } from 'vs/base/common/event';\nimport { IMarkdownString, isMarkdownString, markdownStringEqual } from 'vs/base/common/htmlContent';\nimport { KeyCode } from 'vs/base/common/keyCodes';\nimport { Disposable, IDisposable } from 'vs/base/common/lifecycle';\nimport { ThemeIcon } from 'vs/base/common/themables';\nimport 'vs/css!./button';\nimport { IUpdatableHover } from 'vs/base/browser/ui/hover/hover';\nimport { getBaseLayerHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate2';\n\nexport interface IButtonOptions extends Partial {\n\treadonly title?: boolean | string;\n\treadonly ariaLabel?: boolean | string;\n\treadonly supportIcons?: boolean;\n\treadonly supportShortLabel?: boolean;\n\treadonly secondary?: boolean;\n\treadonly hoverDelegate?: IHoverDelegate;\n}\n\nexport interface IButtonStyles {\n\treadonly buttonBackground: string | undefined;\n\treadonly buttonHoverBackground: string | undefined;\n\treadonly buttonForeground: string | undefined;\n\treadonly buttonSeparator: string | undefined;\n\treadonly buttonSecondaryBackground: string | undefined;\n\treadonly buttonSecondaryHoverBackground: string | undefined;\n\treadonly buttonSecondaryForeground: string | undefined;\n\treadonly buttonBorder: string | undefined;\n}\n\nexport const unthemedButtonStyles: IButtonStyles = {\n\tbuttonBackground: '#0E639C',\n\tbuttonHoverBackground: '#006BB3',\n\tbuttonSeparator: Color.white.toString(),\n\tbuttonForeground: Color.white.toString(),\n\tbuttonBorder: undefined,\n\tbuttonSecondaryBackground: undefined,\n\tbuttonSecondaryForeground: undefined,\n\tbuttonSecondaryHoverBackground: undefined\n};\n\nexport interface IButton extends IDisposable {\n\n\tset label(value: string | IMarkdownString);\n\tset icon(value: ThemeIcon);\n\tset enabled(value: boolean);\n}\n\nexport class Button extends Disposable implements IButton {\n\n\tprotected options: IButtonOptions;\n\tprotected _element: HTMLElement;\n\tprotected _label: string | IMarkdownString = '';\n\tprotected _labelElement: HTMLElement | undefined;\n\tprotected _labelShortElement: HTMLElement | undefined;\n\tprivate _hover: IUpdatableHover | undefined;\n\n\tprivate _onDidClick = this._register(new Emitter());\n\tget onDidClick(): BaseEvent { return this._onDidClick.event; }\n\n\tprivate _onDidEscape = this._register(new Emitter());\n\n\tprivate focusTracker: IFocusTracker;\n\n\tconstructor(container: HTMLElement, options: IButtonOptions) {\n\t\tsuper();\n\n\t\tthis.options = options;\n\n\t\tthis._element = document.createElement('a');\n\t\tthis._element.classList.add('monaco-button');\n\t\tthis._element.tabIndex = 0;\n\t\tthis._element.setAttribute('role', 'button');\n\n\t\tthis._element.classList.toggle('secondary', !!options.secondary);\n\t\tconst background = options.secondary ? options.buttonSecondaryBackground : options.buttonBackground;\n\t\tconst foreground = options.secondary ? options.buttonSecondaryForeground : options.buttonForeground;\n\n\t\tthis._element.style.color = foreground || '';\n\t\tthis._element.style.backgroundColor = background || '';\n\n\t\tif (options.supportShortLabel) {\n\t\t\tthis._labelShortElement = document.createElement('div');\n\t\t\tthis._labelShortElement.classList.add('monaco-button-label-short');\n\t\t\tthis._element.appendChild(this._labelShortElement);\n\n\t\t\tthis._labelElement = document.createElement('div');\n\t\t\tthis._labelElement.classList.add('monaco-button-label');\n\t\t\tthis._element.appendChild(this._labelElement);\n\n\t\t\tthis._element.classList.add('monaco-text-button-with-short-label');\n\t\t}\n\n\t\tif (typeof options.title === 'string') {\n\t\t\tthis.setTitle(options.title);\n\t\t}\n\n\t\tif (typeof options.ariaLabel === 'string') {\n\t\t\tthis._element.setAttribute('aria-label', options.ariaLabel);\n\t\t}\n\t\tcontainer.appendChild(this._element);\n\n\t\tthis._register(Gesture.addTarget(this._element));\n\n\t\t[EventType.CLICK, TouchEventType.Tap].forEach(eventType => {\n\t\t\tthis._register(addDisposableListener(this._element, eventType, e => {\n\t\t\t\tif (!this.enabled) {\n\t\t\t\t\tEventHelper.stop(e);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis._onDidClick.fire(e);\n\t\t\t}));\n\t\t});\n\n\t\tthis._register(addDisposableListener(this._element, EventType.KEY_DOWN, e => {\n\t\t\tconst event = new StandardKeyboardEvent(e);\n\t\t\tlet eventHandled = false;\n\t\t\tif (this.enabled && (event.equals(KeyCode.Enter) || event.equals(KeyCode.Space))) {\n\t\t\t\tthis._onDidClick.fire(e);\n\t\t\t\teventHandled = true;\n\t\t\t} else if (event.equals(KeyCode.Escape)) {\n\t\t\t\tthis._onDidEscape.fire(e);\n\t\t\t\tthis._element.blur();\n\t\t\t\teventHandled = true;\n\t\t\t}\n\n\t\t\tif (eventHandled) {\n\t\t\t\tEventHelper.stop(event, true);\n\t\t\t}\n\t\t}));\n\n\t\tthis._register(addDisposableListener(this._element, EventType.MOUSE_OVER, e => {\n\t\t\tif (!this._element.classList.contains('disabled')) {\n\t\t\t\tthis.updateBackground(true);\n\t\t\t}\n\t\t}));\n\n\t\tthis._register(addDisposableListener(this._element, EventType.MOUSE_OUT, e => {\n\t\t\tthis.updateBackground(false); // restore standard styles\n\t\t}));\n\n\t\t// Also set hover background when button is focused for feedback\n\t\tthis.focusTracker = this._register(trackFocus(this._element));\n\t\tthis._register(this.focusTracker.onDidFocus(() => { if (this.enabled) { this.updateBackground(true); } }));\n\t\tthis._register(this.focusTracker.onDidBlur(() => { if (this.enabled) { this.updateBackground(false); } }));\n\t}\n\n\tpublic override dispose(): void {\n\t\tsuper.dispose();\n\t\tthis._element.remove();\n\t}\n\n\tprivate getContentElements(content: string): HTMLElement[] {\n\t\tconst elements: HTMLSpanElement[] = [];\n\t\tfor (let segment of renderLabelWithIcons(content)) {\n\t\t\tif (typeof (segment) === 'string') {\n\t\t\t\tsegment = segment.trim();\n\n\t\t\t\t// Ignore empty segment\n\t\t\t\tif (segment === '') {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// Convert string segments to nodes\n\t\t\t\tconst node = document.createElement('span');\n\t\t\t\tnode.textContent = segment;\n\t\t\t\telements.push(node);\n\t\t\t} else {\n\t\t\t\telements.push(segment);\n\t\t\t}\n\t\t}\n\n\t\treturn elements;\n\t}\n\n\tprivate updateBackground(hover: boolean): void {\n\t\tlet background;\n\t\tif (this.options.secondary) {\n\t\t\tbackground = hover ? this.options.buttonSecondaryHoverBackground : this.options.buttonSecondaryBackground;\n\t\t} else {\n\t\t\tbackground = hover ? this.options.buttonHoverBackground : this.options.buttonBackground;\n\t\t}\n\t\tif (background) {\n\t\t\tthis._element.style.backgroundColor = background;\n\t\t}\n\t}\n\n\tget element(): HTMLElement {\n\t\treturn this._element;\n\t}\n\n\tset label(value: string | IMarkdownString) {\n\t\tif (this._label === value) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (isMarkdownString(this._label) && isMarkdownString(value) && markdownStringEqual(this._label, value)) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._element.classList.add('monaco-text-button');\n\t\tconst labelElement = this.options.supportShortLabel ? this._labelElement! : this._element;\n\n\t\tif (isMarkdownString(value)) {\n\t\t\tconst rendered = renderMarkdown(value, { inline: true });\n\t\t\trendered.dispose();\n\n\t\t\t// Don't include outer `

    `\n\t\t\tconst root = rendered.element.querySelector('p')?.innerHTML;\n\t\t\tif (root) {\n\t\t\t\t// Only allow a very limited set of inline html tags\n\t\t\t\tconst sanitized = sanitize(root, { ADD_TAGS: ['b', 'i', 'u', 'code', 'span'], ALLOWED_ATTR: ['class'], RETURN_TRUSTED_TYPE: true });\n\t\t\t\tlabelElement.innerHTML = sanitized as unknown as string;\n\t\t\t} else {\n\t\t\t\treset(labelElement);\n\t\t\t}\n\t\t} else {\n\t\t\tif (this.options.supportIcons) {\n\t\t\t\treset(labelElement, ...this.getContentElements(value));\n\t\t\t} else {\n\t\t\t\tlabelElement.textContent = value;\n\t\t\t}\n\t\t}\n\n\t\tlet title: string = '';\n\t\tif (typeof this.options.title === 'string') {\n\t\t\ttitle = this.options.title;\n\t\t} else if (this.options.title) {\n\t\t\ttitle = renderStringAsPlaintext(value);\n\t\t}\n\n\t\tthis.setTitle(title);\n\n\t\tif (typeof this.options.ariaLabel === 'string') {\n\t\t\tthis._element.setAttribute('aria-label', this.options.ariaLabel);\n\t\t} else if (this.options.ariaLabel) {\n\t\t\tthis._element.setAttribute('aria-label', title);\n\t\t}\n\n\t\tthis._label = value;\n\t}\n\n\tget label(): string | IMarkdownString {\n\t\treturn this._label;\n\t}\n\n\tset icon(icon: ThemeIcon) {\n\t\tthis._element.classList.add(...ThemeIcon.asClassNameArray(icon));\n\t}\n\n\tset enabled(value: boolean) {\n\t\tif (value) {\n\t\t\tthis._element.classList.remove('disabled');\n\t\t\tthis._element.setAttribute('aria-disabled', String(false));\n\t\t\tthis._element.tabIndex = 0;\n\t\t} else {\n\t\t\tthis._element.classList.add('disabled');\n\t\t\tthis._element.setAttribute('aria-disabled', String(true));\n\t\t}\n\t}\n\n\tget enabled() {\n\t\treturn !this._element.classList.contains('disabled');\n\t}\n\n\tsetTitle(title: string) {\n\t\tif (!this._hover && title !== '') {\n\t\t\tthis._hover = this._register(getBaseLayerHoverDelegate().setupUpdatableHover(this.options.hoverDelegate ?? getDefaultHoverDelegate('mouse'), this._element, title));\n\t\t} else if (this._hover) {\n\t\t\tthis._hover.update(title);\n\t\t}\n\t}\n}\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\nimport * as dom from 'vs/base/browser/dom';\nimport { DomEmitter } from 'vs/base/browser/event';\nimport { IContentActionHandler } from 'vs/base/browser/formattedTextRenderer';\nimport { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';\nimport { renderMarkdown } from 'vs/base/browser/markdownRenderer';\nimport { AnchorPosition, IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview';\nimport { IUpdatableHover } from 'vs/base/browser/ui/hover/hover';\nimport { getBaseLayerHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate2';\nimport { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegateFactory';\nimport { IListEvent, IListRenderer, IListVirtualDelegate } from 'vs/base/browser/ui/list/list';\nimport { List } from 'vs/base/browser/ui/list/listWidget';\nimport { ISelectBoxDelegate, ISelectBoxOptions, ISelectBoxStyles, ISelectData, ISelectOptionItem } from 'vs/base/browser/ui/selectBox/selectBox';\nimport * as arrays from 'vs/base/common/arrays';\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { KeyCode, KeyCodeUtils } from 'vs/base/common/keyCodes';\nimport { Disposable, IDisposable } from 'vs/base/common/lifecycle';\nimport { isMacintosh } from 'vs/base/common/platform';\nimport { ScrollbarVisibility } from 'vs/base/common/scrollable';\nimport 'vs/css!./selectBoxCustom';\nimport { localize } from 'vs/nls';\n\n\nconst $ = dom.$;\n\nconst SELECT_OPTION_ENTRY_TEMPLATE_ID = 'selectOption.entry.template';\n\ninterface ISelectListTemplateData {\n\troot: HTMLElement;\n\ttext: HTMLElement;\n\tdetail: HTMLElement;\n\tdecoratorRight: HTMLElement;\n}\n\nclass SelectListRenderer implements IListRenderer {\n\n\tget templateId(): string { return SELECT_OPTION_ENTRY_TEMPLATE_ID; }\n\n\trenderTemplate(container: HTMLElement): ISelectListTemplateData {\n\t\tconst data: ISelectListTemplateData = Object.create(null);\n\t\tdata.root = container;\n\t\tdata.text = dom.append(container, $('.option-text'));\n\t\tdata.detail = dom.append(container, $('.option-detail'));\n\t\tdata.decoratorRight = dom.append(container, $('.option-decorator-right'));\n\n\t\treturn data;\n\t}\n\n\trenderElement(element: ISelectOptionItem, index: number, templateData: ISelectListTemplateData): void {\n\t\tconst data: ISelectListTemplateData = templateData;\n\n\t\tconst text = element.text;\n\t\tconst detail = element.detail;\n\t\tconst decoratorRight = element.decoratorRight;\n\n\t\tconst isDisabled = element.isDisabled;\n\n\t\tdata.text.textContent = text;\n\t\tdata.detail.textContent = !!detail ? detail : '';\n\t\tdata.decoratorRight.innerText = !!decoratorRight ? decoratorRight : '';\n\n\t\t// pseudo-select disabled option\n\t\tif (isDisabled) {\n\t\t\tdata.root.classList.add('option-disabled');\n\t\t} else {\n\t\t\t// Make sure we do class removal from prior template rendering\n\t\t\tdata.root.classList.remove('option-disabled');\n\t\t}\n\t}\n\n\tdisposeTemplate(_templateData: ISelectListTemplateData): void {\n\t\t// noop\n\t}\n}\n\nexport class SelectBoxList extends Disposable implements ISelectBoxDelegate, IListVirtualDelegate {\n\n\tprivate static readonly DEFAULT_DROPDOWN_MINIMUM_BOTTOM_MARGIN = 32;\n\tprivate static readonly DEFAULT_DROPDOWN_MINIMUM_TOP_MARGIN = 2;\n\tprivate static readonly DEFAULT_MINIMUM_VISIBLE_OPTIONS = 3;\n\n\tprivate _isVisible: boolean;\n\tprivate selectBoxOptions: ISelectBoxOptions;\n\tprivate selectElement: HTMLSelectElement;\n\tprivate container?: HTMLElement;\n\tprivate options: ISelectOptionItem[] = [];\n\tprivate selected: number;\n\tprivate readonly _onDidSelect: Emitter;\n\tprivate readonly styles: ISelectBoxStyles;\n\tprivate listRenderer!: SelectListRenderer;\n\tprivate contextViewProvider!: IContextViewProvider;\n\tprivate selectDropDownContainer!: HTMLElement;\n\tprivate styleElement!: HTMLStyleElement;\n\tprivate selectList!: List;\n\tprivate selectDropDownListContainer!: HTMLElement;\n\tprivate widthControlElement!: HTMLElement;\n\tprivate _currentSelection = 0;\n\tprivate _dropDownPosition!: AnchorPosition;\n\tprivate _hasDetails: boolean = false;\n\tprivate selectionDetailsPane!: HTMLElement;\n\tprivate _skipLayout: boolean = false;\n\tprivate _cachedMaxDetailsHeight?: number;\n\tprivate _hover?: IUpdatableHover;\n\n\tprivate _sticky: boolean = false; // for dev purposes only\n\n\tconstructor(options: ISelectOptionItem[], selected: number, contextViewProvider: IContextViewProvider, styles: ISelectBoxStyles, selectBoxOptions?: ISelectBoxOptions) {\n\n\t\tsuper();\n\t\tthis._isVisible = false;\n\t\tthis.styles = styles;\n\n\t\tthis.selectBoxOptions = selectBoxOptions || Object.create(null);\n\n\t\tif (typeof this.selectBoxOptions.minBottomMargin !== 'number') {\n\t\t\tthis.selectBoxOptions.minBottomMargin = SelectBoxList.DEFAULT_DROPDOWN_MINIMUM_BOTTOM_MARGIN;\n\t\t} else if (this.selectBoxOptions.minBottomMargin < 0) {\n\t\t\tthis.selectBoxOptions.minBottomMargin = 0;\n\t\t}\n\n\t\tthis.selectElement = document.createElement('select');\n\n\t\t// Use custom CSS vars for padding calculation\n\t\tthis.selectElement.className = 'monaco-select-box monaco-select-box-dropdown-padding';\n\n\t\tif (typeof this.selectBoxOptions.ariaLabel === 'string') {\n\t\t\tthis.selectElement.setAttribute('aria-label', this.selectBoxOptions.ariaLabel);\n\t\t}\n\n\t\tif (typeof this.selectBoxOptions.ariaDescription === 'string') {\n\t\t\tthis.selectElement.setAttribute('aria-description', this.selectBoxOptions.ariaDescription);\n\t\t}\n\n\t\tthis._onDidSelect = new Emitter();\n\t\tthis._register(this._onDidSelect);\n\n\t\tthis.registerListeners();\n\t\tthis.constructSelectDropDown(contextViewProvider);\n\n\t\tthis.selected = selected || 0;\n\n\t\tif (options) {\n\t\t\tthis.setOptions(options, selected);\n\t\t}\n\n\t\tthis.initStyleSheet();\n\n\t}\n\n\tprivate setTitle(title: string): void {\n\t\tif (!this._hover && title) {\n\t\t\tthis._hover = this._register(getBaseLayerHoverDelegate().setupUpdatableHover(getDefaultHoverDelegate('mouse'), this.selectElement, title));\n\t\t} else if (this._hover) {\n\t\t\tthis._hover.update(title);\n\t\t}\n\t}\n\n\t// IDelegate - List renderer\n\n\tgetHeight(): number {\n\t\treturn 22;\n\t}\n\n\tgetTemplateId(): string {\n\t\treturn SELECT_OPTION_ENTRY_TEMPLATE_ID;\n\t}\n\n\tprivate constructSelectDropDown(contextViewProvider: IContextViewProvider) {\n\n\t\t// SetUp ContextView container to hold select Dropdown\n\t\tthis.contextViewProvider = contextViewProvider;\n\t\tthis.selectDropDownContainer = dom.$('.monaco-select-box-dropdown-container');\n\t\t// Use custom CSS vars for padding calculation (shared with parent select)\n\t\tthis.selectDropDownContainer.classList.add('monaco-select-box-dropdown-padding');\n\n\t\t// Setup container for select option details\n\t\tthis.selectionDetailsPane = dom.append(this.selectDropDownContainer, $('.select-box-details-pane'));\n\n\t\t// Create span flex box item/div we can measure and control\n\t\tconst widthControlOuterDiv = dom.append(this.selectDropDownContainer, $('.select-box-dropdown-container-width-control'));\n\t\tconst widthControlInnerDiv = dom.append(widthControlOuterDiv, $('.width-control-div'));\n\t\tthis.widthControlElement = document.createElement('span');\n\t\tthis.widthControlElement.className = 'option-text-width-control';\n\t\tdom.append(widthControlInnerDiv, this.widthControlElement);\n\n\t\t// Always default to below position\n\t\tthis._dropDownPosition = AnchorPosition.BELOW;\n\n\t\t// Inline stylesheet for themes\n\t\tthis.styleElement = dom.createStyleSheet(this.selectDropDownContainer);\n\n\t\t// Prevent dragging of dropdown #114329\n\t\tthis.selectDropDownContainer.setAttribute('draggable', 'true');\n\t\tthis._register(dom.addDisposableListener(this.selectDropDownContainer, dom.EventType.DRAG_START, (e) => {\n\t\t\tdom.EventHelper.stop(e, true);\n\t\t}));\n\t}\n\n\tprivate registerListeners() {\n\n\t\t// Parent native select keyboard listeners\n\n\t\tthis._register(dom.addStandardDisposableListener(this.selectElement, 'change', (e) => {\n\t\t\tthis.selected = e.target.selectedIndex;\n\t\t\tthis._onDidSelect.fire({\n\t\t\t\tindex: e.target.selectedIndex,\n\t\t\t\tselected: e.target.value\n\t\t\t});\n\t\t\tif (!!this.options[this.selected] && !!this.options[this.selected].text) {\n\t\t\t\tthis.setTitle(this.options[this.selected].text);\n\t\t\t}\n\t\t}));\n\n\t\t// Have to implement both keyboard and mouse controllers to handle disabled options\n\t\t// Intercept mouse events to override normal select actions on parents\n\n\t\tthis._register(dom.addDisposableListener(this.selectElement, dom.EventType.CLICK, (e) => {\n\t\t\tdom.EventHelper.stop(e);\n\n\t\t\tif (this._isVisible) {\n\t\t\t\tthis.hideSelectDropDown(true);\n\t\t\t} else {\n\t\t\t\tthis.showSelectDropDown();\n\t\t\t}\n\t\t}));\n\n\t\tthis._register(dom.addDisposableListener(this.selectElement, dom.EventType.MOUSE_DOWN, (e) => {\n\t\t\tdom.EventHelper.stop(e);\n\t\t}));\n\n\t\t// Intercept touch events\n\t\t// The following implementation is slightly different from the mouse event handlers above.\n\t\t// Use the following helper variable, otherwise the list flickers.\n\t\tlet listIsVisibleOnTouchStart: boolean;\n\t\tthis._register(dom.addDisposableListener(this.selectElement, 'touchstart', (e) => {\n\t\t\tlistIsVisibleOnTouchStart = this._isVisible;\n\t\t}));\n\t\tthis._register(dom.addDisposableListener(this.selectElement, 'touchend', (e) => {\n\t\t\tdom.EventHelper.stop(e);\n\n\t\t\tif (listIsVisibleOnTouchStart) {\n\t\t\t\tthis.hideSelectDropDown(true);\n\t\t\t} else {\n\t\t\t\tthis.showSelectDropDown();\n\t\t\t}\n\t\t}));\n\n\t\t// Intercept keyboard handling\n\n\t\tthis._register(dom.addDisposableListener(this.selectElement, dom.EventType.KEY_DOWN, (e: KeyboardEvent) => {\n\t\t\tconst event = new StandardKeyboardEvent(e);\n\t\t\tlet showDropDown = false;\n\n\t\t\t// Create and drop down select list on keyboard select\n\t\t\tif (isMacintosh) {\n\t\t\t\tif (event.keyCode === KeyCode.DownArrow || event.keyCode === KeyCode.UpArrow || event.keyCode === KeyCode.Space || event.keyCode === KeyCode.Enter) {\n\t\t\t\t\tshowDropDown = true;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (event.keyCode === KeyCode.DownArrow && event.altKey || event.keyCode === KeyCode.UpArrow && event.altKey || event.keyCode === KeyCode.Space || event.keyCode === KeyCode.Enter) {\n\t\t\t\t\tshowDropDown = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (showDropDown) {\n\t\t\t\tthis.showSelectDropDown();\n\t\t\t\tdom.EventHelper.stop(e, true);\n\t\t\t}\n\t\t}));\n\t}\n\n\tpublic get onDidSelect(): Event {\n\t\treturn this._onDidSelect.event;\n\t}\n\n\tpublic setOptions(options: ISelectOptionItem[], selected?: number): void {\n\t\tif (!arrays.equals(this.options, options)) {\n\t\t\tthis.options = options;\n\t\t\tthis.selectElement.options.length = 0;\n\t\t\tthis._hasDetails = false;\n\t\t\tthis._cachedMaxDetailsHeight = undefined;\n\n\t\t\tthis.options.forEach((option, index) => {\n\t\t\t\tthis.selectElement.add(this.createOption(option.text, index, option.isDisabled));\n\t\t\t\tif (typeof option.description === 'string') {\n\t\t\t\t\tthis._hasDetails = true;\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\tif (selected !== undefined) {\n\t\t\tthis.select(selected);\n\t\t\t// Set current = selected since this is not necessarily a user exit\n\t\t\tthis._currentSelection = this.selected;\n\t\t}\n\t}\n\n\tprivate setOptionsList() {\n\n\t\t// Mirror options in drop-down\n\t\t// Populate select list for non-native select mode\n\t\tthis.selectList?.splice(0, this.selectList.length, this.options);\n\t}\n\n\tpublic select(index: number): void {\n\n\t\tif (index >= 0 && index < this.options.length) {\n\t\t\tthis.selected = index;\n\t\t} else if (index > this.options.length - 1) {\n\t\t\t// Adjust index to end of list\n\t\t\t// This could make client out of sync with the select\n\t\t\tthis.select(this.options.length - 1);\n\t\t} else if (this.selected < 0) {\n\t\t\tthis.selected = 0;\n\t\t}\n\n\t\tthis.selectElement.selectedIndex = this.selected;\n\t\tif (!!this.options[this.selected] && !!this.options[this.selected].text) {\n\t\t\tthis.setTitle(this.options[this.selected].text);\n\t\t}\n\t}\n\n\tpublic focus(): void {\n\t\tif (this.selectElement) {\n\t\t\tthis.selectElement.tabIndex = 0;\n\t\t\tthis.selectElement.focus();\n\t\t}\n\t}\n\n\tpublic blur(): void {\n\t\tif (this.selectElement) {\n\t\t\tthis.selectElement.tabIndex = -1;\n\t\t\tthis.selectElement.blur();\n\t\t}\n\t}\n\n\tpublic setFocusable(focusable: boolean): void {\n\t\tthis.selectElement.tabIndex = focusable ? 0 : -1;\n\t}\n\n\tpublic render(container: HTMLElement): void {\n\t\tthis.container = container;\n\t\tcontainer.classList.add('select-container');\n\t\tcontainer.appendChild(this.selectElement);\n\t\tthis.styleSelectElement();\n\t}\n\n\tprivate initStyleSheet(): void {\n\n\t\tconst content: string[] = [];\n\n\t\t// Style non-native select mode\n\n\t\tif (this.styles.listFocusBackground) {\n\t\t\tcontent.push(`.monaco-select-box-dropdown-container > .select-box-dropdown-list-container .monaco-list .monaco-list-row.focused { background-color: ${this.styles.listFocusBackground} !important; }`);\n\t\t}\n\n\t\tif (this.styles.listFocusForeground) {\n\t\t\tcontent.push(`.monaco-select-box-dropdown-container > .select-box-dropdown-list-container .monaco-list .monaco-list-row.focused { color: ${this.styles.listFocusForeground} !important; }`);\n\t\t}\n\n\t\tif (this.styles.decoratorRightForeground) {\n\t\t\tcontent.push(`.monaco-select-box-dropdown-container > .select-box-dropdown-list-container .monaco-list .monaco-list-row:not(.focused) .option-decorator-right { color: ${this.styles.decoratorRightForeground}; }`);\n\t\t}\n\n\t\tif (this.styles.selectBackground && this.styles.selectBorder && this.styles.selectBorder !== this.styles.selectBackground) {\n\t\t\tcontent.push(`.monaco-select-box-dropdown-container { border: 1px solid ${this.styles.selectBorder} } `);\n\t\t\tcontent.push(`.monaco-select-box-dropdown-container > .select-box-details-pane.border-top { border-top: 1px solid ${this.styles.selectBorder} } `);\n\t\t\tcontent.push(`.monaco-select-box-dropdown-container > .select-box-details-pane.border-bottom { border-bottom: 1px solid ${this.styles.selectBorder} } `);\n\n\t\t}\n\t\telse if (this.styles.selectListBorder) {\n\t\t\tcontent.push(`.monaco-select-box-dropdown-container > .select-box-details-pane.border-top { border-top: 1px solid ${this.styles.selectListBorder} } `);\n\t\t\tcontent.push(`.monaco-select-box-dropdown-container > .select-box-details-pane.border-bottom { border-bottom: 1px solid ${this.styles.selectListBorder} } `);\n\t\t}\n\n\t\t// Hover foreground - ignore for disabled options\n\t\tif (this.styles.listHoverForeground) {\n\t\t\tcontent.push(`.monaco-select-box-dropdown-container > .select-box-dropdown-list-container .monaco-list .monaco-list-row:not(.option-disabled):not(.focused):hover { color: ${this.styles.listHoverForeground} !important; }`);\n\t\t}\n\n\t\t// Hover background - ignore for disabled options\n\t\tif (this.styles.listHoverBackground) {\n\t\t\tcontent.push(`.monaco-select-box-dropdown-container > .select-box-dropdown-list-container .monaco-list .monaco-list-row:not(.option-disabled):not(.focused):hover { background-color: ${this.styles.listHoverBackground} !important; }`);\n\t\t}\n\n\t\t// Match quick input outline styles - ignore for disabled options\n\t\tif (this.styles.listFocusOutline) {\n\t\t\tcontent.push(`.monaco-select-box-dropdown-container > .select-box-dropdown-list-container .monaco-list .monaco-list-row.focused { outline: 1.6px dotted ${this.styles.listFocusOutline} !important; outline-offset: -1.6px !important; }`);\n\t\t}\n\n\t\tif (this.styles.listHoverOutline) {\n\t\t\tcontent.push(`.monaco-select-box-dropdown-container > .select-box-dropdown-list-container .monaco-list .monaco-list-row:not(.option-disabled):not(.focused):hover { outline: 1.6px dashed ${this.styles.listHoverOutline} !important; outline-offset: -1.6px !important; }`);\n\t\t}\n\n\t\t// Clear list styles on focus and on hover for disabled options\n\t\tcontent.push(`.monaco-select-box-dropdown-container > .select-box-dropdown-list-container .monaco-list .monaco-list-row.option-disabled.focused { background-color: transparent !important; color: inherit !important; outline: none !important; }`);\n\t\tcontent.push(`.monaco-select-box-dropdown-container > .select-box-dropdown-list-container .monaco-list .monaco-list-row.option-disabled:hover { background-color: transparent !important; color: inherit !important; outline: none !important; }`);\n\n\t\tthis.styleElement.textContent = content.join('\\n');\n\t}\n\n\tprivate styleSelectElement(): void {\n\t\tconst background = this.styles.selectBackground ?? '';\n\t\tconst foreground = this.styles.selectForeground ?? '';\n\t\tconst border = this.styles.selectBorder ?? '';\n\n\t\tthis.selectElement.style.backgroundColor = background;\n\t\tthis.selectElement.style.color = foreground;\n\t\tthis.selectElement.style.borderColor = border;\n\t}\n\n\tprivate styleList() {\n\t\tconst background = this.styles.selectBackground ?? '';\n\n\t\tconst listBackground = dom.asCssValueWithDefault(this.styles.selectListBackground, background);\n\t\tthis.selectDropDownListContainer.style.backgroundColor = listBackground;\n\t\tthis.selectionDetailsPane.style.backgroundColor = listBackground;\n\t\tconst optionsBorder = this.styles.focusBorder ?? '';\n\t\tthis.selectDropDownContainer.style.outlineColor = optionsBorder;\n\t\tthis.selectDropDownContainer.style.outlineOffset = '-1px';\n\n\t\tthis.selectList.style(this.styles);\n\t}\n\n\tprivate createOption(value: string, index: number, disabled?: boolean): HTMLOptionElement {\n\t\tconst option = document.createElement('option');\n\t\toption.value = value;\n\t\toption.text = value;\n\t\toption.disabled = !!disabled;\n\n\t\treturn option;\n\t}\n\n\t// ContextView dropdown methods\n\n\tprivate showSelectDropDown() {\n\t\tthis.selectionDetailsPane.innerText = '';\n\n\t\tif (!this.contextViewProvider || this._isVisible) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Lazily create and populate list only at open, moved from constructor\n\t\tthis.createSelectList(this.selectDropDownContainer);\n\t\tthis.setOptionsList();\n\n\t\t// This allows us to flip the position based on measurement\n\t\t// Set drop-down position above/below from required height and margins\n\t\t// If pre-layout cannot fit at least one option do not show drop-down\n\n\t\tthis.contextViewProvider.showContextView({\n\t\t\tgetAnchor: () => this.selectElement,\n\t\t\trender: (container: HTMLElement) => this.renderSelectDropDown(container, true),\n\t\t\tlayout: () => {\n\t\t\t\tthis.layoutSelectDropDown();\n\t\t\t},\n\t\t\tonHide: () => {\n\t\t\t\tthis.selectDropDownContainer.classList.remove('visible');\n\t\t\t\tthis.selectElement.classList.remove('synthetic-focus');\n\t\t\t},\n\t\t\tanchorPosition: this._dropDownPosition\n\t\t}, this.selectBoxOptions.optionsAsChildren ? this.container : undefined);\n\n\t\t// Hide so we can relay out\n\t\tthis._isVisible = true;\n\t\tthis.hideSelectDropDown(false);\n\n\t\tthis.contextViewProvider.showContextView({\n\t\t\tgetAnchor: () => this.selectElement,\n\t\t\trender: (container: HTMLElement) => this.renderSelectDropDown(container),\n\t\t\tlayout: () => this.layoutSelectDropDown(),\n\t\t\tonHide: () => {\n\t\t\t\tthis.selectDropDownContainer.classList.remove('visible');\n\t\t\t\tthis.selectElement.classList.remove('synthetic-focus');\n\t\t\t},\n\t\t\tanchorPosition: this._dropDownPosition\n\t\t}, this.selectBoxOptions.optionsAsChildren ? this.container : undefined);\n\n\t\t// Track initial selection the case user escape, blur\n\t\tthis._currentSelection = this.selected;\n\t\tthis._isVisible = true;\n\t\tthis.selectElement.setAttribute('aria-expanded', 'true');\n\t}\n\n\tprivate hideSelectDropDown(focusSelect: boolean) {\n\t\tif (!this.contextViewProvider || !this._isVisible) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._isVisible = false;\n\t\tthis.selectElement.setAttribute('aria-expanded', 'false');\n\n\t\tif (focusSelect) {\n\t\t\tthis.selectElement.focus();\n\t\t}\n\n\t\tthis.contextViewProvider.hideContextView();\n\t}\n\n\tprivate renderSelectDropDown(container: HTMLElement, preLayoutPosition?: boolean): IDisposable {\n\t\tcontainer.appendChild(this.selectDropDownContainer);\n\n\t\t// Pre-Layout allows us to change position\n\t\tthis.layoutSelectDropDown(preLayoutPosition);\n\n\t\treturn {\n\t\t\tdispose: () => {\n\t\t\t\t// contextView will dispose itself if moving from one View to another\n\t\t\t\ttry {\n\t\t\t\t\tcontainer.removeChild(this.selectDropDownContainer); // remove to take out the CSS rules we add\n\t\t\t\t}\n\t\t\t\tcatch (error) {\n\t\t\t\t\t// Ignore, removed already by change of focus\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n\n\t// Iterate over detailed descriptions, find max height\n\tprivate measureMaxDetailsHeight(): number {\n\t\tlet maxDetailsPaneHeight = 0;\n\t\tthis.options.forEach((_option, index) => {\n\t\t\tthis.updateDetail(index);\n\n\t\t\tif (this.selectionDetailsPane.offsetHeight > maxDetailsPaneHeight) {\n\t\t\t\tmaxDetailsPaneHeight = this.selectionDetailsPane.offsetHeight;\n\t\t\t}\n\t\t});\n\n\t\treturn maxDetailsPaneHeight;\n\t}\n\n\tprivate layoutSelectDropDown(preLayoutPosition?: boolean): boolean {\n\n\t\t// Avoid recursion from layout called in onListFocus\n\t\tif (this._skipLayout) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Layout ContextView drop down select list and container\n\t\t// Have to manage our vertical overflow, sizing, position below or above\n\t\t// Position has to be determined and set prior to contextView instantiation\n\n\t\tif (this.selectList) {\n\n\t\t\t// Make visible to enable measurements\n\t\t\tthis.selectDropDownContainer.classList.add('visible');\n\n\t\t\tconst window = dom.getWindow(this.selectElement);\n\t\t\tconst selectPosition = dom.getDomNodePagePosition(this.selectElement);\n\t\t\tconst styles = dom.getWindow(this.selectElement).getComputedStyle(this.selectElement);\n\t\t\tconst verticalPadding = parseFloat(styles.getPropertyValue('--dropdown-padding-top')) + parseFloat(styles.getPropertyValue('--dropdown-padding-bottom'));\n\t\t\tconst maxSelectDropDownHeightBelow = (window.innerHeight - selectPosition.top - selectPosition.height - (this.selectBoxOptions.minBottomMargin || 0));\n\t\t\tconst maxSelectDropDownHeightAbove = (selectPosition.top - SelectBoxList.DEFAULT_DROPDOWN_MINIMUM_TOP_MARGIN);\n\n\t\t\t// Determine optimal width - min(longest option), opt(parent select, excluding margins), max(ContextView controlled)\n\t\t\tconst selectWidth = this.selectElement.offsetWidth;\n\t\t\tconst selectMinWidth = this.setWidthControlElement(this.widthControlElement);\n\t\t\tconst selectOptimalWidth = Math.max(selectMinWidth, Math.round(selectWidth)).toString() + 'px';\n\n\t\t\tthis.selectDropDownContainer.style.width = selectOptimalWidth;\n\n\t\t\t// Get initial list height and determine space above and below\n\t\t\tthis.selectList.getHTMLElement().style.height = '';\n\t\t\tthis.selectList.layout();\n\t\t\tlet listHeight = this.selectList.contentHeight;\n\n\t\t\tif (this._hasDetails && this._cachedMaxDetailsHeight === undefined) {\n\t\t\t\tthis._cachedMaxDetailsHeight = this.measureMaxDetailsHeight();\n\t\t\t}\n\t\t\tconst maxDetailsPaneHeight = this._hasDetails ? this._cachedMaxDetailsHeight! : 0;\n\n\t\t\tconst minRequiredDropDownHeight = listHeight + verticalPadding + maxDetailsPaneHeight;\n\t\t\tconst maxVisibleOptionsBelow = ((Math.floor((maxSelectDropDownHeightBelow - verticalPadding - maxDetailsPaneHeight) / this.getHeight())));\n\t\t\tconst maxVisibleOptionsAbove = ((Math.floor((maxSelectDropDownHeightAbove - verticalPadding - maxDetailsPaneHeight) / this.getHeight())));\n\n\t\t\t// If we are only doing pre-layout check/adjust position only\n\t\t\t// Calculate vertical space available, flip up if insufficient\n\t\t\t// Use reflected padding on parent select, ContextView style\n\t\t\t// properties not available before DOM attachment\n\n\t\t\tif (preLayoutPosition) {\n\n\t\t\t\t// Check if select moved out of viewport , do not open\n\t\t\t\t// If at least one option cannot be shown, don't open the drop-down or hide/remove if open\n\n\t\t\t\tif ((selectPosition.top + selectPosition.height) > (window.innerHeight - 22)\n\t\t\t\t\t|| selectPosition.top < SelectBoxList.DEFAULT_DROPDOWN_MINIMUM_TOP_MARGIN\n\t\t\t\t\t|| ((maxVisibleOptionsBelow < 1) && (maxVisibleOptionsAbove < 1))) {\n\t\t\t\t\t// Indicate we cannot open\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\t// Determine if we have to flip up\n\t\t\t\t// Always show complete list items - never more than Max available vertical height\n\t\t\t\tif (maxVisibleOptionsBelow < SelectBoxList.DEFAULT_MINIMUM_VISIBLE_OPTIONS\n\t\t\t\t\t&& maxVisibleOptionsAbove > maxVisibleOptionsBelow\n\t\t\t\t\t&& this.options.length > maxVisibleOptionsBelow\n\t\t\t\t) {\n\t\t\t\t\tthis._dropDownPosition = AnchorPosition.ABOVE;\n\t\t\t\t\tthis.selectDropDownContainer.removeChild(this.selectDropDownListContainer);\n\t\t\t\t\tthis.selectDropDownContainer.removeChild(this.selectionDetailsPane);\n\t\t\t\t\tthis.selectDropDownContainer.appendChild(this.selectionDetailsPane);\n\t\t\t\t\tthis.selectDropDownContainer.appendChild(this.selectDropDownListContainer);\n\n\t\t\t\t\tthis.selectionDetailsPane.classList.remove('border-top');\n\t\t\t\t\tthis.selectionDetailsPane.classList.add('border-bottom');\n\n\t\t\t\t} else {\n\t\t\t\t\tthis._dropDownPosition = AnchorPosition.BELOW;\n\t\t\t\t\tthis.selectDropDownContainer.removeChild(this.selectDropDownListContainer);\n\t\t\t\t\tthis.selectDropDownContainer.removeChild(this.selectionDetailsPane);\n\t\t\t\t\tthis.selectDropDownContainer.appendChild(this.selectDropDownListContainer);\n\t\t\t\t\tthis.selectDropDownContainer.appendChild(this.selectionDetailsPane);\n\n\t\t\t\t\tthis.selectionDetailsPane.classList.remove('border-bottom');\n\t\t\t\t\tthis.selectionDetailsPane.classList.add('border-top');\n\t\t\t\t}\n\t\t\t\t// Do full layout on showSelectDropDown only\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\t// Check if select out of viewport or cutting into status bar\n\t\t\tif ((selectPosition.top + selectPosition.height) > (window.innerHeight - 22)\n\t\t\t\t|| selectPosition.top < SelectBoxList.DEFAULT_DROPDOWN_MINIMUM_TOP_MARGIN\n\t\t\t\t|| (this._dropDownPosition === AnchorPosition.BELOW && maxVisibleOptionsBelow < 1)\n\t\t\t\t|| (this._dropDownPosition === AnchorPosition.ABOVE && maxVisibleOptionsAbove < 1)) {\n\t\t\t\t// Cannot properly layout, close and hide\n\t\t\t\tthis.hideSelectDropDown(true);\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// SetUp list dimensions and layout - account for container padding\n\t\t\t// Use position to check above or below available space\n\t\t\tif (this._dropDownPosition === AnchorPosition.BELOW) {\n\t\t\t\tif (this._isVisible && maxVisibleOptionsBelow + maxVisibleOptionsAbove < 1) {\n\t\t\t\t\t// If drop-down is visible, must be doing a DOM re-layout, hide since we don't fit\n\t\t\t\t\t// Hide drop-down, hide contextview, focus on parent select\n\t\t\t\t\tthis.hideSelectDropDown(true);\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\t// Adjust list height to max from select bottom to margin (default/minBottomMargin)\n\t\t\t\tif (minRequiredDropDownHeight > maxSelectDropDownHeightBelow) {\n\t\t\t\t\tlistHeight = (maxVisibleOptionsBelow * this.getHeight());\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (minRequiredDropDownHeight > maxSelectDropDownHeightAbove) {\n\t\t\t\t\tlistHeight = (maxVisibleOptionsAbove * this.getHeight());\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Set adjusted list height and relayout\n\t\t\tthis.selectList.layout(listHeight);\n\t\t\tthis.selectList.domFocus();\n\n\t\t\t// Finally set focus on selected item\n\t\t\tif (this.selectList.length > 0) {\n\t\t\t\tthis.selectList.setFocus([this.selected || 0]);\n\t\t\t\tthis.selectList.reveal(this.selectList.getFocus()[0] || 0);\n\t\t\t}\n\n\t\t\tif (this._hasDetails) {\n\t\t\t\t// Leave the selectDropDownContainer to size itself according to children (list + details) - #57447\n\t\t\t\tthis.selectList.getHTMLElement().style.height = (listHeight + verticalPadding) + 'px';\n\t\t\t\tthis.selectDropDownContainer.style.height = '';\n\t\t\t} else {\n\t\t\t\tthis.selectDropDownContainer.style.height = (listHeight + verticalPadding) + 'px';\n\t\t\t}\n\n\t\t\tthis.updateDetail(this.selected);\n\n\t\t\tthis.selectDropDownContainer.style.width = selectOptimalWidth;\n\n\t\t\t// Maintain focus outline on parent select as well as list container - tabindex for focus\n\t\t\tthis.selectDropDownListContainer.setAttribute('tabindex', '0');\n\t\t\tthis.selectElement.classList.add('synthetic-focus');\n\t\t\tthis.selectDropDownContainer.classList.add('synthetic-focus');\n\n\t\t\treturn true;\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tprivate setWidthControlElement(container: HTMLElement): number {\n\t\tlet elementWidth = 0;\n\n\t\tif (container) {\n\t\t\tlet longest = 0;\n\t\t\tlet longestLength = 0;\n\n\t\t\tthis.options.forEach((option, index) => {\n\t\t\t\tconst detailLength = !!option.detail ? option.detail.length : 0;\n\t\t\t\tconst rightDecoratorLength = !!option.decoratorRight ? option.decoratorRight.length : 0;\n\n\t\t\t\tconst len = option.text.length + detailLength + rightDecoratorLength;\n\t\t\t\tif (len > longestLength) {\n\t\t\t\t\tlongest = index;\n\t\t\t\t\tlongestLength = len;\n\t\t\t\t}\n\t\t\t});\n\n\n\t\t\tcontainer.textContent = this.options[longest].text + (!!this.options[longest].decoratorRight ? (this.options[longest].decoratorRight + ' ') : '');\n\t\t\telementWidth = dom.getTotalWidth(container);\n\t\t}\n\n\t\treturn elementWidth;\n\t}\n\n\tprivate createSelectList(parent: HTMLElement): void {\n\n\t\t// If we have already constructive list on open, skip\n\t\tif (this.selectList) {\n\t\t\treturn;\n\t\t}\n\n\t\t// SetUp container for list\n\t\tthis.selectDropDownListContainer = dom.append(parent, $('.select-box-dropdown-list-container'));\n\n\t\tthis.listRenderer = new SelectListRenderer();\n\n\t\tthis.selectList = new List('SelectBoxCustom', this.selectDropDownListContainer, this, [this.listRenderer], {\n\t\t\tuseShadows: false,\n\t\t\tverticalScrollMode: ScrollbarVisibility.Visible,\n\t\t\tkeyboardSupport: false,\n\t\t\tmouseSupport: false,\n\t\t\taccessibilityProvider: {\n\t\t\t\tgetAriaLabel: element => {\n\t\t\t\t\tlet label = element.text;\n\t\t\t\t\tif (element.detail) {\n\t\t\t\t\t\tlabel += `. ${element.detail}`;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (element.decoratorRight) {\n\t\t\t\t\t\tlabel += `. ${element.decoratorRight}`;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (element.description) {\n\t\t\t\t\t\tlabel += `. ${element.description}`;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn label;\n\t\t\t\t},\n\t\t\t\tgetWidgetAriaLabel: () => localize({ key: 'selectBox', comment: ['Behave like native select dropdown element.'] }, \"Select Box\"),\n\t\t\t\tgetRole: () => isMacintosh ? '' : 'option',\n\t\t\t\tgetWidgetRole: () => 'listbox'\n\t\t\t}\n\t\t});\n\t\tif (this.selectBoxOptions.ariaLabel) {\n\t\t\tthis.selectList.ariaLabel = this.selectBoxOptions.ariaLabel;\n\t\t}\n\n\t\t// SetUp list keyboard controller - control navigation, disabled items, focus\n\t\tconst onKeyDown = this._register(new DomEmitter(this.selectDropDownListContainer, 'keydown'));\n\t\tconst onSelectDropDownKeyDown = Event.chain(onKeyDown.event, $ =>\n\t\t\t$.filter(() => this.selectList.length > 0)\n\t\t\t\t.map(e => new StandardKeyboardEvent(e))\n\t\t);\n\n\t\tthis._register(Event.chain(onSelectDropDownKeyDown, $ => $.filter(e => e.keyCode === KeyCode.Enter))(this.onEnter, this));\n\t\tthis._register(Event.chain(onSelectDropDownKeyDown, $ => $.filter(e => e.keyCode === KeyCode.Tab))(this.onEnter, this)); // Tab should behave the same as enter, #79339\n\t\tthis._register(Event.chain(onSelectDropDownKeyDown, $ => $.filter(e => e.keyCode === KeyCode.Escape))(this.onEscape, this));\n\t\tthis._register(Event.chain(onSelectDropDownKeyDown, $ => $.filter(e => e.keyCode === KeyCode.UpArrow))(this.onUpArrow, this));\n\t\tthis._register(Event.chain(onSelectDropDownKeyDown, $ => $.filter(e => e.keyCode === KeyCode.DownArrow))(this.onDownArrow, this));\n\t\tthis._register(Event.chain(onSelectDropDownKeyDown, $ => $.filter(e => e.keyCode === KeyCode.PageDown))(this.onPageDown, this));\n\t\tthis._register(Event.chain(onSelectDropDownKeyDown, $ => $.filter(e => e.keyCode === KeyCode.PageUp))(this.onPageUp, this));\n\t\tthis._register(Event.chain(onSelectDropDownKeyDown, $ => $.filter(e => e.keyCode === KeyCode.Home))(this.onHome, this));\n\t\tthis._register(Event.chain(onSelectDropDownKeyDown, $ => $.filter(e => e.keyCode === KeyCode.End))(this.onEnd, this));\n\t\tthis._register(Event.chain(onSelectDropDownKeyDown, $ => $.filter(e => (e.keyCode >= KeyCode.Digit0 && e.keyCode <= KeyCode.KeyZ) || (e.keyCode >= KeyCode.Semicolon && e.keyCode <= KeyCode.NumpadDivide)))(this.onCharacter, this));\n\n\t\t// SetUp list mouse controller - control navigation, disabled items, focus\n\t\tthis._register(dom.addDisposableListener(this.selectList.getHTMLElement(), dom.EventType.POINTER_UP, e => this.onPointerUp(e)));\n\n\t\tthis._register(this.selectList.onMouseOver(e => typeof e.index !== 'undefined' && this.selectList.setFocus([e.index])));\n\t\tthis._register(this.selectList.onDidChangeFocus(e => this.onListFocus(e)));\n\n\t\tthis._register(dom.addDisposableListener(this.selectDropDownContainer, dom.EventType.FOCUS_OUT, e => {\n\t\t\tif (!this._isVisible || dom.isAncestor(e.relatedTarget as HTMLElement, this.selectDropDownContainer)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.onListBlur();\n\t\t}));\n\n\t\tthis.selectList.getHTMLElement().setAttribute('aria-label', this.selectBoxOptions.ariaLabel || '');\n\t\tthis.selectList.getHTMLElement().setAttribute('aria-expanded', 'true');\n\n\t\tthis.styleList();\n\t}\n\n\t// List methods\n\n\t// List mouse controller - active exit, select option, fire onDidSelect if change, return focus to parent select\n\t// Also takes in touchend events\n\tprivate onPointerUp(e: PointerEvent): void {\n\n\t\tif (!this.selectList.length) {\n\t\t\treturn;\n\t\t}\n\n\t\tdom.EventHelper.stop(e);\n\n\t\tconst target = e.target;\n\t\tif (!target) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Check our mouse event is on an option (not scrollbar)\n\t\tif (target.classList.contains('slider')) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst listRowElement = target.closest('.monaco-list-row');\n\n\t\tif (!listRowElement) {\n\t\t\treturn;\n\t\t}\n\t\tconst index = Number(listRowElement.getAttribute('data-index'));\n\t\tconst disabled = listRowElement.classList.contains('option-disabled');\n\n\t\t// Ignore mouse selection of disabled options\n\t\tif (index >= 0 && index < this.options.length && !disabled) {\n\t\t\tthis.selected = index;\n\t\t\tthis.select(this.selected);\n\n\t\t\tthis.selectList.setFocus([this.selected]);\n\t\t\tthis.selectList.reveal(this.selectList.getFocus()[0]);\n\n\t\t\t// Only fire if selection change\n\t\t\tif (this.selected !== this._currentSelection) {\n\t\t\t\t// Set current = selected\n\t\t\t\tthis._currentSelection = this.selected;\n\n\t\t\t\tthis._onDidSelect.fire({\n\t\t\t\t\tindex: this.selectElement.selectedIndex,\n\t\t\t\t\tselected: this.options[this.selected].text\n\n\t\t\t\t});\n\t\t\t\tif (!!this.options[this.selected] && !!this.options[this.selected].text) {\n\t\t\t\t\tthis.setTitle(this.options[this.selected].text);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.hideSelectDropDown(true);\n\t\t}\n\t}\n\n\t// List Exit - passive - implicit no selection change, hide drop-down\n\tprivate onListBlur(): void {\n\t\tif (this._sticky) { return; }\n\t\tif (this.selected !== this._currentSelection) {\n\t\t\t// Reset selected to current if no change\n\t\t\tthis.select(this._currentSelection);\n\t\t}\n\n\t\tthis.hideSelectDropDown(false);\n\t}\n\n\n\tprivate renderDescriptionMarkdown(text: string, actionHandler?: IContentActionHandler): HTMLElement {\n\t\tconst cleanRenderedMarkdown = (element: Node) => {\n\t\t\tfor (let i = 0; i < element.childNodes.length; i++) {\n\t\t\t\tconst child = element.childNodes.item(i);\n\n\t\t\t\tconst tagName = child.tagName && child.tagName.toLowerCase();\n\t\t\t\tif (tagName === 'img') {\n\t\t\t\t\telement.removeChild(child);\n\t\t\t\t} else {\n\t\t\t\t\tcleanRenderedMarkdown(child);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tconst rendered = renderMarkdown({ value: text, supportThemeIcons: true }, { actionHandler });\n\n\t\trendered.element.classList.add('select-box-description-markdown');\n\t\tcleanRenderedMarkdown(rendered.element);\n\n\t\treturn rendered.element;\n\t}\n\n\t// List Focus Change - passive - update details pane with newly focused element's data\n\tprivate onListFocus(e: IListEvent) {\n\t\t// Skip during initial layout\n\t\tif (!this._isVisible || !this._hasDetails) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.updateDetail(e.indexes[0]);\n\t}\n\n\tprivate updateDetail(selectedIndex: number): void {\n\t\tthis.selectionDetailsPane.innerText = '';\n\t\tconst option = this.options[selectedIndex];\n\t\tconst description = option?.description ?? '';\n\t\tconst descriptionIsMarkdown = option?.descriptionIsMarkdown ?? false;\n\n\t\tif (description) {\n\t\t\tif (descriptionIsMarkdown) {\n\t\t\t\tconst actionHandler = option.descriptionMarkdownActionHandler;\n\t\t\t\tthis.selectionDetailsPane.appendChild(this.renderDescriptionMarkdown(description, actionHandler));\n\t\t\t} else {\n\t\t\t\tthis.selectionDetailsPane.innerText = description;\n\t\t\t}\n\t\t\tthis.selectionDetailsPane.style.display = 'block';\n\t\t} else {\n\t\t\tthis.selectionDetailsPane.style.display = 'none';\n\t\t}\n\n\t\t// Avoid recursion\n\t\tthis._skipLayout = true;\n\t\tthis.contextViewProvider.layout();\n\t\tthis._skipLayout = false;\n\t}\n\n\t// List keyboard controller\n\n\t// List exit - active - hide ContextView dropdown, reset selection, return focus to parent select\n\tprivate onEscape(e: StandardKeyboardEvent): void {\n\t\tdom.EventHelper.stop(e);\n\n\t\t// Reset selection to value when opened\n\t\tthis.select(this._currentSelection);\n\t\tthis.hideSelectDropDown(true);\n\t}\n\n\t// List exit - active - hide ContextView dropdown, return focus to parent select, fire onDidSelect if change\n\tprivate onEnter(e: StandardKeyboardEvent): void {\n\t\tdom.EventHelper.stop(e);\n\n\t\t// Only fire if selection change\n\t\tif (this.selected !== this._currentSelection) {\n\t\t\tthis._currentSelection = this.selected;\n\t\t\tthis._onDidSelect.fire({\n\t\t\t\tindex: this.selectElement.selectedIndex,\n\t\t\t\tselected: this.options[this.selected].text\n\t\t\t});\n\t\t\tif (!!this.options[this.selected] && !!this.options[this.selected].text) {\n\t\t\t\tthis.setTitle(this.options[this.selected].text);\n\t\t\t}\n\t\t}\n\n\t\tthis.hideSelectDropDown(true);\n\t}\n\n\t// List navigation - have to handle a disabled option (jump over)\n\tprivate onDownArrow(e: StandardKeyboardEvent): void {\n\t\tif (this.selected < this.options.length - 1) {\n\t\t\tdom.EventHelper.stop(e, true);\n\n\t\t\t// Skip disabled options\n\t\t\tconst nextOptionDisabled = this.options[this.selected + 1].isDisabled;\n\n\t\t\tif (nextOptionDisabled && this.options.length > this.selected + 2) {\n\t\t\t\tthis.selected += 2;\n\t\t\t} else if (nextOptionDisabled) {\n\t\t\t\treturn;\n\t\t\t} else {\n\t\t\t\tthis.selected++;\n\t\t\t}\n\n\t\t\t// Set focus/selection - only fire event when closing drop-down or on blur\n\t\t\tthis.select(this.selected);\n\t\t\tthis.selectList.setFocus([this.selected]);\n\t\t\tthis.selectList.reveal(this.selectList.getFocus()[0]);\n\t\t}\n\t}\n\n\tprivate onUpArrow(e: StandardKeyboardEvent): void {\n\t\tif (this.selected > 0) {\n\t\t\tdom.EventHelper.stop(e, true);\n\t\t\t// Skip disabled options\n\t\t\tconst previousOptionDisabled = this.options[this.selected - 1].isDisabled;\n\t\t\tif (previousOptionDisabled && this.selected > 1) {\n\t\t\t\tthis.selected -= 2;\n\t\t\t} else {\n\t\t\t\tthis.selected--;\n\t\t\t}\n\t\t\t// Set focus/selection - only fire event when closing drop-down or on blur\n\t\t\tthis.select(this.selected);\n\t\t\tthis.selectList.setFocus([this.selected]);\n\t\t\tthis.selectList.reveal(this.selectList.getFocus()[0]);\n\t\t}\n\t}\n\n\tprivate onPageUp(e: StandardKeyboardEvent): void {\n\t\tdom.EventHelper.stop(e);\n\n\t\tthis.selectList.focusPreviousPage();\n\n\t\t// Allow scrolling to settle\n\t\tsetTimeout(() => {\n\t\t\tthis.selected = this.selectList.getFocus()[0];\n\n\t\t\t// Shift selection down if we land on a disabled option\n\t\t\tif (this.options[this.selected].isDisabled && this.selected < this.options.length - 1) {\n\t\t\t\tthis.selected++;\n\t\t\t\tthis.selectList.setFocus([this.selected]);\n\t\t\t}\n\t\t\tthis.selectList.reveal(this.selected);\n\t\t\tthis.select(this.selected);\n\t\t}, 1);\n\t}\n\n\tprivate onPageDown(e: StandardKeyboardEvent): void {\n\t\tdom.EventHelper.stop(e);\n\n\t\tthis.selectList.focusNextPage();\n\n\t\t// Allow scrolling to settle\n\t\tsetTimeout(() => {\n\t\t\tthis.selected = this.selectList.getFocus()[0];\n\n\t\t\t// Shift selection up if we land on a disabled option\n\t\t\tif (this.options[this.selected].isDisabled && this.selected > 0) {\n\t\t\t\tthis.selected--;\n\t\t\t\tthis.selectList.setFocus([this.selected]);\n\t\t\t}\n\t\t\tthis.selectList.reveal(this.selected);\n\t\t\tthis.select(this.selected);\n\t\t}, 1);\n\t}\n\n\tprivate onHome(e: StandardKeyboardEvent): void {\n\t\tdom.EventHelper.stop(e);\n\n\t\tif (this.options.length < 2) {\n\t\t\treturn;\n\t\t}\n\t\tthis.selected = 0;\n\t\tif (this.options[this.selected].isDisabled && this.selected > 1) {\n\t\t\tthis.selected++;\n\t\t}\n\t\tthis.selectList.setFocus([this.selected]);\n\t\tthis.selectList.reveal(this.selected);\n\t\tthis.select(this.selected);\n\t}\n\n\tprivate onEnd(e: StandardKeyboardEvent): void {\n\t\tdom.EventHelper.stop(e);\n\n\t\tif (this.options.length < 2) {\n\t\t\treturn;\n\t\t}\n\t\tthis.selected = this.options.length - 1;\n\t\tif (this.options[this.selected].isDisabled && this.selected > 1) {\n\t\t\tthis.selected--;\n\t\t}\n\t\tthis.selectList.setFocus([this.selected]);\n\t\tthis.selectList.reveal(this.selected);\n\t\tthis.select(this.selected);\n\t}\n\n\t// Mimic option first character navigation of native select\n\tprivate onCharacter(e: StandardKeyboardEvent): void {\n\t\tconst ch = KeyCodeUtils.toString(e.keyCode);\n\t\tlet optionIndex = -1;\n\n\t\tfor (let i = 0; i < this.options.length - 1; i++) {\n\t\t\toptionIndex = (i + this.selected + 1) % this.options.length;\n\t\t\tif (this.options[optionIndex].text.charAt(0).toUpperCase() === ch && !this.options[optionIndex].isDisabled) {\n\t\t\t\tthis.select(optionIndex);\n\t\t\t\tthis.selectList.setFocus([optionIndex]);\n\t\t\t\tthis.selectList.reveal(this.selectList.getFocus()[0]);\n\t\t\t\tdom.EventHelper.stop(e);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic override dispose(): void {\n\t\tthis.hideSelectDropDown(false);\n\t\tsuper.dispose();\n\t}\n}\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\nimport { IContentActionHandler } from 'vs/base/browser/formattedTextRenderer';\nimport { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview';\nimport { IListStyles } from 'vs/base/browser/ui/list/listWidget';\nimport { SelectBoxList } from 'vs/base/browser/ui/selectBox/selectBoxCustom';\nimport { SelectBoxNative } from 'vs/base/browser/ui/selectBox/selectBoxNative';\nimport { Widget } from 'vs/base/browser/ui/widget';\nimport { Event } from 'vs/base/common/event';\nimport { IDisposable } from 'vs/base/common/lifecycle';\nimport { isMacintosh } from 'vs/base/common/platform';\nimport 'vs/css!./selectBox';\n\n\n\n// Public SelectBox interface - Calls routed to appropriate select implementation class\n\nexport interface ISelectBoxDelegate extends IDisposable {\n\n\t// Public SelectBox Interface\n\treadonly onDidSelect: Event;\n\tsetOptions(options: ISelectOptionItem[], selected?: number): void;\n\tselect(index: number): void;\n\tfocus(): void;\n\tblur(): void;\n\tsetFocusable(focus: boolean): void;\n\n\t// Delegated Widget interface\n\trender(container: HTMLElement): void;\n}\n\nexport interface ISelectBoxOptions {\n\tuseCustomDrawn?: boolean;\n\tariaLabel?: string;\n\tariaDescription?: string;\n\tminBottomMargin?: number;\n\toptionsAsChildren?: boolean;\n}\n\n// Utilize optionItem interface to capture all option parameters\nexport interface ISelectOptionItem {\n\ttext: string;\n\tdetail?: string;\n\tdecoratorRight?: string;\n\tdescription?: string;\n\tdescriptionIsMarkdown?: boolean;\n\tdescriptionMarkdownActionHandler?: IContentActionHandler;\n\tisDisabled?: boolean;\n}\n\nexport interface ISelectBoxStyles extends IListStyles {\n\treadonly selectBackground: string | undefined;\n\treadonly selectListBackground: string | undefined;\n\treadonly selectForeground: string | undefined;\n\treadonly decoratorRightForeground: string | undefined;\n\treadonly selectBorder: string | undefined;\n\treadonly selectListBorder: string | undefined;\n\treadonly focusBorder: string | undefined;\n}\n\nexport interface ISelectData {\n\tselected: string;\n\tindex: number;\n}\n\nexport class SelectBox extends Widget implements ISelectBoxDelegate {\n\tprivate selectBoxDelegate: ISelectBoxDelegate;\n\n\tconstructor(options: ISelectOptionItem[], selected: number, contextViewProvider: IContextViewProvider, styles: ISelectBoxStyles, selectBoxOptions?: ISelectBoxOptions) {\n\t\tsuper();\n\n\t\t// Default to native SelectBox for OSX unless overridden\n\t\tif (isMacintosh && !selectBoxOptions?.useCustomDrawn) {\n\t\t\tthis.selectBoxDelegate = new SelectBoxNative(options, selected, styles, selectBoxOptions);\n\t\t} else {\n\t\t\tthis.selectBoxDelegate = new SelectBoxList(options, selected, contextViewProvider, styles, selectBoxOptions);\n\t\t}\n\n\t\tthis._register(this.selectBoxDelegate);\n\t}\n\n\t// Public SelectBox Methods - routed through delegate interface\n\n\tget onDidSelect(): Event {\n\t\treturn this.selectBoxDelegate.onDidSelect;\n\t}\n\n\tsetOptions(options: ISelectOptionItem[], selected?: number): void {\n\t\tthis.selectBoxDelegate.setOptions(options, selected);\n\t}\n\n\tselect(index: number): void {\n\t\tthis.selectBoxDelegate.select(index);\n\t}\n\n\tfocus(): void {\n\t\tthis.selectBoxDelegate.focus();\n\t}\n\n\tblur(): void {\n\t\tthis.selectBoxDelegate.blur();\n\t}\n\n\tsetFocusable(focusable: boolean): void {\n\t\tthis.selectBoxDelegate.setFocusable(focusable);\n\t}\n\n\trender(container: HTMLElement): void {\n\t\tthis.selectBoxDelegate.render(container);\n\t}\n}\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\nimport { isFirefox } from 'vs/base/browser/browser';\nimport { DataTransfers } from 'vs/base/browser/dnd';\nimport { addDisposableListener, EventHelper, EventLike, EventType } from 'vs/base/browser/dom';\nimport { EventType as TouchEventType, Gesture } from 'vs/base/browser/touch';\nimport { IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';\nimport { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview';\nimport { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegateFactory';\nimport { IHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate';\nimport { ISelectBoxOptions, ISelectBoxStyles, ISelectOptionItem, SelectBox } from 'vs/base/browser/ui/selectBox/selectBox';\nimport { Action, ActionRunner, IAction, IActionChangeEvent, IActionRunner, Separator } from 'vs/base/common/actions';\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport * as platform from 'vs/base/common/platform';\nimport * as types from 'vs/base/common/types';\nimport 'vs/css!./actionbar';\nimport * as nls from 'vs/nls';\nimport { IUpdatableHover } from 'vs/base/browser/ui/hover/hover';\nimport { getBaseLayerHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate2';\n\nexport interface IBaseActionViewItemOptions {\n\tdraggable?: boolean;\n\tisMenu?: boolean;\n\tuseEventAsContext?: boolean;\n\thoverDelegate?: IHoverDelegate;\n}\n\nexport class BaseActionViewItem extends Disposable implements IActionViewItem {\n\n\telement: HTMLElement | undefined;\n\n\t_context: unknown;\n\treadonly _action: IAction;\n\n\tprivate customHover?: IUpdatableHover;\n\n\tget action() {\n\t\treturn this._action;\n\t}\n\n\tprivate _actionRunner: IActionRunner | undefined;\n\n\tconstructor(context: unknown, action: IAction, protected options: IBaseActionViewItemOptions = {}) {\n\t\tsuper();\n\n\t\tthis._context = context || this;\n\t\tthis._action = action;\n\n\t\tif (action instanceof Action) {\n\t\t\tthis._register(action.onDidChange(event => {\n\t\t\t\tif (!this.element) {\n\t\t\t\t\t// we have not been rendered yet, so there\n\t\t\t\t\t// is no point in updating the UI\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis.handleActionChangeEvent(event);\n\t\t\t}));\n\t\t}\n\t}\n\n\tprivate handleActionChangeEvent(event: IActionChangeEvent): void {\n\t\tif (event.enabled !== undefined) {\n\t\t\tthis.updateEnabled();\n\t\t}\n\n\t\tif (event.checked !== undefined) {\n\t\t\tthis.updateChecked();\n\t\t}\n\n\t\tif (event.class !== undefined) {\n\t\t\tthis.updateClass();\n\t\t}\n\n\t\tif (event.label !== undefined) {\n\t\t\tthis.updateLabel();\n\t\t\tthis.updateTooltip();\n\t\t}\n\n\t\tif (event.tooltip !== undefined) {\n\t\t\tthis.updateTooltip();\n\t\t}\n\t}\n\n\tget actionRunner(): IActionRunner {\n\t\tif (!this._actionRunner) {\n\t\t\tthis._actionRunner = this._register(new ActionRunner());\n\t\t}\n\n\t\treturn this._actionRunner;\n\t}\n\n\tset actionRunner(actionRunner: IActionRunner) {\n\t\tthis._actionRunner = actionRunner;\n\t}\n\n\tisEnabled(): boolean {\n\t\treturn this._action.enabled;\n\t}\n\n\tsetActionContext(newContext: unknown): void {\n\t\tthis._context = newContext;\n\t}\n\n\trender(container: HTMLElement): void {\n\t\tconst element = this.element = container;\n\t\tthis._register(Gesture.addTarget(container));\n\n\t\tconst enableDragging = this.options && this.options.draggable;\n\t\tif (enableDragging) {\n\t\t\tcontainer.draggable = true;\n\n\t\t\tif (isFirefox) {\n\t\t\t\t// Firefox: requires to set a text data transfer to get going\n\t\t\t\tthis._register(addDisposableListener(container, EventType.DRAG_START, e => e.dataTransfer?.setData(DataTransfers.TEXT, this._action.label)));\n\t\t\t}\n\t\t}\n\n\t\tthis._register(addDisposableListener(element, TouchEventType.Tap, e => this.onClick(e, true))); // Preserve focus on tap #125470\n\n\t\tthis._register(addDisposableListener(element, EventType.MOUSE_DOWN, e => {\n\t\t\tif (!enableDragging) {\n\t\t\t\tEventHelper.stop(e, true); // do not run when dragging is on because that would disable it\n\t\t\t}\n\n\t\t\tif (this._action.enabled && e.button === 0) {\n\t\t\t\telement.classList.add('active');\n\t\t\t}\n\t\t}));\n\n\t\tif (platform.isMacintosh) {\n\t\t\t// macOS: allow to trigger the button when holding Ctrl+key and pressing the\n\t\t\t// main mouse button. This is for scenarios where e.g. some interaction forces\n\t\t\t// the Ctrl+key to be pressed and hold but the user still wants to interact\n\t\t\t// with the actions (for example quick access in quick navigation mode).\n\t\t\tthis._register(addDisposableListener(element, EventType.CONTEXT_MENU, e => {\n\t\t\t\tif (e.button === 0 && e.ctrlKey === true) {\n\t\t\t\t\tthis.onClick(e);\n\t\t\t\t}\n\t\t\t}));\n\t\t}\n\n\t\tthis._register(addDisposableListener(element, EventType.CLICK, e => {\n\t\t\tEventHelper.stop(e, true);\n\n\t\t\t// menus do not use the click event\n\t\t\tif (!(this.options && this.options.isMenu)) {\n\t\t\t\tthis.onClick(e);\n\t\t\t}\n\t\t}));\n\n\t\tthis._register(addDisposableListener(element, EventType.DBLCLICK, e => {\n\t\t\tEventHelper.stop(e, true);\n\t\t}));\n\n\t\t[EventType.MOUSE_UP, EventType.MOUSE_OUT].forEach(event => {\n\t\t\tthis._register(addDisposableListener(element, event, e => {\n\t\t\t\tEventHelper.stop(e);\n\t\t\t\telement.classList.remove('active');\n\t\t\t}));\n\t\t});\n\t}\n\n\tonClick(event: EventLike, preserveFocus = false): void {\n\t\tEventHelper.stop(event, true);\n\n\t\tconst context = types.isUndefinedOrNull(this._context) ? this.options?.useEventAsContext ? event : { preserveFocus } : this._context;\n\t\tthis.actionRunner.run(this._action, context);\n\t}\n\n\t// Only set the tabIndex on the element once it is about to get focused\n\t// That way this element wont be a tab stop when it is not needed #106441\n\tfocus(): void {\n\t\tif (this.element) {\n\t\t\tthis.element.tabIndex = 0;\n\t\t\tthis.element.focus();\n\t\t\tthis.element.classList.add('focused');\n\t\t}\n\t}\n\n\tblur(): void {\n\t\tif (this.element) {\n\t\t\tthis.element.blur();\n\t\t\tthis.element.tabIndex = -1;\n\t\t\tthis.element.classList.remove('focused');\n\t\t}\n\t}\n\n\tsetFocusable(focusable: boolean): void {\n\t\tif (this.element) {\n\t\t\tthis.element.tabIndex = focusable ? 0 : -1;\n\t\t}\n\t}\n\n\tget trapsArrowNavigation(): boolean {\n\t\treturn false;\n\t}\n\n\tprotected updateEnabled(): void {\n\t\t// implement in subclass\n\t}\n\n\tprotected updateLabel(): void {\n\t\t// implement in subclass\n\t}\n\n\tprotected getClass(): string | undefined {\n\t\treturn this.action.class;\n\t}\n\n\tprotected getTooltip(): string | undefined {\n\t\treturn this.action.tooltip;\n\t}\n\n\tprotected updateTooltip(): void {\n\t\tif (!this.element) {\n\t\t\treturn;\n\t\t}\n\t\tconst title = this.getTooltip() ?? '';\n\t\tthis.updateAriaLabel();\n\n\t\tif (this.options.hoverDelegate?.showNativeHover) {\n\t\t\t/* While custom hover is not inside custom hover */\n\t\t\tthis.element.title = title;\n\t\t} else {\n\t\t\tif (!this.customHover && title !== '') {\n\t\t\t\tconst hoverDelegate = this.options.hoverDelegate ?? getDefaultHoverDelegate('element');\n\t\t\t\tthis.customHover = this._store.add(getBaseLayerHoverDelegate().setupUpdatableHover(hoverDelegate, this.element, title));\n\t\t\t} else if (this.customHover) {\n\t\t\t\tthis.customHover.update(title);\n\t\t\t}\n\t\t}\n\t}\n\n\tprotected updateAriaLabel(): void {\n\t\tif (this.element) {\n\t\t\tconst title = this.getTooltip() ?? '';\n\t\t\tthis.element.setAttribute('aria-label', title);\n\t\t}\n\t}\n\n\tprotected updateClass(): void {\n\t\t// implement in subclass\n\t}\n\n\tprotected updateChecked(): void {\n\t\t// implement in subclass\n\t}\n\n\toverride dispose(): void {\n\t\tif (this.element) {\n\t\t\tthis.element.remove();\n\t\t\tthis.element = undefined;\n\t\t}\n\t\tthis._context = undefined;\n\t\tsuper.dispose();\n\t}\n}\n\nexport interface IActionViewItemOptions extends IBaseActionViewItemOptions {\n\ticon?: boolean;\n\tlabel?: boolean;\n\tkeybinding?: string | null;\n}\n\nexport class ActionViewItem extends BaseActionViewItem {\n\n\tprotected label: HTMLElement | undefined;\n\tprotected override options: IActionViewItemOptions;\n\n\tprivate cssClass?: string;\n\n\tconstructor(context: unknown, action: IAction, options: IActionViewItemOptions) {\n\t\tsuper(context, action, options);\n\n\t\tthis.options = options;\n\t\tthis.options.icon = options.icon !== undefined ? options.icon : false;\n\t\tthis.options.label = options.label !== undefined ? options.label : true;\n\t\tthis.cssClass = '';\n\t}\n\n\toverride render(container: HTMLElement): void {\n\t\tsuper.render(container);\n\t\ttypes.assertType(this.element);\n\n\t\tconst label = document.createElement('a');\n\t\tlabel.classList.add('action-label');\n\t\tlabel.setAttribute('role', this.getDefaultAriaRole());\n\n\t\tthis.label = label;\n\t\tthis.element.appendChild(label);\n\n\t\tif (this.options.label && this.options.keybinding) {\n\t\t\tconst kbLabel = document.createElement('span');\n\t\t\tkbLabel.classList.add('keybinding');\n\t\t\tkbLabel.textContent = this.options.keybinding;\n\t\t\tthis.element.appendChild(kbLabel);\n\t\t}\n\n\t\tthis.updateClass();\n\t\tthis.updateLabel();\n\t\tthis.updateTooltip();\n\t\tthis.updateEnabled();\n\t\tthis.updateChecked();\n\t}\n\n\tprivate getDefaultAriaRole(): 'presentation' | 'menuitem' | 'button' {\n\t\tif (this._action.id === Separator.ID) {\n\t\t\treturn 'presentation'; // A separator is a presentation item\n\t\t} else {\n\t\t\tif (this.options.isMenu) {\n\t\t\t\treturn 'menuitem';\n\t\t\t} else {\n\t\t\t\treturn 'button';\n\t\t\t}\n\t\t}\n\t}\n\n\t// Only set the tabIndex on the element once it is about to get focused\n\t// That way this element wont be a tab stop when it is not needed #106441\n\toverride focus(): void {\n\t\tif (this.label) {\n\t\t\tthis.label.tabIndex = 0;\n\t\t\tthis.label.focus();\n\t\t}\n\t}\n\n\toverride blur(): void {\n\t\tif (this.label) {\n\t\t\tthis.label.tabIndex = -1;\n\t\t}\n\t}\n\n\toverride setFocusable(focusable: boolean): void {\n\t\tif (this.label) {\n\t\t\tthis.label.tabIndex = focusable ? 0 : -1;\n\t\t}\n\t}\n\n\tprotected override updateLabel(): void {\n\t\tif (this.options.label && this.label) {\n\t\t\tthis.label.textContent = this.action.label;\n\t\t}\n\t}\n\n\tprotected override getTooltip() {\n\t\tlet title: string | null = null;\n\n\t\tif (this.action.tooltip) {\n\t\t\ttitle = this.action.tooltip;\n\n\t\t} else if (!this.options.label && this.action.label && this.options.icon) {\n\t\t\ttitle = this.action.label;\n\n\t\t\tif (this.options.keybinding) {\n\t\t\t\ttitle = nls.localize({ key: 'titleLabel', comment: ['action title', 'action keybinding'] }, \"{0} ({1})\", title, this.options.keybinding);\n\t\t\t}\n\t\t}\n\t\treturn title ?? undefined;\n\t}\n\n\tprotected override updateClass(): void {\n\t\tif (this.cssClass && this.label) {\n\t\t\tthis.label.classList.remove(...this.cssClass.split(' '));\n\t\t}\n\t\tif (this.options.icon) {\n\t\t\tthis.cssClass = this.getClass();\n\n\t\t\tif (this.label) {\n\t\t\t\tthis.label.classList.add('codicon');\n\t\t\t\tif (this.cssClass) {\n\t\t\t\t\tthis.label.classList.add(...this.cssClass.split(' '));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.updateEnabled();\n\t\t} else {\n\t\t\tthis.label?.classList.remove('codicon');\n\t\t}\n\t}\n\n\tprotected override updateEnabled(): void {\n\t\tif (this.action.enabled) {\n\t\t\tif (this.label) {\n\t\t\t\tthis.label.removeAttribute('aria-disabled');\n\t\t\t\tthis.label.classList.remove('disabled');\n\t\t\t}\n\n\t\t\tthis.element?.classList.remove('disabled');\n\t\t} else {\n\t\t\tif (this.label) {\n\t\t\t\tthis.label.setAttribute('aria-disabled', 'true');\n\t\t\t\tthis.label.classList.add('disabled');\n\t\t\t}\n\n\t\t\tthis.element?.classList.add('disabled');\n\t\t}\n\t}\n\n\tprotected override updateAriaLabel(): void {\n\t\tif (this.label) {\n\t\t\tconst title = this.getTooltip() ?? '';\n\t\t\tthis.label.setAttribute('aria-label', title);\n\t\t}\n\t}\n\n\tprotected override updateChecked(): void {\n\t\tif (this.label) {\n\t\t\tif (this.action.checked !== undefined) {\n\t\t\t\tthis.label.classList.toggle('checked', this.action.checked);\n\t\t\t\tthis.label.setAttribute('aria-checked', this.action.checked ? 'true' : 'false');\n\t\t\t\tthis.label.setAttribute('role', 'checkbox');\n\t\t\t} else {\n\t\t\t\tthis.label.classList.remove('checked');\n\t\t\t\tthis.label.removeAttribute('aria-checked');\n\t\t\t\tthis.label.setAttribute('role', this.getDefaultAriaRole());\n\t\t\t}\n\t\t}\n\t}\n}\n\nexport class SelectActionViewItem extends BaseActionViewItem {\n\tprotected selectBox: SelectBox;\n\n\tconstructor(ctx: unknown, action: IAction, options: ISelectOptionItem[], selected: number, contextViewProvider: IContextViewProvider, styles: ISelectBoxStyles, selectBoxOptions?: ISelectBoxOptions) {\n\t\tsuper(ctx, action);\n\n\t\tthis.selectBox = new SelectBox(options, selected, contextViewProvider, styles, selectBoxOptions);\n\t\tthis.selectBox.setFocusable(false);\n\n\t\tthis._register(this.selectBox);\n\t\tthis.registerListeners();\n\t}\n\n\tselect(index: number): void {\n\t\tthis.selectBox.select(index);\n\t}\n\n\tprivate registerListeners(): void {\n\t\tthis._register(this.selectBox.onDidSelect(e => this.runAction(e.selected, e.index)));\n\t}\n\n\tprotected runAction(option: string, index: number): void {\n\t\tthis.actionRunner.run(this._action, this.getActionContext(option, index));\n\t}\n\n\tprotected getActionContext(option: string, index: number): T | string {\n\t\treturn option;\n\t}\n\n\toverride setFocusable(focusable: boolean): void {\n\t\tthis.selectBox.setFocusable(focusable);\n\t}\n\n\toverride focus(): void {\n\t\tthis.selectBox?.focus();\n\t}\n\n\toverride blur(): void {\n\t\tthis.selectBox?.blur();\n\t}\n\n\toverride render(container: HTMLElement): void {\n\t\tthis.selectBox.render(container);\n\t}\n}\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\nimport * as DOM from 'vs/base/browser/dom';\nimport { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';\nimport { ActionViewItem, BaseActionViewItem, IActionViewItemOptions } from 'vs/base/browser/ui/actionbar/actionViewItems';\nimport { createInstantHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegateFactory';\nimport { IHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate';\nimport { ActionRunner, IAction, IActionRunner, IRunEvent, Separator } from 'vs/base/common/actions';\nimport { Emitter } from 'vs/base/common/event';\nimport { KeyCode, KeyMod } from 'vs/base/common/keyCodes';\nimport { Disposable, DisposableMap, DisposableStore, dispose, IDisposable } from 'vs/base/common/lifecycle';\nimport * as types from 'vs/base/common/types';\nimport 'vs/css!./actionbar';\n\nexport interface IActionViewItem extends IDisposable {\n\taction: IAction;\n\tactionRunner: IActionRunner;\n\tsetActionContext(context: unknown): void;\n\trender(element: HTMLElement): void;\n\tisEnabled(): boolean;\n\tfocus(fromRight?: boolean): void; // TODO@isidorn what is this?\n\tblur(): void;\n\tshowHover?(): void;\n}\n\nexport interface IActionViewItemProvider {\n\t(action: IAction, options: IActionViewItemOptions): IActionViewItem | undefined;\n}\n\nexport const enum ActionsOrientation {\n\tHORIZONTAL,\n\tVERTICAL,\n}\n\nexport interface ActionTrigger {\n\tkeys?: KeyCode[];\n\tkeyDown: boolean;\n}\n\nexport interface IActionBarOptions {\n\treadonly orientation?: ActionsOrientation;\n\treadonly context?: unknown;\n\treadonly actionViewItemProvider?: IActionViewItemProvider;\n\treadonly actionRunner?: IActionRunner;\n\treadonly ariaLabel?: string;\n\treadonly ariaRole?: string;\n\treadonly triggerKeys?: ActionTrigger;\n\treadonly allowContextMenu?: boolean;\n\treadonly preventLoopNavigation?: boolean;\n\treadonly focusOnlyEnabledItems?: boolean;\n\treadonly hoverDelegate?: IHoverDelegate;\n\t/**\n\t * If true, toggled primary items are highlighted with a background color.\n\t * Some action bars exclusively use icon states, we don't want to enable this for them.\n\t * Thus, this is opt-in.\n\t */\n\treadonly highlightToggledItems?: boolean;\n}\n\nexport interface IActionOptions extends IActionViewItemOptions {\n\tindex?: number;\n}\n\nexport class ActionBar extends Disposable implements IActionRunner {\n\n\tprivate readonly options: IActionBarOptions;\n\tprivate readonly _hoverDelegate: IHoverDelegate;\n\n\tprivate _actionRunner: IActionRunner;\n\tprivate readonly _actionRunnerDisposables = this._register(new DisposableStore());\n\tprivate _context: unknown;\n\tprivate readonly _orientation: ActionsOrientation;\n\tprivate readonly _triggerKeys: {\n\t\tkeys: KeyCode[];\n\t\tkeyDown: boolean;\n\t};\n\n\t// View Items\n\tviewItems: IActionViewItem[];\n\tprivate readonly viewItemDisposables = this._register(new DisposableMap());\n\tprivate previouslyFocusedItem?: number;\n\tprotected focusedItem?: number;\n\tprivate focusTracker: DOM.IFocusTracker;\n\n\t// Trigger Key Tracking\n\tprivate triggerKeyDown: boolean = false;\n\n\tprivate focusable: boolean = true;\n\n\t// Elements\n\tdomNode: HTMLElement;\n\tprotected readonly actionsList: HTMLElement;\n\n\tprivate readonly _onDidBlur = this._register(new Emitter());\n\treadonly onDidBlur = this._onDidBlur.event;\n\n\tprivate readonly _onDidCancel = this._register(new Emitter({ onWillAddFirstListener: () => this.cancelHasListener = true }));\n\treadonly onDidCancel = this._onDidCancel.event;\n\tprivate cancelHasListener = false;\n\n\tprivate readonly _onDidRun = this._register(new Emitter());\n\treadonly onDidRun = this._onDidRun.event;\n\n\tprivate readonly _onWillRun = this._register(new Emitter());\n\treadonly onWillRun = this._onWillRun.event;\n\n\tconstructor(container: HTMLElement, options: IActionBarOptions = {}) {\n\t\tsuper();\n\n\t\tthis.options = options;\n\t\tthis._context = options.context ?? null;\n\t\tthis._orientation = this.options.orientation ?? ActionsOrientation.HORIZONTAL;\n\t\tthis._triggerKeys = {\n\t\t\tkeyDown: this.options.triggerKeys?.keyDown ?? false,\n\t\t\tkeys: this.options.triggerKeys?.keys ?? [KeyCode.Enter, KeyCode.Space]\n\t\t};\n\n\t\tthis._hoverDelegate = options.hoverDelegate ?? this._register(createInstantHoverDelegate());\n\n\t\tif (this.options.actionRunner) {\n\t\t\tthis._actionRunner = this.options.actionRunner;\n\t\t} else {\n\t\t\tthis._actionRunner = new ActionRunner();\n\t\t\tthis._actionRunnerDisposables.add(this._actionRunner);\n\t\t}\n\n\t\tthis._actionRunnerDisposables.add(this._actionRunner.onDidRun(e => this._onDidRun.fire(e)));\n\t\tthis._actionRunnerDisposables.add(this._actionRunner.onWillRun(e => this._onWillRun.fire(e)));\n\n\t\tthis.viewItems = [];\n\t\tthis.focusedItem = undefined;\n\n\t\tthis.domNode = document.createElement('div');\n\t\tthis.domNode.className = 'monaco-action-bar';\n\n\t\tlet previousKeys: KeyCode[];\n\t\tlet nextKeys: KeyCode[];\n\n\t\tswitch (this._orientation) {\n\t\t\tcase ActionsOrientation.HORIZONTAL:\n\t\t\t\tpreviousKeys = [KeyCode.LeftArrow];\n\t\t\t\tnextKeys = [KeyCode.RightArrow];\n\t\t\t\tbreak;\n\t\t\tcase ActionsOrientation.VERTICAL:\n\t\t\t\tpreviousKeys = [KeyCode.UpArrow];\n\t\t\t\tnextKeys = [KeyCode.DownArrow];\n\t\t\t\tthis.domNode.className += ' vertical';\n\t\t\t\tbreak;\n\t\t}\n\n\t\tthis._register(DOM.addDisposableListener(this.domNode, DOM.EventType.KEY_DOWN, e => {\n\t\t\tconst event = new StandardKeyboardEvent(e);\n\t\t\tlet eventHandled = true;\n\t\t\tconst focusedItem = typeof this.focusedItem === 'number' ? this.viewItems[this.focusedItem] : undefined;\n\n\t\t\tif (previousKeys && (event.equals(previousKeys[0]) || event.equals(previousKeys[1]))) {\n\t\t\t\teventHandled = this.focusPrevious();\n\t\t\t} else if (nextKeys && (event.equals(nextKeys[0]) || event.equals(nextKeys[1]))) {\n\t\t\t\teventHandled = this.focusNext();\n\t\t\t} else if (event.equals(KeyCode.Escape) && this.cancelHasListener) {\n\t\t\t\tthis._onDidCancel.fire();\n\t\t\t} else if (event.equals(KeyCode.Home)) {\n\t\t\t\teventHandled = this.focusFirst();\n\t\t\t} else if (event.equals(KeyCode.End)) {\n\t\t\t\teventHandled = this.focusLast();\n\t\t\t} else if (event.equals(KeyCode.Tab) && focusedItem instanceof BaseActionViewItem && focusedItem.trapsArrowNavigation) {\n\t\t\t\teventHandled = this.focusNext();\n\t\t\t} else if (this.isTriggerKeyEvent(event)) {\n\t\t\t\t// Staying out of the else branch even if not triggered\n\t\t\t\tif (this._triggerKeys.keyDown) {\n\t\t\t\t\tthis.doTrigger(event);\n\t\t\t\t} else {\n\t\t\t\t\tthis.triggerKeyDown = true;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\teventHandled = false;\n\t\t\t}\n\n\t\t\tif (eventHandled) {\n\t\t\t\tevent.preventDefault();\n\t\t\t\tevent.stopPropagation();\n\t\t\t}\n\t\t}));\n\n\t\tthis._register(DOM.addDisposableListener(this.domNode, DOM.EventType.KEY_UP, e => {\n\t\t\tconst event = new StandardKeyboardEvent(e);\n\n\t\t\t// Run action on Enter/Space\n\t\t\tif (this.isTriggerKeyEvent(event)) {\n\t\t\t\tif (!this._triggerKeys.keyDown && this.triggerKeyDown) {\n\t\t\t\t\tthis.triggerKeyDown = false;\n\t\t\t\t\tthis.doTrigger(event);\n\t\t\t\t}\n\n\t\t\t\tevent.preventDefault();\n\t\t\t\tevent.stopPropagation();\n\t\t\t}\n\n\t\t\t// Recompute focused item\n\t\t\telse if (event.equals(KeyCode.Tab) || event.equals(KeyMod.Shift | KeyCode.Tab) || event.equals(KeyCode.UpArrow) || event.equals(KeyCode.DownArrow) || event.equals(KeyCode.LeftArrow) || event.equals(KeyCode.RightArrow)) {\n\t\t\t\tthis.updateFocusedItem();\n\t\t\t}\n\t\t}));\n\n\t\tthis.focusTracker = this._register(DOM.trackFocus(this.domNode));\n\t\tthis._register(this.focusTracker.onDidBlur(() => {\n\t\t\tif (DOM.getActiveElement() === this.domNode || !DOM.isAncestor(DOM.getActiveElement(), this.domNode)) {\n\t\t\t\tthis._onDidBlur.fire();\n\t\t\t\tthis.previouslyFocusedItem = this.focusedItem;\n\t\t\t\tthis.focusedItem = undefined;\n\t\t\t\tthis.triggerKeyDown = false;\n\t\t\t}\n\t\t}));\n\n\t\tthis._register(this.focusTracker.onDidFocus(() => this.updateFocusedItem()));\n\n\t\tthis.actionsList = document.createElement('ul');\n\t\tthis.actionsList.className = 'actions-container';\n\t\tif (this.options.highlightToggledItems) {\n\t\t\tthis.actionsList.classList.add('highlight-toggled');\n\t\t}\n\t\tthis.actionsList.setAttribute('role', this.options.ariaRole || 'toolbar');\n\n\t\tif (this.options.ariaLabel) {\n\t\t\tthis.actionsList.setAttribute('aria-label', this.options.ariaLabel);\n\t\t}\n\n\t\tthis.domNode.appendChild(this.actionsList);\n\n\t\tcontainer.appendChild(this.domNode);\n\t}\n\n\tprivate refreshRole(): void {\n\t\tif (this.length() >= 1) {\n\t\t\tthis.actionsList.setAttribute('role', this.options.ariaRole || 'toolbar');\n\t\t} else {\n\t\t\tthis.actionsList.setAttribute('role', 'presentation');\n\t\t}\n\t}\n\n\t// Some action bars should not be focusable at times\n\t// When an action bar is not focusable make sure to make all the elements inside it not focusable\n\t// When an action bar is focusable again, make sure the first item can be focused\n\tsetFocusable(focusable: boolean): void {\n\t\tthis.focusable = focusable;\n\t\tif (this.focusable) {\n\t\t\tconst firstEnabled = this.viewItems.find(vi => vi instanceof BaseActionViewItem && vi.isEnabled());\n\t\t\tif (firstEnabled instanceof BaseActionViewItem) {\n\t\t\t\tfirstEnabled.setFocusable(true);\n\t\t\t}\n\t\t} else {\n\t\t\tthis.viewItems.forEach(vi => {\n\t\t\t\tif (vi instanceof BaseActionViewItem) {\n\t\t\t\t\tvi.setFocusable(false);\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate isTriggerKeyEvent(event: StandardKeyboardEvent): boolean {\n\t\tlet ret = false;\n\t\tthis._triggerKeys.keys.forEach(keyCode => {\n\t\t\tret = ret || event.equals(keyCode);\n\t\t});\n\n\t\treturn ret;\n\t}\n\n\tprivate updateFocusedItem(): void {\n\t\tfor (let i = 0; i < this.actionsList.children.length; i++) {\n\t\t\tconst elem = this.actionsList.children[i];\n\t\t\tif (DOM.isAncestor(DOM.getActiveElement(), elem)) {\n\t\t\t\tthis.focusedItem = i;\n\t\t\t\tthis.viewItems[this.focusedItem]?.showHover?.();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tget context(): unknown {\n\t\treturn this._context;\n\t}\n\n\tset context(context: unknown) {\n\t\tthis._context = context;\n\t\tthis.viewItems.forEach(i => i.setActionContext(context));\n\t}\n\n\tget actionRunner(): IActionRunner {\n\t\treturn this._actionRunner;\n\t}\n\n\tset actionRunner(actionRunner: IActionRunner) {\n\t\tthis._actionRunner = actionRunner;\n\n\t\t// when setting a new `IActionRunner` make sure to dispose old listeners and\n\t\t// start to forward events from the new listener\n\t\tthis._actionRunnerDisposables.clear();\n\t\tthis._actionRunnerDisposables.add(this._actionRunner.onDidRun(e => this._onDidRun.fire(e)));\n\t\tthis._actionRunnerDisposables.add(this._actionRunner.onWillRun(e => this._onWillRun.fire(e)));\n\t\tthis.viewItems.forEach(item => item.actionRunner = actionRunner);\n\t}\n\n\tgetContainer(): HTMLElement {\n\t\treturn this.domNode;\n\t}\n\n\tgetAction(indexOrElement: number | HTMLElement): IAction | undefined {\n\n\t\t// by index\n\t\tif (typeof indexOrElement === 'number') {\n\t\t\treturn this.viewItems[indexOrElement]?.action;\n\t\t}\n\n\t\t// by element\n\t\tif (indexOrElement instanceof HTMLElement) {\n\t\t\twhile (indexOrElement.parentElement !== this.actionsList) {\n\t\t\t\tif (!indexOrElement.parentElement) {\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\t\t\t\tindexOrElement = indexOrElement.parentElement;\n\t\t\t}\n\t\t\tfor (let i = 0; i < this.actionsList.childNodes.length; i++) {\n\t\t\t\tif (this.actionsList.childNodes[i] === indexOrElement) {\n\t\t\t\t\treturn this.viewItems[i].action;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\tpush(arg: IAction | ReadonlyArray, options: IActionOptions = {}): void {\n\t\tconst actions: ReadonlyArray = Array.isArray(arg) ? arg : [arg];\n\n\t\tlet index = types.isNumber(options.index) ? options.index : null;\n\n\t\tactions.forEach((action: IAction) => {\n\t\t\tconst actionViewItemElement = document.createElement('li');\n\t\t\tactionViewItemElement.className = 'action-item';\n\t\t\tactionViewItemElement.setAttribute('role', 'presentation');\n\n\t\t\tlet item: IActionViewItem | undefined;\n\n\t\t\tconst viewItemOptions = { hoverDelegate: this._hoverDelegate, ...options };\n\t\t\tif (this.options.actionViewItemProvider) {\n\t\t\t\titem = this.options.actionViewItemProvider(action, viewItemOptions);\n\t\t\t}\n\n\t\t\tif (!item) {\n\t\t\t\titem = new ActionViewItem(this.context, action, viewItemOptions);\n\t\t\t}\n\n\t\t\t// Prevent native context menu on actions\n\t\t\tif (!this.options.allowContextMenu) {\n\t\t\t\tthis.viewItemDisposables.set(item, DOM.addDisposableListener(actionViewItemElement, DOM.EventType.CONTEXT_MENU, (e: DOM.EventLike) => {\n\t\t\t\t\tDOM.EventHelper.stop(e, true);\n\t\t\t\t}));\n\t\t\t}\n\n\t\t\titem.actionRunner = this._actionRunner;\n\t\t\titem.setActionContext(this.context);\n\t\t\titem.render(actionViewItemElement);\n\n\t\t\tif (this.focusable && item instanceof BaseActionViewItem && this.viewItems.length === 0) {\n\t\t\t\t// We need to allow for the first enabled item to be focused on using tab navigation #106441\n\t\t\t\titem.setFocusable(true);\n\t\t\t}\n\n\t\t\tif (index === null || index < 0 || index >= this.actionsList.children.length) {\n\t\t\t\tthis.actionsList.appendChild(actionViewItemElement);\n\t\t\t\tthis.viewItems.push(item);\n\t\t\t} else {\n\t\t\t\tthis.actionsList.insertBefore(actionViewItemElement, this.actionsList.children[index]);\n\t\t\t\tthis.viewItems.splice(index, 0, item);\n\t\t\t\tindex++;\n\t\t\t}\n\t\t});\n\t\tif (typeof this.focusedItem === 'number') {\n\t\t\t// After a clear actions might be re-added to simply toggle some actions. We should preserve focus #97128\n\t\t\tthis.focus(this.focusedItem);\n\t\t}\n\t\tthis.refreshRole();\n\t}\n\n\tclear(): void {\n\t\tif (this.isEmpty()) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.viewItems = dispose(this.viewItems);\n\t\tthis.viewItemDisposables.clearAndDisposeAll();\n\t\tDOM.clearNode(this.actionsList);\n\t\tthis.refreshRole();\n\t}\n\n\tlength(): number {\n\t\treturn this.viewItems.length;\n\t}\n\n\tisEmpty(): boolean {\n\t\treturn this.viewItems.length === 0;\n\t}\n\n\tfocus(index?: number): void;\n\tfocus(selectFirst?: boolean): void;\n\tfocus(arg?: number | boolean): void {\n\t\tlet selectFirst: boolean = false;\n\t\tlet index: number | undefined = undefined;\n\t\tif (arg === undefined) {\n\t\t\tselectFirst = true;\n\t\t} else if (typeof arg === 'number') {\n\t\t\tindex = arg;\n\t\t} else if (typeof arg === 'boolean') {\n\t\t\tselectFirst = arg;\n\t\t}\n\n\t\tif (selectFirst && typeof this.focusedItem === 'undefined') {\n\t\t\tconst firstEnabled = this.viewItems.findIndex(item => item.isEnabled());\n\t\t\t// Focus the first enabled item\n\t\t\tthis.focusedItem = firstEnabled === -1 ? undefined : firstEnabled;\n\t\t\tthis.updateFocus(undefined, undefined, true);\n\t\t} else {\n\t\t\tif (index !== undefined) {\n\t\t\t\tthis.focusedItem = index;\n\t\t\t}\n\n\t\t\tthis.updateFocus(undefined, undefined, true);\n\t\t}\n\t}\n\n\tprivate focusFirst(): boolean {\n\t\tthis.focusedItem = this.length() - 1;\n\t\treturn this.focusNext(true);\n\t}\n\n\tprivate focusLast(): boolean {\n\t\tthis.focusedItem = 0;\n\t\treturn this.focusPrevious(true);\n\t}\n\n\tprotected focusNext(forceLoop?: boolean): boolean {\n\t\tif (typeof this.focusedItem === 'undefined') {\n\t\t\tthis.focusedItem = this.viewItems.length - 1;\n\t\t} else if (this.viewItems.length <= 1) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst startIndex = this.focusedItem;\n\t\tlet item: IActionViewItem;\n\t\tdo {\n\n\t\t\tif (!forceLoop && this.options.preventLoopNavigation && this.focusedItem + 1 >= this.viewItems.length) {\n\t\t\t\tthis.focusedItem = startIndex;\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tthis.focusedItem = (this.focusedItem + 1) % this.viewItems.length;\n\t\t\titem = this.viewItems[this.focusedItem];\n\t\t} while (this.focusedItem !== startIndex && ((this.options.focusOnlyEnabledItems && !item.isEnabled()) || item.action.id === Separator.ID));\n\n\t\tthis.updateFocus();\n\t\treturn true;\n\t}\n\n\tprotected focusPrevious(forceLoop?: boolean): boolean {\n\t\tif (typeof this.focusedItem === 'undefined') {\n\t\t\tthis.focusedItem = 0;\n\t\t} else if (this.viewItems.length <= 1) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst startIndex = this.focusedItem;\n\t\tlet item: IActionViewItem;\n\n\t\tdo {\n\t\t\tthis.focusedItem = this.focusedItem - 1;\n\t\t\tif (this.focusedItem < 0) {\n\t\t\t\tif (!forceLoop && this.options.preventLoopNavigation) {\n\t\t\t\t\tthis.focusedItem = startIndex;\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tthis.focusedItem = this.viewItems.length - 1;\n\t\t\t}\n\t\t\titem = this.viewItems[this.focusedItem];\n\t\t} while (this.focusedItem !== startIndex && ((this.options.focusOnlyEnabledItems && !item.isEnabled()) || item.action.id === Separator.ID));\n\n\n\t\tthis.updateFocus(true);\n\t\treturn true;\n\t}\n\n\tprotected updateFocus(fromRight?: boolean, preventScroll?: boolean, forceFocus: boolean = false): void {\n\t\tif (typeof this.focusedItem === 'undefined') {\n\t\t\tthis.actionsList.focus({ preventScroll });\n\t\t}\n\n\t\tif (this.previouslyFocusedItem !== undefined && this.previouslyFocusedItem !== this.focusedItem) {\n\t\t\tthis.viewItems[this.previouslyFocusedItem]?.blur();\n\t\t}\n\t\tconst actionViewItem = this.focusedItem !== undefined ? this.viewItems[this.focusedItem] : undefined;\n\t\tif (actionViewItem) {\n\t\t\tlet focusItem = true;\n\n\t\t\tif (!types.isFunction(actionViewItem.focus)) {\n\t\t\t\tfocusItem = false;\n\t\t\t}\n\n\t\t\tif (this.options.focusOnlyEnabledItems && types.isFunction(actionViewItem.isEnabled) && !actionViewItem.isEnabled()) {\n\t\t\t\tfocusItem = false;\n\t\t\t}\n\n\t\t\tif (actionViewItem.action.id === Separator.ID) {\n\t\t\t\tfocusItem = false;\n\t\t\t}\n\t\t\tif (!focusItem) {\n\t\t\t\tthis.actionsList.focus({ preventScroll });\n\t\t\t\tthis.previouslyFocusedItem = undefined;\n\t\t\t} else if (forceFocus || this.previouslyFocusedItem !== this.focusedItem) {\n\t\t\t\tactionViewItem.focus(fromRight);\n\t\t\t\tthis.previouslyFocusedItem = this.focusedItem;\n\t\t\t}\n\t\t\tif (focusItem) {\n\t\t\t\tactionViewItem.showHover?.();\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate doTrigger(event: StandardKeyboardEvent): void {\n\t\tif (typeof this.focusedItem === 'undefined') {\n\t\t\treturn; //nothing to focus\n\t\t}\n\n\t\t// trigger action\n\t\tconst actionViewItem = this.viewItems[this.focusedItem];\n\t\tif (actionViewItem instanceof BaseActionViewItem) {\n\t\t\tconst context = (actionViewItem._context === null || actionViewItem._context === undefined) ? event : actionViewItem._context;\n\t\t\tthis.run(actionViewItem._action, context);\n\t\t}\n\t}\n\n\tasync run(action: IAction, context?: unknown): Promise {\n\t\tawait this._actionRunner.run(action, context);\n\t}\n\n\toverride dispose(): void {\n\t\tthis._context = undefined;\n\t\tthis.viewItems = dispose(this.viewItems);\n\t\tthis.getContainer().remove();\n\t\tsuper.dispose();\n\t}\n}\n","\nimport { IContextMenuProvider } from 'vs/base/browser/contextmenu';\nimport { $, append } from 'vs/base/browser/dom';\nimport { IActionViewItemProvider } from 'vs/base/browser/ui/actionbar/actionbar';\nimport { BaseActionViewItem, IBaseActionViewItemOptions } from 'vs/base/browser/ui/actionbar/actionViewItems';\nimport { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview';\nimport { DropdownMenu, IActionProvider, IDropdownMenuOptions, ILabelRenderer } from 'vs/base/browser/ui/dropdown/dropdown';\nimport { IAction, IActionRunner } from 'vs/base/common/actions';\nimport { Emitter } from 'vs/base/common/event';\nimport { ResolvedKeybinding } from 'vs/base/common/keybindings';\nimport { IDisposable } from 'vs/base/common/lifecycle';\nimport 'vs/css!./dropdown';\nimport { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegateFactory';\nimport { getBaseLayerHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate2';\n\nexport interface IKeybindingProvider {\n\t(action: IAction): ResolvedKeybinding | undefined;\n}\n\nexport interface IAnchorAlignmentProvider {\n\t(): AnchorAlignment;\n}\n\nexport interface IDropdownMenuActionViewItemOptions extends IBaseActionViewItemOptions {\n\treadonly actionViewItemProvider?: IActionViewItemProvider;\n\treadonly keybindingProvider?: IKeybindingProvider;\n\treadonly actionRunner?: IActionRunner;\n\treadonly classNames?: string[] | string;\n\treadonly anchorAlignmentProvider?: IAnchorAlignmentProvider;\n\treadonly menuAsChild?: boolean;\n\treadonly skipTelemetry?: boolean;\n}\n\nexport class DropdownMenuActionViewItem extends BaseActionViewItem {\n\tprivate menuActionsOrProvider: readonly IAction[] | IActionProvider;\n\tprivate dropdownMenu: DropdownMenu | undefined;\n\tprivate contextMenuProvider: IContextMenuProvider;\n\tprivate actionItem: HTMLElement | null = null;\n\n\tprivate _onDidChangeVisibility = this._register(new Emitter());\n\treadonly onDidChangeVisibility = this._onDidChangeVisibility.event;\n\n\tprotected override readonly options: IDropdownMenuActionViewItemOptions;\n\n\tconstructor(\n\t\taction: IAction,\n\t\tmenuActionsOrProvider: readonly IAction[] | IActionProvider,\n\t\tcontextMenuProvider: IContextMenuProvider,\n\t\toptions: IDropdownMenuActionViewItemOptions = Object.create(null)\n\t) {\n\t\tsuper(null, action, options);\n\n\t\tthis.menuActionsOrProvider = menuActionsOrProvider;\n\t\tthis.contextMenuProvider = contextMenuProvider;\n\t\tthis.options = options;\n\n\t\tif (this.options.actionRunner) {\n\t\t\tthis.actionRunner = this.options.actionRunner;\n\t\t}\n\t}\n\n\toverride render(container: HTMLElement): void {\n\t\tthis.actionItem = container;\n\n\t\tconst labelRenderer: ILabelRenderer = (el: HTMLElement): IDisposable | null => {\n\t\t\tthis.element = append(el, $('a.action-label'));\n\n\t\t\tlet classNames: string[] = [];\n\n\t\t\tif (typeof this.options.classNames === 'string') {\n\t\t\t\tclassNames = this.options.classNames.split(/\\s+/g).filter(s => !!s);\n\t\t\t} else if (this.options.classNames) {\n\t\t\t\tclassNames = this.options.classNames;\n\t\t\t}\n\n\t\t\t// todo@aeschli: remove codicon, should come through `this.options.classNames`\n\t\t\tif (!classNames.find(c => c === 'icon')) {\n\t\t\t\tclassNames.push('codicon');\n\t\t\t}\n\n\t\t\tthis.element.classList.add(...classNames);\n\n\t\t\tthis.element.setAttribute('role', 'button');\n\t\t\tthis.element.setAttribute('aria-haspopup', 'true');\n\t\t\tthis.element.setAttribute('aria-expanded', 'false');\n\t\t\tif (this._action.label) {\n\t\t\t\tthis._register(getBaseLayerHoverDelegate().setupUpdatableHover(this.options.hoverDelegate ?? getDefaultHoverDelegate('mouse'), this.element, this._action.label));\n\t\t\t}\n\t\t\tthis.element.ariaLabel = this._action.label || '';\n\n\t\t\treturn null;\n\t\t};\n\n\t\tconst isActionsArray = Array.isArray(this.menuActionsOrProvider);\n\t\tconst options: IDropdownMenuOptions = {\n\t\t\tcontextMenuProvider: this.contextMenuProvider,\n\t\t\tlabelRenderer: labelRenderer,\n\t\t\tmenuAsChild: this.options.menuAsChild,\n\t\t\tactions: isActionsArray ? this.menuActionsOrProvider as IAction[] : undefined,\n\t\t\tactionProvider: isActionsArray ? undefined : this.menuActionsOrProvider as IActionProvider,\n\t\t\tskipTelemetry: this.options.skipTelemetry\n\t\t};\n\n\t\tthis.dropdownMenu = this._register(new DropdownMenu(container, options));\n\t\tthis._register(this.dropdownMenu.onDidChangeVisibility(visible => {\n\t\t\tthis.element?.setAttribute('aria-expanded', `${visible}`);\n\t\t\tthis._onDidChangeVisibility.fire(visible);\n\t\t}));\n\n\t\tthis.dropdownMenu.menuOptions = {\n\t\t\tactionViewItemProvider: this.options.actionViewItemProvider,\n\t\t\tactionRunner: this.actionRunner,\n\t\t\tgetKeyBinding: this.options.keybindingProvider,\n\t\t\tcontext: this._context\n\t\t};\n\n\t\tif (this.options.anchorAlignmentProvider) {\n\t\t\tconst that = this;\n\n\t\t\tthis.dropdownMenu.menuOptions = {\n\t\t\t\t...this.dropdownMenu.menuOptions,\n\t\t\t\tget anchorAlignment(): AnchorAlignment {\n\t\t\t\t\treturn that.options.anchorAlignmentProvider!();\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t\tthis.updateTooltip();\n\t\tthis.updateEnabled();\n\t}\n\n\tprotected override getTooltip(): string | undefined {\n\t\tlet title: string | null = null;\n\n\t\tif (this.action.tooltip) {\n\t\t\ttitle = this.action.tooltip;\n\t\t} else if (this.action.label) {\n\t\t\ttitle = this.action.label;\n\t\t}\n\n\t\treturn title ?? undefined;\n\t}\n\n\toverride setActionContext(newContext: unknown): void {\n\t\tsuper.setActionContext(newContext);\n\n\t\tif (this.dropdownMenu) {\n\t\t\tif (this.dropdownMenu.menuOptions) {\n\t\t\t\tthis.dropdownMenu.menuOptions.context = newContext;\n\t\t\t} else {\n\t\t\t\tthis.dropdownMenu.menuOptions = { context: newContext };\n\t\t\t}\n\t\t}\n\t}\n\n\tshow(): void {\n\t\tthis.dropdownMenu?.show();\n\t}\n\n\tprotected override updateEnabled(): void {\n\t\tconst disabled = !this.action.enabled;\n\t\tthis.actionItem?.classList.toggle('disabled', disabled);\n\t\tthis.element?.classList.toggle('disabled', disabled);\n\t}\n}\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\nimport * as dom from 'vs/base/browser/dom';\nimport { DomEmitter } from 'vs/base/browser/event';\nimport { renderFormattedText, renderText } from 'vs/base/browser/formattedTextRenderer';\nimport { IHistoryNavigationWidget } from 'vs/base/browser/history';\nimport { MarkdownRenderOptions } from 'vs/base/browser/markdownRenderer';\nimport { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';\nimport * as aria from 'vs/base/browser/ui/aria/aria';\nimport { AnchorAlignment, IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview';\nimport { IUpdatableHover } from 'vs/base/browser/ui/hover/hover';\nimport { getBaseLayerHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate2';\nimport { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegateFactory';\nimport { ScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';\nimport { Widget } from 'vs/base/browser/ui/widget';\nimport { IAction } from 'vs/base/common/actions';\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { HistoryNavigator } from 'vs/base/common/history';\nimport { equals } from 'vs/base/common/objects';\nimport { ScrollbarVisibility } from 'vs/base/common/scrollable';\nimport 'vs/css!./inputBox';\nimport * as nls from 'vs/nls';\n\n\nconst $ = dom.$;\n\nexport interface IInputOptions {\n\treadonly placeholder?: string;\n\treadonly showPlaceholderOnFocus?: boolean;\n\treadonly tooltip?: string;\n\treadonly ariaLabel?: string;\n\treadonly type?: string;\n\treadonly validationOptions?: IInputValidationOptions;\n\treadonly flexibleHeight?: boolean;\n\treadonly flexibleWidth?: boolean;\n\treadonly flexibleMaxHeight?: number;\n\treadonly actions?: ReadonlyArray;\n\treadonly inputBoxStyles: IInputBoxStyles;\n}\n\nexport interface IInputBoxStyles {\n\treadonly inputBackground: string | undefined;\n\treadonly inputForeground: string | undefined;\n\treadonly inputBorder: string | undefined;\n\treadonly inputValidationInfoBorder: string | undefined;\n\treadonly inputValidationInfoBackground: string | undefined;\n\treadonly inputValidationInfoForeground: string | undefined;\n\treadonly inputValidationWarningBorder: string | undefined;\n\treadonly inputValidationWarningBackground: string | undefined;\n\treadonly inputValidationWarningForeground: string | undefined;\n\treadonly inputValidationErrorBorder: string | undefined;\n\treadonly inputValidationErrorBackground: string | undefined;\n\treadonly inputValidationErrorForeground: string | undefined;\n}\n\nexport interface IInputValidator {\n\t(value: string): IMessage | null;\n}\n\nexport interface IMessage {\n\treadonly content?: string;\n\treadonly formatContent?: boolean; // defaults to false\n\treadonly type?: MessageType;\n}\n\nexport interface IInputValidationOptions {\n\tvalidation?: IInputValidator;\n}\n\nexport const enum MessageType {\n\tINFO = 1,\n\tWARNING = 2,\n\tERROR = 3\n}\n\nexport interface IRange {\n\tstart: number;\n\tend: number;\n}\n\nexport const unthemedInboxStyles: IInputBoxStyles = {\n\tinputBackground: '#3C3C3C',\n\tinputForeground: '#CCCCCC',\n\tinputValidationInfoBorder: '#55AAFF',\n\tinputValidationInfoBackground: '#063B49',\n\tinputValidationWarningBorder: '#B89500',\n\tinputValidationWarningBackground: '#352A05',\n\tinputValidationErrorBorder: '#BE1100',\n\tinputValidationErrorBackground: '#5A1D1D',\n\tinputBorder: undefined,\n\tinputValidationErrorForeground: undefined,\n\tinputValidationInfoForeground: undefined,\n\tinputValidationWarningForeground: undefined\n};\n\nexport class InputBox extends Widget {\n\tprivate contextViewProvider?: IContextViewProvider;\n\telement: HTMLElement;\n\tprotected input: HTMLInputElement;\n\tprivate actionbar?: ActionBar;\n\tprivate readonly options: IInputOptions;\n\tprivate message: IMessage | null;\n\tprotected placeholder: string;\n\tprivate tooltip: string;\n\tprivate ariaLabel: string;\n\tprivate validation?: IInputValidator;\n\tprivate state: 'idle' | 'open' | 'closed' = 'idle';\n\n\tprivate mirror: HTMLElement | undefined;\n\tprivate cachedHeight: number | undefined;\n\tprivate cachedContentHeight: number | undefined;\n\tprivate maxHeight: number = Number.POSITIVE_INFINITY;\n\tprivate scrollableElement: ScrollableElement | undefined;\n\tprivate hover: IUpdatableHover | undefined;\n\n\tprivate _onDidChange = this._register(new Emitter());\n\tpublic readonly onDidChange: Event = this._onDidChange.event;\n\n\tprivate _onDidHeightChange = this._register(new Emitter());\n\tpublic readonly onDidHeightChange: Event = this._onDidHeightChange.event;\n\n\tconstructor(container: HTMLElement, contextViewProvider: IContextViewProvider | undefined, options: IInputOptions) {\n\t\tsuper();\n\n\t\tthis.contextViewProvider = contextViewProvider;\n\t\tthis.options = options;\n\n\t\tthis.message = null;\n\t\tthis.placeholder = this.options.placeholder || '';\n\t\tthis.tooltip = this.options.tooltip ?? (this.placeholder || '');\n\t\tthis.ariaLabel = this.options.ariaLabel || '';\n\n\t\tif (this.options.validationOptions) {\n\t\t\tthis.validation = this.options.validationOptions.validation;\n\t\t}\n\n\t\tthis.element = dom.append(container, $('.monaco-inputbox.idle'));\n\n\t\tconst tagName = this.options.flexibleHeight ? 'textarea' : 'input';\n\n\t\tconst wrapper = dom.append(this.element, $('.ibwrapper'));\n\t\tthis.input = dom.append(wrapper, $(tagName + '.input.empty'));\n\t\tthis.input.setAttribute('autocorrect', 'off');\n\t\tthis.input.setAttribute('autocapitalize', 'off');\n\t\tthis.input.setAttribute('spellcheck', 'false');\n\n\t\tthis.onfocus(this.input, () => this.element.classList.add('synthetic-focus'));\n\t\tthis.onblur(this.input, () => this.element.classList.remove('synthetic-focus'));\n\n\t\tif (this.options.flexibleHeight) {\n\t\t\tthis.maxHeight = typeof this.options.flexibleMaxHeight === 'number' ? this.options.flexibleMaxHeight : Number.POSITIVE_INFINITY;\n\n\t\t\tthis.mirror = dom.append(wrapper, $('div.mirror'));\n\t\t\tthis.mirror.innerText = '\\u00a0';\n\n\t\t\tthis.scrollableElement = new ScrollableElement(this.element, { vertical: ScrollbarVisibility.Auto });\n\n\t\t\tif (this.options.flexibleWidth) {\n\t\t\t\tthis.input.setAttribute('wrap', 'off');\n\t\t\t\tthis.mirror.style.whiteSpace = 'pre';\n\t\t\t\tthis.mirror.style.wordWrap = 'initial';\n\t\t\t}\n\n\t\t\tdom.append(container, this.scrollableElement.getDomNode());\n\t\t\tthis._register(this.scrollableElement);\n\n\t\t\t// from ScrollableElement to DOM\n\t\t\tthis._register(this.scrollableElement.onScroll(e => this.input.scrollTop = e.scrollTop));\n\n\t\t\tconst onSelectionChange = this._register(new DomEmitter(container.ownerDocument, 'selectionchange'));\n\t\t\tconst onAnchoredSelectionChange = Event.filter(onSelectionChange.event, () => {\n\t\t\t\tconst selection = container.ownerDocument.getSelection();\n\t\t\t\treturn selection?.anchorNode === wrapper;\n\t\t\t});\n\n\t\t\t// from DOM to ScrollableElement\n\t\t\tthis._register(onAnchoredSelectionChange(this.updateScrollDimensions, this));\n\t\t\tthis._register(this.onDidHeightChange(this.updateScrollDimensions, this));\n\t\t} else {\n\t\t\tthis.input.type = this.options.type || 'text';\n\t\t\tthis.input.setAttribute('wrap', 'off');\n\t\t}\n\n\t\tif (this.ariaLabel) {\n\t\t\tthis.input.setAttribute('aria-label', this.ariaLabel);\n\t\t}\n\n\t\tif (this.placeholder && !this.options.showPlaceholderOnFocus) {\n\t\t\tthis.setPlaceHolder(this.placeholder);\n\t\t}\n\n\t\tif (this.tooltip) {\n\t\t\tthis.setTooltip(this.tooltip);\n\t\t}\n\n\t\tthis.oninput(this.input, () => this.onValueChange());\n\t\tthis.onblur(this.input, () => this.onBlur());\n\t\tthis.onfocus(this.input, () => this.onFocus());\n\n\t\tthis._register(this.ignoreGesture(this.input));\n\n\t\tsetTimeout(() => this.updateMirror(), 0);\n\n\t\t// Support actions\n\t\tif (this.options.actions) {\n\t\t\tthis.actionbar = this._register(new ActionBar(this.element));\n\t\t\tthis.actionbar.push(this.options.actions, { icon: true, label: false });\n\t\t}\n\n\t\tthis.applyStyles();\n\t}\n\n\tprotected onBlur(): void {\n\t\tthis._hideMessage();\n\t\tif (this.options.showPlaceholderOnFocus) {\n\t\t\tthis.input.setAttribute('placeholder', '');\n\t\t}\n\t}\n\n\tprotected onFocus(): void {\n\t\tthis._showMessage();\n\t\tif (this.options.showPlaceholderOnFocus) {\n\t\t\tthis.input.setAttribute('placeholder', this.placeholder || '');\n\t\t}\n\t}\n\n\tpublic setPlaceHolder(placeHolder: string): void {\n\t\tthis.placeholder = placeHolder;\n\t\tthis.input.setAttribute('placeholder', placeHolder);\n\t}\n\n\tpublic setTooltip(tooltip: string): void {\n\t\tthis.tooltip = tooltip;\n\t\tif (!this.hover) {\n\t\t\tthis.hover = this._register(getBaseLayerHoverDelegate().setupUpdatableHover(getDefaultHoverDelegate('mouse'), this.input, tooltip));\n\t\t} else {\n\t\t\tthis.hover.update(tooltip);\n\t\t}\n\t}\n\n\tpublic get inputElement(): HTMLInputElement {\n\t\treturn this.input;\n\t}\n\n\tpublic get value(): string {\n\t\treturn this.input.value;\n\t}\n\n\tpublic set value(newValue: string) {\n\t\tif (this.input.value !== newValue) {\n\t\t\tthis.input.value = newValue;\n\t\t\tthis.onValueChange();\n\t\t}\n\t}\n\n\tpublic get height(): number {\n\t\treturn typeof this.cachedHeight === 'number' ? this.cachedHeight : dom.getTotalHeight(this.element);\n\t}\n\n\tpublic focus(): void {\n\t\tthis.input.focus();\n\t}\n\n\tpublic blur(): void {\n\t\tthis.input.blur();\n\t}\n\n\tpublic hasFocus(): boolean {\n\t\treturn dom.isActiveElement(this.input);\n\t}\n\n\tpublic select(range: IRange | null = null): void {\n\t\tthis.input.select();\n\n\t\tif (range) {\n\t\t\tthis.input.setSelectionRange(range.start, range.end);\n\t\t\tif (range.end === this.input.value.length) {\n\t\t\t\tthis.input.scrollLeft = this.input.scrollWidth;\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic isSelectionAtEnd(): boolean {\n\t\treturn this.input.selectionEnd === this.input.value.length && this.input.selectionStart === this.input.selectionEnd;\n\t}\n\n\tpublic getSelection(): IRange | null {\n\t\tconst selectionStart = this.input.selectionStart;\n\t\tif (selectionStart === null) {\n\t\t\treturn null;\n\t\t}\n\t\tconst selectionEnd = this.input.selectionEnd ?? selectionStart;\n\t\treturn {\n\t\t\tstart: selectionStart,\n\t\t\tend: selectionEnd,\n\t\t};\n\t}\n\n\tpublic enable(): void {\n\t\tthis.input.removeAttribute('disabled');\n\t}\n\n\tpublic disable(): void {\n\t\tthis.blur();\n\t\tthis.input.disabled = true;\n\t\tthis._hideMessage();\n\t}\n\n\tpublic set paddingRight(paddingRight: number) {\n\t\t// Set width to avoid hint text overlapping buttons\n\t\tthis.input.style.width = `calc(100% - ${paddingRight}px)`;\n\n\t\tif (this.mirror) {\n\t\t\tthis.mirror.style.paddingRight = paddingRight + 'px';\n\t\t}\n\t}\n\n\tprivate updateScrollDimensions(): void {\n\t\tif (typeof this.cachedContentHeight !== 'number' || typeof this.cachedHeight !== 'number' || !this.scrollableElement) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst scrollHeight = this.cachedContentHeight;\n\t\tconst height = this.cachedHeight;\n\t\tconst scrollTop = this.input.scrollTop;\n\n\t\tthis.scrollableElement.setScrollDimensions({ scrollHeight, height });\n\t\tthis.scrollableElement.setScrollPosition({ scrollTop });\n\t}\n\n\tpublic showMessage(message: IMessage, force?: boolean): void {\n\t\tif (this.state === 'open' && equals(this.message, message)) {\n\t\t\t// Already showing\n\t\t\treturn;\n\t\t}\n\n\t\tthis.message = message;\n\n\t\tthis.element.classList.remove('idle');\n\t\tthis.element.classList.remove('info');\n\t\tthis.element.classList.remove('warning');\n\t\tthis.element.classList.remove('error');\n\t\tthis.element.classList.add(this.classForType(message.type));\n\n\t\tconst styles = this.stylesForType(this.message.type);\n\t\tthis.element.style.border = `1px solid ${dom.asCssValueWithDefault(styles.border, 'transparent')}`;\n\n\t\tif (this.message.content && (this.hasFocus() || force)) {\n\t\t\tthis._showMessage();\n\t\t}\n\t}\n\n\tpublic hideMessage(): void {\n\t\tthis.message = null;\n\n\t\tthis.element.classList.remove('info');\n\t\tthis.element.classList.remove('warning');\n\t\tthis.element.classList.remove('error');\n\t\tthis.element.classList.add('idle');\n\n\t\tthis._hideMessage();\n\t\tthis.applyStyles();\n\t}\n\n\tpublic validate(): MessageType | undefined {\n\t\tlet errorMsg: IMessage | null = null;\n\n\t\tif (this.validation) {\n\t\t\terrorMsg = this.validation(this.value);\n\n\t\t\tif (errorMsg) {\n\t\t\t\tthis.inputElement.setAttribute('aria-invalid', 'true');\n\t\t\t\tthis.showMessage(errorMsg);\n\t\t\t}\n\t\t\telse if (this.inputElement.hasAttribute('aria-invalid')) {\n\t\t\t\tthis.inputElement.removeAttribute('aria-invalid');\n\t\t\t\tthis.hideMessage();\n\t\t\t}\n\t\t}\n\n\t\treturn errorMsg?.type;\n\t}\n\n\tpublic stylesForType(type: MessageType | undefined): { border: string | undefined; background: string | undefined; foreground: string | undefined } {\n\t\tconst styles = this.options.inputBoxStyles;\n\t\tswitch (type) {\n\t\t\tcase MessageType.INFO: return { border: styles.inputValidationInfoBorder, background: styles.inputValidationInfoBackground, foreground: styles.inputValidationInfoForeground };\n\t\t\tcase MessageType.WARNING: return { border: styles.inputValidationWarningBorder, background: styles.inputValidationWarningBackground, foreground: styles.inputValidationWarningForeground };\n\t\t\tdefault: return { border: styles.inputValidationErrorBorder, background: styles.inputValidationErrorBackground, foreground: styles.inputValidationErrorForeground };\n\t\t}\n\t}\n\n\tprivate classForType(type: MessageType | undefined): string {\n\t\tswitch (type) {\n\t\t\tcase MessageType.INFO: return 'info';\n\t\t\tcase MessageType.WARNING: return 'warning';\n\t\t\tdefault: return 'error';\n\t\t}\n\t}\n\n\tprivate _showMessage(): void {\n\t\tif (!this.contextViewProvider || !this.message) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet div: HTMLElement;\n\t\tconst layout = () => div.style.width = dom.getTotalWidth(this.element) + 'px';\n\n\t\tthis.contextViewProvider.showContextView({\n\t\t\tgetAnchor: () => this.element,\n\t\t\tanchorAlignment: AnchorAlignment.RIGHT,\n\t\t\trender: (container: HTMLElement) => {\n\t\t\t\tif (!this.message) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\tdiv = dom.append(container, $('.monaco-inputbox-container'));\n\t\t\t\tlayout();\n\n\t\t\t\tconst renderOptions: MarkdownRenderOptions = {\n\t\t\t\t\tinline: true,\n\t\t\t\t\tclassName: 'monaco-inputbox-message'\n\t\t\t\t};\n\n\t\t\t\tconst spanElement = (this.message.formatContent\n\t\t\t\t\t? renderFormattedText(this.message.content!, renderOptions)\n\t\t\t\t\t: renderText(this.message.content!, renderOptions));\n\t\t\t\tspanElement.classList.add(this.classForType(this.message.type));\n\n\t\t\t\tconst styles = this.stylesForType(this.message.type);\n\t\t\t\tspanElement.style.backgroundColor = styles.background ?? '';\n\t\t\t\tspanElement.style.color = styles.foreground ?? '';\n\t\t\t\tspanElement.style.border = styles.border ? `1px solid ${styles.border}` : '';\n\n\t\t\t\tdom.append(div, spanElement);\n\n\t\t\t\treturn null;\n\t\t\t},\n\t\t\tonHide: () => {\n\t\t\t\tthis.state = 'closed';\n\t\t\t},\n\t\t\tlayout: layout\n\t\t});\n\n\t\t// ARIA Support\n\t\tlet alertText: string;\n\t\tif (this.message.type === MessageType.ERROR) {\n\t\t\talertText = nls.localize('alertErrorMessage', \"Error: {0}\", this.message.content);\n\t\t} else if (this.message.type === MessageType.WARNING) {\n\t\t\talertText = nls.localize('alertWarningMessage', \"Warning: {0}\", this.message.content);\n\t\t} else {\n\t\t\talertText = nls.localize('alertInfoMessage', \"Info: {0}\", this.message.content);\n\t\t}\n\n\t\taria.alert(alertText);\n\n\t\tthis.state = 'open';\n\t}\n\n\tprivate _hideMessage(): void {\n\t\tif (!this.contextViewProvider) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.state === 'open') {\n\t\t\tthis.contextViewProvider.hideContextView();\n\t\t}\n\n\t\tthis.state = 'idle';\n\t}\n\n\tprivate onValueChange(): void {\n\t\tthis._onDidChange.fire(this.value);\n\n\t\tthis.validate();\n\t\tthis.updateMirror();\n\t\tthis.input.classList.toggle('empty', !this.value);\n\n\t\tif (this.state === 'open' && this.contextViewProvider) {\n\t\t\tthis.contextViewProvider.layout();\n\t\t}\n\t}\n\n\tprivate updateMirror(): void {\n\t\tif (!this.mirror) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst value = this.value;\n\t\tconst lastCharCode = value.charCodeAt(value.length - 1);\n\t\tconst suffix = lastCharCode === 10 ? ' ' : '';\n\t\tconst mirrorTextContent = (value + suffix)\n\t\t\t.replace(/\\u000c/g, ''); // Don't measure with the form feed character, which messes up sizing\n\n\t\tif (mirrorTextContent) {\n\t\t\tthis.mirror.textContent = value + suffix;\n\t\t} else {\n\t\t\tthis.mirror.innerText = '\\u00a0';\n\t\t}\n\n\t\tthis.layout();\n\t}\n\n\tprotected applyStyles(): void {\n\t\tconst styles = this.options.inputBoxStyles;\n\n\t\tconst background = styles.inputBackground ?? '';\n\t\tconst foreground = styles.inputForeground ?? '';\n\t\tconst border = styles.inputBorder ?? '';\n\n\t\tthis.element.style.backgroundColor = background;\n\t\tthis.element.style.color = foreground;\n\t\tthis.input.style.backgroundColor = 'inherit';\n\t\tthis.input.style.color = foreground;\n\n\t\t// there's always a border, even if the color is not set.\n\t\tthis.element.style.border = `1px solid ${dom.asCssValueWithDefault(border, 'transparent')}`;\n\t}\n\n\tpublic layout(): void {\n\t\tif (!this.mirror) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst previousHeight = this.cachedContentHeight;\n\t\tthis.cachedContentHeight = dom.getTotalHeight(this.mirror);\n\n\t\tif (previousHeight !== this.cachedContentHeight) {\n\t\t\tthis.cachedHeight = Math.min(this.cachedContentHeight, this.maxHeight);\n\t\t\tthis.input.style.height = this.cachedHeight + 'px';\n\t\t\tthis._onDidHeightChange.fire(this.cachedContentHeight);\n\t\t}\n\t}\n\n\tpublic insertAtCursor(text: string): void {\n\t\tconst inputElement = this.inputElement;\n\t\tconst start = inputElement.selectionStart;\n\t\tconst end = inputElement.selectionEnd;\n\t\tconst content = inputElement.value;\n\n\t\tif (start !== null && end !== null) {\n\t\t\tthis.value = content.substr(0, start) + text + content.substr(end);\n\t\t\tinputElement.setSelectionRange(start + 1, start + 1);\n\t\t\tthis.layout();\n\t\t}\n\t}\n\n\tpublic override dispose(): void {\n\t\tthis._hideMessage();\n\n\t\tthis.message = null;\n\n\t\tthis.actionbar?.dispose();\n\n\t\tsuper.dispose();\n\t}\n}\n\nexport interface IHistoryInputOptions extends IInputOptions {\n\thistory: string[];\n\treadonly showHistoryHint?: () => boolean;\n}\n\nexport class HistoryInputBox extends InputBox implements IHistoryNavigationWidget {\n\n\tprivate readonly history: HistoryNavigator;\n\tprivate observer: MutationObserver | undefined;\n\n\tprivate readonly _onDidFocus = this._register(new Emitter());\n\treadonly onDidFocus = this._onDidFocus.event;\n\n\tprivate readonly _onDidBlur = this._register(new Emitter());\n\treadonly onDidBlur = this._onDidBlur.event;\n\n\tconstructor(container: HTMLElement, contextViewProvider: IContextViewProvider | undefined, options: IHistoryInputOptions) {\n\t\tconst NLS_PLACEHOLDER_HISTORY_HINT_SUFFIX_NO_PARENS = nls.localize({\n\t\t\tkey: 'history.inputbox.hint.suffix.noparens',\n\t\t\tcomment: ['Text is the suffix of an input field placeholder coming after the action the input field performs, this will be used when the input field ends in a closing parenthesis \")\", for example \"Filter (e.g. text, !exclude)\". The character inserted into the final string is \\u21C5 to represent the up and down arrow keys.']\n\t\t}, ' or {0} for history', `\\u21C5`);\n\t\tconst NLS_PLACEHOLDER_HISTORY_HINT_SUFFIX_IN_PARENS = nls.localize({\n\t\t\tkey: 'history.inputbox.hint.suffix.inparens',\n\t\t\tcomment: ['Text is the suffix of an input field placeholder coming after the action the input field performs, this will be used when the input field does NOT end in a closing parenthesis (eg. \"Find\"). The character inserted into the final string is \\u21C5 to represent the up and down arrow keys.']\n\t\t}, ' ({0} for history)', `\\u21C5`);\n\n\t\tsuper(container, contextViewProvider, options);\n\t\tthis.history = new HistoryNavigator(options.history, 100);\n\n\t\t// Function to append the history suffix to the placeholder if necessary\n\t\tconst addSuffix = () => {\n\t\t\tif (options.showHistoryHint && options.showHistoryHint() && !this.placeholder.endsWith(NLS_PLACEHOLDER_HISTORY_HINT_SUFFIX_NO_PARENS) && !this.placeholder.endsWith(NLS_PLACEHOLDER_HISTORY_HINT_SUFFIX_IN_PARENS) && this.history.getHistory().length) {\n\t\t\t\tconst suffix = this.placeholder.endsWith(')') ? NLS_PLACEHOLDER_HISTORY_HINT_SUFFIX_NO_PARENS : NLS_PLACEHOLDER_HISTORY_HINT_SUFFIX_IN_PARENS;\n\t\t\t\tconst suffixedPlaceholder = this.placeholder + suffix;\n\t\t\t\tif (options.showPlaceholderOnFocus && !dom.isActiveElement(this.input)) {\n\t\t\t\t\tthis.placeholder = suffixedPlaceholder;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tthis.setPlaceHolder(suffixedPlaceholder);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\t// Spot the change to the textarea class attribute which occurs when it changes between non-empty and empty,\n\t\t// and add the history suffix to the placeholder if not yet present\n\t\tthis.observer = new MutationObserver((mutationList: MutationRecord[], observer: MutationObserver) => {\n\t\t\tmutationList.forEach((mutation: MutationRecord) => {\n\t\t\t\tif (!mutation.target.textContent) {\n\t\t\t\t\taddSuffix();\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t\tthis.observer.observe(this.input, { attributeFilter: ['class'] });\n\n\t\tthis.onfocus(this.input, () => addSuffix());\n\t\tthis.onblur(this.input, () => {\n\t\t\tconst resetPlaceholder = (historyHint: string) => {\n\t\t\t\tif (!this.placeholder.endsWith(historyHint)) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tconst revertedPlaceholder = this.placeholder.slice(0, this.placeholder.length - historyHint.length);\n\t\t\t\t\tif (options.showPlaceholderOnFocus) {\n\t\t\t\t\t\tthis.placeholder = revertedPlaceholder;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tthis.setPlaceHolder(revertedPlaceholder);\n\t\t\t\t\t}\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t};\n\t\t\tif (!resetPlaceholder(NLS_PLACEHOLDER_HISTORY_HINT_SUFFIX_IN_PARENS)) {\n\t\t\t\tresetPlaceholder(NLS_PLACEHOLDER_HISTORY_HINT_SUFFIX_NO_PARENS);\n\t\t\t}\n\t\t});\n\t}\n\n\toverride dispose() {\n\t\tsuper.dispose();\n\t\tif (this.observer) {\n\t\t\tthis.observer.disconnect();\n\t\t\tthis.observer = undefined;\n\t\t}\n\t}\n\n\tpublic addToHistory(always?: boolean): void {\n\t\tif (this.value && (always || this.value !== this.getCurrentValue())) {\n\t\t\tthis.history.add(this.value);\n\t\t}\n\t}\n\n\tpublic isAtLastInHistory(): boolean {\n\t\treturn this.history.isLast();\n\t}\n\n\tpublic isNowhereInHistory(): boolean {\n\t\treturn this.history.isNowhere();\n\t}\n\n\tpublic showNextValue(): void {\n\t\tif (!this.history.has(this.value)) {\n\t\t\tthis.addToHistory();\n\t\t}\n\n\t\tlet next = this.getNextValue();\n\t\tif (next) {\n\t\t\tnext = next === this.value ? this.getNextValue() : next;\n\t\t}\n\n\t\tthis.value = next ?? '';\n\t\taria.status(this.value ? this.value : nls.localize('clearedInput', \"Cleared Input\"));\n\t}\n\n\tpublic showPreviousValue(): void {\n\t\tif (!this.history.has(this.value)) {\n\t\t\tthis.addToHistory();\n\t\t}\n\n\t\tlet previous = this.getPreviousValue();\n\t\tif (previous) {\n\t\t\tprevious = previous === this.value ? this.getPreviousValue() : previous;\n\t\t}\n\n\t\tif (previous) {\n\t\t\tthis.value = previous;\n\t\t\taria.status(this.value);\n\t\t}\n\t}\n\n\tpublic override setPlaceHolder(placeHolder: string): void {\n\t\tsuper.setPlaceHolder(placeHolder);\n\t\tthis.setTooltip(placeHolder);\n\t}\n\n\tprotected override onBlur(): void {\n\t\tsuper.onBlur();\n\t\tthis._onDidBlur.fire();\n\t}\n\n\tprotected override onFocus(): void {\n\t\tsuper.onFocus();\n\t\tthis._onDidFocus.fire();\n\t}\n\n\tprivate getCurrentValue(): string | null {\n\t\tlet currentValue = this.history.current();\n\t\tif (!currentValue) {\n\t\t\tcurrentValue = this.history.last();\n\t\t\tthis.history.next();\n\t\t}\n\t\treturn currentValue;\n\t}\n\n\tprivate getPreviousValue(): string | null {\n\t\treturn this.history.previous() || this.history.first();\n\t}\n\n\tprivate getNextValue(): string | null {\n\t\treturn this.history.next();\n\t}\n}\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\nimport * as dom from 'vs/base/browser/dom';\nimport { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';\nimport { IMouseEvent } from 'vs/base/browser/mouseEvent';\nimport { IToggleStyles, Toggle } from 'vs/base/browser/ui/toggle/toggle';\nimport { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview';\nimport { CaseSensitiveToggle, RegexToggle, WholeWordsToggle } from 'vs/base/browser/ui/findinput/findInputToggles';\nimport { HistoryInputBox, IInputBoxStyles, IInputValidator, IMessage as InputBoxMessage } from 'vs/base/browser/ui/inputbox/inputBox';\nimport { Widget } from 'vs/base/browser/ui/widget';\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { KeyCode } from 'vs/base/common/keyCodes';\nimport 'vs/css!./findInput';\nimport * as nls from 'vs/nls';\nimport { DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle';\nimport { createInstantHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegateFactory';\n\n\nexport interface IFindInputOptions {\n\treadonly placeholder?: string;\n\treadonly width?: number;\n\treadonly validation?: IInputValidator;\n\treadonly label: string;\n\treadonly flexibleHeight?: boolean;\n\treadonly flexibleWidth?: boolean;\n\treadonly flexibleMaxHeight?: number;\n\n\treadonly showCommonFindToggles?: boolean;\n\treadonly appendCaseSensitiveLabel?: string;\n\treadonly appendWholeWordsLabel?: string;\n\treadonly appendRegexLabel?: string;\n\treadonly history?: string[];\n\treadonly additionalToggles?: Toggle[];\n\treadonly showHistoryHint?: () => boolean;\n\treadonly toggleStyles: IToggleStyles;\n\treadonly inputBoxStyles: IInputBoxStyles;\n}\n\nconst NLS_DEFAULT_LABEL = nls.localize('defaultLabel', \"input\");\n\nexport class FindInput extends Widget {\n\n\tprivate placeholder: string;\n\tprivate validation?: IInputValidator;\n\tprivate label: string;\n\tprivate readonly showCommonFindToggles: boolean;\n\tprivate fixFocusOnOptionClickEnabled = true;\n\tprivate imeSessionInProgress = false;\n\tprivate readonly additionalTogglesDisposables: MutableDisposable = this._register(new MutableDisposable());\n\n\tprotected readonly controls: HTMLDivElement;\n\tprotected readonly regex?: RegexToggle;\n\tprotected readonly wholeWords?: WholeWordsToggle;\n\tprotected readonly caseSensitive?: CaseSensitiveToggle;\n\tprotected additionalToggles: Toggle[] = [];\n\tpublic readonly domNode: HTMLElement;\n\tpublic readonly inputBox: HistoryInputBox;\n\n\tprivate readonly _onDidOptionChange = this._register(new Emitter());\n\tpublic readonly onDidOptionChange: Event = this._onDidOptionChange.event;\n\n\tprivate readonly _onKeyDown = this._register(new Emitter());\n\tpublic readonly onKeyDown: Event = this._onKeyDown.event;\n\n\tprivate readonly _onMouseDown = this._register(new Emitter());\n\tpublic readonly onMouseDown: Event = this._onMouseDown.event;\n\n\tprivate readonly _onInput = this._register(new Emitter());\n\n\tprivate readonly _onKeyUp = this._register(new Emitter());\n\n\tprivate _onCaseSensitiveKeyDown = this._register(new Emitter());\n\tpublic readonly onCaseSensitiveKeyDown: Event = this._onCaseSensitiveKeyDown.event;\n\n\tprivate _onRegexKeyDown = this._register(new Emitter());\n\tpublic readonly onRegexKeyDown: Event = this._onRegexKeyDown.event;\n\n\tconstructor(parent: HTMLElement | null, contextViewProvider: IContextViewProvider | undefined, options: IFindInputOptions) {\n\t\tsuper();\n\t\tthis.placeholder = options.placeholder || '';\n\t\tthis.validation = options.validation;\n\t\tthis.label = options.label || NLS_DEFAULT_LABEL;\n\t\tthis.showCommonFindToggles = !!options.showCommonFindToggles;\n\n\t\tconst appendCaseSensitiveLabel = options.appendCaseSensitiveLabel || '';\n\t\tconst appendWholeWordsLabel = options.appendWholeWordsLabel || '';\n\t\tconst appendRegexLabel = options.appendRegexLabel || '';\n\t\tconst history = options.history || [];\n\t\tconst flexibleHeight = !!options.flexibleHeight;\n\t\tconst flexibleWidth = !!options.flexibleWidth;\n\t\tconst flexibleMaxHeight = options.flexibleMaxHeight;\n\n\t\tthis.domNode = document.createElement('div');\n\t\tthis.domNode.classList.add('monaco-findInput');\n\n\t\tthis.inputBox = this._register(new HistoryInputBox(this.domNode, contextViewProvider, {\n\t\t\tplaceholder: this.placeholder || '',\n\t\t\tariaLabel: this.label || '',\n\t\t\tvalidationOptions: {\n\t\t\t\tvalidation: this.validation\n\t\t\t},\n\t\t\thistory,\n\t\t\tshowHistoryHint: options.showHistoryHint,\n\t\t\tflexibleHeight,\n\t\t\tflexibleWidth,\n\t\t\tflexibleMaxHeight,\n\t\t\tinputBoxStyles: options.inputBoxStyles,\n\t\t}));\n\n\t\tconst hoverDelegate = this._register(createInstantHoverDelegate());\n\n\t\tif (this.showCommonFindToggles) {\n\t\t\tthis.regex = this._register(new RegexToggle({\n\t\t\t\tappendTitle: appendRegexLabel,\n\t\t\t\tisChecked: false,\n\t\t\t\thoverDelegate,\n\t\t\t\t...options.toggleStyles\n\t\t\t}));\n\t\t\tthis._register(this.regex.onChange(viaKeyboard => {\n\t\t\t\tthis._onDidOptionChange.fire(viaKeyboard);\n\t\t\t\tif (!viaKeyboard && this.fixFocusOnOptionClickEnabled) {\n\t\t\t\t\tthis.inputBox.focus();\n\t\t\t\t}\n\t\t\t\tthis.validate();\n\t\t\t}));\n\t\t\tthis._register(this.regex.onKeyDown(e => {\n\t\t\t\tthis._onRegexKeyDown.fire(e);\n\t\t\t}));\n\n\t\t\tthis.wholeWords = this._register(new WholeWordsToggle({\n\t\t\t\tappendTitle: appendWholeWordsLabel,\n\t\t\t\tisChecked: false,\n\t\t\t\thoverDelegate,\n\t\t\t\t...options.toggleStyles\n\t\t\t}));\n\t\t\tthis._register(this.wholeWords.onChange(viaKeyboard => {\n\t\t\t\tthis._onDidOptionChange.fire(viaKeyboard);\n\t\t\t\tif (!viaKeyboard && this.fixFocusOnOptionClickEnabled) {\n\t\t\t\t\tthis.inputBox.focus();\n\t\t\t\t}\n\t\t\t\tthis.validate();\n\t\t\t}));\n\n\t\t\tthis.caseSensitive = this._register(new CaseSensitiveToggle({\n\t\t\t\tappendTitle: appendCaseSensitiveLabel,\n\t\t\t\tisChecked: false,\n\t\t\t\thoverDelegate,\n\t\t\t\t...options.toggleStyles\n\t\t\t}));\n\t\t\tthis._register(this.caseSensitive.onChange(viaKeyboard => {\n\t\t\t\tthis._onDidOptionChange.fire(viaKeyboard);\n\t\t\t\tif (!viaKeyboard && this.fixFocusOnOptionClickEnabled) {\n\t\t\t\t\tthis.inputBox.focus();\n\t\t\t\t}\n\t\t\t\tthis.validate();\n\t\t\t}));\n\t\t\tthis._register(this.caseSensitive.onKeyDown(e => {\n\t\t\t\tthis._onCaseSensitiveKeyDown.fire(e);\n\t\t\t}));\n\n\t\t\t// Arrow-Key support to navigate between options\n\t\t\tconst indexes = [this.caseSensitive.domNode, this.wholeWords.domNode, this.regex.domNode];\n\t\t\tthis.onkeydown(this.domNode, (event: IKeyboardEvent) => {\n\t\t\t\tif (event.equals(KeyCode.LeftArrow) || event.equals(KeyCode.RightArrow) || event.equals(KeyCode.Escape)) {\n\t\t\t\t\tconst index = indexes.indexOf(this.domNode.ownerDocument.activeElement);\n\t\t\t\t\tif (index >= 0) {\n\t\t\t\t\t\tlet newIndex: number = -1;\n\t\t\t\t\t\tif (event.equals(KeyCode.RightArrow)) {\n\t\t\t\t\t\t\tnewIndex = (index + 1) % indexes.length;\n\t\t\t\t\t\t} else if (event.equals(KeyCode.LeftArrow)) {\n\t\t\t\t\t\t\tif (index === 0) {\n\t\t\t\t\t\t\t\tnewIndex = indexes.length - 1;\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tnewIndex = index - 1;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (event.equals(KeyCode.Escape)) {\n\t\t\t\t\t\t\tindexes[index].blur();\n\t\t\t\t\t\t\tthis.inputBox.focus();\n\t\t\t\t\t\t} else if (newIndex >= 0) {\n\t\t\t\t\t\t\tindexes[newIndex].focus();\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tdom.EventHelper.stop(event, true);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\tthis.controls = document.createElement('div');\n\t\tthis.controls.className = 'controls';\n\t\tthis.controls.style.display = this.showCommonFindToggles ? '' : 'none';\n\t\tif (this.caseSensitive) {\n\t\t\tthis.controls.append(this.caseSensitive.domNode);\n\t\t}\n\t\tif (this.wholeWords) {\n\t\t\tthis.controls.appendChild(this.wholeWords.domNode);\n\t\t}\n\t\tif (this.regex) {\n\t\t\tthis.controls.appendChild(this.regex.domNode);\n\t\t}\n\n\t\tthis.setAdditionalToggles(options?.additionalToggles);\n\n\t\tif (this.controls) {\n\t\t\tthis.domNode.appendChild(this.controls);\n\t\t}\n\n\t\tparent?.appendChild(this.domNode);\n\n\t\tthis._register(dom.addDisposableListener(this.inputBox.inputElement, 'compositionstart', (e: CompositionEvent) => {\n\t\t\tthis.imeSessionInProgress = true;\n\t\t}));\n\t\tthis._register(dom.addDisposableListener(this.inputBox.inputElement, 'compositionend', (e: CompositionEvent) => {\n\t\t\tthis.imeSessionInProgress = false;\n\t\t\tthis._onInput.fire();\n\t\t}));\n\n\t\tthis.onkeydown(this.inputBox.inputElement, (e) => this._onKeyDown.fire(e));\n\t\tthis.onkeyup(this.inputBox.inputElement, (e) => this._onKeyUp.fire(e));\n\t\tthis.oninput(this.inputBox.inputElement, (e) => this._onInput.fire());\n\t\tthis.onmousedown(this.inputBox.inputElement, (e) => this._onMouseDown.fire(e));\n\t}\n\n\tpublic get onDidChange(): Event {\n\t\treturn this.inputBox.onDidChange;\n\t}\n\n\tpublic layout(style: { collapsedFindWidget: boolean; narrowFindWidget: boolean; reducedFindWidget: boolean }) {\n\t\tthis.inputBox.layout();\n\t\tthis.updateInputBoxPadding(style.collapsedFindWidget);\n\t}\n\n\tpublic enable(): void {\n\t\tthis.domNode.classList.remove('disabled');\n\t\tthis.inputBox.enable();\n\t\tthis.regex?.enable();\n\t\tthis.wholeWords?.enable();\n\t\tthis.caseSensitive?.enable();\n\n\t\tfor (const toggle of this.additionalToggles) {\n\t\t\ttoggle.enable();\n\t\t}\n\t}\n\n\tpublic disable(): void {\n\t\tthis.domNode.classList.add('disabled');\n\t\tthis.inputBox.disable();\n\t\tthis.regex?.disable();\n\t\tthis.wholeWords?.disable();\n\t\tthis.caseSensitive?.disable();\n\n\t\tfor (const toggle of this.additionalToggles) {\n\t\t\ttoggle.disable();\n\t\t}\n\t}\n\n\tpublic setFocusInputOnOptionClick(value: boolean): void {\n\t\tthis.fixFocusOnOptionClickEnabled = value;\n\t}\n\n\tpublic setEnabled(enabled: boolean): void {\n\t\tif (enabled) {\n\t\t\tthis.enable();\n\t\t} else {\n\t\t\tthis.disable();\n\t\t}\n\t}\n\n\tpublic setAdditionalToggles(toggles: Toggle[] | undefined): void {\n\t\tfor (const currentToggle of this.additionalToggles) {\n\t\t\tcurrentToggle.domNode.remove();\n\t\t}\n\t\tthis.additionalToggles = [];\n\t\tthis.additionalTogglesDisposables.value = new DisposableStore();\n\n\t\tfor (const toggle of toggles ?? []) {\n\t\t\tthis.additionalTogglesDisposables.value.add(toggle);\n\t\t\tthis.controls.appendChild(toggle.domNode);\n\n\t\t\tthis.additionalTogglesDisposables.value.add(toggle.onChange(viaKeyboard => {\n\t\t\t\tthis._onDidOptionChange.fire(viaKeyboard);\n\t\t\t\tif (!viaKeyboard && this.fixFocusOnOptionClickEnabled) {\n\t\t\t\t\tthis.inputBox.focus();\n\t\t\t\t}\n\t\t\t}));\n\n\t\t\tthis.additionalToggles.push(toggle);\n\t\t}\n\n\t\tif (this.additionalToggles.length > 0) {\n\t\t\tthis.controls.style.display = '';\n\t\t}\n\n\t\tthis.updateInputBoxPadding();\n\t}\n\n\tprivate updateInputBoxPadding(controlsHidden = false) {\n\t\tif (controlsHidden) {\n\t\t\tthis.inputBox.paddingRight = 0;\n\t\t} else {\n\t\t\tthis.inputBox.paddingRight =\n\t\t\t\t((this.caseSensitive?.width() ?? 0) + (this.wholeWords?.width() ?? 0) + (this.regex?.width() ?? 0))\n\t\t\t\t+ this.additionalToggles.reduce((r, t) => r + t.width(), 0);\n\t\t}\n\t}\n\n\tpublic getValue(): string {\n\t\treturn this.inputBox.value;\n\t}\n\n\tpublic setValue(value: string): void {\n\t\tif (this.inputBox.value !== value) {\n\t\t\tthis.inputBox.value = value;\n\t\t}\n\t}\n\n\tpublic select(): void {\n\t\tthis.inputBox.select();\n\t}\n\n\tpublic focus(): void {\n\t\tthis.inputBox.focus();\n\t}\n\n\tpublic getCaseSensitive(): boolean {\n\t\treturn this.caseSensitive?.checked ?? false;\n\t}\n\n\tpublic setCaseSensitive(value: boolean): void {\n\t\tif (this.caseSensitive) {\n\t\t\tthis.caseSensitive.checked = value;\n\t\t}\n\t}\n\n\tpublic getWholeWords(): boolean {\n\t\treturn this.wholeWords?.checked ?? false;\n\t}\n\n\tpublic setWholeWords(value: boolean): void {\n\t\tif (this.wholeWords) {\n\t\t\tthis.wholeWords.checked = value;\n\t\t}\n\t}\n\n\tpublic getRegex(): boolean {\n\t\treturn this.regex?.checked ?? false;\n\t}\n\n\tpublic setRegex(value: boolean): void {\n\t\tif (this.regex) {\n\t\t\tthis.regex.checked = value;\n\t\t\tthis.validate();\n\t\t}\n\t}\n\n\tpublic focusOnCaseSensitive(): void {\n\t\tthis.caseSensitive?.focus();\n\t}\n\n\tprivate _lastHighlightFindOptions: number = 0;\n\tpublic highlightFindOptions(): void {\n\t\tthis.domNode.classList.remove('highlight-' + (this._lastHighlightFindOptions));\n\t\tthis._lastHighlightFindOptions = 1 - this._lastHighlightFindOptions;\n\t\tthis.domNode.classList.add('highlight-' + (this._lastHighlightFindOptions));\n\t}\n\n\tpublic validate(): void {\n\t\tthis.inputBox.validate();\n\t}\n\n\tpublic showMessage(message: InputBoxMessage): void {\n\t\tthis.inputBox.showMessage(message);\n\t}\n\n\tpublic clearMessage(): void {\n\t\tthis.inputBox.hideMessage();\n\t}\n}\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\nimport * as dom from 'vs/base/browser/dom';\nimport { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';\nimport { IMouseEvent } from 'vs/base/browser/mouseEvent';\nimport { IToggleStyles, Toggle } from 'vs/base/browser/ui/toggle/toggle';\nimport { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview';\nimport { IFindInputToggleOpts } from 'vs/base/browser/ui/findinput/findInputToggles';\nimport { HistoryInputBox, IInputBoxStyles, IInputValidator } from 'vs/base/browser/ui/inputbox/inputBox';\nimport { Widget } from 'vs/base/browser/ui/widget';\nimport { Codicon } from 'vs/base/common/codicons';\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { KeyCode } from 'vs/base/common/keyCodes';\nimport 'vs/css!./findInput';\nimport * as nls from 'vs/nls';\nimport { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegateFactory';\n\n\nexport interface IReplaceInputOptions {\n\treadonly placeholder?: string;\n\treadonly validation?: IInputValidator;\n\treadonly label: string;\n\treadonly flexibleHeight?: boolean;\n\treadonly flexibleWidth?: boolean;\n\treadonly flexibleMaxHeight?: number;\n\n\treadonly appendPreserveCaseLabel?: string;\n\treadonly history?: string[];\n\treadonly showHistoryHint?: () => boolean;\n\treadonly inputBoxStyles: IInputBoxStyles;\n\treadonly toggleStyles: IToggleStyles;\n}\n\nconst NLS_DEFAULT_LABEL = nls.localize('defaultLabel', \"input\");\nconst NLS_PRESERVE_CASE_LABEL = nls.localize('label.preserveCaseToggle', \"Preserve Case\");\n\nclass PreserveCaseToggle extends Toggle {\n\tconstructor(opts: IFindInputToggleOpts) {\n\t\tsuper({\n\t\t\t// TODO: does this need its own icon?\n\t\t\ticon: Codicon.preserveCase,\n\t\t\ttitle: NLS_PRESERVE_CASE_LABEL + opts.appendTitle,\n\t\t\tisChecked: opts.isChecked,\n\t\t\thoverDelegate: opts.hoverDelegate ?? getDefaultHoverDelegate('element'),\n\t\t\tinputActiveOptionBorder: opts.inputActiveOptionBorder,\n\t\t\tinputActiveOptionForeground: opts.inputActiveOptionForeground,\n\t\t\tinputActiveOptionBackground: opts.inputActiveOptionBackground,\n\t\t});\n\t}\n}\n\nexport class ReplaceInput extends Widget {\n\n\tprivate contextViewProvider: IContextViewProvider | undefined;\n\tprivate placeholder: string;\n\tprivate validation?: IInputValidator;\n\tprivate label: string;\n\tprivate fixFocusOnOptionClickEnabled = true;\n\n\tprivate preserveCase: PreserveCaseToggle;\n\tprivate cachedOptionsWidth: number = 0;\n\tpublic domNode: HTMLElement;\n\tpublic inputBox: HistoryInputBox;\n\n\tprivate readonly _onDidOptionChange = this._register(new Emitter());\n\tpublic readonly onDidOptionChange: Event = this._onDidOptionChange.event;\n\n\tprivate readonly _onKeyDown = this._register(new Emitter());\n\tpublic readonly onKeyDown: Event = this._onKeyDown.event;\n\n\tprivate readonly _onMouseDown = this._register(new Emitter());\n\n\tprivate readonly _onInput = this._register(new Emitter());\n\n\tprivate readonly _onKeyUp = this._register(new Emitter());\n\n\tprivate _onPreserveCaseKeyDown = this._register(new Emitter());\n\tpublic readonly onPreserveCaseKeyDown: Event = this._onPreserveCaseKeyDown.event;\n\n\tconstructor(parent: HTMLElement | null, contextViewProvider: IContextViewProvider | undefined, private readonly _showOptionButtons: boolean, options: IReplaceInputOptions) {\n\t\tsuper();\n\t\tthis.contextViewProvider = contextViewProvider;\n\t\tthis.placeholder = options.placeholder || '';\n\t\tthis.validation = options.validation;\n\t\tthis.label = options.label || NLS_DEFAULT_LABEL;\n\n\t\tconst appendPreserveCaseLabel = options.appendPreserveCaseLabel || '';\n\t\tconst history = options.history || [];\n\t\tconst flexibleHeight = !!options.flexibleHeight;\n\t\tconst flexibleWidth = !!options.flexibleWidth;\n\t\tconst flexibleMaxHeight = options.flexibleMaxHeight;\n\n\t\tthis.domNode = document.createElement('div');\n\t\tthis.domNode.classList.add('monaco-findInput');\n\n\t\tthis.inputBox = this._register(new HistoryInputBox(this.domNode, this.contextViewProvider, {\n\t\t\tariaLabel: this.label || '',\n\t\t\tplaceholder: this.placeholder || '',\n\t\t\tvalidationOptions: {\n\t\t\t\tvalidation: this.validation\n\t\t\t},\n\t\t\thistory,\n\t\t\tshowHistoryHint: options.showHistoryHint,\n\t\t\tflexibleHeight,\n\t\t\tflexibleWidth,\n\t\t\tflexibleMaxHeight,\n\t\t\tinputBoxStyles: options.inputBoxStyles\n\t\t}));\n\n\t\tthis.preserveCase = this._register(new PreserveCaseToggle({\n\t\t\tappendTitle: appendPreserveCaseLabel,\n\t\t\tisChecked: false,\n\t\t\t...options.toggleStyles\n\t\t}));\n\t\tthis._register(this.preserveCase.onChange(viaKeyboard => {\n\t\t\tthis._onDidOptionChange.fire(viaKeyboard);\n\t\t\tif (!viaKeyboard && this.fixFocusOnOptionClickEnabled) {\n\t\t\t\tthis.inputBox.focus();\n\t\t\t}\n\t\t\tthis.validate();\n\t\t}));\n\t\tthis._register(this.preserveCase.onKeyDown(e => {\n\t\t\tthis._onPreserveCaseKeyDown.fire(e);\n\t\t}));\n\n\t\tif (this._showOptionButtons) {\n\t\t\tthis.cachedOptionsWidth = this.preserveCase.width();\n\t\t} else {\n\t\t\tthis.cachedOptionsWidth = 0;\n\t\t}\n\n\t\t// Arrow-Key support to navigate between options\n\t\tconst indexes = [this.preserveCase.domNode];\n\t\tthis.onkeydown(this.domNode, (event: IKeyboardEvent) => {\n\t\t\tif (event.equals(KeyCode.LeftArrow) || event.equals(KeyCode.RightArrow) || event.equals(KeyCode.Escape)) {\n\t\t\t\tconst index = indexes.indexOf(this.domNode.ownerDocument.activeElement);\n\t\t\t\tif (index >= 0) {\n\t\t\t\t\tlet newIndex: number = -1;\n\t\t\t\t\tif (event.equals(KeyCode.RightArrow)) {\n\t\t\t\t\t\tnewIndex = (index + 1) % indexes.length;\n\t\t\t\t\t} else if (event.equals(KeyCode.LeftArrow)) {\n\t\t\t\t\t\tif (index === 0) {\n\t\t\t\t\t\t\tnewIndex = indexes.length - 1;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tnewIndex = index - 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (event.equals(KeyCode.Escape)) {\n\t\t\t\t\t\tindexes[index].blur();\n\t\t\t\t\t\tthis.inputBox.focus();\n\t\t\t\t\t} else if (newIndex >= 0) {\n\t\t\t\t\t\tindexes[newIndex].focus();\n\t\t\t\t\t}\n\n\t\t\t\t\tdom.EventHelper.stop(event, true);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\n\t\tconst controls = document.createElement('div');\n\t\tcontrols.className = 'controls';\n\t\tcontrols.style.display = this._showOptionButtons ? 'block' : 'none';\n\t\tcontrols.appendChild(this.preserveCase.domNode);\n\n\t\tthis.domNode.appendChild(controls);\n\n\t\tparent?.appendChild(this.domNode);\n\n\t\tthis.onkeydown(this.inputBox.inputElement, (e) => this._onKeyDown.fire(e));\n\t\tthis.onkeyup(this.inputBox.inputElement, (e) => this._onKeyUp.fire(e));\n\t\tthis.oninput(this.inputBox.inputElement, (e) => this._onInput.fire());\n\t\tthis.onmousedown(this.inputBox.inputElement, (e) => this._onMouseDown.fire(e));\n\t}\n\n\tpublic enable(): void {\n\t\tthis.domNode.classList.remove('disabled');\n\t\tthis.inputBox.enable();\n\t\tthis.preserveCase.enable();\n\t}\n\n\tpublic disable(): void {\n\t\tthis.domNode.classList.add('disabled');\n\t\tthis.inputBox.disable();\n\t\tthis.preserveCase.disable();\n\t}\n\n\tpublic setEnabled(enabled: boolean): void {\n\t\tif (enabled) {\n\t\t\tthis.enable();\n\t\t} else {\n\t\t\tthis.disable();\n\t\t}\n\t}\n\n\tpublic select(): void {\n\t\tthis.inputBox.select();\n\t}\n\n\tpublic focus(): void {\n\t\tthis.inputBox.focus();\n\t}\n\n\tpublic getPreserveCase(): boolean {\n\t\treturn this.preserveCase.checked;\n\t}\n\n\tpublic setPreserveCase(value: boolean): void {\n\t\tthis.preserveCase.checked = value;\n\t}\n\n\tpublic focusOnPreserve(): void {\n\t\tthis.preserveCase.focus();\n\t}\n\n\tpublic validate(): void {\n\t\tthis.inputBox?.validate();\n\t}\n\n\tpublic set width(newWidth: number) {\n\t\tthis.inputBox.paddingRight = this.cachedOptionsWidth;\n\t\tthis.domNode.style.width = newWidth + 'px';\n\t}\n\n\tpublic override dispose(): void {\n\t\tsuper.dispose();\n\t}\n}\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\nimport { isFirefox } from 'vs/base/browser/browser';\nimport { EventType as TouchEventType, Gesture } from 'vs/base/browser/touch';\nimport { $, addDisposableListener, append, clearNode, createStyleSheet, Dimension, EventHelper, EventLike, EventType, getActiveElement, getWindow, IDomNodePagePosition, isAncestor, isInShadowDOM } from 'vs/base/browser/dom';\nimport { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';\nimport { StandardMouseEvent } from 'vs/base/browser/mouseEvent';\nimport { ActionBar, ActionsOrientation, IActionViewItemProvider } from 'vs/base/browser/ui/actionbar/actionbar';\nimport { ActionViewItem, BaseActionViewItem, IActionViewItemOptions } from 'vs/base/browser/ui/actionbar/actionViewItems';\nimport { AnchorAlignment, layout, LayoutAnchorPosition } from 'vs/base/browser/ui/contextview/contextview';\nimport { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';\nimport { EmptySubmenuAction, IAction, IActionRunner, Separator, SubmenuAction } from 'vs/base/common/actions';\nimport { RunOnceScheduler } from 'vs/base/common/async';\nimport { Codicon } from 'vs/base/common/codicons';\nimport { getCodiconFontCharacters } from 'vs/base/common/codiconsUtil';\nimport { ThemeIcon } from 'vs/base/common/themables';\nimport { Event } from 'vs/base/common/event';\nimport { stripIcons } from 'vs/base/common/iconLabels';\nimport { KeyCode } from 'vs/base/common/keyCodes';\nimport { ResolvedKeybinding } from 'vs/base/common/keybindings';\nimport { DisposableStore } from 'vs/base/common/lifecycle';\nimport { isLinux, isMacintosh } from 'vs/base/common/platform';\nimport { ScrollbarVisibility, ScrollEvent } from 'vs/base/common/scrollable';\nimport * as strings from 'vs/base/common/strings';\n\nexport const MENU_MNEMONIC_REGEX = /\\(&([^\\s&])\\)|(^|[^&])&([^\\s&])/;\nexport const MENU_ESCAPED_MNEMONIC_REGEX = /(&)?(&)([^\\s&])/g;\n\n\n\nexport enum HorizontalDirection {\n\tRight,\n\tLeft\n}\n\nexport enum VerticalDirection {\n\tAbove,\n\tBelow\n}\n\nexport interface IMenuDirection {\n\thorizontal: HorizontalDirection;\n\tvertical: VerticalDirection;\n}\n\nexport interface IMenuOptions {\n\tcontext?: unknown;\n\tactionViewItemProvider?: IActionViewItemProvider;\n\tactionRunner?: IActionRunner;\n\tgetKeyBinding?: (action: IAction) => ResolvedKeybinding | undefined;\n\tariaLabel?: string;\n\tenableMnemonics?: boolean;\n\tanchorAlignment?: AnchorAlignment;\n\texpandDirection?: IMenuDirection;\n\tuseEventAsContext?: boolean;\n\tsubmenuIds?: Set;\n}\n\nexport interface IMenuStyles {\n\tshadowColor: string | undefined;\n\tborderColor: string | undefined;\n\tforegroundColor: string | undefined;\n\tbackgroundColor: string | undefined;\n\tselectionForegroundColor: string | undefined;\n\tselectionBackgroundColor: string | undefined;\n\tselectionBorderColor: string | undefined;\n\tseparatorColor: string | undefined;\n\tscrollbarShadow: string | undefined;\n\tscrollbarSliderBackground: string | undefined;\n\tscrollbarSliderHoverBackground: string | undefined;\n\tscrollbarSliderActiveBackground: string | undefined;\n}\n\ninterface ISubMenuData {\n\tparent: Menu;\n\tsubmenu?: Menu;\n}\n\nexport class Menu extends ActionBar {\n\tprivate mnemonics: Map>;\n\tprivate scrollableElement: DomScrollableElement;\n\tprivate menuElement: HTMLElement;\n\tstatic globalStyleSheet: HTMLStyleElement;\n\tprotected styleSheet: HTMLStyleElement | undefined;\n\n\tconstructor(container: HTMLElement, actions: ReadonlyArray, options: IMenuOptions, private readonly menuStyles: IMenuStyles) {\n\t\tcontainer.classList.add('monaco-menu-container');\n\t\tcontainer.setAttribute('role', 'presentation');\n\t\tconst menuElement = document.createElement('div');\n\t\tmenuElement.classList.add('monaco-menu');\n\t\tmenuElement.setAttribute('role', 'presentation');\n\n\t\tsuper(menuElement, {\n\t\t\torientation: ActionsOrientation.VERTICAL,\n\t\t\tactionViewItemProvider: action => this.doGetActionViewItem(action, options, parentData),\n\t\t\tcontext: options.context,\n\t\t\tactionRunner: options.actionRunner,\n\t\t\tariaLabel: options.ariaLabel,\n\t\t\tariaRole: 'menu',\n\t\t\tfocusOnlyEnabledItems: true,\n\t\t\ttriggerKeys: { keys: [KeyCode.Enter, ...(isMacintosh || isLinux ? [KeyCode.Space] : [])], keyDown: true }\n\t\t});\n\n\t\tthis.menuElement = menuElement;\n\n\t\tthis.actionsList.tabIndex = 0;\n\n\t\tthis.initializeOrUpdateStyleSheet(container, menuStyles);\n\n\t\tthis._register(Gesture.addTarget(menuElement));\n\n\t\tthis._register(addDisposableListener(menuElement, EventType.KEY_DOWN, (e) => {\n\t\t\tconst event = new StandardKeyboardEvent(e);\n\n\t\t\t// Stop tab navigation of menus\n\t\t\tif (event.equals(KeyCode.Tab)) {\n\t\t\t\te.preventDefault();\n\t\t\t}\n\t\t}));\n\n\t\tif (options.enableMnemonics) {\n\t\t\tthis._register(addDisposableListener(menuElement, EventType.KEY_DOWN, (e) => {\n\t\t\t\tconst key = e.key.toLocaleLowerCase();\n\t\t\t\tif (this.mnemonics.has(key)) {\n\t\t\t\t\tEventHelper.stop(e, true);\n\t\t\t\t\tconst actions = this.mnemonics.get(key)!;\n\n\t\t\t\t\tif (actions.length === 1) {\n\t\t\t\t\t\tif (actions[0] instanceof SubmenuMenuActionViewItem && actions[0].container) {\n\t\t\t\t\t\t\tthis.focusItemByElement(actions[0].container);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tactions[0].onClick(e);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (actions.length > 1) {\n\t\t\t\t\t\tconst action = actions.shift();\n\t\t\t\t\t\tif (action && action.container) {\n\t\t\t\t\t\t\tthis.focusItemByElement(action.container);\n\t\t\t\t\t\t\tactions.push(action);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tthis.mnemonics.set(key, actions);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}));\n\t\t}\n\n\t\tif (isLinux) {\n\t\t\tthis._register(addDisposableListener(menuElement, EventType.KEY_DOWN, e => {\n\t\t\t\tconst event = new StandardKeyboardEvent(e);\n\n\t\t\t\tif (event.equals(KeyCode.Home) || event.equals(KeyCode.PageUp)) {\n\t\t\t\t\tthis.focusedItem = this.viewItems.length - 1;\n\t\t\t\t\tthis.focusNext();\n\t\t\t\t\tEventHelper.stop(e, true);\n\t\t\t\t} else if (event.equals(KeyCode.End) || event.equals(KeyCode.PageDown)) {\n\t\t\t\t\tthis.focusedItem = 0;\n\t\t\t\t\tthis.focusPrevious();\n\t\t\t\t\tEventHelper.stop(e, true);\n\t\t\t\t}\n\t\t\t}));\n\t\t}\n\n\t\tthis._register(addDisposableListener(this.domNode, EventType.MOUSE_OUT, e => {\n\t\t\tconst relatedTarget = e.relatedTarget as HTMLElement;\n\t\t\tif (!isAncestor(relatedTarget, this.domNode)) {\n\t\t\t\tthis.focusedItem = undefined;\n\t\t\t\tthis.updateFocus();\n\t\t\t\te.stopPropagation();\n\t\t\t}\n\t\t}));\n\n\t\tthis._register(addDisposableListener(this.actionsList, EventType.MOUSE_OVER, e => {\n\t\t\tlet target = e.target as HTMLElement;\n\t\t\tif (!target || !isAncestor(target, this.actionsList) || target === this.actionsList) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\twhile (target.parentElement !== this.actionsList && target.parentElement !== null) {\n\t\t\t\ttarget = target.parentElement;\n\t\t\t}\n\n\t\t\tif (target.classList.contains('action-item')) {\n\t\t\t\tconst lastFocusedItem = this.focusedItem;\n\t\t\t\tthis.setFocusedItem(target);\n\n\t\t\t\tif (lastFocusedItem !== this.focusedItem) {\n\t\t\t\t\tthis.updateFocus();\n\t\t\t\t}\n\t\t\t}\n\t\t}));\n\n\t\t// Support touch on actions list to focus items (needed for submenus)\n\t\tthis._register(Gesture.addTarget(this.actionsList));\n\t\tthis._register(addDisposableListener(this.actionsList, TouchEventType.Tap, e => {\n\t\t\tlet target = e.initialTarget as HTMLElement;\n\t\t\tif (!target || !isAncestor(target, this.actionsList) || target === this.actionsList) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\twhile (target.parentElement !== this.actionsList && target.parentElement !== null) {\n\t\t\t\ttarget = target.parentElement;\n\t\t\t}\n\n\t\t\tif (target.classList.contains('action-item')) {\n\t\t\t\tconst lastFocusedItem = this.focusedItem;\n\t\t\t\tthis.setFocusedItem(target);\n\n\t\t\t\tif (lastFocusedItem !== this.focusedItem) {\n\t\t\t\t\tthis.updateFocus();\n\t\t\t\t}\n\t\t\t}\n\t\t}));\n\n\n\t\tconst parentData: ISubMenuData = {\n\t\t\tparent: this\n\t\t};\n\n\t\tthis.mnemonics = new Map>();\n\n\t\t// Scroll Logic\n\t\tthis.scrollableElement = this._register(new DomScrollableElement(menuElement, {\n\t\t\talwaysConsumeMouseWheel: true,\n\t\t\thorizontal: ScrollbarVisibility.Hidden,\n\t\t\tvertical: ScrollbarVisibility.Visible,\n\t\t\tverticalScrollbarSize: 7,\n\t\t\thandleMouseWheel: true,\n\t\t\tuseShadows: true\n\t\t}));\n\n\t\tconst scrollElement = this.scrollableElement.getDomNode();\n\t\tscrollElement.style.position = '';\n\n\t\tthis.styleScrollElement(scrollElement, menuStyles);\n\n\t\t// Support scroll on menu drag\n\t\tthis._register(addDisposableListener(menuElement, TouchEventType.Change, e => {\n\t\t\tEventHelper.stop(e, true);\n\n\t\t\tconst scrollTop = this.scrollableElement.getScrollPosition().scrollTop;\n\t\t\tthis.scrollableElement.setScrollPosition({ scrollTop: scrollTop - e.translationY });\n\t\t}));\n\n\t\tthis._register(addDisposableListener(scrollElement, EventType.MOUSE_UP, e => {\n\t\t\t// Absorb clicks in menu dead space https://github.com/microsoft/vscode/issues/63575\n\t\t\t// We do this on the scroll element so the scroll bar doesn't dismiss the menu either\n\t\t\te.preventDefault();\n\t\t}));\n\n\t\tconst window = getWindow(container);\n\t\tmenuElement.style.maxHeight = `${Math.max(10, window.innerHeight - container.getBoundingClientRect().top - 35)}px`;\n\n\t\tactions = actions.filter((a, idx) => {\n\t\t\tif (options.submenuIds?.has(a.id)) {\n\t\t\t\tconsole.warn(`Found submenu cycle: ${a.id}`);\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// Filter out consecutive or useless separators\n\t\t\tif (a instanceof Separator) {\n\t\t\t\tif (idx === actions.length - 1 || idx === 0) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tconst prevAction = actions[idx - 1];\n\t\t\t\tif (prevAction instanceof Separator) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn true;\n\t\t});\n\n\t\tthis.push(actions, { icon: true, label: true, isMenu: true });\n\n\t\tcontainer.appendChild(this.scrollableElement.getDomNode());\n\t\tthis.scrollableElement.scanDomNode();\n\n\t\tthis.viewItems.filter(item => !(item instanceof MenuSeparatorActionViewItem)).forEach((item, index, array) => {\n\t\t\t(item as BaseMenuActionViewItem).updatePositionInSet(index + 1, array.length);\n\t\t});\n\t}\n\n\tprivate initializeOrUpdateStyleSheet(container: HTMLElement, style: IMenuStyles): void {\n\t\tif (!this.styleSheet) {\n\t\t\tif (isInShadowDOM(container)) {\n\t\t\t\tthis.styleSheet = createStyleSheet(container);\n\t\t\t} else {\n\t\t\t\tif (!Menu.globalStyleSheet) {\n\t\t\t\t\tMenu.globalStyleSheet = createStyleSheet();\n\t\t\t\t}\n\t\t\t\tthis.styleSheet = Menu.globalStyleSheet;\n\t\t\t}\n\t\t}\n\t\tthis.styleSheet.textContent = getMenuWidgetCSS(style, isInShadowDOM(container));\n\t}\n\n\tprivate styleScrollElement(scrollElement: HTMLElement, style: IMenuStyles): void {\n\n\t\tconst fgColor = style.foregroundColor ?? '';\n\t\tconst bgColor = style.backgroundColor ?? '';\n\t\tconst border = style.borderColor ? `1px solid ${style.borderColor}` : '';\n\t\tconst borderRadius = '5px';\n\t\tconst shadow = style.shadowColor ? `0 2px 8px ${style.shadowColor}` : '';\n\n\t\tscrollElement.style.outline = border;\n\t\tscrollElement.style.borderRadius = borderRadius;\n\t\tscrollElement.style.color = fgColor;\n\t\tscrollElement.style.backgroundColor = bgColor;\n\t\tscrollElement.style.boxShadow = shadow;\n\t}\n\n\toverride getContainer(): HTMLElement {\n\t\treturn this.scrollableElement.getDomNode();\n\t}\n\n\tget onScroll(): Event {\n\t\treturn this.scrollableElement.onScroll;\n\t}\n\n\tprivate focusItemByElement(element: HTMLElement) {\n\t\tconst lastFocusedItem = this.focusedItem;\n\t\tthis.setFocusedItem(element);\n\n\t\tif (lastFocusedItem !== this.focusedItem) {\n\t\t\tthis.updateFocus();\n\t\t}\n\t}\n\n\tprivate setFocusedItem(element: HTMLElement): void {\n\t\tfor (let i = 0; i < this.actionsList.children.length; i++) {\n\t\t\tconst elem = this.actionsList.children[i];\n\t\t\tif (element === elem) {\n\t\t\t\tthis.focusedItem = i;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tprotected override updateFocus(fromRight?: boolean): void {\n\t\tsuper.updateFocus(fromRight, true, true);\n\n\t\tif (typeof this.focusedItem !== 'undefined') {\n\t\t\t// Workaround for #80047 caused by an issue in chromium\n\t\t\t// https://bugs.chromium.org/p/chromium/issues/detail?id=414283\n\t\t\t// When that's fixed, just call this.scrollableElement.scanDomNode()\n\t\t\tthis.scrollableElement.setScrollPosition({\n\t\t\t\tscrollTop: Math.round(this.menuElement.scrollTop)\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate doGetActionViewItem(action: IAction, options: IMenuOptions, parentData: ISubMenuData): BaseActionViewItem {\n\t\tif (action instanceof Separator) {\n\t\t\treturn new MenuSeparatorActionViewItem(options.context, action, { icon: true }, this.menuStyles);\n\t\t} else if (action instanceof SubmenuAction) {\n\t\t\tconst menuActionViewItem = new SubmenuMenuActionViewItem(action, action.actions, parentData, { ...options, submenuIds: new Set([...(options.submenuIds || []), action.id]) }, this.menuStyles);\n\n\t\t\tif (options.enableMnemonics) {\n\t\t\t\tconst mnemonic = menuActionViewItem.getMnemonic();\n\t\t\t\tif (mnemonic && menuActionViewItem.isEnabled()) {\n\t\t\t\t\tlet actionViewItems: BaseMenuActionViewItem[] = [];\n\t\t\t\t\tif (this.mnemonics.has(mnemonic)) {\n\t\t\t\t\t\tactionViewItems = this.mnemonics.get(mnemonic)!;\n\t\t\t\t\t}\n\n\t\t\t\t\tactionViewItems.push(menuActionViewItem);\n\n\t\t\t\t\tthis.mnemonics.set(mnemonic, actionViewItems);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn menuActionViewItem;\n\t\t} else {\n\t\t\tconst menuItemOptions: IMenuItemOptions = { enableMnemonics: options.enableMnemonics, useEventAsContext: options.useEventAsContext };\n\t\t\tif (options.getKeyBinding) {\n\t\t\t\tconst keybinding = options.getKeyBinding(action);\n\t\t\t\tif (keybinding) {\n\t\t\t\t\tconst keybindingLabel = keybinding.getLabel();\n\n\t\t\t\t\tif (keybindingLabel) {\n\t\t\t\t\t\tmenuItemOptions.keybinding = keybindingLabel;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst menuActionViewItem = new BaseMenuActionViewItem(options.context, action, menuItemOptions, this.menuStyles);\n\n\t\t\tif (options.enableMnemonics) {\n\t\t\t\tconst mnemonic = menuActionViewItem.getMnemonic();\n\t\t\t\tif (mnemonic && menuActionViewItem.isEnabled()) {\n\t\t\t\t\tlet actionViewItems: BaseMenuActionViewItem[] = [];\n\t\t\t\t\tif (this.mnemonics.has(mnemonic)) {\n\t\t\t\t\t\tactionViewItems = this.mnemonics.get(mnemonic)!;\n\t\t\t\t\t}\n\n\t\t\t\t\tactionViewItems.push(menuActionViewItem);\n\n\t\t\t\t\tthis.mnemonics.set(mnemonic, actionViewItems);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn menuActionViewItem;\n\t\t}\n\t}\n}\n\ninterface IMenuItemOptions extends IActionViewItemOptions {\n\tenableMnemonics?: boolean;\n}\n\nclass BaseMenuActionViewItem extends BaseActionViewItem {\n\n\tpublic container: HTMLElement | undefined;\n\n\tprotected override options: IMenuItemOptions;\n\tprotected item: HTMLElement | undefined;\n\n\tprivate runOnceToEnableMouseUp: RunOnceScheduler;\n\tprivate label: HTMLElement | undefined;\n\tprivate check: HTMLElement | undefined;\n\tprivate mnemonic: string | undefined;\n\tprivate cssClass: string;\n\n\tconstructor(ctx: unknown, action: IAction, options: IMenuItemOptions, protected readonly menuStyle: IMenuStyles) {\n\t\toptions.isMenu = true;\n\t\tsuper(action, action, options);\n\n\t\tthis.options = options;\n\t\tthis.options.icon = options.icon !== undefined ? options.icon : false;\n\t\tthis.options.label = options.label !== undefined ? options.label : true;\n\t\tthis.cssClass = '';\n\n\t\t// Set mnemonic\n\t\tif (this.options.label && options.enableMnemonics) {\n\t\t\tconst label = this.action.label;\n\t\t\tif (label) {\n\t\t\t\tconst matches = MENU_MNEMONIC_REGEX.exec(label);\n\t\t\t\tif (matches) {\n\t\t\t\t\tthis.mnemonic = (!!matches[1] ? matches[1] : matches[3]).toLocaleLowerCase();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Add mouse up listener later to avoid accidental clicks\n\t\tthis.runOnceToEnableMouseUp = new RunOnceScheduler(() => {\n\t\t\tif (!this.element) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis._register(addDisposableListener(this.element, EventType.MOUSE_UP, e => {\n\t\t\t\t// removed default prevention as it conflicts\n\t\t\t\t// with BaseActionViewItem #101537\n\t\t\t\t// add back if issues arise and link new issue\n\t\t\t\tEventHelper.stop(e, true);\n\n\t\t\t\t// See https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Interact_with_the_clipboard\n\t\t\t\t// > Writing to the clipboard\n\t\t\t\t// > You can use the \"cut\" and \"copy\" commands without any special\n\t\t\t\t// permission if you are using them in a short-lived event handler\n\t\t\t\t// for a user action (for example, a click handler).\n\n\t\t\t\t// => to get the Copy and Paste context menu actions working on Firefox,\n\t\t\t\t// there should be no timeout here\n\t\t\t\tif (isFirefox) {\n\t\t\t\t\tconst mouseEvent = new StandardMouseEvent(getWindow(this.element), e);\n\n\t\t\t\t\t// Allowing right click to trigger the event causes the issue described below,\n\t\t\t\t\t// but since the solution below does not work in FF, we must disable right click\n\t\t\t\t\tif (mouseEvent.rightButton) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.onClick(e);\n\t\t\t\t}\n\n\t\t\t\t// In all other cases, set timeout to allow context menu cancellation to trigger\n\t\t\t\t// otherwise the action will destroy the menu and a second context menu\n\t\t\t\t// will still trigger for right click.\n\t\t\t\telse {\n\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\tthis.onClick(e);\n\t\t\t\t\t}, 0);\n\t\t\t\t}\n\t\t\t}));\n\n\t\t\tthis._register(addDisposableListener(this.element, EventType.CONTEXT_MENU, e => {\n\t\t\t\tEventHelper.stop(e, true);\n\t\t\t}));\n\t\t}, 100);\n\n\t\tthis._register(this.runOnceToEnableMouseUp);\n\t}\n\n\toverride render(container: HTMLElement): void {\n\t\tsuper.render(container);\n\n\t\tif (!this.element) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.container = container;\n\n\t\tthis.item = append(this.element, $('a.action-menu-item'));\n\t\tif (this._action.id === Separator.ID) {\n\t\t\t// A separator is a presentation item\n\t\t\tthis.item.setAttribute('role', 'presentation');\n\t\t} else {\n\t\t\tthis.item.setAttribute('role', 'menuitem');\n\t\t\tif (this.mnemonic) {\n\t\t\t\tthis.item.setAttribute('aria-keyshortcuts', `${this.mnemonic}`);\n\t\t\t}\n\t\t}\n\n\t\tthis.check = append(this.item, $('span.menu-item-check' + ThemeIcon.asCSSSelector(Codicon.menuSelection)));\n\t\tthis.check.setAttribute('role', 'none');\n\n\t\tthis.label = append(this.item, $('span.action-label'));\n\n\t\tif (this.options.label && this.options.keybinding) {\n\t\t\tappend(this.item, $('span.keybinding')).textContent = this.options.keybinding;\n\t\t}\n\n\t\t// Adds mouse up listener to actually run the action\n\t\tthis.runOnceToEnableMouseUp.schedule();\n\n\t\tthis.updateClass();\n\t\tthis.updateLabel();\n\t\tthis.updateTooltip();\n\t\tthis.updateEnabled();\n\t\tthis.updateChecked();\n\n\t\tthis.applyStyle();\n\t}\n\n\toverride blur(): void {\n\t\tsuper.blur();\n\t\tthis.applyStyle();\n\t}\n\n\toverride focus(): void {\n\t\tsuper.focus();\n\n\t\tthis.item?.focus();\n\n\t\tthis.applyStyle();\n\t}\n\n\tupdatePositionInSet(pos: number, setSize: number): void {\n\t\tif (this.item) {\n\t\t\tthis.item.setAttribute('aria-posinset', `${pos}`);\n\t\t\tthis.item.setAttribute('aria-setsize', `${setSize}`);\n\t\t}\n\t}\n\n\tprotected override updateLabel(): void {\n\t\tif (!this.label) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.options.label) {\n\t\t\tclearNode(this.label);\n\n\t\t\tlet label = stripIcons(this.action.label);\n\t\t\tif (label) {\n\t\t\t\tconst cleanLabel = cleanMnemonic(label);\n\t\t\t\tif (!this.options.enableMnemonics) {\n\t\t\t\t\tlabel = cleanLabel;\n\t\t\t\t}\n\n\t\t\t\tthis.label.setAttribute('aria-label', cleanLabel.replace(/&&/g, '&'));\n\n\t\t\t\tconst matches = MENU_MNEMONIC_REGEX.exec(label);\n\n\t\t\t\tif (matches) {\n\t\t\t\t\tlabel = strings.escape(label);\n\n\t\t\t\t\t// This is global, reset it\n\t\t\t\t\tMENU_ESCAPED_MNEMONIC_REGEX.lastIndex = 0;\n\t\t\t\t\tlet escMatch = MENU_ESCAPED_MNEMONIC_REGEX.exec(label);\n\n\t\t\t\t\t// We can't use negative lookbehind so if we match our negative and skip\n\t\t\t\t\twhile (escMatch && escMatch[1]) {\n\t\t\t\t\t\tescMatch = MENU_ESCAPED_MNEMONIC_REGEX.exec(label);\n\t\t\t\t\t}\n\n\t\t\t\t\tconst replaceDoubleEscapes = (str: string) => str.replace(/&&/g, '&');\n\n\t\t\t\t\tif (escMatch) {\n\t\t\t\t\t\tthis.label.append(\n\t\t\t\t\t\t\tstrings.ltrim(replaceDoubleEscapes(label.substr(0, escMatch.index)), ' '),\n\t\t\t\t\t\t\t$('u', { 'aria-hidden': 'true' },\n\t\t\t\t\t\t\t\tescMatch[3]),\n\t\t\t\t\t\t\tstrings.rtrim(replaceDoubleEscapes(label.substr(escMatch.index + escMatch[0].length)), ' '));\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.label.innerText = replaceDoubleEscapes(label).trim();\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.item?.setAttribute('aria-keyshortcuts', (!!matches[1] ? matches[1] : matches[3]).toLocaleLowerCase());\n\t\t\t\t} else {\n\t\t\t\t\tthis.label.innerText = label.replace(/&&/g, '&').trim();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprotected override updateTooltip(): void {\n\t\t// menus should function like native menus and they do not have tooltips\n\t}\n\n\tprotected override updateClass(): void {\n\t\tif (this.cssClass && this.item) {\n\t\t\tthis.item.classList.remove(...this.cssClass.split(' '));\n\t\t}\n\t\tif (this.options.icon && this.label) {\n\t\t\tthis.cssClass = this.action.class || '';\n\t\t\tthis.label.classList.add('icon');\n\t\t\tif (this.cssClass) {\n\t\t\t\tthis.label.classList.add(...this.cssClass.split(' '));\n\t\t\t}\n\t\t\tthis.updateEnabled();\n\t\t} else if (this.label) {\n\t\t\tthis.label.classList.remove('icon');\n\t\t}\n\t}\n\n\tprotected override updateEnabled(): void {\n\t\tif (this.action.enabled) {\n\t\t\tif (this.element) {\n\t\t\t\tthis.element.classList.remove('disabled');\n\t\t\t\tthis.element.removeAttribute('aria-disabled');\n\t\t\t}\n\n\t\t\tif (this.item) {\n\t\t\t\tthis.item.classList.remove('disabled');\n\t\t\t\tthis.item.removeAttribute('aria-disabled');\n\t\t\t\tthis.item.tabIndex = 0;\n\t\t\t}\n\t\t} else {\n\t\t\tif (this.element) {\n\t\t\t\tthis.element.classList.add('disabled');\n\t\t\t\tthis.element.setAttribute('aria-disabled', 'true');\n\t\t\t}\n\n\t\t\tif (this.item) {\n\t\t\t\tthis.item.classList.add('disabled');\n\t\t\t\tthis.item.setAttribute('aria-disabled', 'true');\n\t\t\t}\n\t\t}\n\t}\n\n\tprotected override updateChecked(): void {\n\t\tif (!this.item) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst checked = this.action.checked;\n\t\tthis.item.classList.toggle('checked', !!checked);\n\t\tif (checked !== undefined) {\n\t\t\tthis.item.setAttribute('role', 'menuitemcheckbox');\n\t\t\tthis.item.setAttribute('aria-checked', checked ? 'true' : 'false');\n\t\t} else {\n\t\t\tthis.item.setAttribute('role', 'menuitem');\n\t\t\tthis.item.setAttribute('aria-checked', '');\n\t\t}\n\t}\n\n\tgetMnemonic(): string | undefined {\n\t\treturn this.mnemonic;\n\t}\n\n\tprotected applyStyle(): void {\n\t\tconst isSelected = this.element && this.element.classList.contains('focused');\n\t\tconst fgColor = isSelected && this.menuStyle.selectionForegroundColor ? this.menuStyle.selectionForegroundColor : this.menuStyle.foregroundColor;\n\t\tconst bgColor = isSelected && this.menuStyle.selectionBackgroundColor ? this.menuStyle.selectionBackgroundColor : undefined;\n\t\tconst outline = isSelected && this.menuStyle.selectionBorderColor ? `1px solid ${this.menuStyle.selectionBorderColor}` : '';\n\t\tconst outlineOffset = isSelected && this.menuStyle.selectionBorderColor ? `-1px` : '';\n\n\t\tif (this.item) {\n\t\t\tthis.item.style.color = fgColor ?? '';\n\t\t\tthis.item.style.backgroundColor = bgColor ?? '';\n\t\t\tthis.item.style.outline = outline;\n\t\t\tthis.item.style.outlineOffset = outlineOffset;\n\t\t}\n\n\t\tif (this.check) {\n\t\t\tthis.check.style.color = fgColor ?? '';\n\t\t}\n\t}\n}\n\nclass SubmenuMenuActionViewItem extends BaseMenuActionViewItem {\n\tprivate mysubmenu: Menu | null = null;\n\tprivate submenuContainer: HTMLElement | undefined;\n\tprivate submenuIndicator: HTMLElement | undefined;\n\tprivate readonly submenuDisposables = this._register(new DisposableStore());\n\tprivate mouseOver: boolean = false;\n\tprivate showScheduler: RunOnceScheduler;\n\tprivate hideScheduler: RunOnceScheduler;\n\tprivate expandDirection: IMenuDirection;\n\n\tconstructor(\n\t\taction: IAction,\n\t\tprivate submenuActions: ReadonlyArray,\n\t\tprivate parentData: ISubMenuData,\n\t\tprivate submenuOptions: IMenuOptions,\n\t\tmenuStyles: IMenuStyles\n\t) {\n\t\tsuper(action, action, submenuOptions, menuStyles);\n\n\t\tthis.expandDirection = submenuOptions && submenuOptions.expandDirection !== undefined ? submenuOptions.expandDirection : { horizontal: HorizontalDirection.Right, vertical: VerticalDirection.Below };\n\n\t\tthis.showScheduler = new RunOnceScheduler(() => {\n\t\t\tif (this.mouseOver) {\n\t\t\t\tthis.cleanupExistingSubmenu(false);\n\t\t\t\tthis.createSubmenu(false);\n\t\t\t}\n\t\t}, 250);\n\n\t\tthis.hideScheduler = new RunOnceScheduler(() => {\n\t\t\tif (this.element && (!isAncestor(getActiveElement(), this.element) && this.parentData.submenu === this.mysubmenu)) {\n\t\t\t\tthis.parentData.parent.focus(false);\n\t\t\t\tthis.cleanupExistingSubmenu(true);\n\t\t\t}\n\t\t}, 750);\n\t}\n\n\toverride render(container: HTMLElement): void {\n\t\tsuper.render(container);\n\n\t\tif (!this.element) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.item) {\n\t\t\tthis.item.classList.add('monaco-submenu-item');\n\t\t\tthis.item.tabIndex = 0;\n\t\t\tthis.item.setAttribute('aria-haspopup', 'true');\n\t\t\tthis.updateAriaExpanded('false');\n\t\t\tthis.submenuIndicator = append(this.item, $('span.submenu-indicator' + ThemeIcon.asCSSSelector(Codicon.menuSubmenu)));\n\t\t\tthis.submenuIndicator.setAttribute('aria-hidden', 'true');\n\t\t}\n\n\t\tthis._register(addDisposableListener(this.element, EventType.KEY_UP, e => {\n\t\t\tconst event = new StandardKeyboardEvent(e);\n\t\t\tif (event.equals(KeyCode.RightArrow) || event.equals(KeyCode.Enter)) {\n\t\t\t\tEventHelper.stop(e, true);\n\n\t\t\t\tthis.createSubmenu(true);\n\t\t\t}\n\t\t}));\n\n\t\tthis._register(addDisposableListener(this.element, EventType.KEY_DOWN, e => {\n\t\t\tconst event = new StandardKeyboardEvent(e);\n\n\t\t\tif (getActiveElement() === this.item) {\n\t\t\t\tif (event.equals(KeyCode.RightArrow) || event.equals(KeyCode.Enter)) {\n\t\t\t\t\tEventHelper.stop(e, true);\n\t\t\t\t}\n\t\t\t}\n\t\t}));\n\n\t\tthis._register(addDisposableListener(this.element, EventType.MOUSE_OVER, e => {\n\t\t\tif (!this.mouseOver) {\n\t\t\t\tthis.mouseOver = true;\n\n\t\t\t\tthis.showScheduler.schedule();\n\t\t\t}\n\t\t}));\n\n\t\tthis._register(addDisposableListener(this.element, EventType.MOUSE_LEAVE, e => {\n\t\t\tthis.mouseOver = false;\n\t\t}));\n\n\t\tthis._register(addDisposableListener(this.element, EventType.FOCUS_OUT, e => {\n\t\t\tif (this.element && !isAncestor(getActiveElement(), this.element)) {\n\t\t\t\tthis.hideScheduler.schedule();\n\t\t\t}\n\t\t}));\n\n\t\tthis._register(this.parentData.parent.onScroll(() => {\n\t\t\tif (this.parentData.submenu === this.mysubmenu) {\n\t\t\t\tthis.parentData.parent.focus(false);\n\t\t\t\tthis.cleanupExistingSubmenu(true);\n\t\t\t}\n\t\t}));\n\t}\n\n\tprotected override updateEnabled(): void {\n\t\t// override on submenu entry\n\t\t// native menus do not observe enablement on sumbenus\n\t\t// we mimic that behavior\n\t}\n\n\toverride onClick(e: EventLike): void {\n\t\t// stop clicking from trying to run an action\n\t\tEventHelper.stop(e, true);\n\n\t\tthis.cleanupExistingSubmenu(false);\n\t\tthis.createSubmenu(true);\n\t}\n\n\tprivate cleanupExistingSubmenu(force: boolean): void {\n\t\tif (this.parentData.submenu && (force || (this.parentData.submenu !== this.mysubmenu))) {\n\n\t\t\t// disposal may throw if the submenu has already been removed\n\t\t\ttry {\n\t\t\t\tthis.parentData.submenu.dispose();\n\t\t\t} catch { }\n\n\t\t\tthis.parentData.submenu = undefined;\n\t\t\tthis.updateAriaExpanded('false');\n\t\t\tif (this.submenuContainer) {\n\t\t\t\tthis.submenuDisposables.clear();\n\t\t\t\tthis.submenuContainer = undefined;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate calculateSubmenuMenuLayout(windowDimensions: Dimension, submenu: Dimension, entry: IDomNodePagePosition, expandDirection: IMenuDirection): { top: number; left: number } {\n\t\tconst ret = { top: 0, left: 0 };\n\n\t\t// Start with horizontal\n\t\tret.left = layout(windowDimensions.width, submenu.width, { position: expandDirection.horizontal === HorizontalDirection.Right ? LayoutAnchorPosition.Before : LayoutAnchorPosition.After, offset: entry.left, size: entry.width });\n\n\t\t// We don't have enough room to layout the menu fully, so we are overlapping the menu\n\t\tif (ret.left >= entry.left && ret.left < entry.left + entry.width) {\n\t\t\tif (entry.left + 10 + submenu.width <= windowDimensions.width) {\n\t\t\t\tret.left = entry.left + 10;\n\t\t\t}\n\n\t\t\tentry.top += 10;\n\t\t\tentry.height = 0;\n\t\t}\n\n\t\t// Now that we have a horizontal position, try layout vertically\n\t\tret.top = layout(windowDimensions.height, submenu.height, { position: LayoutAnchorPosition.Before, offset: entry.top, size: 0 });\n\n\t\t// We didn't have enough room below, but we did above, so we shift down to align the menu\n\t\tif (ret.top + submenu.height === entry.top && ret.top + entry.height + submenu.height <= windowDimensions.height) {\n\t\t\tret.top += entry.height;\n\t\t}\n\n\t\treturn ret;\n\t}\n\n\tprivate createSubmenu(selectFirstItem = true): void {\n\t\tif (!this.element) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (!this.parentData.submenu) {\n\t\t\tthis.updateAriaExpanded('true');\n\t\t\tthis.submenuContainer = append(this.element, $('div.monaco-submenu'));\n\t\t\tthis.submenuContainer.classList.add('menubar-menu-items-holder', 'context-view');\n\n\t\t\t// Set the top value of the menu container before construction\n\t\t\t// This allows the menu constructor to calculate the proper max height\n\t\t\tconst computedStyles = getWindow(this.parentData.parent.domNode).getComputedStyle(this.parentData.parent.domNode);\n\t\t\tconst paddingTop = parseFloat(computedStyles.paddingTop || '0') || 0;\n\t\t\t// this.submenuContainer.style.top = `${this.element.offsetTop - this.parentData.parent.scrollOffset - paddingTop}px`;\n\t\t\tthis.submenuContainer.style.zIndex = '1';\n\t\t\tthis.submenuContainer.style.position = 'fixed';\n\t\t\tthis.submenuContainer.style.top = '0';\n\t\t\tthis.submenuContainer.style.left = '0';\n\n\t\t\tthis.parentData.submenu = new Menu(this.submenuContainer, this.submenuActions.length ? this.submenuActions : [new EmptySubmenuAction()], this.submenuOptions, this.menuStyle);\n\n\t\t\t// layout submenu\n\t\t\tconst entryBox = this.element.getBoundingClientRect();\n\t\t\tconst entryBoxUpdated = {\n\t\t\t\ttop: entryBox.top - paddingTop,\n\t\t\t\tleft: entryBox.left,\n\t\t\t\theight: entryBox.height + 2 * paddingTop,\n\t\t\t\twidth: entryBox.width\n\t\t\t};\n\n\t\t\tconst viewBox = this.submenuContainer.getBoundingClientRect();\n\n\t\t\tconst window = getWindow(this.element);\n\t\t\tconst { top, left } = this.calculateSubmenuMenuLayout(new Dimension(window.innerWidth, window.innerHeight), Dimension.lift(viewBox), entryBoxUpdated, this.expandDirection);\n\t\t\t// subtract offsets caused by transform parent\n\t\t\tthis.submenuContainer.style.left = `${left - viewBox.left}px`;\n\t\t\tthis.submenuContainer.style.top = `${top - viewBox.top}px`;\n\n\t\t\tthis.submenuDisposables.add(addDisposableListener(this.submenuContainer, EventType.KEY_UP, e => {\n\t\t\t\tconst event = new StandardKeyboardEvent(e);\n\t\t\t\tif (event.equals(KeyCode.LeftArrow)) {\n\t\t\t\t\tEventHelper.stop(e, true);\n\n\t\t\t\t\tthis.parentData.parent.focus();\n\n\t\t\t\t\tthis.cleanupExistingSubmenu(true);\n\t\t\t\t}\n\t\t\t}));\n\n\t\t\tthis.submenuDisposables.add(addDisposableListener(this.submenuContainer, EventType.KEY_DOWN, e => {\n\t\t\t\tconst event = new StandardKeyboardEvent(e);\n\t\t\t\tif (event.equals(KeyCode.LeftArrow)) {\n\t\t\t\t\tEventHelper.stop(e, true);\n\t\t\t\t}\n\t\t\t}));\n\n\n\t\t\tthis.submenuDisposables.add(this.parentData.submenu.onDidCancel(() => {\n\t\t\t\tthis.parentData.parent.focus();\n\n\t\t\t\tthis.cleanupExistingSubmenu(true);\n\t\t\t}));\n\n\t\t\tthis.parentData.submenu.focus(selectFirstItem);\n\n\t\t\tthis.mysubmenu = this.parentData.submenu;\n\t\t} else {\n\t\t\tthis.parentData.submenu.focus(false);\n\t\t}\n\t}\n\n\tprivate updateAriaExpanded(value: string): void {\n\t\tif (this.item) {\n\t\t\tthis.item?.setAttribute('aria-expanded', value);\n\t\t}\n\t}\n\n\tprotected override applyStyle(): void {\n\t\tsuper.applyStyle();\n\n\t\tconst isSelected = this.element && this.element.classList.contains('focused');\n\t\tconst fgColor = isSelected && this.menuStyle.selectionForegroundColor ? this.menuStyle.selectionForegroundColor : this.menuStyle.foregroundColor;\n\n\t\tif (this.submenuIndicator) {\n\t\t\tthis.submenuIndicator.style.color = fgColor ?? '';\n\t\t}\n\t}\n\n\toverride dispose(): void {\n\t\tsuper.dispose();\n\n\t\tthis.hideScheduler.dispose();\n\n\t\tif (this.mysubmenu) {\n\t\t\tthis.mysubmenu.dispose();\n\t\t\tthis.mysubmenu = null;\n\t\t}\n\n\t\tif (this.submenuContainer) {\n\t\t\tthis.submenuContainer = undefined;\n\t\t}\n\t}\n}\n\nclass MenuSeparatorActionViewItem extends ActionViewItem {\n\tconstructor(context: unknown, action: IAction, options: IActionViewItemOptions, private readonly menuStyles: IMenuStyles) {\n\t\tsuper(context, action, options);\n\t}\n\n\toverride render(container: HTMLElement): void {\n\t\tsuper.render(container);\n\t\tif (this.label) {\n\t\t\tthis.label.style.borderBottomColor = this.menuStyles.separatorColor ? `${this.menuStyles.separatorColor}` : '';\n\t\t}\n\t}\n}\n\nexport function cleanMnemonic(label: string): string {\n\tconst regex = MENU_MNEMONIC_REGEX;\n\n\tconst matches = regex.exec(label);\n\tif (!matches) {\n\t\treturn label;\n\t}\n\n\tconst mnemonicInText = !matches[1];\n\n\treturn label.replace(regex, mnemonicInText ? '$2$3' : '').trim();\n}\n\nexport function formatRule(c: ThemeIcon) {\n\tconst fontCharacter = getCodiconFontCharacters()[c.id];\n\treturn `.codicon-${c.id}:before { content: '\\\\${fontCharacter.toString(16)}'; }`;\n}\n\nfunction getMenuWidgetCSS(style: IMenuStyles, isForShadowDom: boolean): string {\n\tlet result = /* css */`\n.monaco-menu {\n\tfont-size: 13px;\n\tborder-radius: 5px;\n\tmin-width: 160px;\n}\n\n${formatRule(Codicon.menuSelection)}\n${formatRule(Codicon.menuSubmenu)}\n\n.monaco-menu .monaco-action-bar {\n\ttext-align: right;\n\toverflow: hidden;\n\twhite-space: nowrap;\n}\n\n.monaco-menu .monaco-action-bar .actions-container {\n\tdisplay: flex;\n\tmargin: 0 auto;\n\tpadding: 0;\n\twidth: 100%;\n\tjustify-content: flex-end;\n}\n\n.monaco-menu .monaco-action-bar.vertical .actions-container {\n\tdisplay: inline-block;\n}\n\n.monaco-menu .monaco-action-bar.reverse .actions-container {\n\tflex-direction: row-reverse;\n}\n\n.monaco-menu .monaco-action-bar .action-item {\n\tcursor: pointer;\n\tdisplay: inline-block;\n\ttransition: transform 50ms ease;\n\tposition: relative; /* DO NOT REMOVE - this is the key to preventing the ghosting icon bug in Chrome 42 */\n}\n\n.monaco-menu .monaco-action-bar .action-item.disabled {\n\tcursor: default;\n}\n\n.monaco-menu .monaco-action-bar .action-item .icon,\n.monaco-menu .monaco-action-bar .action-item .codicon {\n\tdisplay: inline-block;\n}\n\n.monaco-menu .monaco-action-bar .action-item .codicon {\n\tdisplay: flex;\n\talign-items: center;\n}\n\n.monaco-menu .monaco-action-bar .action-label {\n\tfont-size: 11px;\n\tmargin-right: 4px;\n}\n\n.monaco-menu .monaco-action-bar .action-item.disabled .action-label,\n.monaco-menu .monaco-action-bar .action-item.disabled .action-label:hover {\n\tcolor: var(--vscode-disabledForeground);\n}\n\n/* Vertical actions */\n\n.monaco-menu .monaco-action-bar.vertical {\n\ttext-align: left;\n}\n\n.monaco-menu .monaco-action-bar.vertical .action-item {\n\tdisplay: block;\n}\n\n.monaco-menu .monaco-action-bar.vertical .action-label.separator {\n\tdisplay: block;\n\tborder-bottom: 1px solid var(--vscode-menu-separatorBackground);\n\tpadding-top: 1px;\n\tpadding: 30px;\n}\n\n.monaco-menu .secondary-actions .monaco-action-bar .action-label {\n\tmargin-left: 6px;\n}\n\n/* Action Items */\n.monaco-menu .monaco-action-bar .action-item.select-container {\n\toverflow: hidden; /* somehow the dropdown overflows its container, we prevent it here to not push */\n\tflex: 1;\n\tmax-width: 170px;\n\tmin-width: 60px;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tmargin-right: 10px;\n}\n\n.monaco-menu .monaco-action-bar.vertical {\n\tmargin-left: 0;\n\toverflow: visible;\n}\n\n.monaco-menu .monaco-action-bar.vertical .actions-container {\n\tdisplay: block;\n}\n\n.monaco-menu .monaco-action-bar.vertical .action-item {\n\tpadding: 0;\n\ttransform: none;\n\tdisplay: flex;\n}\n\n.monaco-menu .monaco-action-bar.vertical .action-item.active {\n\ttransform: none;\n}\n\n.monaco-menu .monaco-action-bar.vertical .action-menu-item {\n\tflex: 1 1 auto;\n\tdisplay: flex;\n\theight: 2em;\n\talign-items: center;\n\tposition: relative;\n\tmargin: 0 4px;\n\tborder-radius: 4px;\n}\n\n.monaco-menu .monaco-action-bar.vertical .action-menu-item:hover .keybinding,\n.monaco-menu .monaco-action-bar.vertical .action-menu-item:focus .keybinding {\n\topacity: unset;\n}\n\n.monaco-menu .monaco-action-bar.vertical .action-label {\n\tflex: 1 1 auto;\n\ttext-decoration: none;\n\tpadding: 0 1em;\n\tbackground: none;\n\tfont-size: 12px;\n\tline-height: 1;\n}\n\n.monaco-menu .monaco-action-bar.vertical .keybinding,\n.monaco-menu .monaco-action-bar.vertical .submenu-indicator {\n\tdisplay: inline-block;\n\tflex: 2 1 auto;\n\tpadding: 0 1em;\n\ttext-align: right;\n\tfont-size: 12px;\n\tline-height: 1;\n}\n\n.monaco-menu .monaco-action-bar.vertical .submenu-indicator {\n\theight: 100%;\n}\n\n.monaco-menu .monaco-action-bar.vertical .submenu-indicator.codicon {\n\tfont-size: 16px !important;\n\tdisplay: flex;\n\talign-items: center;\n}\n\n.monaco-menu .monaco-action-bar.vertical .submenu-indicator.codicon::before {\n\tmargin-left: auto;\n\tmargin-right: -20px;\n}\n\n.monaco-menu .monaco-action-bar.vertical .action-item.disabled .keybinding,\n.monaco-menu .monaco-action-bar.vertical .action-item.disabled .submenu-indicator {\n\topacity: 0.4;\n}\n\n.monaco-menu .monaco-action-bar.vertical .action-label:not(.separator) {\n\tdisplay: inline-block;\n\tbox-sizing: border-box;\n\tmargin: 0;\n}\n\n.monaco-menu .monaco-action-bar.vertical .action-item {\n\tposition: static;\n\toverflow: visible;\n}\n\n.monaco-menu .monaco-action-bar.vertical .action-item .monaco-submenu {\n\tposition: absolute;\n}\n\n.monaco-menu .monaco-action-bar.vertical .action-label.separator {\n\twidth: 100%;\n\theight: 0px !important;\n\topacity: 1;\n}\n\n.monaco-menu .monaco-action-bar.vertical .action-label.separator.text {\n\tpadding: 0.7em 1em 0.1em 1em;\n\tfont-weight: bold;\n\topacity: 1;\n}\n\n.monaco-menu .monaco-action-bar.vertical .action-label:hover {\n\tcolor: inherit;\n}\n\n.monaco-menu .monaco-action-bar.vertical .menu-item-check {\n\tposition: absolute;\n\tvisibility: hidden;\n\twidth: 1em;\n\theight: 100%;\n}\n\n.monaco-menu .monaco-action-bar.vertical .action-menu-item.checked .menu-item-check {\n\tvisibility: visible;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n}\n\n/* Context Menu */\n\n.context-view.monaco-menu-container {\n\toutline: 0;\n\tborder: none;\n\tanimation: fadeIn 0.083s linear;\n\t-webkit-app-region: no-drag;\n}\n\n.context-view.monaco-menu-container :focus,\n.context-view.monaco-menu-container .monaco-action-bar.vertical:focus,\n.context-view.monaco-menu-container .monaco-action-bar.vertical :focus {\n\toutline: 0;\n}\n\n.hc-black .context-view.monaco-menu-container,\n.hc-light .context-view.monaco-menu-container,\n:host-context(.hc-black) .context-view.monaco-menu-container,\n:host-context(.hc-light) .context-view.monaco-menu-container {\n\tbox-shadow: none;\n}\n\n.hc-black .monaco-menu .monaco-action-bar.vertical .action-item.focused,\n.hc-light .monaco-menu .monaco-action-bar.vertical .action-item.focused,\n:host-context(.hc-black) .monaco-menu .monaco-action-bar.vertical .action-item.focused,\n:host-context(.hc-light) .monaco-menu .monaco-action-bar.vertical .action-item.focused {\n\tbackground: none;\n}\n\n/* Vertical Action Bar Styles */\n\n.monaco-menu .monaco-action-bar.vertical {\n\tpadding: 4px 0;\n}\n\n.monaco-menu .monaco-action-bar.vertical .action-menu-item {\n\theight: 2em;\n}\n\n.monaco-menu .monaco-action-bar.vertical .action-label:not(.separator),\n.monaco-menu .monaco-action-bar.vertical .keybinding {\n\tfont-size: inherit;\n\tpadding: 0 2em;\n\tmax-height: 100%;\n}\n\n.monaco-menu .monaco-action-bar.vertical .menu-item-check {\n\tfont-size: inherit;\n\twidth: 2em;\n}\n\n.monaco-menu .monaco-action-bar.vertical .action-label.separator {\n\tfont-size: inherit;\n\tmargin: 5px 0 !important;\n\tpadding: 0;\n\tborder-radius: 0;\n}\n\n.linux .monaco-menu .monaco-action-bar.vertical .action-label.separator,\n:host-context(.linux) .monaco-menu .monaco-action-bar.vertical .action-label.separator {\n\tmargin-left: 0;\n\tmargin-right: 0;\n}\n\n.monaco-menu .monaco-action-bar.vertical .submenu-indicator {\n\tfont-size: 60%;\n\tpadding: 0 1.8em;\n}\n\n.linux .monaco-menu .monaco-action-bar.vertical .submenu-indicator,\n:host-context(.linux) .monaco-menu .monaco-action-bar.vertical .submenu-indicator {\n\theight: 100%;\n\tmask-size: 10px 10px;\n\t-webkit-mask-size: 10px 10px;\n}\n\n.monaco-menu .action-item {\n\tcursor: default;\n}`;\n\n\tif (isForShadowDom) {\n\t\t// Only define scrollbar styles when used inside shadow dom,\n\t\t// otherwise leave their styling to the global workbench styling.\n\t\tresult += `\n\t\t\t/* Arrows */\n\t\t\t.monaco-scrollable-element > .scrollbar > .scra {\n\t\t\t\tcursor: pointer;\n\t\t\t\tfont-size: 11px !important;\n\t\t\t}\n\n\t\t\t.monaco-scrollable-element > .visible {\n\t\t\t\topacity: 1;\n\n\t\t\t\t/* Background rule added for IE9 - to allow clicks on dom node */\n\t\t\t\tbackground:rgba(0,0,0,0);\n\n\t\t\t\ttransition: opacity 100ms linear;\n\t\t\t}\n\t\t\t.monaco-scrollable-element > .invisible {\n\t\t\t\topacity: 0;\n\t\t\t\tpointer-events: none;\n\t\t\t}\n\t\t\t.monaco-scrollable-element > .invisible.fade {\n\t\t\t\ttransition: opacity 800ms linear;\n\t\t\t}\n\n\t\t\t/* Scrollable Content Inset Shadow */\n\t\t\t.monaco-scrollable-element > .shadow {\n\t\t\t\tposition: absolute;\n\t\t\t\tdisplay: none;\n\t\t\t}\n\t\t\t.monaco-scrollable-element > .shadow.top {\n\t\t\t\tdisplay: block;\n\t\t\t\ttop: 0;\n\t\t\t\tleft: 3px;\n\t\t\t\theight: 3px;\n\t\t\t\twidth: 100%;\n\t\t\t}\n\t\t\t.monaco-scrollable-element > .shadow.left {\n\t\t\t\tdisplay: block;\n\t\t\t\ttop: 3px;\n\t\t\t\tleft: 0;\n\t\t\t\theight: 100%;\n\t\t\t\twidth: 3px;\n\t\t\t}\n\t\t\t.monaco-scrollable-element > .shadow.top-left-corner {\n\t\t\t\tdisplay: block;\n\t\t\t\ttop: 0;\n\t\t\t\tleft: 0;\n\t\t\t\theight: 3px;\n\t\t\t\twidth: 3px;\n\t\t\t}\n\t\t`;\n\n\t\t// Scrollbars\n\t\tconst scrollbarShadowColor = style.scrollbarShadow;\n\t\tif (scrollbarShadowColor) {\n\t\t\tresult += `\n\t\t\t\t.monaco-scrollable-element > .shadow.top {\n\t\t\t\t\tbox-shadow: ${scrollbarShadowColor} 0 6px 6px -6px inset;\n\t\t\t\t}\n\n\t\t\t\t.monaco-scrollable-element > .shadow.left {\n\t\t\t\t\tbox-shadow: ${scrollbarShadowColor} 6px 0 6px -6px inset;\n\t\t\t\t}\n\n\t\t\t\t.monaco-scrollable-element > .shadow.top.left {\n\t\t\t\t\tbox-shadow: ${scrollbarShadowColor} 6px 6px 6px -6px inset;\n\t\t\t\t}\n\t\t\t`;\n\t\t}\n\n\t\tconst scrollbarSliderBackgroundColor = style.scrollbarSliderBackground;\n\t\tif (scrollbarSliderBackgroundColor) {\n\t\t\tresult += `\n\t\t\t\t.monaco-scrollable-element > .scrollbar > .slider {\n\t\t\t\t\tbackground: ${scrollbarSliderBackgroundColor};\n\t\t\t\t}\n\t\t\t`;\n\t\t}\n\n\t\tconst scrollbarSliderHoverBackgroundColor = style.scrollbarSliderHoverBackground;\n\t\tif (scrollbarSliderHoverBackgroundColor) {\n\t\t\tresult += `\n\t\t\t\t.monaco-scrollable-element > .scrollbar > .slider:hover {\n\t\t\t\t\tbackground: ${scrollbarSliderHoverBackgroundColor};\n\t\t\t\t}\n\t\t\t`;\n\t\t}\n\n\t\tconst scrollbarSliderActiveBackgroundColor = style.scrollbarSliderActiveBackground;\n\t\tif (scrollbarSliderActiveBackgroundColor) {\n\t\t\tresult += `\n\t\t\t\t.monaco-scrollable-element > .scrollbar > .slider.active {\n\t\t\t\t\tbackground: ${scrollbarSliderActiveBackgroundColor};\n\t\t\t\t}\n\t\t\t`;\n\t\t}\n\t}\n\n\treturn result;\n}\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\nimport { IContextMenuProvider } from 'vs/base/browser/contextmenu';\nimport { ActionBar, ActionsOrientation, IActionViewItemProvider } from 'vs/base/browser/ui/actionbar/actionbar';\nimport { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview';\nimport { DropdownMenuActionViewItem } from 'vs/base/browser/ui/dropdown/dropdownActionViewItem';\nimport { Action, IAction, IActionRunner, SubmenuAction } from 'vs/base/common/actions';\nimport { Codicon } from 'vs/base/common/codicons';\nimport { ThemeIcon } from 'vs/base/common/themables';\nimport { EventMultiplexer } from 'vs/base/common/event';\nimport { ResolvedKeybinding } from 'vs/base/common/keybindings';\nimport { Disposable, DisposableStore } from 'vs/base/common/lifecycle';\nimport 'vs/css!./toolbar';\nimport * as nls from 'vs/nls';\nimport { IHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate';\nimport { createInstantHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegateFactory';\n\n\n\nexport interface IToolBarOptions {\n\torientation?: ActionsOrientation;\n\tactionViewItemProvider?: IActionViewItemProvider;\n\tariaLabel?: string;\n\tgetKeyBinding?: (action: IAction) => ResolvedKeybinding | undefined;\n\tactionRunner?: IActionRunner;\n\ttoggleMenuTitle?: string;\n\tanchorAlignmentProvider?: () => AnchorAlignment;\n\trenderDropdownAsChildElement?: boolean;\n\tmoreIcon?: ThemeIcon;\n\tallowContextMenu?: boolean;\n\tskipTelemetry?: boolean;\n\thoverDelegate?: IHoverDelegate;\n\n\t/**\n\t * If true, toggled primary items are highlighted with a background color.\n\t */\n\thighlightToggledItems?: boolean;\n}\n\n/**\n * A widget that combines an action bar for primary actions and a dropdown for secondary actions.\n */\nexport class ToolBar extends Disposable {\n\tprivate options: IToolBarOptions;\n\tprotected readonly actionBar: ActionBar;\n\tprivate toggleMenuAction: ToggleMenuAction;\n\tprivate toggleMenuActionViewItem: DropdownMenuActionViewItem | undefined;\n\tprivate submenuActionViewItems: DropdownMenuActionViewItem[] = [];\n\tprivate hasSecondaryActions: boolean = false;\n\tprivate readonly lookupKeybindings: boolean;\n\tprivate readonly element: HTMLElement;\n\n\tprivate _onDidChangeDropdownVisibility = this._register(new EventMultiplexer());\n\treadonly onDidChangeDropdownVisibility = this._onDidChangeDropdownVisibility.event;\n\tprivate readonly disposables = this._register(new DisposableStore());\n\n\tconstructor(container: HTMLElement, contextMenuProvider: IContextMenuProvider, options: IToolBarOptions = { orientation: ActionsOrientation.HORIZONTAL }) {\n\t\tsuper();\n\n\t\toptions.hoverDelegate = options.hoverDelegate ?? this._register(createInstantHoverDelegate());\n\t\tthis.options = options;\n\t\tthis.lookupKeybindings = typeof this.options.getKeyBinding === 'function';\n\n\t\tthis.toggleMenuAction = this._register(new ToggleMenuAction(() => this.toggleMenuActionViewItem?.show(), options.toggleMenuTitle));\n\n\t\tthis.element = document.createElement('div');\n\t\tthis.element.className = 'monaco-toolbar';\n\t\tcontainer.appendChild(this.element);\n\n\t\tthis.actionBar = this._register(new ActionBar(this.element, {\n\t\t\torientation: options.orientation,\n\t\t\tariaLabel: options.ariaLabel,\n\t\t\tactionRunner: options.actionRunner,\n\t\t\tallowContextMenu: options.allowContextMenu,\n\t\t\thighlightToggledItems: options.highlightToggledItems,\n\t\t\thoverDelegate: options.hoverDelegate,\n\t\t\tactionViewItemProvider: (action, viewItemOptions) => {\n\t\t\t\tif (action.id === ToggleMenuAction.ID) {\n\t\t\t\t\tthis.toggleMenuActionViewItem = new DropdownMenuActionViewItem(\n\t\t\t\t\t\taction,\n\t\t\t\t\t\t(action).menuActions,\n\t\t\t\t\t\tcontextMenuProvider,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tactionViewItemProvider: this.options.actionViewItemProvider,\n\t\t\t\t\t\t\tactionRunner: this.actionRunner,\n\t\t\t\t\t\t\tkeybindingProvider: this.options.getKeyBinding,\n\t\t\t\t\t\t\tclassNames: ThemeIcon.asClassNameArray(options.moreIcon ?? Codicon.toolBarMore),\n\t\t\t\t\t\t\tanchorAlignmentProvider: this.options.anchorAlignmentProvider,\n\t\t\t\t\t\t\tmenuAsChild: !!this.options.renderDropdownAsChildElement,\n\t\t\t\t\t\t\tskipTelemetry: this.options.skipTelemetry,\n\t\t\t\t\t\t\tisMenu: true,\n\t\t\t\t\t\t\thoverDelegate: this.options.hoverDelegate\n\t\t\t\t\t\t}\n\t\t\t\t\t);\n\t\t\t\t\tthis.toggleMenuActionViewItem.setActionContext(this.actionBar.context);\n\t\t\t\t\tthis.disposables.add(this._onDidChangeDropdownVisibility.add(this.toggleMenuActionViewItem.onDidChangeVisibility));\n\n\t\t\t\t\treturn this.toggleMenuActionViewItem;\n\t\t\t\t}\n\n\t\t\t\tif (options.actionViewItemProvider) {\n\t\t\t\t\tconst result = options.actionViewItemProvider(action, viewItemOptions);\n\n\t\t\t\t\tif (result) {\n\t\t\t\t\t\treturn result;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (action instanceof SubmenuAction) {\n\t\t\t\t\tconst result = new DropdownMenuActionViewItem(\n\t\t\t\t\t\taction,\n\t\t\t\t\t\taction.actions,\n\t\t\t\t\t\tcontextMenuProvider,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tactionViewItemProvider: this.options.actionViewItemProvider,\n\t\t\t\t\t\t\tactionRunner: this.actionRunner,\n\t\t\t\t\t\t\tkeybindingProvider: this.options.getKeyBinding,\n\t\t\t\t\t\t\tclassNames: action.class,\n\t\t\t\t\t\t\tanchorAlignmentProvider: this.options.anchorAlignmentProvider,\n\t\t\t\t\t\t\tmenuAsChild: !!this.options.renderDropdownAsChildElement,\n\t\t\t\t\t\t\tskipTelemetry: this.options.skipTelemetry,\n\t\t\t\t\t\t\thoverDelegate: this.options.hoverDelegate\n\t\t\t\t\t\t}\n\t\t\t\t\t);\n\t\t\t\t\tresult.setActionContext(this.actionBar.context);\n\t\t\t\t\tthis.submenuActionViewItems.push(result);\n\t\t\t\t\tthis.disposables.add(this._onDidChangeDropdownVisibility.add(result.onDidChangeVisibility));\n\n\t\t\t\t\treturn result;\n\t\t\t\t}\n\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t}));\n\t}\n\n\tset actionRunner(actionRunner: IActionRunner) {\n\t\tthis.actionBar.actionRunner = actionRunner;\n\t}\n\n\tget actionRunner(): IActionRunner {\n\t\treturn this.actionBar.actionRunner;\n\t}\n\n\tgetElement(): HTMLElement {\n\t\treturn this.element;\n\t}\n\n\tgetItemAction(indexOrElement: number | HTMLElement) {\n\t\treturn this.actionBar.getAction(indexOrElement);\n\t}\n\n\tsetActions(primaryActions: ReadonlyArray, secondaryActions?: ReadonlyArray): void {\n\t\tthis.clear();\n\n\t\tconst primaryActionsToSet = primaryActions ? primaryActions.slice(0) : [];\n\n\t\t// Inject additional action to open secondary actions if present\n\t\tthis.hasSecondaryActions = !!(secondaryActions && secondaryActions.length > 0);\n\t\tif (this.hasSecondaryActions && secondaryActions) {\n\t\t\tthis.toggleMenuAction.menuActions = secondaryActions.slice(0);\n\t\t\tprimaryActionsToSet.push(this.toggleMenuAction);\n\t\t}\n\n\t\tprimaryActionsToSet.forEach(action => {\n\t\t\tthis.actionBar.push(action, { icon: true, label: false, keybinding: this.getKeybindingLabel(action) });\n\t\t});\n\t}\n\n\tprivate getKeybindingLabel(action: IAction): string | undefined {\n\t\tconst key = this.lookupKeybindings ? this.options.getKeyBinding?.(action) : undefined;\n\n\t\treturn key?.getLabel() ?? undefined;\n\t}\n\n\tprivate clear(): void {\n\t\tthis.submenuActionViewItems = [];\n\t\tthis.disposables.clear();\n\t\tthis.actionBar.clear();\n\t}\n\n\toverride dispose(): void {\n\t\tthis.clear();\n\t\tthis.disposables.dispose();\n\t\tsuper.dispose();\n\t}\n}\n\nexport class ToggleMenuAction extends Action {\n\n\tstatic readonly ID = 'toolbar.toggle.more';\n\n\tprivate _menuActions: ReadonlyArray;\n\tprivate toggleDropdownMenu: () => void;\n\n\tconstructor(toggleDropdownMenu: () => void, title?: string) {\n\t\ttitle = title || nls.localize('moreActions', \"More Actions...\");\n\t\tsuper(ToggleMenuAction.ID, title, undefined, true);\n\n\t\tthis._menuActions = [];\n\t\tthis.toggleDropdownMenu = toggleDropdownMenu;\n\t}\n\n\toverride async run(): Promise {\n\t\tthis.toggleDropdownMenu();\n\t}\n\n\tget menuActions(): ReadonlyArray {\n\t\treturn this._menuActions;\n\t}\n\n\tset menuActions(actions: ReadonlyArray) {\n\t\tthis._menuActions = actions;\n\t}\n}\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\nimport { IDragAndDropData } from 'vs/base/browser/dnd';\nimport { $, append, clearNode, createStyleSheet, getWindow, h, hasParentWithClass, asCssValueWithDefault, isKeyboardEvent } from 'vs/base/browser/dom';\nimport { DomEmitter } from 'vs/base/browser/event';\nimport { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';\nimport { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';\nimport { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview';\nimport { FindInput } from 'vs/base/browser/ui/findinput/findInput';\nimport { IInputBoxStyles, IMessage, MessageType, unthemedInboxStyles } from 'vs/base/browser/ui/inputbox/inputBox';\nimport { IIdentityProvider, IKeyboardNavigationLabelProvider, IListContextMenuEvent, IListDragAndDrop, IListDragOverReaction, IListMouseEvent, IListRenderer, IListTouchEvent, IListVirtualDelegate } from 'vs/base/browser/ui/list/list';\nimport { ElementsDragAndDropData, ListViewTargetSector } from 'vs/base/browser/ui/list/listView';\nimport { IListAccessibilityProvider, IListOptions, IListStyles, isActionItem, isButton, isInputElement, isMonacoCustomToggle, isMonacoEditor, isStickyScrollContainer, isStickyScrollElement, List, MouseController, TypeNavigationMode } from 'vs/base/browser/ui/list/listWidget';\nimport { IToggleStyles, Toggle, unthemedToggleStyles } from 'vs/base/browser/ui/toggle/toggle';\nimport { getVisibleState, isFilterResult } from 'vs/base/browser/ui/tree/indexTreeModel';\nimport { ICollapseStateChangeEvent, ITreeContextMenuEvent, ITreeDragAndDrop, ITreeEvent, ITreeFilter, ITreeModel, ITreeModelSpliceEvent, ITreeMouseEvent, ITreeNode, ITreeRenderer, TreeDragOverBubble, TreeFilterResult, TreeMouseEventTarget, TreeVisibility } from 'vs/base/browser/ui/tree/tree';\nimport { Action } from 'vs/base/common/actions';\nimport { distinct, equals, range } from 'vs/base/common/arrays';\nimport { Delayer, disposableTimeout, timeout } from 'vs/base/common/async';\nimport { Codicon } from 'vs/base/common/codicons';\nimport { ThemeIcon } from 'vs/base/common/themables';\nimport { SetMap } from 'vs/base/common/map';\nimport { Emitter, Event, EventBufferer, Relay } from 'vs/base/common/event';\nimport { fuzzyScore, FuzzyScore } from 'vs/base/common/filters';\nimport { KeyCode } from 'vs/base/common/keyCodes';\nimport { Disposable, DisposableStore, dispose, IDisposable, toDisposable } from 'vs/base/common/lifecycle';\nimport { clamp } from 'vs/base/common/numbers';\nimport { ScrollEvent } from 'vs/base/common/scrollable';\nimport { ISpliceable } from 'vs/base/common/sequence';\nimport { isNumber } from 'vs/base/common/types';\nimport 'vs/css!./media/tree';\nimport { localize } from 'vs/nls';\nimport { IHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate';\nimport { createInstantHoverDelegate, getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegateFactory';\nimport { autorun, constObservable } from 'vs/base/common/observable';\n\nclass TreeElementsDragAndDropData extends ElementsDragAndDropData {\n\n\tconstructor(private data: ElementsDragAndDropData, TContext>) {\n\t\tsuper(data.elements.map(node => node.element));\n\t}\n}\n\nfunction asTreeDragAndDropData(data: IDragAndDropData): IDragAndDropData {\n\tif (data instanceof ElementsDragAndDropData) {\n\t\treturn new TreeElementsDragAndDropData(data);\n\t}\n\n\treturn data;\n}\n\nclass TreeNodeListDragAndDrop implements IListDragAndDrop> {\n\n\tprivate autoExpandNode: ITreeNode | undefined;\n\tprivate autoExpandDisposable: IDisposable = Disposable.None;\n\tprivate readonly disposables = new DisposableStore();\n\n\tconstructor(private modelProvider: () => ITreeModel, private dnd: ITreeDragAndDrop) { }\n\n\tgetDragURI(node: ITreeNode): string | null {\n\t\treturn this.dnd.getDragURI(node.element);\n\t}\n\n\tgetDragLabel(nodes: ITreeNode[], originalEvent: DragEvent): string | undefined {\n\t\tif (this.dnd.getDragLabel) {\n\t\t\treturn this.dnd.getDragLabel(nodes.map(node => node.element), originalEvent);\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\tonDragStart(data: IDragAndDropData, originalEvent: DragEvent): void {\n\t\tthis.dnd.onDragStart?.(asTreeDragAndDropData(data), originalEvent);\n\t}\n\n\tonDragOver(data: IDragAndDropData, targetNode: ITreeNode | undefined, targetIndex: number | undefined, targetSector: ListViewTargetSector | undefined, originalEvent: DragEvent, raw = true): boolean | IListDragOverReaction {\n\t\tconst result = this.dnd.onDragOver(asTreeDragAndDropData(data), targetNode && targetNode.element, targetIndex, targetSector, originalEvent);\n\t\tconst didChangeAutoExpandNode = this.autoExpandNode !== targetNode;\n\n\t\tif (didChangeAutoExpandNode) {\n\t\t\tthis.autoExpandDisposable.dispose();\n\t\t\tthis.autoExpandNode = targetNode;\n\t\t}\n\n\t\tif (typeof targetNode === 'undefined') {\n\t\t\treturn result;\n\t\t}\n\n\t\tif (didChangeAutoExpandNode && typeof result !== 'boolean' && result.autoExpand) {\n\t\t\tthis.autoExpandDisposable = disposableTimeout(() => {\n\t\t\t\tconst model = this.modelProvider();\n\t\t\t\tconst ref = model.getNodeLocation(targetNode);\n\n\t\t\t\tif (model.isCollapsed(ref)) {\n\t\t\t\t\tmodel.setCollapsed(ref, false);\n\t\t\t\t}\n\n\t\t\t\tthis.autoExpandNode = undefined;\n\t\t\t}, 500, this.disposables);\n\t\t}\n\n\t\tif (typeof result === 'boolean' || !result.accept || typeof result.bubble === 'undefined' || result.feedback) {\n\t\t\tif (!raw) {\n\t\t\t\tconst accept = typeof result === 'boolean' ? result : result.accept;\n\t\t\t\tconst effect = typeof result === 'boolean' ? undefined : result.effect;\n\t\t\t\treturn { accept, effect, feedback: [targetIndex!] };\n\t\t\t}\n\n\t\t\treturn result;\n\t\t}\n\n\t\tif (result.bubble === TreeDragOverBubble.Up) {\n\t\t\tconst model = this.modelProvider();\n\t\t\tconst ref = model.getNodeLocation(targetNode);\n\t\t\tconst parentRef = model.getParentNodeLocation(ref);\n\t\t\tconst parentNode = model.getNode(parentRef);\n\t\t\tconst parentIndex = parentRef && model.getListIndex(parentRef);\n\n\t\t\treturn this.onDragOver(data, parentNode, parentIndex, targetSector, originalEvent, false);\n\t\t}\n\n\t\tconst model = this.modelProvider();\n\t\tconst ref = model.getNodeLocation(targetNode);\n\t\tconst start = model.getListIndex(ref);\n\t\tconst length = model.getListRenderCount(ref);\n\n\t\treturn { ...result, feedback: range(start, start + length) };\n\t}\n\n\tdrop(data: IDragAndDropData, targetNode: ITreeNode | undefined, targetIndex: number | undefined, targetSector: ListViewTargetSector | undefined, originalEvent: DragEvent): void {\n\t\tthis.autoExpandDisposable.dispose();\n\t\tthis.autoExpandNode = undefined;\n\n\t\tthis.dnd.drop(asTreeDragAndDropData(data), targetNode && targetNode.element, targetIndex, targetSector, originalEvent);\n\t}\n\n\tonDragEnd(originalEvent: DragEvent): void {\n\t\tthis.dnd.onDragEnd?.(originalEvent);\n\t}\n\n\tdispose(): void {\n\t\tthis.disposables.dispose();\n\t\tthis.dnd.dispose();\n\t}\n}\n\nfunction asListOptions(modelProvider: () => ITreeModel, options?: IAbstractTreeOptions): IListOptions> | undefined {\n\treturn options && {\n\t\t...options,\n\t\tidentityProvider: options.identityProvider && {\n\t\t\tgetId(el) {\n\t\t\t\treturn options.identityProvider!.getId(el.element);\n\t\t\t}\n\t\t},\n\t\tdnd: options.dnd && new TreeNodeListDragAndDrop(modelProvider, options.dnd),\n\t\tmultipleSelectionController: options.multipleSelectionController && {\n\t\t\tisSelectionSingleChangeEvent(e) {\n\t\t\t\treturn options.multipleSelectionController!.isSelectionSingleChangeEvent({ ...e, element: e.element } as any);\n\t\t\t},\n\t\t\tisSelectionRangeChangeEvent(e) {\n\t\t\t\treturn options.multipleSelectionController!.isSelectionRangeChangeEvent({ ...e, element: e.element } as any);\n\t\t\t}\n\t\t},\n\t\taccessibilityProvider: options.accessibilityProvider && {\n\t\t\t...options.accessibilityProvider,\n\t\t\tgetSetSize(node) {\n\t\t\t\tconst model = modelProvider();\n\t\t\t\tconst ref = model.getNodeLocation(node);\n\t\t\t\tconst parentRef = model.getParentNodeLocation(ref);\n\t\t\t\tconst parentNode = model.getNode(parentRef);\n\n\t\t\t\treturn parentNode.visibleChildrenCount;\n\t\t\t},\n\t\t\tgetPosInSet(node) {\n\t\t\t\treturn node.visibleChildIndex + 1;\n\t\t\t},\n\t\t\tisChecked: options.accessibilityProvider && options.accessibilityProvider.isChecked ? (node) => {\n\t\t\t\treturn options.accessibilityProvider!.isChecked!(node.element);\n\t\t\t} : undefined,\n\t\t\tgetRole: options.accessibilityProvider && options.accessibilityProvider.getRole ? (node) => {\n\t\t\t\treturn options.accessibilityProvider!.getRole!(node.element);\n\t\t\t} : () => 'treeitem',\n\t\t\tgetAriaLabel(e) {\n\t\t\t\treturn options.accessibilityProvider!.getAriaLabel(e.element);\n\t\t\t},\n\t\t\tgetWidgetAriaLabel() {\n\t\t\t\treturn options.accessibilityProvider!.getWidgetAriaLabel();\n\t\t\t},\n\t\t\tgetWidgetRole: options.accessibilityProvider && options.accessibilityProvider.getWidgetRole ? () => options.accessibilityProvider!.getWidgetRole!() : () => 'tree',\n\t\t\tgetAriaLevel: options.accessibilityProvider && options.accessibilityProvider.getAriaLevel ? (node) => options.accessibilityProvider!.getAriaLevel!(node.element) : (node) => {\n\t\t\t\treturn node.depth;\n\t\t\t},\n\t\t\tgetActiveDescendantId: options.accessibilityProvider.getActiveDescendantId && (node => {\n\t\t\t\treturn options.accessibilityProvider!.getActiveDescendantId!(node.element);\n\t\t\t})\n\t\t},\n\t\tkeyboardNavigationLabelProvider: options.keyboardNavigationLabelProvider && {\n\t\t\t...options.keyboardNavigationLabelProvider,\n\t\t\tgetKeyboardNavigationLabel(node) {\n\t\t\t\treturn options.keyboardNavigationLabelProvider!.getKeyboardNavigationLabel(node.element);\n\t\t\t}\n\t\t}\n\t};\n}\n\nexport class ComposedTreeDelegate implements IListVirtualDelegate {\n\n\tconstructor(private delegate: IListVirtualDelegate) { }\n\n\tgetHeight(element: N): number {\n\t\treturn this.delegate.getHeight(element.element);\n\t}\n\n\tgetTemplateId(element: N): string {\n\t\treturn this.delegate.getTemplateId(element.element);\n\t}\n\n\thasDynamicHeight(element: N): boolean {\n\t\treturn !!this.delegate.hasDynamicHeight && this.delegate.hasDynamicHeight(element.element);\n\t}\n\n\tsetDynamicHeight(element: N, height: number): void {\n\t\tthis.delegate.setDynamicHeight?.(element.element, height);\n\t}\n}\n\ninterface ITreeListTemplateData {\n\treadonly container: HTMLElement;\n\treadonly indent: HTMLElement;\n\treadonly twistie: HTMLElement;\n\tindentGuidesDisposable: IDisposable;\n\treadonly templateData: T;\n}\n\nexport enum RenderIndentGuides {\n\tNone = 'none',\n\tOnHover = 'onHover',\n\tAlways = 'always'\n}\n\ninterface ITreeRendererOptions {\n\treadonly indent?: number;\n\treadonly renderIndentGuides?: RenderIndentGuides;\n\t// TODO@joao replace this with collapsible: boolean | 'ondemand'\n\treadonly hideTwistiesOfChildlessElements?: boolean;\n}\n\ninterface Collection {\n\treadonly elements: T[];\n\treadonly onDidChange: Event;\n}\n\nclass EventCollection implements Collection, IDisposable {\n\n\tprivate readonly disposables = new DisposableStore();\n\treadonly onDidChange: Event;\n\n\tget elements(): T[] {\n\t\treturn this._elements;\n\t}\n\n\tconstructor(onDidChange: Event, private _elements: T[] = []) {\n\t\tthis.onDidChange = Event.forEach(onDidChange, elements => this._elements = elements, this.disposables);\n\t}\n\n\tdispose(): void {\n\t\tthis.disposables.dispose();\n\t}\n}\n\nexport class TreeRenderer implements IListRenderer, ITreeListTemplateData> {\n\n\tprivate static readonly DefaultIndent = 8;\n\n\treadonly templateId: string;\n\tprivate renderedElements = new Map>();\n\tprivate renderedNodes = new Map, ITreeListTemplateData>();\n\tprivate indent: number = TreeRenderer.DefaultIndent;\n\tprivate hideTwistiesOfChildlessElements: boolean = false;\n\n\tprivate shouldRenderIndentGuides: boolean = false;\n\tprivate activeIndentNodes = new Set>();\n\tprivate indentGuidesDisposable: IDisposable = Disposable.None;\n\n\tprivate readonly disposables = new DisposableStore();\n\n\tconstructor(\n\t\tprivate renderer: ITreeRenderer,\n\t\tprivate modelProvider: () => ITreeModel,\n\t\tonDidChangeCollapseState: Event>,\n\t\tprivate activeNodes: Collection>,\n\t\tprivate renderedIndentGuides: SetMap, HTMLDivElement>,\n\t\toptions: ITreeRendererOptions = {}\n\t) {\n\t\tthis.templateId = renderer.templateId;\n\t\tthis.updateOptions(options);\n\n\t\tEvent.map(onDidChangeCollapseState, e => e.node)(this.onDidChangeNodeTwistieState, this, this.disposables);\n\t\trenderer.onDidChangeTwistieState?.(this.onDidChangeTwistieState, this, this.disposables);\n\t}\n\n\tupdateOptions(options: ITreeRendererOptions = {}): void {\n\t\tif (typeof options.indent !== 'undefined') {\n\t\t\tconst indent = clamp(options.indent, 0, 40);\n\n\t\t\tif (indent !== this.indent) {\n\t\t\t\tthis.indent = indent;\n\n\t\t\t\tfor (const [node, templateData] of this.renderedNodes) {\n\t\t\t\t\tthis.renderTreeElement(node, templateData);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (typeof options.renderIndentGuides !== 'undefined') {\n\t\t\tconst shouldRenderIndentGuides = options.renderIndentGuides !== RenderIndentGuides.None;\n\n\t\t\tif (shouldRenderIndentGuides !== this.shouldRenderIndentGuides) {\n\t\t\t\tthis.shouldRenderIndentGuides = shouldRenderIndentGuides;\n\n\t\t\t\tfor (const [node, templateData] of this.renderedNodes) {\n\t\t\t\t\tthis._renderIndentGuides(node, templateData);\n\t\t\t\t}\n\n\t\t\t\tthis.indentGuidesDisposable.dispose();\n\n\t\t\t\tif (shouldRenderIndentGuides) {\n\t\t\t\t\tconst disposables = new DisposableStore();\n\t\t\t\t\tthis.activeNodes.onDidChange(this._onDidChangeActiveNodes, this, disposables);\n\t\t\t\t\tthis.indentGuidesDisposable = disposables;\n\n\t\t\t\t\tthis._onDidChangeActiveNodes(this.activeNodes.elements);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (typeof options.hideTwistiesOfChildlessElements !== 'undefined') {\n\t\t\tthis.hideTwistiesOfChildlessElements = options.hideTwistiesOfChildlessElements;\n\t\t}\n\t}\n\n\trenderTemplate(container: HTMLElement): ITreeListTemplateData {\n\t\tconst el = append(container, $('.monaco-tl-row'));\n\t\tconst indent = append(el, $('.monaco-tl-indent'));\n\t\tconst twistie = append(el, $('.monaco-tl-twistie'));\n\t\tconst contents = append(el, $('.monaco-tl-contents'));\n\t\tconst templateData = this.renderer.renderTemplate(contents);\n\n\t\treturn { container, indent, twistie, indentGuidesDisposable: Disposable.None, templateData };\n\t}\n\n\trenderElement(node: ITreeNode, index: number, templateData: ITreeListTemplateData, height: number | undefined): void {\n\t\tthis.renderedNodes.set(node, templateData);\n\t\tthis.renderedElements.set(node.element, node);\n\t\tthis.renderTreeElement(node, templateData);\n\t\tthis.renderer.renderElement(node, index, templateData.templateData, height);\n\t}\n\n\tdisposeElement(node: ITreeNode, index: number, templateData: ITreeListTemplateData, height: number | undefined): void {\n\t\ttemplateData.indentGuidesDisposable.dispose();\n\n\t\tthis.renderer.disposeElement?.(node, index, templateData.templateData, height);\n\n\t\tif (typeof height === 'number') {\n\t\t\tthis.renderedNodes.delete(node);\n\t\t\tthis.renderedElements.delete(node.element);\n\t\t}\n\t}\n\n\tdisposeTemplate(templateData: ITreeListTemplateData): void {\n\t\tthis.renderer.disposeTemplate(templateData.templateData);\n\t}\n\n\tprivate onDidChangeTwistieState(element: T): void {\n\t\tconst node = this.renderedElements.get(element);\n\n\t\tif (!node) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.onDidChangeNodeTwistieState(node);\n\t}\n\n\tprivate onDidChangeNodeTwistieState(node: ITreeNode): void {\n\t\tconst templateData = this.renderedNodes.get(node);\n\n\t\tif (!templateData) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._onDidChangeActiveNodes(this.activeNodes.elements);\n\t\tthis.renderTreeElement(node, templateData);\n\t}\n\n\tprivate renderTreeElement(node: ITreeNode, templateData: ITreeListTemplateData) {\n\t\tconst indent = TreeRenderer.DefaultIndent + (node.depth - 1) * this.indent;\n\t\ttemplateData.twistie.style.paddingLeft = `${indent}px`;\n\t\ttemplateData.indent.style.width = `${indent + this.indent - 16}px`;\n\n\t\tif (node.collapsible) {\n\t\t\ttemplateData.container.setAttribute('aria-expanded', String(!node.collapsed));\n\t\t} else {\n\t\t\ttemplateData.container.removeAttribute('aria-expanded');\n\t\t}\n\n\t\ttemplateData.twistie.classList.remove(...ThemeIcon.asClassNameArray(Codicon.treeItemExpanded));\n\n\t\tlet twistieRendered = false;\n\n\t\tif (this.renderer.renderTwistie) {\n\t\t\ttwistieRendered = this.renderer.renderTwistie(node.element, templateData.twistie);\n\t\t}\n\n\t\tif (node.collapsible && (!this.hideTwistiesOfChildlessElements || node.visibleChildrenCount > 0)) {\n\t\t\tif (!twistieRendered) {\n\t\t\t\ttemplateData.twistie.classList.add(...ThemeIcon.asClassNameArray(Codicon.treeItemExpanded));\n\t\t\t}\n\n\t\t\ttemplateData.twistie.classList.add('collapsible');\n\t\t\ttemplateData.twistie.classList.toggle('collapsed', node.collapsed);\n\t\t} else {\n\t\t\ttemplateData.twistie.classList.remove('collapsible', 'collapsed');\n\t\t}\n\n\t\tthis._renderIndentGuides(node, templateData);\n\t}\n\n\tprivate _renderIndentGuides(node: ITreeNode, templateData: ITreeListTemplateData): void {\n\t\tclearNode(templateData.indent);\n\t\ttemplateData.indentGuidesDisposable.dispose();\n\n\t\tif (!this.shouldRenderIndentGuides) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst disposableStore = new DisposableStore();\n\t\tconst model = this.modelProvider();\n\n\t\twhile (true) {\n\t\t\tconst ref = model.getNodeLocation(node);\n\t\t\tconst parentRef = model.getParentNodeLocation(ref);\n\n\t\t\tif (!parentRef) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tconst parent = model.getNode(parentRef);\n\t\t\tconst guide = $('.indent-guide', { style: `width: ${this.indent}px` });\n\n\t\t\tif (this.activeIndentNodes.has(parent)) {\n\t\t\t\tguide.classList.add('active');\n\t\t\t}\n\n\t\t\tif (templateData.indent.childElementCount === 0) {\n\t\t\t\ttemplateData.indent.appendChild(guide);\n\t\t\t} else {\n\t\t\t\ttemplateData.indent.insertBefore(guide, templateData.indent.firstElementChild);\n\t\t\t}\n\n\t\t\tthis.renderedIndentGuides.add(parent, guide);\n\t\t\tdisposableStore.add(toDisposable(() => this.renderedIndentGuides.delete(parent, guide)));\n\n\t\t\tnode = parent;\n\t\t}\n\n\t\ttemplateData.indentGuidesDisposable = disposableStore;\n\t}\n\n\tprivate _onDidChangeActiveNodes(nodes: ITreeNode[]): void {\n\t\tif (!this.shouldRenderIndentGuides) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst set = new Set>();\n\t\tconst model = this.modelProvider();\n\n\t\tnodes.forEach(node => {\n\t\t\tconst ref = model.getNodeLocation(node);\n\t\t\ttry {\n\t\t\t\tconst parentRef = model.getParentNodeLocation(ref);\n\n\t\t\t\tif (node.collapsible && node.children.length > 0 && !node.collapsed) {\n\t\t\t\t\tset.add(node);\n\t\t\t\t} else if (parentRef) {\n\t\t\t\t\tset.add(model.getNode(parentRef));\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// noop\n\t\t\t}\n\t\t});\n\n\t\tthis.activeIndentNodes.forEach(node => {\n\t\t\tif (!set.has(node)) {\n\t\t\t\tthis.renderedIndentGuides.forEach(node, line => line.classList.remove('active'));\n\t\t\t}\n\t\t});\n\n\t\tset.forEach(node => {\n\t\t\tif (!this.activeIndentNodes.has(node)) {\n\t\t\t\tthis.renderedIndentGuides.forEach(node, line => line.classList.add('active'));\n\t\t\t}\n\t\t});\n\n\t\tthis.activeIndentNodes = set;\n\t}\n\n\tdispose(): void {\n\t\tthis.renderedNodes.clear();\n\t\tthis.renderedElements.clear();\n\t\tthis.indentGuidesDisposable.dispose();\n\t\tdispose(this.disposables);\n\t}\n}\n\nexport type LabelFuzzyScore = { label: string; score: FuzzyScore };\n\nclass FindFilter implements ITreeFilter, IDisposable {\n\tprivate _totalCount = 0;\n\tget totalCount(): number { return this._totalCount; }\n\tprivate _matchCount = 0;\n\tget matchCount(): number { return this._matchCount; }\n\n\tprivate _pattern: string = '';\n\tprivate _lowercasePattern: string = '';\n\tprivate readonly disposables = new DisposableStore();\n\n\tconstructor(\n\t\tprivate tree: AbstractTree,\n\t\tprivate keyboardNavigationLabelProvider: IKeyboardNavigationLabelProvider,\n\t\tprivate _filter?: ITreeFilter\n\t) {\n\t\ttree.onWillRefilter(this.reset, this, this.disposables);\n\t}\n\n\tfilter(element: T, parentVisibility: TreeVisibility): TreeFilterResult {\n\t\tlet visibility = TreeVisibility.Visible;\n\n\t\tif (this._filter) {\n\t\t\tconst result = this._filter.filter(element, parentVisibility);\n\n\t\t\tif (typeof result === 'boolean') {\n\t\t\t\tvisibility = result ? TreeVisibility.Visible : TreeVisibility.Hidden;\n\t\t\t} else if (isFilterResult(result)) {\n\t\t\t\tvisibility = getVisibleState(result.visibility);\n\t\t\t} else {\n\t\t\t\tvisibility = result;\n\t\t\t}\n\n\t\t\tif (visibility === TreeVisibility.Hidden) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\tthis._totalCount++;\n\n\t\tif (!this._pattern) {\n\t\t\tthis._matchCount++;\n\t\t\treturn { data: FuzzyScore.Default, visibility };\n\t\t}\n\n\t\tconst label = this.keyboardNavigationLabelProvider.getKeyboardNavigationLabel(element);\n\t\tconst labels = Array.isArray(label) ? label : [label];\n\n\t\tfor (const l of labels) {\n\t\t\tconst labelStr: string = l && l.toString();\n\t\t\tif (typeof labelStr === 'undefined') {\n\t\t\t\treturn { data: FuzzyScore.Default, visibility };\n\t\t\t}\n\n\t\t\tlet score: FuzzyScore | undefined;\n\t\t\tif (this.tree.findMatchType === TreeFindMatchType.Contiguous) {\n\t\t\t\tconst index = labelStr.toLowerCase().indexOf(this._lowercasePattern);\n\t\t\t\tif (index > -1) {\n\t\t\t\t\tscore = [Number.MAX_SAFE_INTEGER, 0];\n\t\t\t\t\tfor (let i = this._lowercasePattern.length; i > 0; i--) {\n\t\t\t\t\t\tscore.push(index + i - 1);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tscore = fuzzyScore(this._pattern, this._lowercasePattern, 0, labelStr, labelStr.toLowerCase(), 0, { firstMatchCanBeWeak: true, boostFullMatch: true });\n\t\t\t}\n\t\t\tif (score) {\n\t\t\t\tthis._matchCount++;\n\t\t\t\treturn labels.length === 1 ?\n\t\t\t\t\t{ data: score, visibility } :\n\t\t\t\t\t{ data: { label: labelStr, score: score }, visibility };\n\t\t\t}\n\t\t}\n\n\t\tif (this.tree.findMode === TreeFindMode.Filter) {\n\t\t\tif (typeof this.tree.options.defaultFindVisibility === 'number') {\n\t\t\t\treturn this.tree.options.defaultFindVisibility;\n\t\t\t} else if (this.tree.options.defaultFindVisibility) {\n\t\t\t\treturn this.tree.options.defaultFindVisibility(element);\n\t\t\t} else {\n\t\t\t\treturn TreeVisibility.Recurse;\n\t\t\t}\n\t\t} else {\n\t\t\treturn { data: FuzzyScore.Default, visibility };\n\t\t}\n\t}\n\n\tprivate reset(): void {\n\t\tthis._totalCount = 0;\n\t\tthis._matchCount = 0;\n\t}\n\n\tdispose(): void {\n\t\tdispose(this.disposables);\n\t}\n}\n\nexport interface ITreeFindToggleOpts {\n\treadonly isChecked: boolean;\n\treadonly inputActiveOptionBorder: string | undefined;\n\treadonly inputActiveOptionForeground: string | undefined;\n\treadonly inputActiveOptionBackground: string | undefined;\n\treadonly hoverDelegate?: IHoverDelegate;\n}\n\nexport class ModeToggle extends Toggle {\n\tconstructor(opts: ITreeFindToggleOpts) {\n\t\tsuper({\n\t\t\ticon: Codicon.listFilter,\n\t\t\ttitle: localize('filter', \"Filter\"),\n\t\t\tisChecked: opts.isChecked ?? false,\n\t\t\thoverDelegate: opts.hoverDelegate ?? getDefaultHoverDelegate('element'),\n\t\t\tinputActiveOptionBorder: opts.inputActiveOptionBorder,\n\t\t\tinputActiveOptionForeground: opts.inputActiveOptionForeground,\n\t\t\tinputActiveOptionBackground: opts.inputActiveOptionBackground\n\t\t});\n\t}\n}\n\nexport class FuzzyToggle extends Toggle {\n\tconstructor(opts: ITreeFindToggleOpts) {\n\t\tsuper({\n\t\t\ticon: Codicon.searchFuzzy,\n\t\t\ttitle: localize('fuzzySearch', \"Fuzzy Match\"),\n\t\t\tisChecked: opts.isChecked ?? false,\n\t\t\thoverDelegate: opts.hoverDelegate ?? getDefaultHoverDelegate('element'),\n\t\t\tinputActiveOptionBorder: opts.inputActiveOptionBorder,\n\t\t\tinputActiveOptionForeground: opts.inputActiveOptionForeground,\n\t\t\tinputActiveOptionBackground: opts.inputActiveOptionBackground\n\t\t});\n\t}\n}\n\nexport interface IFindWidgetStyles {\n\tlistFilterWidgetBackground: string | undefined;\n\tlistFilterWidgetOutline: string | undefined;\n\tlistFilterWidgetNoMatchesOutline: string | undefined;\n\tlistFilterWidgetShadow: string | undefined;\n\treadonly toggleStyles: IToggleStyles;\n\treadonly inputBoxStyles: IInputBoxStyles;\n}\n\nexport interface IFindWidgetOptions {\n\treadonly history?: string[];\n\treadonly styles?: IFindWidgetStyles;\n}\n\nconst unthemedFindWidgetStyles: IFindWidgetStyles = {\n\tinputBoxStyles: unthemedInboxStyles,\n\ttoggleStyles: unthemedToggleStyles,\n\tlistFilterWidgetBackground: undefined,\n\tlistFilterWidgetNoMatchesOutline: undefined,\n\tlistFilterWidgetOutline: undefined,\n\tlistFilterWidgetShadow: undefined\n};\n\nexport enum TreeFindMode {\n\tHighlight,\n\tFilter\n}\n\nexport enum TreeFindMatchType {\n\tFuzzy,\n\tContiguous\n}\n\nclass FindWidget extends Disposable {\n\n\tprivate readonly elements = h('.monaco-tree-type-filter', [\n\t\th('.monaco-tree-type-filter-grab.codicon.codicon-debug-gripper@grab', { tabIndex: 0 }),\n\t\th('.monaco-tree-type-filter-input@findInput'),\n\t\th('.monaco-tree-type-filter-actionbar@actionbar'),\n\t]);\n\n\tset mode(mode: TreeFindMode) {\n\t\tthis.modeToggle.checked = mode === TreeFindMode.Filter;\n\t\tthis.findInput.inputBox.setPlaceHolder(mode === TreeFindMode.Filter ? localize('type to filter', \"Type to filter\") : localize('type to search', \"Type to search\"));\n\t}\n\n\tset matchType(matchType: TreeFindMatchType) {\n\t\tthis.matchTypeToggle.checked = matchType === TreeFindMatchType.Fuzzy;\n\t}\n\n\tprivate readonly modeToggle: ModeToggle;\n\tprivate readonly matchTypeToggle: FuzzyToggle;\n\tprivate readonly findInput: FindInput;\n\tprivate readonly actionbar: ActionBar;\n\tprivate width = 0;\n\tprivate right = 0;\n\tprivate top = 0;\n\n\treadonly _onDidDisable = new Emitter();\n\treadonly onDidChangeValue: Event;\n\treadonly onDidChangeMode: Event;\n\treadonly onDidChangeMatchType: Event;\n\n\tconstructor(\n\t\tcontainer: HTMLElement,\n\t\tprivate tree: AbstractTree,\n\t\tcontextViewProvider: IContextViewProvider,\n\t\tmode: TreeFindMode,\n\t\tmatchType: TreeFindMatchType,\n\t\toptions?: IFindWidgetOptions\n\t) {\n\t\tsuper();\n\n\t\tcontainer.appendChild(this.elements.root);\n\t\tthis._register(toDisposable(() => container.removeChild(this.elements.root)));\n\n\t\tconst styles = options?.styles ?? unthemedFindWidgetStyles;\n\n\t\tif (styles.listFilterWidgetBackground) {\n\t\t\tthis.elements.root.style.backgroundColor = styles.listFilterWidgetBackground;\n\t\t}\n\n\t\tif (styles.listFilterWidgetShadow) {\n\t\t\tthis.elements.root.style.boxShadow = `0 0 8px 2px ${styles.listFilterWidgetShadow}`;\n\t\t}\n\n\t\tconst toggleHoverDelegate = this._register(createInstantHoverDelegate());\n\t\tthis.modeToggle = this._register(new ModeToggle({ ...styles.toggleStyles, isChecked: mode === TreeFindMode.Filter, hoverDelegate: toggleHoverDelegate }));\n\t\tthis.matchTypeToggle = this._register(new FuzzyToggle({ ...styles.toggleStyles, isChecked: matchType === TreeFindMatchType.Fuzzy, hoverDelegate: toggleHoverDelegate }));\n\t\tthis.onDidChangeMode = Event.map(this.modeToggle.onChange, () => this.modeToggle.checked ? TreeFindMode.Filter : TreeFindMode.Highlight, this._store);\n\t\tthis.onDidChangeMatchType = Event.map(this.matchTypeToggle.onChange, () => this.matchTypeToggle.checked ? TreeFindMatchType.Fuzzy : TreeFindMatchType.Contiguous, this._store);\n\n\t\tthis.findInput = this._register(new FindInput(this.elements.findInput, contextViewProvider, {\n\t\t\tlabel: localize('type to search', \"Type to search\"),\n\t\t\tadditionalToggles: [this.modeToggle, this.matchTypeToggle],\n\t\t\tshowCommonFindToggles: false,\n\t\t\tinputBoxStyles: styles.inputBoxStyles,\n\t\t\ttoggleStyles: styles.toggleStyles,\n\t\t\thistory: options?.history\n\t\t}));\n\n\t\tthis.actionbar = this._register(new ActionBar(this.elements.actionbar));\n\t\tthis.mode = mode;\n\n\t\tconst emitter = this._register(new DomEmitter(this.findInput.inputBox.inputElement, 'keydown'));\n\t\tconst onKeyDown = Event.chain(emitter.event, $ => $.map(e => new StandardKeyboardEvent(e)));\n\n\t\tthis._register(onKeyDown((e): any => {\n\t\t\t// Using equals() so we reserve modified keys for future use\n\t\t\tif (e.equals(KeyCode.Enter)) {\n\t\t\t\t// This is the only keyboard way to return to the tree from a history item that isn't the last one\n\t\t\t\te.preventDefault();\n\t\t\t\te.stopPropagation();\n\t\t\t\tthis.findInput.inputBox.addToHistory();\n\t\t\t\tthis.tree.domFocus();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (e.equals(KeyCode.DownArrow)) {\n\t\t\t\te.preventDefault();\n\t\t\t\te.stopPropagation();\n\t\t\t\tif (this.findInput.inputBox.isAtLastInHistory() || this.findInput.inputBox.isNowhereInHistory()) {\n\t\t\t\t\t// Retain original pre-history DownArrow behavior\n\t\t\t\t\tthis.findInput.inputBox.addToHistory();\n\t\t\t\t\tthis.tree.domFocus();\n\t\t\t\t} else {\n\t\t\t\t\t// Downward through history\n\t\t\t\t\tthis.findInput.inputBox.showNextValue();\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (e.equals(KeyCode.UpArrow)) {\n\t\t\t\te.preventDefault();\n\t\t\t\te.stopPropagation();\n\t\t\t\t// Upward through history\n\t\t\t\tthis.findInput.inputBox.showPreviousValue();\n\t\t\t\treturn;\n\t\t\t}\n\t\t}));\n\n\t\tconst closeAction = this._register(new Action('close', localize('close', \"Close\"), 'codicon codicon-close', true, () => this.dispose()));\n\t\tthis.actionbar.push(closeAction, { icon: true, label: false });\n\n\t\tconst onGrabMouseDown = this._register(new DomEmitter(this.elements.grab, 'mousedown'));\n\n\t\tthis._register(onGrabMouseDown.event(e => {\n\t\t\tconst disposables = new DisposableStore();\n\t\t\tconst onWindowMouseMove = disposables.add(new DomEmitter(getWindow(e), 'mousemove'));\n\t\t\tconst onWindowMouseUp = disposables.add(new DomEmitter(getWindow(e), 'mouseup'));\n\n\t\t\tconst startRight = this.right;\n\t\t\tconst startX = e.pageX;\n\t\t\tconst startTop = this.top;\n\t\t\tconst startY = e.pageY;\n\t\t\tthis.elements.grab.classList.add('grabbing');\n\n\t\t\tconst transition = this.elements.root.style.transition;\n\t\t\tthis.elements.root.style.transition = 'unset';\n\n\t\t\tconst update = (e: MouseEvent) => {\n\t\t\t\tconst deltaX = e.pageX - startX;\n\t\t\t\tthis.right = startRight - deltaX;\n\t\t\t\tconst deltaY = e.pageY - startY;\n\t\t\t\tthis.top = startTop + deltaY;\n\t\t\t\tthis.layout();\n\t\t\t};\n\n\t\t\tdisposables.add(onWindowMouseMove.event(update));\n\t\t\tdisposables.add(onWindowMouseUp.event(e => {\n\t\t\t\tupdate(e);\n\t\t\t\tthis.elements.grab.classList.remove('grabbing');\n\t\t\t\tthis.elements.root.style.transition = transition;\n\t\t\t\tdisposables.dispose();\n\t\t\t}));\n\t\t}));\n\n\t\tconst onGrabKeyDown = Event.chain(this._register(new DomEmitter(this.elements.grab, 'keydown')).event, $ => $.map(e => new StandardKeyboardEvent(e)));\n\n\t\tthis._register(onGrabKeyDown((e): any => {\n\t\t\tlet right: number | undefined;\n\t\t\tlet top: number | undefined;\n\n\t\t\tif (e.keyCode === KeyCode.LeftArrow) {\n\t\t\t\tright = Number.POSITIVE_INFINITY;\n\t\t\t} else if (e.keyCode === KeyCode.RightArrow) {\n\t\t\t\tright = 0;\n\t\t\t} else if (e.keyCode === KeyCode.Space) {\n\t\t\t\tright = this.right === 0 ? Number.POSITIVE_INFINITY : 0;\n\t\t\t}\n\n\t\t\tif (e.keyCode === KeyCode.UpArrow) {\n\t\t\t\ttop = 0;\n\t\t\t} else if (e.keyCode === KeyCode.DownArrow) {\n\t\t\t\ttop = Number.POSITIVE_INFINITY;\n\t\t\t}\n\n\t\t\tif (right !== undefined) {\n\t\t\t\te.preventDefault();\n\t\t\t\te.stopPropagation();\n\t\t\t\tthis.right = right;\n\t\t\t\tthis.layout();\n\t\t\t}\n\n\t\t\tif (top !== undefined) {\n\t\t\t\te.preventDefault();\n\t\t\t\te.stopPropagation();\n\t\t\t\tthis.top = top;\n\t\t\t\tconst transition = this.elements.root.style.transition;\n\t\t\t\tthis.elements.root.style.transition = 'unset';\n\t\t\t\tthis.layout();\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\tthis.elements.root.style.transition = transition;\n\t\t\t\t}, 0);\n\t\t\t}\n\t\t}));\n\n\t\tthis.onDidChangeValue = this.findInput.onDidChange;\n\t}\n\n\tlayout(width: number = this.width): void {\n\t\tthis.width = width;\n\t\tthis.right = clamp(this.right, 0, Math.max(0, width - 212));\n\t\tthis.elements.root.style.right = `${this.right}px`;\n\t\tthis.top = clamp(this.top, 0, 24);\n\t\tthis.elements.root.style.top = `${this.top}px`;\n\t}\n\n\tshowMessage(message: IMessage): void {\n\t\tthis.findInput.showMessage(message);\n\t}\n\n\tclearMessage(): void {\n\t\tthis.findInput.clearMessage();\n\t}\n\n\toverride async dispose(): Promise {\n\t\tthis._onDidDisable.fire();\n\t\tthis.elements.root.classList.add('disabled');\n\t\tawait timeout(300);\n\t\tsuper.dispose();\n\t}\n}\n\ninterface IFindControllerOptions extends IFindWidgetOptions { }\n\nclass FindController implements IDisposable {\n\n\tprivate _history: string[] | undefined;\n\n\tprivate _pattern = '';\n\tget pattern(): string { return this._pattern; }\n\n\tprivate _mode: TreeFindMode;\n\tget mode(): TreeFindMode { return this._mode; }\n\tset mode(mode: TreeFindMode) {\n\t\tif (mode === this._mode) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._mode = mode;\n\n\t\tif (this.widget) {\n\t\t\tthis.widget.mode = this._mode;\n\t\t}\n\n\t\tthis.tree.refilter();\n\t\tthis.render();\n\t\tthis._onDidChangeMode.fire(mode);\n\t}\n\n\tprivate _matchType: TreeFindMatchType;\n\tget matchType(): TreeFindMatchType { return this._matchType; }\n\tset matchType(matchType: TreeFindMatchType) {\n\t\tif (matchType === this._matchType) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._matchType = matchType;\n\n\t\tif (this.widget) {\n\t\t\tthis.widget.matchType = this._matchType;\n\t\t}\n\n\t\tthis.tree.refilter();\n\t\tthis.render();\n\t\tthis._onDidChangeMatchType.fire(matchType);\n\t}\n\n\tprivate widget: FindWidget | undefined;\n\tprivate width = 0;\n\n\tprivate readonly _onDidChangeMode = new Emitter();\n\treadonly onDidChangeMode = this._onDidChangeMode.event;\n\n\tprivate readonly _onDidChangeMatchType = new Emitter();\n\treadonly onDidChangeMatchType = this._onDidChangeMatchType.event;\n\n\tprivate readonly _onDidChangePattern = new Emitter();\n\n\tprivate readonly _onDidChangeOpenState = new Emitter();\n\treadonly onDidChangeOpenState = this._onDidChangeOpenState.event;\n\n\tprivate readonly enabledDisposables = new DisposableStore();\n\tprivate readonly disposables = new DisposableStore();\n\n\tconstructor(\n\t\tprivate tree: AbstractTree,\n\t\tmodel: ITreeModel,\n\t\tprivate view: List>,\n\t\tprivate filter: FindFilter,\n\t\tprivate readonly contextViewProvider: IContextViewProvider,\n\t\tprivate readonly options: IFindControllerOptions = {}\n\t) {\n\t\tthis._mode = tree.options.defaultFindMode ?? TreeFindMode.Highlight;\n\t\tthis._matchType = tree.options.defaultFindMatchType ?? TreeFindMatchType.Fuzzy;\n\t\tmodel.onDidSplice(this.onDidSpliceModel, this, this.disposables);\n\t}\n\n\tupdateOptions(optionsUpdate: IAbstractTreeOptionsUpdate = {}): void {\n\t\tif (optionsUpdate.defaultFindMode !== undefined) {\n\t\t\tthis.mode = optionsUpdate.defaultFindMode;\n\t\t}\n\n\t\tif (optionsUpdate.defaultFindMatchType !== undefined) {\n\t\t\tthis.matchType = optionsUpdate.defaultFindMatchType;\n\t\t}\n\t}\n\n\tprivate onDidSpliceModel(): void {\n\t\tif (!this.widget || this.pattern.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.tree.refilter();\n\t\tthis.render();\n\t}\n\n\tprivate render(): void {\n\t\tconst noMatches = this.filter.totalCount > 0 && this.filter.matchCount === 0;\n\n\t\tif (this.pattern && noMatches) {\n\t\t\tif (this.tree.options.showNotFoundMessage ?? true) {\n\t\t\t\tthis.widget?.showMessage({ type: MessageType.WARNING, content: localize('not found', \"No elements found.\") });\n\t\t\t} else {\n\t\t\t\tthis.widget?.showMessage({ type: MessageType.WARNING });\n\t\t\t}\n\t\t} else {\n\t\t\tthis.widget?.clearMessage();\n\t\t}\n\t}\n\n\tshouldAllowFocus(node: ITreeNode): boolean {\n\t\tif (!this.widget || !this.pattern) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif (this.filter.totalCount > 0 && this.filter.matchCount <= 1) {\n\t\t\treturn true;\n\t\t}\n\n\t\treturn !FuzzyScore.isDefault(node.filterData as any as FuzzyScore);\n\t}\n\n\tlayout(width: number): void {\n\t\tthis.width = width;\n\t\tthis.widget?.layout(width);\n\t}\n\n\tdispose() {\n\t\tthis._history = undefined;\n\t\tthis._onDidChangePattern.dispose();\n\t\tthis.enabledDisposables.dispose();\n\t\tthis.disposables.dispose();\n\t}\n}\n\nexport interface StickyScrollNode {\n\treadonly node: ITreeNode;\n\treadonly startIndex: number;\n\treadonly endIndex: number;\n\treadonly height: number;\n\treadonly position: number;\n}\n\nfunction stickyScrollNodeStateEquals(node1: StickyScrollNode, node2: StickyScrollNode) {\n\treturn node1.position === node2.position && stickyScrollNodeEquals(node1, node2);\n}\n\nfunction stickyScrollNodeEquals(node1: StickyScrollNode, node2: StickyScrollNode) {\n\treturn node1.node.element === node2.node.element &&\n\t\tnode1.startIndex === node2.startIndex &&\n\t\tnode1.height === node2.height &&\n\t\tnode1.endIndex === node2.endIndex;\n}\n\nclass StickyScrollState {\n\n\tconstructor(\n\t\treadonly stickyNodes: StickyScrollNode[] = []\n\t) { }\n\n\tget count(): number { return this.stickyNodes.length; }\n\n\tequal(state: StickyScrollState): boolean {\n\t\treturn equals(this.stickyNodes, state.stickyNodes, stickyScrollNodeStateEquals);\n\t}\n\n\tlastNodePartiallyVisible(): boolean {\n\t\tif (this.count === 0) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst lastStickyNode = this.stickyNodes[this.count - 1];\n\t\tif (this.count === 1) {\n\t\t\treturn lastStickyNode.position !== 0;\n\t\t}\n\n\t\tconst secondLastStickyNode = this.stickyNodes[this.count - 2];\n\t\treturn secondLastStickyNode.position + secondLastStickyNode.height !== lastStickyNode.position;\n\t}\n\n\tanimationStateChanged(previousState: StickyScrollState): boolean {\n\t\tif (!equals(this.stickyNodes, previousState.stickyNodes, stickyScrollNodeEquals)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (this.count === 0) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst lastStickyNode = this.stickyNodes[this.count - 1];\n\t\tconst previousLastStickyNode = previousState.stickyNodes[previousState.count - 1];\n\n\t\treturn lastStickyNode.position !== previousLastStickyNode.position;\n\t}\n}\n\nexport interface IStickyScrollDelegate {\n\tconstrainStickyScrollNodes(stickyNodes: StickyScrollNode[], stickyScrollMaxItemCount: number, maxWidgetHeight: number): StickyScrollNode[];\n}\n\nclass DefaultStickyScrollDelegate implements IStickyScrollDelegate {\n\n\tconstrainStickyScrollNodes(stickyNodes: StickyScrollNode[], stickyScrollMaxItemCount: number, maxWidgetHeight: number): StickyScrollNode[] {\n\n\t\tfor (let i = 0; i < stickyNodes.length; i++) {\n\t\t\tconst stickyNode = stickyNodes[i];\n\t\t\tconst stickyNodeBottom = stickyNode.position + stickyNode.height;\n\t\t\tif (stickyNodeBottom > maxWidgetHeight || i >= stickyScrollMaxItemCount) {\n\t\t\t\treturn stickyNodes.slice(0, i);\n\t\t\t}\n\t\t}\n\n\t\treturn stickyNodes;\n\t}\n}\n\nclass StickyScrollController extends Disposable {\n\n\treadonly onDidChangeHasFocus: Event;\n\treadonly onContextMenu: Event>;\n\n\tprivate readonly stickyScrollDelegate: IStickyScrollDelegate;\n\n\tprivate stickyScrollMaxItemCount: number;\n\tprivate readonly maxWidgetViewRatio = 0.4;\n\n\tprivate readonly _widget: StickyScrollWidget;\n\n\tconstructor(\n\t\tprivate readonly tree: AbstractTree,\n\t\tprivate readonly model: ITreeModel,\n\t\tprivate readonly view: List>,\n\t\trenderers: TreeRenderer[],\n\t\tprivate readonly treeDelegate: IListVirtualDelegate>,\n\t\toptions: IAbstractTreeOptions = {},\n\t) {\n\t\tsuper();\n\n\t\tconst stickyScrollOptions = this.validateStickySettings(options);\n\t\tthis.stickyScrollMaxItemCount = stickyScrollOptions.stickyScrollMaxItemCount;\n\n\t\tthis.stickyScrollDelegate = options.stickyScrollDelegate ?? new DefaultStickyScrollDelegate();\n\n\t\tthis._widget = this._register(new StickyScrollWidget(view.getScrollableElement(), view, tree, renderers, treeDelegate, options.accessibilityProvider));\n\t\tthis.onDidChangeHasFocus = this._widget.onDidChangeHasFocus;\n\t\tthis.onContextMenu = this._widget.onContextMenu;\n\n\t\tthis._register(view.onDidScroll(() => this.update()));\n\t\tthis._register(view.onDidChangeContentHeight(() => this.update()));\n\t\tthis._register(tree.onDidChangeCollapseState(() => this.update()));\n\n\t\tthis.update();\n\t}\n\n\tget height(): number {\n\t\treturn this._widget.height;\n\t}\n\n\tprivate getNodeAtHeight(height: number): ITreeNode | undefined {\n\t\tlet index;\n\t\tif (height === 0) {\n\t\t\tindex = this.view.firstVisibleIndex;\n\t\t} else {\n\t\t\tindex = this.view.indexAt(height + this.view.scrollTop);\n\t\t}\n\n\t\tif (index < 0 || index >= this.view.length) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\treturn this.view.element(index);\n\t}\n\n\tprivate update() {\n\t\tconst firstVisibleNode = this.getNodeAtHeight(0);\n\n\t\t// Don't render anything if there are no elements\n\t\tif (!firstVisibleNode || this.tree.scrollTop === 0) {\n\t\t\tthis._widget.setState(undefined);\n\t\t\treturn;\n\t\t}\n\n\t\tconst stickyState = this.findStickyState(firstVisibleNode);\n\t\tthis._widget.setState(stickyState);\n\t}\n\n\tprivate findStickyState(firstVisibleNode: ITreeNode): StickyScrollState | undefined {\n\t\tconst stickyNodes: StickyScrollNode[] = [];\n\t\tlet firstVisibleNodeUnderWidget: ITreeNode | undefined = firstVisibleNode;\n\t\tlet stickyNodesHeight = 0;\n\n\t\tlet nextStickyNode = this.getNextStickyNode(firstVisibleNodeUnderWidget, undefined, stickyNodesHeight);\n\t\twhile (nextStickyNode) {\n\n\t\t\tstickyNodes.push(nextStickyNode);\n\t\t\tstickyNodesHeight += nextStickyNode.height;\n\n\t\t\tif (stickyNodes.length <= this.stickyScrollMaxItemCount) {\n\t\t\t\tfirstVisibleNodeUnderWidget = this.getNextVisibleNode(nextStickyNode);\n\t\t\t\tif (!firstVisibleNodeUnderWidget) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tnextStickyNode = this.getNextStickyNode(firstVisibleNodeUnderWidget, nextStickyNode.node, stickyNodesHeight);\n\t\t}\n\n\t\tconst contrainedStickyNodes = this.constrainStickyNodes(stickyNodes);\n\t\treturn contrainedStickyNodes.length ? new StickyScrollState(contrainedStickyNodes) : undefined;\n\t}\n\n\tprivate getNextVisibleNode(previousStickyNode: StickyScrollNode): ITreeNode | undefined {\n\t\treturn this.getNodeAtHeight(previousStickyNode.position + previousStickyNode.height);\n\t}\n\n\tprivate getNextStickyNode(firstVisibleNodeUnderWidget: ITreeNode, previousStickyNode: ITreeNode | undefined, stickyNodesHeight: number): StickyScrollNode | undefined {\n\t\tconst nextStickyNode = this.getAncestorUnderPrevious(firstVisibleNodeUnderWidget, previousStickyNode);\n\t\tif (!nextStickyNode) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (nextStickyNode === firstVisibleNodeUnderWidget) {\n\t\t\tif (!this.nodeIsUncollapsedParent(firstVisibleNodeUnderWidget)) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\n\t\t\tif (this.nodeTopAlignsWithStickyNodesBottom(firstVisibleNodeUnderWidget, stickyNodesHeight)) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t}\n\n\t\treturn this.createStickyScrollNode(nextStickyNode, stickyNodesHeight);\n\t}\n\n\tprivate nodeTopAlignsWithStickyNodesBottom(node: ITreeNode, stickyNodesHeight: number): boolean {\n\t\tconst nodeIndex = this.getNodeIndex(node);\n\t\tconst elementTop = this.view.getElementTop(nodeIndex);\n\t\tconst stickyPosition = stickyNodesHeight;\n\t\treturn this.view.scrollTop === elementTop - stickyPosition;\n\t}\n\n\tprivate createStickyScrollNode(node: ITreeNode, currentStickyNodesHeight: number): StickyScrollNode {\n\t\tconst height = this.treeDelegate.getHeight(node);\n\t\tconst { startIndex, endIndex } = this.getNodeRange(node);\n\n\t\tconst position = this.calculateStickyNodePosition(endIndex, currentStickyNodesHeight, height);\n\n\t\treturn { node, position, height, startIndex, endIndex };\n\t}\n\n\tprivate getAncestorUnderPrevious(node: ITreeNode, previousAncestor: ITreeNode | undefined = undefined): ITreeNode | undefined {\n\t\tlet currentAncestor: ITreeNode = node;\n\t\tlet parentOfcurrentAncestor: ITreeNode | undefined = this.getParentNode(currentAncestor);\n\n\t\twhile (parentOfcurrentAncestor) {\n\t\t\tif (parentOfcurrentAncestor === previousAncestor) {\n\t\t\t\treturn currentAncestor;\n\t\t\t}\n\t\t\tcurrentAncestor = parentOfcurrentAncestor;\n\t\t\tparentOfcurrentAncestor = this.getParentNode(currentAncestor);\n\t\t}\n\n\t\tif (previousAncestor === undefined) {\n\t\t\treturn currentAncestor;\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\tprivate calculateStickyNodePosition(lastDescendantIndex: number, stickyRowPositionTop: number, stickyNodeHeight: number): number {\n\t\tlet lastChildRelativeTop = this.view.getRelativeTop(lastDescendantIndex);\n\n\t\t// If the last descendant is only partially visible at the top of the view, getRelativeTop() returns null\n\t\t// In that case, utilize the next node's relative top to calculate the sticky node's position\n\t\tif (lastChildRelativeTop === null && this.view.firstVisibleIndex === lastDescendantIndex && lastDescendantIndex + 1 < this.view.length) {\n\t\t\tconst nodeHeight = this.treeDelegate.getHeight(this.view.element(lastDescendantIndex));\n\t\t\tconst nextNodeRelativeTop = this.view.getRelativeTop(lastDescendantIndex + 1);\n\t\t\tlastChildRelativeTop = nextNodeRelativeTop ? nextNodeRelativeTop - nodeHeight / this.view.renderHeight : null;\n\t\t}\n\n\t\tif (lastChildRelativeTop === null) {\n\t\t\treturn stickyRowPositionTop;\n\t\t}\n\n\t\tconst lastChildNode = this.view.element(lastDescendantIndex);\n\t\tconst lastChildHeight = this.treeDelegate.getHeight(lastChildNode);\n\t\tconst topOfLastChild = lastChildRelativeTop * this.view.renderHeight;\n\t\tconst bottomOfLastChild = topOfLastChild + lastChildHeight;\n\n\t\tif (stickyRowPositionTop + stickyNodeHeight > bottomOfLastChild && stickyRowPositionTop <= bottomOfLastChild) {\n\t\t\treturn bottomOfLastChild - stickyNodeHeight;\n\t\t}\n\n\t\treturn stickyRowPositionTop;\n\t}\n\n\tprivate constrainStickyNodes(stickyNodes: StickyScrollNode[]): StickyScrollNode[] {\n\t\tif (stickyNodes.length === 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\t// Check if sticky nodes need to be constrained\n\t\tconst maximumStickyWidgetHeight = this.view.renderHeight * this.maxWidgetViewRatio;\n\t\tconst lastStickyNode = stickyNodes[stickyNodes.length - 1];\n\t\tif (stickyNodes.length <= this.stickyScrollMaxItemCount && lastStickyNode.position + lastStickyNode.height <= maximumStickyWidgetHeight) {\n\t\t\treturn stickyNodes;\n\t\t}\n\n\t\t// constrain sticky nodes\n\t\tconst constrainedStickyNodes = this.stickyScrollDelegate.constrainStickyScrollNodes(stickyNodes, this.stickyScrollMaxItemCount, maximumStickyWidgetHeight);\n\n\t\tif (!constrainedStickyNodes.length) {\n\t\t\treturn [];\n\t\t}\n\n\t\t// Validate constraints\n\t\tconst lastConstrainedStickyNode = constrainedStickyNodes[constrainedStickyNodes.length - 1];\n\t\tif (constrainedStickyNodes.length > this.stickyScrollMaxItemCount || lastConstrainedStickyNode.position + lastConstrainedStickyNode.height > maximumStickyWidgetHeight) {\n\t\t\tthrow new Error('stickyScrollDelegate violates constraints');\n\t\t}\n\n\t\treturn constrainedStickyNodes;\n\t}\n\n\tprivate getParentNode(node: ITreeNode): ITreeNode | undefined {\n\t\tconst nodeLocation = this.model.getNodeLocation(node);\n\t\tconst parentLocation = this.model.getParentNodeLocation(nodeLocation);\n\t\treturn parentLocation ? this.model.getNode(parentLocation) : undefined;\n\t}\n\n\tprivate nodeIsUncollapsedParent(node: ITreeNode): boolean {\n\t\tconst nodeLocation = this.model.getNodeLocation(node);\n\t\treturn this.model.getListRenderCount(nodeLocation) > 1;\n\t}\n\n\tprivate getNodeIndex(node: ITreeNode): number {\n\t\tconst nodeLocation = this.model.getNodeLocation(node);\n\t\tconst nodeIndex = this.model.getListIndex(nodeLocation);\n\t\treturn nodeIndex;\n\t}\n\n\tprivate getNodeRange(node: ITreeNode): { startIndex: number; endIndex: number } {\n\t\tconst nodeLocation = this.model.getNodeLocation(node);\n\t\tconst startIndex = this.model.getListIndex(nodeLocation);\n\n\t\tif (startIndex < 0) {\n\t\t\tthrow new Error('Node not found in tree');\n\t\t}\n\n\t\tconst renderCount = this.model.getListRenderCount(nodeLocation);\n\t\tconst endIndex = startIndex + renderCount - 1;\n\n\t\treturn { startIndex, endIndex };\n\t}\n\n\tnodePositionTopBelowWidget(node: ITreeNode): number {\n\t\tconst ancestors = [];\n\t\tlet currentAncestor = this.getParentNode(node);\n\t\twhile (currentAncestor) {\n\t\t\tancestors.push(currentAncestor);\n\t\t\tcurrentAncestor = this.getParentNode(currentAncestor);\n\t\t}\n\n\t\tlet widgetHeight = 0;\n\t\tfor (let i = 0; i < ancestors.length && i < this.stickyScrollMaxItemCount; i++) {\n\t\t\twidgetHeight += this.treeDelegate.getHeight(ancestors[i]);\n\t\t}\n\t\treturn widgetHeight;\n\t}\n\n\tdomFocus(): void {\n\t\tthis._widget.domFocus();\n\t}\n\n\t// Whether sticky scroll was the last focused part in the tree or not\n\tfocusedLast(): boolean {\n\t\treturn this._widget.focusedLast();\n\t}\n\n\tupdateOptions(optionsUpdate: IAbstractTreeOptionsUpdate = {}): void {\n\t\tif (!optionsUpdate.stickyScrollMaxItemCount) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst validatedOptions = this.validateStickySettings(optionsUpdate);\n\t\tif (this.stickyScrollMaxItemCount !== validatedOptions.stickyScrollMaxItemCount) {\n\t\t\tthis.stickyScrollMaxItemCount = validatedOptions.stickyScrollMaxItemCount;\n\t\t\tthis.update();\n\t\t}\n\t}\n\n\tvalidateStickySettings(options: IAbstractTreeOptionsUpdate): { stickyScrollMaxItemCount: number } {\n\t\tlet stickyScrollMaxItemCount = 7;\n\t\tif (typeof options.stickyScrollMaxItemCount === 'number') {\n\t\t\tstickyScrollMaxItemCount = Math.max(options.stickyScrollMaxItemCount, 1);\n\t\t}\n\t\treturn { stickyScrollMaxItemCount };\n\t}\n}\n\nclass StickyScrollWidget implements IDisposable {\n\n\tprivate readonly _rootDomNode: HTMLElement;\n\tprivate _previousState: StickyScrollState | undefined;\n\tprivate _previousElements: HTMLElement[] = [];\n\tprivate readonly _previousStateDisposables: DisposableStore = new DisposableStore();\n\n\tprivate stickyScrollFocus: StickyScrollFocus;\n\treadonly onDidChangeHasFocus: Event;\n\treadonly onContextMenu: Event>;\n\n\tconstructor(\n\t\tcontainer: HTMLElement,\n\t\tprivate readonly view: List>,\n\t\tprivate readonly tree: AbstractTree,\n\t\tprivate readonly treeRenderers: TreeRenderer[],\n\t\tprivate readonly treeDelegate: IListVirtualDelegate>,\n\t\tprivate readonly accessibilityProvider: IListAccessibilityProvider | undefined,\n\t) {\n\n\t\tthis._rootDomNode = $('.monaco-tree-sticky-container.empty');\n\t\tcontainer.appendChild(this._rootDomNode);\n\n\t\tconst shadow = $('.monaco-tree-sticky-container-shadow');\n\t\tthis._rootDomNode.appendChild(shadow);\n\n\t\tthis.stickyScrollFocus = new StickyScrollFocus(this._rootDomNode, view);\n\t\tthis.onDidChangeHasFocus = this.stickyScrollFocus.onDidChangeHasFocus;\n\t\tthis.onContextMenu = this.stickyScrollFocus.onContextMenu;\n\t}\n\n\tget height(): number {\n\t\tif (!this._previousState) {\n\t\t\treturn 0;\n\t\t}\n\t\tconst lastElement = this._previousState.stickyNodes[this._previousState.count - 1];\n\t\treturn lastElement.position + lastElement.height;\n\t}\n\n\tsetState(state: StickyScrollState | undefined): void {\n\n\t\tconst wasVisible = !!this._previousState && this._previousState.count > 0;\n\t\tconst isVisible = !!state && state.count > 0;\n\n\t\t// If state has not changed, do nothing\n\t\tif ((!wasVisible && !isVisible) || (wasVisible && isVisible && this._previousState!.equal(state))) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Update visibility of the widget if changed\n\t\tif (wasVisible !== isVisible) {\n\t\t\tthis.setVisible(isVisible);\n\t\t}\n\n\t\tif (!isVisible) {\n\t\t\tthis._previousState = undefined;\n\t\t\tthis._previousElements = [];\n\t\t\tthis._previousStateDisposables.clear();\n\t\t\treturn;\n\t\t}\n\n\t\tconst lastStickyNode = state.stickyNodes[state.count - 1];\n\n\t\t// If the new state is only a change in the last node's position, update the position of the last element\n\t\tif (this._previousState && state.animationStateChanged(this._previousState)) {\n\t\t\tthis._previousElements[this._previousState.count - 1].style.top = `${lastStickyNode.position}px`;\n\t\t}\n\t\t// create new dom elements\n\t\telse {\n\t\t\tthis._previousStateDisposables.clear();\n\n\t\t\tconst elements = Array(state.count);\n\t\t\tfor (let stickyIndex = state.count - 1; stickyIndex >= 0; stickyIndex--) {\n\t\t\t\tconst stickyNode = state.stickyNodes[stickyIndex];\n\n\t\t\t\tconst { element, disposable } = this.createElement(stickyNode, stickyIndex, state.count);\n\t\t\t\telements[stickyIndex] = element;\n\n\t\t\t\tthis._rootDomNode.appendChild(element);\n\t\t\t\tthis._previousStateDisposables.add(disposable);\n\t\t\t}\n\n\t\t\tthis.stickyScrollFocus.updateElements(elements, state);\n\n\t\t\tthis._previousElements = elements;\n\t\t}\n\n\t\tthis._previousState = state;\n\n\t\t// Set the height of the widget to the bottom of the last sticky node\n\t\tthis._rootDomNode.style.height = `${lastStickyNode.position + lastStickyNode.height}px`;\n\t}\n\n\tprivate createElement(stickyNode: StickyScrollNode, stickyIndex: number, stickyNodesTotal: number): { element: HTMLElement; disposable: IDisposable } {\n\n\t\tconst nodeIndex = stickyNode.startIndex;\n\n\t\t// Sticky element container\n\t\tconst stickyElement = document.createElement('div');\n\t\tstickyElement.style.top = `${stickyNode.position}px`;\n\n\t\tif (this.tree.options.setRowHeight !== false) {\n\t\t\tstickyElement.style.height = `${stickyNode.height}px`;\n\t\t}\n\n\t\tif (this.tree.options.setRowLineHeight !== false) {\n\t\t\tstickyElement.style.lineHeight = `${stickyNode.height}px`;\n\t\t}\n\n\t\tstickyElement.classList.add('monaco-tree-sticky-row');\n\t\tstickyElement.classList.add('monaco-list-row');\n\n\t\tstickyElement.setAttribute('data-index', `${nodeIndex}`);\n\t\tstickyElement.setAttribute('data-parity', nodeIndex % 2 === 0 ? 'even' : 'odd');\n\t\tstickyElement.setAttribute('id', this.view.getElementID(nodeIndex));\n\t\tconst accessibilityDisposable = this.setAccessibilityAttributes(stickyElement, stickyNode.node.element, stickyIndex, stickyNodesTotal);\n\n\t\t// Get the renderer for the node\n\t\tconst nodeTemplateId = this.treeDelegate.getTemplateId(stickyNode.node);\n\t\tconst renderer = this.treeRenderers.find((renderer) => renderer.templateId === nodeTemplateId);\n\t\tif (!renderer) {\n\t\t\tthrow new Error(`No renderer found for template id ${nodeTemplateId}`);\n\t\t}\n\n\t\t// To make sure we do not influence the original node, we create a copy of the node\n\t\t// We need to check if it is already a unique instance of the node by the delegate\n\t\tlet nodeCopy = stickyNode.node;\n\t\tif (nodeCopy === this.tree.getNode(this.tree.getNodeLocation(stickyNode.node))) {\n\t\t\tnodeCopy = new Proxy(stickyNode.node, {});\n\t\t}\n\n\t\t// Render the element\n\t\tconst templateData = renderer.renderTemplate(stickyElement);\n\t\trenderer.renderElement(nodeCopy, stickyNode.startIndex, templateData, stickyNode.height);\n\n\t\t// Remove the element from the DOM when state is disposed\n\t\tconst disposable = toDisposable(() => {\n\t\t\taccessibilityDisposable.dispose();\n\t\t\trenderer.disposeElement(nodeCopy, stickyNode.startIndex, templateData, stickyNode.height);\n\t\t\trenderer.disposeTemplate(templateData);\n\t\t\tstickyElement.remove();\n\t\t});\n\n\t\treturn { element: stickyElement, disposable };\n\t}\n\n\tprivate setAccessibilityAttributes(container: HTMLElement, element: T, stickyIndex: number, stickyNodesTotal: number): IDisposable {\n\t\tif (!this.accessibilityProvider) {\n\t\t\treturn Disposable.None;\n\t\t}\n\n\t\tif (this.accessibilityProvider.getSetSize) {\n\t\t\tcontainer.setAttribute('aria-setsize', String(this.accessibilityProvider.getSetSize(element, stickyIndex, stickyNodesTotal)));\n\t\t}\n\t\tif (this.accessibilityProvider.getPosInSet) {\n\t\t\tcontainer.setAttribute('aria-posinset', String(this.accessibilityProvider.getPosInSet(element, stickyIndex)));\n\t\t}\n\t\tif (this.accessibilityProvider.getRole) {\n\t\t\tcontainer.setAttribute('role', this.accessibilityProvider.getRole(element) ?? 'treeitem');\n\t\t}\n\n\t\tconst ariaLabel = this.accessibilityProvider.getAriaLabel(element);\n\t\tconst observable = (ariaLabel && typeof ariaLabel !== 'string') ? ariaLabel : constObservable(ariaLabel);\n\t\tconst result = autorun(reader => {\n\t\t\tconst value = reader.readObservable(observable);\n\n\t\t\tif (value) {\n\t\t\t\tcontainer.setAttribute('aria-label', value);\n\t\t\t} else {\n\t\t\t\tcontainer.removeAttribute('aria-label');\n\t\t\t}\n\t\t});\n\n\t\tif (typeof ariaLabel === 'string') {\n\t\t} else if (ariaLabel) {\n\t\t\tcontainer.setAttribute('aria-label', ariaLabel.get());\n\t\t}\n\n\t\tconst ariaLevel = this.accessibilityProvider.getAriaLevel && this.accessibilityProvider.getAriaLevel(element);\n\t\tif (typeof ariaLevel === 'number') {\n\t\t\tcontainer.setAttribute('aria-level', `${ariaLevel}`);\n\t\t}\n\n\t\t// Sticky Scroll elements can not be selected\n\t\tcontainer.setAttribute('aria-selected', String(false));\n\n\t\treturn result;\n\t}\n\n\tprivate setVisible(visible: boolean): void {\n\t\tthis._rootDomNode.classList.toggle('empty', !visible);\n\n\t\tif (!visible) {\n\t\t\tthis.stickyScrollFocus.updateElements([], undefined);\n\t\t}\n\t}\n\n\tdomFocus(): void {\n\t\tthis.stickyScrollFocus.domFocus();\n\t}\n\n\tfocusedLast(): boolean {\n\t\treturn this.stickyScrollFocus.focusedLast();\n\t}\n\n\tdispose(): void {\n\t\tthis.stickyScrollFocus.dispose();\n\t\tthis._previousStateDisposables.dispose();\n\t\tthis._rootDomNode.remove();\n\t}\n}\n\nclass StickyScrollFocus extends Disposable {\n\n\tprivate focusedIndex: number = -1;\n\tprivate elements: HTMLElement[] = [];\n\tprivate state: StickyScrollState | undefined;\n\n\tprivate _onDidChangeHasFocus = new Emitter();\n\treadonly onDidChangeHasFocus = this._onDidChangeHasFocus.event;\n\n\tprivate _onContextMenu = new Emitter>();\n\treadonly onContextMenu: Event> = this._onContextMenu.event;\n\n\tprivate _domHasFocus: boolean = false;\n\tprivate get domHasFocus(): boolean { return this._domHasFocus; }\n\tprivate set domHasFocus(hasFocus: boolean) {\n\t\tif (hasFocus !== this._domHasFocus) {\n\t\t\tthis._onDidChangeHasFocus.fire(hasFocus);\n\t\t\tthis._domHasFocus = hasFocus;\n\t\t}\n\t}\n\n\tconstructor(\n\t\tprivate readonly container: HTMLElement,\n\t\tprivate readonly view: List>\n\t) {\n\t\tsuper();\n\n\t\tthis.container.addEventListener('focus', () => this.onFocus());\n\t\tthis.container.addEventListener('blur', () => this.onBlur());\n\n\t\tthis._register(this.view.onDidFocus(() => this.toggleStickyScrollFocused(false)));\n\t\tthis._register(this.view.onKeyDown((e) => this.onKeyDown(e)));\n\t\tthis._register(this.view.onMouseDown((e) => this.onMouseDown(e)));\n\t\tthis._register(this.view.onContextMenu((e) => this.handleContextMenu(e)));\n\t}\n\n\tprivate handleContextMenu(e: IListContextMenuEvent>): void {\n\t\tconst target = e.browserEvent.target as HTMLElement;\n\t\tif (!isStickyScrollContainer(target) && !isStickyScrollElement(target)) {\n\t\t\tif (this.focusedLast()) {\n\t\t\t\tthis.view.domFocus();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// The list handles the context menu triggered by a mouse event\n\t\t// In that case only set the focus of the element clicked and leave the rest to the list to handle\n\t\tif (!isKeyboardEvent(e.browserEvent)) {\n\t\t\tif (!this.state) {\n\t\t\t\tthrow new Error('Context menu should not be triggered when state is undefined');\n\t\t\t}\n\n\t\t\tconst stickyIndex = this.state.stickyNodes.findIndex(stickyNode => stickyNode.node.element === e.element?.element);\n\n\t\t\tif (stickyIndex === -1) {\n\t\t\t\tthrow new Error('Context menu should not be triggered when element is not in sticky scroll widget');\n\t\t\t}\n\t\t\tthis.container.focus();\n\t\t\tthis.setFocus(stickyIndex);\n\t\t\treturn;\n\t\t}\n\n\t\tif (!this.state || this.focusedIndex < 0) {\n\t\t\tthrow new Error('Context menu key should not be triggered when focus is not in sticky scroll widget');\n\t\t}\n\n\t\tconst stickyNode = this.state.stickyNodes[this.focusedIndex];\n\t\tconst element = stickyNode.node.element;\n\t\tconst anchor = this.elements[this.focusedIndex];\n\t\tthis._onContextMenu.fire({ element, anchor, browserEvent: e.browserEvent, isStickyScroll: true });\n\t}\n\n\tprivate onKeyDown(e: KeyboardEvent): void {\n\t\t// Sticky Scroll Navigation\n\t\tif (this.domHasFocus && this.state) {\n\t\t\t// Move up\n\t\t\tif (e.key === 'ArrowUp') {\n\t\t\t\tthis.setFocusedElement(Math.max(0, this.focusedIndex - 1));\n\t\t\t\te.preventDefault();\n\t\t\t\te.stopPropagation();\n\t\t\t}\n\t\t\t// Move down, if last sticky node is focused, move focus into first child of last sticky node\n\t\t\telse if (e.key === 'ArrowDown' || e.key === 'ArrowRight') {\n\t\t\t\tif (this.focusedIndex >= this.state.count - 1) {\n\t\t\t\t\tconst nodeIndexToFocus = this.state.stickyNodes[this.state.count - 1].startIndex + 1;\n\t\t\t\t\tthis.view.domFocus();\n\t\t\t\t\tthis.view.setFocus([nodeIndexToFocus]);\n\t\t\t\t\tthis.scrollNodeUnderWidget(nodeIndexToFocus, this.state);\n\t\t\t\t} else {\n\t\t\t\t\tthis.setFocusedElement(this.focusedIndex + 1);\n\t\t\t\t}\n\t\t\t\te.preventDefault();\n\t\t\t\te.stopPropagation();\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate onMouseDown(e: IListMouseEvent>): void {\n\t\tconst target = e.browserEvent.target as HTMLElement;\n\t\tif (!isStickyScrollContainer(target) && !isStickyScrollElement(target)) {\n\t\t\treturn;\n\t\t}\n\n\t\te.browserEvent.preventDefault();\n\t\te.browserEvent.stopPropagation();\n\t}\n\n\tupdateElements(elements: HTMLElement[], state: StickyScrollState | undefined): void {\n\t\tif (state && state.count === 0) {\n\t\t\tthrow new Error('Sticky scroll state must be undefined when there are no sticky nodes');\n\t\t}\n\t\tif (state && state.count !== elements.length) {\n\t\t\tthrow new Error('Sticky scroll focus received illigel state');\n\t\t}\n\n\t\tconst previousIndex = this.focusedIndex;\n\t\tthis.removeFocus();\n\n\t\tthis.elements = elements;\n\t\tthis.state = state;\n\n\t\tif (state) {\n\t\t\tconst newFocusedIndex = clamp(previousIndex, 0, state.count - 1);\n\t\t\tthis.setFocus(newFocusedIndex);\n\t\t} else {\n\t\t\tif (this.domHasFocus) {\n\t\t\t\tthis.view.domFocus();\n\t\t\t}\n\t\t}\n\n\t\t// must come last as it calls blur()\n\t\tthis.container.tabIndex = state ? 0 : -1;\n\t}\n\n\tprivate setFocusedElement(stickyIndex: number): void {\n\t\t// doesn't imply that the widget has (or will have) focus\n\n\t\tconst state = this.state;\n\t\tif (!state) {\n\t\t\tthrow new Error('Cannot set focus when state is undefined');\n\t\t}\n\n\t\tthis.setFocus(stickyIndex);\n\n\t\tif (stickyIndex < state.count - 1) {\n\t\t\treturn;\n\t\t}\n\n\t\t// If the last sticky node is not fully visible, scroll it into view\n\t\tif (state.lastNodePartiallyVisible()) {\n\t\t\tconst lastStickyNode = state.stickyNodes[stickyIndex];\n\t\t\tthis.scrollNodeUnderWidget(lastStickyNode.endIndex + 1, state);\n\t\t}\n\t}\n\n\tprivate scrollNodeUnderWidget(nodeIndex: number, state: StickyScrollState) {\n\t\tconst lastStickyNode = state.stickyNodes[state.count - 1];\n\t\tconst secondLastStickyNode = state.count > 1 ? state.stickyNodes[state.count - 2] : undefined;\n\n\t\tconst elementScrollTop = this.view.getElementTop(nodeIndex);\n\t\tconst elementTargetViewTop = secondLastStickyNode ? secondLastStickyNode.position + secondLastStickyNode.height + lastStickyNode.height : lastStickyNode.height;\n\t\tthis.view.scrollTop = elementScrollTop - elementTargetViewTop;\n\t}\n\n\tdomFocus(): void {\n\t\tif (!this.state) {\n\t\t\tthrow new Error('Cannot focus when state is undefined');\n\t\t}\n\n\t\tthis.container.focus();\n\t}\n\n\tfocusedLast(): boolean {\n\t\tif (!this.state) {\n\t\t\treturn false;\n\t\t}\n\t\treturn this.view.getHTMLElement().classList.contains('sticky-scroll-focused');\n\t}\n\n\tprivate removeFocus(): void {\n\t\tif (this.focusedIndex === -1) {\n\t\t\treturn;\n\t\t}\n\t\tthis.toggleElementFocus(this.elements[this.focusedIndex], false);\n\t\tthis.focusedIndex = -1;\n\t}\n\n\tprivate setFocus(newFocusIndex: number): void {\n\t\tif (0 > newFocusIndex) {\n\t\t\tthrow new Error('addFocus() can not remove focus');\n\t\t}\n\t\tif (!this.state && newFocusIndex >= 0) {\n\t\t\tthrow new Error('Cannot set focus index when state is undefined');\n\t\t}\n\t\tif (this.state && newFocusIndex >= this.state.count) {\n\t\t\tthrow new Error('Cannot set focus index to an index that does not exist');\n\t\t}\n\n\t\tconst oldIndex = this.focusedIndex;\n\t\tif (oldIndex >= 0) {\n\t\t\tthis.toggleElementFocus(this.elements[oldIndex], false);\n\t\t}\n\t\tif (newFocusIndex >= 0) {\n\t\t\tthis.toggleElementFocus(this.elements[newFocusIndex], true);\n\t\t}\n\t\tthis.focusedIndex = newFocusIndex;\n\t}\n\n\tprivate toggleElementFocus(element: HTMLElement, focused: boolean): void {\n\t\tthis.toggleElementActiveFocus(element, focused && this.domHasFocus);\n\t\tthis.toggleElementPassiveFocus(element, focused);\n\t}\n\n\tprivate toggleCurrentElementActiveFocus(focused: boolean): void {\n\t\tif (this.focusedIndex === -1) {\n\t\t\treturn;\n\t\t}\n\t\tthis.toggleElementActiveFocus(this.elements[this.focusedIndex], focused);\n\t}\n\n\tprivate toggleElementActiveFocus(element: HTMLElement, focused: boolean) {\n\t\t// active focus is set when sticky scroll has focus\n\t\telement.classList.toggle('focused', focused);\n\t}\n\n\tprivate toggleElementPassiveFocus(element: HTMLElement, focused: boolean) {\n\t\t// passive focus allows to show focus when sticky scroll does not have focus\n\t\t// for example when the context menu has focus\n\t\telement.classList.toggle('passive-focused', focused);\n\t}\n\n\tprivate toggleStickyScrollFocused(focused: boolean) {\n\t\t// Weather the last focus in the view was sticky scroll and not the list\n\t\t// Is only removed when the focus is back in the tree an no longer in sticky scroll\n\t\tthis.view.getHTMLElement().classList.toggle('sticky-scroll-focused', focused);\n\t}\n\n\tprivate onFocus(): void {\n\t\tif (!this.state || this.elements.length === 0) {\n\t\t\tthrow new Error('Cannot focus when state is undefined or elements are empty');\n\t\t}\n\t\tthis.domHasFocus = true;\n\t\tthis.toggleStickyScrollFocused(true);\n\t\tthis.toggleCurrentElementActiveFocus(true);\n\t\tif (this.focusedIndex === -1) {\n\t\t\tthis.setFocus(0);\n\t\t}\n\t}\n\n\tprivate onBlur(): void {\n\t\tthis.domHasFocus = false;\n\t\tthis.toggleCurrentElementActiveFocus(false);\n\t}\n\n\toverride dispose(): void {\n\t\tthis.toggleStickyScrollFocused(false);\n\t\tthis._onDidChangeHasFocus.fire(false);\n\t\tsuper.dispose();\n\t}\n}\n\nfunction asTreeMouseEvent(event: IListMouseEvent>): ITreeMouseEvent {\n\tlet target: TreeMouseEventTarget = TreeMouseEventTarget.Unknown;\n\n\tif (hasParentWithClass(event.browserEvent.target as HTMLElement, 'monaco-tl-twistie', 'monaco-tl-row')) {\n\t\ttarget = TreeMouseEventTarget.Twistie;\n\t} else if (hasParentWithClass(event.browserEvent.target as HTMLElement, 'monaco-tl-contents', 'monaco-tl-row')) {\n\t\ttarget = TreeMouseEventTarget.Element;\n\t} else if (hasParentWithClass(event.browserEvent.target as HTMLElement, 'monaco-tree-type-filter', 'monaco-list')) {\n\t\ttarget = TreeMouseEventTarget.Filter;\n\t}\n\n\treturn {\n\t\tbrowserEvent: event.browserEvent,\n\t\telement: event.element ? event.element.element : null,\n\t\ttarget\n\t};\n}\n\nfunction asTreeContextMenuEvent(event: IListContextMenuEvent>): ITreeContextMenuEvent {\n\tconst isStickyScroll = isStickyScrollContainer(event.browserEvent.target as HTMLElement);\n\n\treturn {\n\t\telement: event.element ? event.element.element : null,\n\t\tbrowserEvent: event.browserEvent,\n\t\tanchor: event.anchor,\n\t\tisStickyScroll\n\t};\n}\n\nexport interface IAbstractTreeOptionsUpdate extends ITreeRendererOptions {\n\treadonly multipleSelectionSupport?: boolean;\n\treadonly typeNavigationMode?: TypeNavigationMode;\n\treadonly defaultFindMode?: TreeFindMode;\n\treadonly defaultFindMatchType?: TreeFindMatchType;\n\treadonly showNotFoundMessage?: boolean;\n\treadonly smoothScrolling?: boolean;\n\treadonly horizontalScrolling?: boolean;\n\treadonly scrollByPage?: boolean;\n\treadonly mouseWheelScrollSensitivity?: number;\n\treadonly fastScrollSensitivity?: number;\n\treadonly expandOnDoubleClick?: boolean;\n\treadonly expandOnlyOnTwistieClick?: boolean | ((e: any) => boolean); // e is T\n\treadonly enableStickyScroll?: boolean;\n\treadonly stickyScrollMaxItemCount?: number;\n}\n\nexport interface IAbstractTreeOptions extends IAbstractTreeOptionsUpdate, IListOptions {\n\treadonly contextViewProvider?: IContextViewProvider;\n\treadonly collapseByDefault?: boolean; // defaults to false\n\treadonly allowNonCollapsibleParents?: boolean; // defaults to false\n\treadonly filter?: ITreeFilter;\n\treadonly dnd?: ITreeDragAndDrop;\n\treadonly paddingBottom?: number;\n\treadonly findWidgetEnabled?: boolean;\n\treadonly findWidgetStyles?: IFindWidgetStyles;\n\treadonly defaultFindVisibility?: TreeVisibility | ((e: T) => TreeVisibility);\n\treadonly stickyScrollDelegate?: IStickyScrollDelegate;\n}\n\nfunction dfs(node: ITreeNode, fn: (node: ITreeNode) => void): void {\n\tfn(node);\n\tnode.children.forEach(child => dfs(child, fn));\n}\n\n/**\n * The trait concept needs to exist at the tree level, because collapsed\n * tree nodes will not be known by the list.\n */\nclass Trait {\n\n\tprivate nodes: ITreeNode[] = [];\n\tprivate elements: T[] | undefined;\n\n\tprivate readonly _onDidChange = new Emitter>();\n\treadonly onDidChange = this._onDidChange.event;\n\n\tprivate _nodeSet: Set> | undefined;\n\tprivate get nodeSet(): Set> {\n\t\tif (!this._nodeSet) {\n\t\t\tthis._nodeSet = this.createNodeSet();\n\t\t}\n\n\t\treturn this._nodeSet;\n\t}\n\n\tconstructor(\n\t\tprivate getFirstViewElementWithTrait: () => ITreeNode | undefined,\n\t\tprivate identityProvider?: IIdentityProvider\n\t) { }\n\n\tset(nodes: ITreeNode[], browserEvent?: UIEvent): void {\n\t\tif (!(browserEvent as any)?.__forceEvent && equals(this.nodes, nodes)) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._set(nodes, false, browserEvent);\n\t}\n\n\tprivate _set(nodes: ITreeNode[], silent: boolean, browserEvent?: UIEvent): void {\n\t\tthis.nodes = [...nodes];\n\t\tthis.elements = undefined;\n\t\tthis._nodeSet = undefined;\n\n\t\tif (!silent) {\n\t\t\tconst that = this;\n\t\t\tthis._onDidChange.fire({ get elements() { return that.get(); }, browserEvent });\n\t\t}\n\t}\n\n\tget(): T[] {\n\t\tif (!this.elements) {\n\t\t\tthis.elements = this.nodes.map(node => node.element);\n\t\t}\n\n\t\treturn [...this.elements];\n\t}\n\n\tgetNodes(): readonly ITreeNode[] {\n\t\treturn this.nodes;\n\t}\n\n\thas(node: ITreeNode): boolean {\n\t\treturn this.nodeSet.has(node);\n\t}\n\n\tonDidModelSplice({ insertedNodes, deletedNodes }: ITreeModelSpliceEvent): void {\n\t\tif (!this.identityProvider) {\n\t\t\tconst set = this.createNodeSet();\n\t\t\tconst visit = (node: ITreeNode) => set.delete(node);\n\t\t\tdeletedNodes.forEach(node => dfs(node, visit));\n\t\t\tthis.set([...set.values()]);\n\t\t\treturn;\n\t\t}\n\n\t\tconst deletedNodesIdSet = new Set();\n\t\tconst deletedNodesVisitor = (node: ITreeNode) => deletedNodesIdSet.add(this.identityProvider!.getId(node.element).toString());\n\t\tdeletedNodes.forEach(node => dfs(node, deletedNodesVisitor));\n\n\t\tconst insertedNodesMap = new Map>();\n\t\tconst insertedNodesVisitor = (node: ITreeNode) => insertedNodesMap.set(this.identityProvider!.getId(node.element).toString(), node);\n\t\tinsertedNodes.forEach(node => dfs(node, insertedNodesVisitor));\n\n\t\tconst nodes: ITreeNode[] = [];\n\n\t\tfor (const node of this.nodes) {\n\t\t\tconst id = this.identityProvider.getId(node.element).toString();\n\t\t\tconst wasDeleted = deletedNodesIdSet.has(id);\n\n\t\t\tif (!wasDeleted) {\n\t\t\t\tnodes.push(node);\n\t\t\t} else {\n\t\t\t\tconst insertedNode = insertedNodesMap.get(id);\n\n\t\t\t\tif (insertedNode && insertedNode.visible) {\n\t\t\t\t\tnodes.push(insertedNode);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (this.nodes.length > 0 && nodes.length === 0) {\n\t\t\tconst node = this.getFirstViewElementWithTrait();\n\n\t\t\tif (node) {\n\t\t\t\tnodes.push(node);\n\t\t\t}\n\t\t}\n\n\t\tthis._set(nodes, true);\n\t}\n\n\tprivate createNodeSet(): Set> {\n\t\tconst set = new Set>();\n\n\t\tfor (const node of this.nodes) {\n\t\t\tset.add(node);\n\t\t}\n\n\t\treturn set;\n\t}\n}\n\nclass TreeNodeListMouseController extends MouseController> {\n\n\tconstructor(\n\t\tlist: TreeNodeList,\n\t\tprivate tree: AbstractTree,\n\t\tprivate stickyScrollProvider: () => StickyScrollController | undefined\n\t) {\n\t\tsuper(list);\n\t}\n\n\tprotected override onViewPointer(e: IListMouseEvent>): void {\n\t\tif (isButton(e.browserEvent.target as HTMLElement) ||\n\t\t\tisInputElement(e.browserEvent.target as HTMLElement) ||\n\t\t\tisMonacoEditor(e.browserEvent.target as HTMLElement)) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (e.browserEvent.isHandledByList) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst node = e.element;\n\n\t\tif (!node) {\n\t\t\treturn super.onViewPointer(e);\n\t\t}\n\n\t\tif (this.isSelectionRangeChangeEvent(e) || this.isSelectionSingleChangeEvent(e)) {\n\t\t\treturn super.onViewPointer(e);\n\t\t}\n\n\t\tconst target = e.browserEvent.target as HTMLElement;\n\t\tconst onTwistie = target.classList.contains('monaco-tl-twistie')\n\t\t\t|| (target.classList.contains('monaco-icon-label') && target.classList.contains('folder-icon') && e.browserEvent.offsetX < 16);\n\t\tconst isStickyElement = isStickyScrollElement(e.browserEvent.target as HTMLElement);\n\n\t\tlet expandOnlyOnTwistieClick = false;\n\n\t\tif (isStickyElement) {\n\t\t\texpandOnlyOnTwistieClick = true;\n\t\t}\n\t\telse if (typeof this.tree.expandOnlyOnTwistieClick === 'function') {\n\t\t\texpandOnlyOnTwistieClick = this.tree.expandOnlyOnTwistieClick(node.element);\n\t\t} else {\n\t\t\texpandOnlyOnTwistieClick = !!this.tree.expandOnlyOnTwistieClick;\n\t\t}\n\n\t\tif (!isStickyElement) {\n\t\t\tif (expandOnlyOnTwistieClick && !onTwistie && e.browserEvent.detail !== 2) {\n\t\t\t\treturn super.onViewPointer(e);\n\t\t\t}\n\n\t\t\tif (!this.tree.expandOnDoubleClick && e.browserEvent.detail === 2) {\n\t\t\t\treturn super.onViewPointer(e);\n\t\t\t}\n\t\t} else {\n\t\t\tthis.handleStickyScrollMouseEvent(e, node);\n\t\t}\n\n\t\tif (node.collapsible && (!isStickyElement || onTwistie)) {\n\t\t\tconst location = this.tree.getNodeLocation(node);\n\t\t\tconst recursive = e.browserEvent.altKey;\n\t\t\tthis.tree.setFocus([location]);\n\t\t\tthis.tree.toggleCollapsed(location, recursive);\n\n\t\t\tif (onTwistie) {\n\t\t\t\t// Do not set this before calling a handler on the super class, because it will reject it as handled\n\t\t\t\te.browserEvent.isHandledByList = true;\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tif (!isStickyElement) {\n\t\t\tsuper.onViewPointer(e);\n\t\t}\n\t}\n\n\tprivate handleStickyScrollMouseEvent(e: IListMouseEvent>, node: ITreeNode): void {\n\t\tif (isMonacoCustomToggle(e.browserEvent.target as HTMLElement) || isActionItem(e.browserEvent.target as HTMLElement)) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst stickyScrollController = this.stickyScrollProvider();\n\t\tif (!stickyScrollController) {\n\t\t\tthrow new Error('Sticky scroll controller not found');\n\t\t}\n\n\t\tconst nodeIndex = this.list.indexOf(node);\n\t\tconst elementScrollTop = this.list.getElementTop(nodeIndex);\n\t\tconst elementTargetViewTop = stickyScrollController.nodePositionTopBelowWidget(node);\n\t\tthis.tree.scrollTop = elementScrollTop - elementTargetViewTop;\n\t\tthis.list.domFocus();\n\t\tthis.list.setFocus([nodeIndex]);\n\t\tthis.list.setSelection([nodeIndex]);\n\t}\n\n\tprotected override onDoubleClick(e: IListMouseEvent>): void {\n\t\tconst onTwistie = (e.browserEvent.target as HTMLElement).classList.contains('monaco-tl-twistie');\n\n\t\tif (onTwistie || !this.tree.expandOnDoubleClick) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (e.browserEvent.isHandledByList) {\n\t\t\treturn;\n\t\t}\n\n\t\tsuper.onDoubleClick(e);\n\t}\n\n\t// to make sure dom focus is not stolen (for example with context menu)\n\tprotected override onMouseDown(e: IListMouseEvent> | IListTouchEvent>): void {\n\t\tconst target = e.browserEvent.target as HTMLElement;\n\t\tif (!isStickyScrollContainer(target) && !isStickyScrollElement(target)) {\n\t\t\tsuper.onMouseDown(e);\n\t\t\treturn;\n\t\t}\n\t}\n\n\tprotected override onContextMenu(e: IListContextMenuEvent>): void {\n\t\tconst target = e.browserEvent.target as HTMLElement;\n\t\tif (!isStickyScrollContainer(target) && !isStickyScrollElement(target)) {\n\t\t\tsuper.onContextMenu(e);\n\t\t\treturn;\n\t\t}\n\t}\n}\n\ninterface ITreeNodeListOptions extends IListOptions> {\n\treadonly tree: AbstractTree;\n\treadonly stickyScrollProvider: () => StickyScrollController | undefined;\n}\n\n/**\n * We use this List subclass to restore selection and focus as nodes\n * get rendered in the list, possibly due to a node expand() call.\n */\nclass TreeNodeList extends List> {\n\n\tconstructor(\n\t\tuser: string,\n\t\tcontainer: HTMLElement,\n\t\tvirtualDelegate: IListVirtualDelegate>,\n\t\trenderers: IListRenderer[],\n\t\tprivate focusTrait: Trait,\n\t\tprivate selectionTrait: Trait,\n\t\tprivate anchorTrait: Trait,\n\t\toptions: ITreeNodeListOptions\n\t) {\n\t\tsuper(user, container, virtualDelegate, renderers, options);\n\t}\n\n\tprotected override createMouseController(options: ITreeNodeListOptions): MouseController> {\n\t\treturn new TreeNodeListMouseController(this, options.tree, options.stickyScrollProvider);\n\t}\n\n\toverride splice(start: number, deleteCount: number, elements: readonly ITreeNode[] = []): void {\n\t\tsuper.splice(start, deleteCount, elements);\n\n\t\tif (elements.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst additionalFocus: number[] = [];\n\t\tconst additionalSelection: number[] = [];\n\t\tlet anchor: number | undefined;\n\n\t\telements.forEach((node, index) => {\n\t\t\tif (this.focusTrait.has(node)) {\n\t\t\t\tadditionalFocus.push(start + index);\n\t\t\t}\n\n\t\t\tif (this.selectionTrait.has(node)) {\n\t\t\t\tadditionalSelection.push(start + index);\n\t\t\t}\n\n\t\t\tif (this.anchorTrait.has(node)) {\n\t\t\t\tanchor = start + index;\n\t\t\t}\n\t\t});\n\n\t\tif (additionalFocus.length > 0) {\n\t\t\tsuper.setFocus(distinct([...super.getFocus(), ...additionalFocus]));\n\t\t}\n\n\t\tif (additionalSelection.length > 0) {\n\t\t\tsuper.setSelection(distinct([...super.getSelection(), ...additionalSelection]));\n\t\t}\n\n\t\tif (typeof anchor === 'number') {\n\t\t\tsuper.setAnchor(anchor);\n\t\t}\n\t}\n\n\toverride setFocus(indexes: number[], browserEvent?: UIEvent, fromAPI = false): void {\n\t\tsuper.setFocus(indexes, browserEvent);\n\n\t\tif (!fromAPI) {\n\t\t\tthis.focusTrait.set(indexes.map(i => this.element(i)), browserEvent);\n\t\t}\n\t}\n\n\toverride setSelection(indexes: number[], browserEvent?: UIEvent, fromAPI = false): void {\n\t\tsuper.setSelection(indexes, browserEvent);\n\n\t\tif (!fromAPI) {\n\t\t\tthis.selectionTrait.set(indexes.map(i => this.element(i)), browserEvent);\n\t\t}\n\t}\n\n\toverride setAnchor(index: number | undefined, fromAPI = false): void {\n\t\tsuper.setAnchor(index);\n\n\t\tif (!fromAPI) {\n\t\t\tif (typeof index === 'undefined') {\n\t\t\t\tthis.anchorTrait.set([]);\n\t\t\t} else {\n\t\t\t\tthis.anchorTrait.set([this.element(index)]);\n\t\t\t}\n\t\t}\n\t}\n}\n\nexport abstract class AbstractTree implements IDisposable {\n\n\tprotected view: TreeNodeList;\n\tprivate renderers: TreeRenderer[];\n\tprotected model: ITreeModel;\n\tprivate treeDelegate: ComposedTreeDelegate>;\n\tprivate focus: Trait;\n\tprivate selection: Trait;\n\tprivate anchor: Trait;\n\tprivate eventBufferer = new EventBufferer();\n\tprivate findController?: FindController;\n\treadonly onDidChangeFindOpenState: Event = Event.None;\n\tonDidChangeStickyScrollFocused: Event = Event.None;\n\tprivate focusNavigationFilter: ((node: ITreeNode) => boolean) | undefined;\n\tprivate stickyScrollController?: StickyScrollController;\n\tprivate styleElement: HTMLStyleElement;\n\tprotected readonly disposables = new DisposableStore();\n\n\tget onDidScroll(): Event { return this.view.onDidScroll; }\n\n\tget onDidChangeFocus(): Event> { return this.eventBufferer.wrapEvent(this.focus.onDidChange); }\n\tget onDidChangeSelection(): Event> { return this.eventBufferer.wrapEvent(this.selection.onDidChange); }\n\tget onMouseDblClick(): Event> { return Event.filter(Event.map(this.view.onMouseDblClick, asTreeMouseEvent), e => e.target !== TreeMouseEventTarget.Filter); }\n\tget onMouseOver(): Event> { return Event.map(this.view.onMouseOver, asTreeMouseEvent); }\n\tget onMouseOut(): Event> { return Event.map(this.view.onMouseOut, asTreeMouseEvent); }\n\tget onContextMenu(): Event> { return Event.any(Event.filter(Event.map(this.view.onContextMenu, asTreeContextMenuEvent), e => !e.isStickyScroll), this.stickyScrollController?.onContextMenu ?? Event.None); }\n\tget onPointer(): Event> { return Event.map(this.view.onPointer, asTreeMouseEvent); }\n\n\tget onKeyDown(): Event { return this.view.onKeyDown; }\n\n\tget onDidFocus(): Event { return this.view.onDidFocus; }\n\n\tget onDidChangeModel(): Event { return Event.signal(this.model.onDidSplice); }\n\tget onDidChangeCollapseState(): Event> { return this.model.onDidChangeCollapseState; }\n\n\tprivate readonly _onWillRefilter = new Emitter();\n\treadonly onWillRefilter: Event = this._onWillRefilter.event;\n\n\tget findMode(): TreeFindMode { return this.findController?.mode ?? TreeFindMode.Highlight; }\n\tset findMode(findMode: TreeFindMode) { if (this.findController) { this.findController.mode = findMode; } }\n\treadonly onDidChangeFindMode: Event;\n\n\tget findMatchType(): TreeFindMatchType { return this.findController?.matchType ?? TreeFindMatchType.Fuzzy; }\n\tset findMatchType(findFuzzy: TreeFindMatchType) { if (this.findController) { this.findController.matchType = findFuzzy; } }\n\treadonly onDidChangeFindMatchType: Event;\n\n\tget expandOnDoubleClick(): boolean { return typeof this._options.expandOnDoubleClick === 'undefined' ? true : this._options.expandOnDoubleClick; }\n\tget expandOnlyOnTwistieClick(): boolean | ((e: T) => boolean) { return typeof this._options.expandOnlyOnTwistieClick === 'undefined' ? true : this._options.expandOnlyOnTwistieClick; }\n\n\tprivate readonly _onDidUpdateOptions = new Emitter>();\n\n\tget onDidDispose(): Event { return this.view.onDidDispose; }\n\n\tconstructor(\n\t\tprivate readonly _user: string,\n\t\tcontainer: HTMLElement,\n\t\tdelegate: IListVirtualDelegate,\n\t\trenderers: ITreeRenderer[],\n\t\tprivate _options: IAbstractTreeOptions = {}\n\t) {\n\t\tthis.treeDelegate = new ComposedTreeDelegate>(delegate);\n\n\t\tconst onDidChangeCollapseStateRelay = new Relay>();\n\t\tconst onDidChangeActiveNodes = new Relay[]>();\n\t\tconst activeNodes = this.disposables.add(new EventCollection(onDidChangeActiveNodes.event));\n\t\tconst renderedIndentGuides = new SetMap, HTMLDivElement>();\n\t\tthis.renderers = renderers.map(r => new TreeRenderer(r, () => this.model, onDidChangeCollapseStateRelay.event, activeNodes, renderedIndentGuides, _options));\n\t\tfor (const r of this.renderers) {\n\t\t\tthis.disposables.add(r);\n\t\t}\n\n\t\tlet filter: FindFilter | undefined;\n\n\t\tif (_options.keyboardNavigationLabelProvider) {\n\t\t\tfilter = new FindFilter(this, _options.keyboardNavigationLabelProvider, _options.filter as any as ITreeFilter);\n\t\t\t_options = { ..._options, filter: filter as ITreeFilter }; // TODO need typescript help here\n\t\t\tthis.disposables.add(filter);\n\t\t}\n\n\t\tthis.focus = new Trait(() => this.view.getFocusedElements()[0], _options.identityProvider);\n\t\tthis.selection = new Trait(() => this.view.getSelectedElements()[0], _options.identityProvider);\n\t\tthis.anchor = new Trait(() => this.view.getAnchorElement(), _options.identityProvider);\n\t\tthis.view = new TreeNodeList(_user, container, this.treeDelegate, this.renderers, this.focus, this.selection, this.anchor, { ...asListOptions(() => this.model, _options), tree: this, stickyScrollProvider: () => this.stickyScrollController });\n\n\t\tthis.model = this.createModel(_user, this.view, _options);\n\t\tonDidChangeCollapseStateRelay.input = this.model.onDidChangeCollapseState;\n\n\t\tconst onDidModelSplice = Event.forEach(this.model.onDidSplice, e => {\n\t\t\tthis.eventBufferer.bufferEvents(() => {\n\t\t\t\tthis.focus.onDidModelSplice(e);\n\t\t\t\tthis.selection.onDidModelSplice(e);\n\t\t\t});\n\t\t}, this.disposables);\n\n\t\t// Make sure the `forEach` always runs\n\t\tonDidModelSplice(() => null, null, this.disposables);\n\n\t\t// Active nodes can change when the model changes or when focus or selection change.\n\t\t// We debounce it with 0 delay since these events may fire in the same stack and we only\n\t\t// want to run this once. It also doesn't matter if it runs on the next tick since it's only\n\t\t// a nice to have UI feature.\n\t\tconst activeNodesEmitter = this.disposables.add(new Emitter[]>());\n\t\tconst activeNodesDebounce = this.disposables.add(new Delayer(0));\n\t\tthis.disposables.add(Event.any(onDidModelSplice, this.focus.onDidChange, this.selection.onDidChange)(() => {\n\t\t\tactiveNodesDebounce.trigger(() => {\n\t\t\t\tconst set = new Set>();\n\n\t\t\t\tfor (const node of this.focus.getNodes()) {\n\t\t\t\t\tset.add(node);\n\t\t\t\t}\n\n\t\t\t\tfor (const node of this.selection.getNodes()) {\n\t\t\t\t\tset.add(node);\n\t\t\t\t}\n\n\t\t\t\tactiveNodesEmitter.fire([...set.values()]);\n\t\t\t});\n\t\t}));\n\t\tonDidChangeActiveNodes.input = activeNodesEmitter.event;\n\n\t\tif (_options.keyboardSupport !== false) {\n\t\t\tconst onKeyDown = Event.chain(this.view.onKeyDown, $ =>\n\t\t\t\t$.filter(e => !isInputElement(e.target as HTMLElement))\n\t\t\t\t\t.map(e => new StandardKeyboardEvent(e))\n\t\t\t);\n\n\t\t\tEvent.chain(onKeyDown, $ => $.filter(e => e.keyCode === KeyCode.LeftArrow))(this.onLeftArrow, this, this.disposables);\n\t\t\tEvent.chain(onKeyDown, $ => $.filter(e => e.keyCode === KeyCode.RightArrow))(this.onRightArrow, this, this.disposables);\n\t\t\tEvent.chain(onKeyDown, $ => $.filter(e => e.keyCode === KeyCode.Space))(this.onSpace, this, this.disposables);\n\t\t}\n\n\t\tif ((_options.findWidgetEnabled ?? true) && _options.keyboardNavigationLabelProvider && _options.contextViewProvider) {\n\t\t\tconst opts = this.options.findWidgetStyles ? { styles: this.options.findWidgetStyles } : undefined;\n\t\t\tthis.findController = new FindController(this, this.model, this.view, filter!, _options.contextViewProvider, opts);\n\t\t\tthis.focusNavigationFilter = node => this.findController!.shouldAllowFocus(node);\n\t\t\tthis.onDidChangeFindOpenState = this.findController.onDidChangeOpenState;\n\t\t\tthis.disposables.add(this.findController);\n\t\t\tthis.onDidChangeFindMode = this.findController.onDidChangeMode;\n\t\t\tthis.onDidChangeFindMatchType = this.findController.onDidChangeMatchType;\n\t\t} else {\n\t\t\tthis.onDidChangeFindMode = Event.None;\n\t\t\tthis.onDidChangeFindMatchType = Event.None;\n\t\t}\n\n\t\tif (_options.enableStickyScroll) {\n\t\t\tthis.stickyScrollController = new StickyScrollController(this, this.model, this.view, this.renderers, this.treeDelegate, _options);\n\t\t\tthis.onDidChangeStickyScrollFocused = this.stickyScrollController.onDidChangeHasFocus;\n\t\t}\n\n\t\tthis.styleElement = createStyleSheet(this.view.getHTMLElement());\n\t\tthis.getHTMLElement().classList.toggle('always', this._options.renderIndentGuides === RenderIndentGuides.Always);\n\t}\n\n\tupdateOptions(optionsUpdate: IAbstractTreeOptionsUpdate = {}): void {\n\t\tthis._options = { ...this._options, ...optionsUpdate };\n\n\t\tfor (const renderer of this.renderers) {\n\t\t\trenderer.updateOptions(optionsUpdate);\n\t\t}\n\n\t\tthis.view.updateOptions(this._options);\n\t\tthis.findController?.updateOptions(optionsUpdate);\n\t\tthis.updateStickyScroll(optionsUpdate);\n\n\t\tthis._onDidUpdateOptions.fire(this._options);\n\n\t\tthis.getHTMLElement().classList.toggle('always', this._options.renderIndentGuides === RenderIndentGuides.Always);\n\t}\n\n\tget options(): IAbstractTreeOptions {\n\t\treturn this._options;\n\t}\n\n\tprivate updateStickyScroll(optionsUpdate: IAbstractTreeOptionsUpdate) {\n\t\tif (!this.stickyScrollController && this._options.enableStickyScroll) {\n\t\t\tthis.stickyScrollController = new StickyScrollController(this, this.model, this.view, this.renderers, this.treeDelegate, this._options);\n\t\t\tthis.onDidChangeStickyScrollFocused = this.stickyScrollController.onDidChangeHasFocus;\n\t\t} else if (this.stickyScrollController && !this._options.enableStickyScroll) {\n\t\t\tthis.onDidChangeStickyScrollFocused = Event.None;\n\t\t\tthis.stickyScrollController.dispose();\n\t\t\tthis.stickyScrollController = undefined;\n\t\t}\n\t\tthis.stickyScrollController?.updateOptions(optionsUpdate);\n\t}\n\n\t// Widget\n\n\tgetHTMLElement(): HTMLElement {\n\t\treturn this.view.getHTMLElement();\n\t}\n\n\tget scrollTop(): number {\n\t\treturn this.view.scrollTop;\n\t}\n\n\tset scrollTop(scrollTop: number) {\n\t\tthis.view.scrollTop = scrollTop;\n\t}\n\n\tget scrollHeight(): number {\n\t\treturn this.view.scrollHeight;\n\t}\n\n\tget renderHeight(): number {\n\t\treturn this.view.renderHeight;\n\t}\n\n\tget ariaLabel(): string {\n\t\treturn this.view.ariaLabel;\n\t}\n\n\tset ariaLabel(value: string) {\n\t\tthis.view.ariaLabel = value;\n\t}\n\n\tdomFocus(): void {\n\t\tif (this.stickyScrollController?.focusedLast()) {\n\t\t\tthis.stickyScrollController.domFocus();\n\t\t} else {\n\t\t\tthis.view.domFocus();\n\t\t}\n\t}\n\n\tlayout(height?: number, width?: number): void {\n\t\tthis.view.layout(height, width);\n\n\t\tif (isNumber(width)) {\n\t\t\tthis.findController?.layout(width);\n\t\t}\n\t}\n\n\tstyle(styles: IListStyles): void {\n\t\tconst suffix = `.${this.view.domId}`;\n\t\tconst content: string[] = [];\n\n\t\tif (styles.treeIndentGuidesStroke) {\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.treeInactiveIndentGuidesStroke}; }`);\n\t\t\tcontent.push(`.monaco-list${suffix} .monaco-tl-indent > .indent-guide.active { border-color: ${styles.treeIndentGuidesStroke}; }`);\n\t\t}\n\n\t\t// Sticky Scroll Background\n\t\tconst stickyScrollBackground = styles.treeStickyScrollBackground ?? styles.listBackground;\n\t\tif (stickyScrollBackground) {\n\t\t\tcontent.push(`.monaco-list${suffix} .monaco-scrollable-element .monaco-tree-sticky-container { background-color: ${stickyScrollBackground}; }`);\n\t\t\tcontent.push(`.monaco-list${suffix} .monaco-scrollable-element .monaco-tree-sticky-container .monaco-tree-sticky-row { background-color: ${stickyScrollBackground}; }`);\n\t\t}\n\n\t\t// Sticky Scroll Border\n\t\tif (styles.treeStickyScrollBorder) {\n\t\t\tcontent.push(`.monaco-list${suffix} .monaco-scrollable-element .monaco-tree-sticky-container { border-bottom: 1px solid ${styles.treeStickyScrollBorder}; }`);\n\t\t}\n\n\t\t// Sticky Scroll Shadow\n\t\tif (styles.treeStickyScrollShadow) {\n\t\t\tcontent.push(`.monaco-list${suffix} .monaco-scrollable-element .monaco-tree-sticky-container .monaco-tree-sticky-container-shadow { box-shadow: ${styles.treeStickyScrollShadow} 0 6px 6px -6px inset; height: 3px; }`);\n\t\t}\n\n\t\t// Sticky Scroll Focus\n\t\tif (styles.listFocusForeground) {\n\t\t\tcontent.push(`.monaco-list${suffix}.sticky-scroll-focused .monaco-scrollable-element .monaco-tree-sticky-container:focus .monaco-list-row.focused { color: ${styles.listFocusForeground}; }`);\n\t\t\tcontent.push(`.monaco-list${suffix}:not(.sticky-scroll-focused) .monaco-scrollable-element .monaco-tree-sticky-container .monaco-list-row.focused { color: inherit; }`);\n\t\t}\n\n\t\t// Sticky Scroll Focus Outlines\n\t\tconst focusAndSelectionOutline = asCssValueWithDefault(styles.listFocusAndSelectionOutline, asCssValueWithDefault(styles.listSelectionOutline, styles.listFocusOutline ?? ''));\n\t\tif (focusAndSelectionOutline) { // default: listFocusOutline\n\t\t\tcontent.push(`.monaco-list${suffix}.sticky-scroll-focused .monaco-scrollable-element .monaco-tree-sticky-container:focus .monaco-list-row.focused.selected { outline: 1px solid ${focusAndSelectionOutline}; outline-offset: -1px;}`);\n\t\t\tcontent.push(`.monaco-list${suffix}:not(.sticky-scroll-focused) .monaco-scrollable-element .monaco-tree-sticky-container .monaco-list-row.focused.selected { outline: inherit;}`);\n\t\t}\n\n\t\tif (styles.listFocusOutline) { // default: set\n\t\t\tcontent.push(`.monaco-list${suffix}.sticky-scroll-focused .monaco-scrollable-element .monaco-tree-sticky-container:focus .monaco-list-row.focused { outline: 1px solid ${styles.listFocusOutline}; outline-offset: -1px; }`);\n\t\t\tcontent.push(`.monaco-list${suffix}:not(.sticky-scroll-focused) .monaco-scrollable-element .monaco-tree-sticky-container .monaco-list-row.focused { outline: inherit; }`);\n\n\t\t\tcontent.push(`.monaco-workbench.context-menu-visible .monaco-list${suffix}.last-focused.sticky-scroll-focused .monaco-scrollable-element .monaco-tree-sticky-container .monaco-list-row.passive-focused { outline: 1px solid ${styles.listFocusOutline}; outline-offset: -1px; }`);\n\n\t\t\tcontent.push(`.monaco-workbench.context-menu-visible .monaco-list${suffix}.last-focused.sticky-scroll-focused .monaco-list-rows .monaco-list-row.focused { outline: inherit; }`);\n\t\t\tcontent.push(`.monaco-workbench.context-menu-visible .monaco-list${suffix}.last-focused:not(.sticky-scroll-focused) .monaco-tree-sticky-container .monaco-list-rows .monaco-list-row.focused { outline: inherit; }`);\n\t\t}\n\n\t\tthis.styleElement.textContent = content.join('\\n');\n\n\t\tthis.view.style(styles);\n\t}\n\n\t// Tree navigation\n\n\tgetParentElement(location: TRef): T {\n\t\tconst parentRef = this.model.getParentNodeLocation(location);\n\t\tconst parentNode = this.model.getNode(parentRef);\n\t\treturn parentNode.element;\n\t}\n\n\tgetFirstElementChild(location: TRef): T | undefined {\n\t\treturn this.model.getFirstElementChild(location);\n\t}\n\n\t// Tree\n\n\tgetNode(location?: TRef): ITreeNode {\n\t\treturn this.model.getNode(location);\n\t}\n\n\tgetNodeLocation(node: ITreeNode): TRef {\n\t\treturn this.model.getNodeLocation(node);\n\t}\n\n\tcollapse(location: TRef, recursive: boolean = false): boolean {\n\t\treturn this.model.setCollapsed(location, true, recursive);\n\t}\n\n\texpand(location: TRef, recursive: boolean = false): boolean {\n\t\treturn this.model.setCollapsed(location, false, recursive);\n\t}\n\n\ttoggleCollapsed(location: TRef, recursive: boolean = false): boolean {\n\t\treturn this.model.setCollapsed(location, undefined, recursive);\n\t}\n\n\tisCollapsible(location: TRef): boolean {\n\t\treturn this.model.isCollapsible(location);\n\t}\n\n\tsetCollapsible(location: TRef, collapsible?: boolean): boolean {\n\t\treturn this.model.setCollapsible(location, collapsible);\n\t}\n\n\tisCollapsed(location: TRef): boolean {\n\t\treturn this.model.isCollapsed(location);\n\t}\n\n\trefilter(): void {\n\t\tthis._onWillRefilter.fire(undefined);\n\t\tthis.model.refilter();\n\t}\n\n\tsetSelection(elements: TRef[], browserEvent?: UIEvent): void {\n\t\tthis.eventBufferer.bufferEvents(() => {\n\t\t\tconst nodes = elements.map(e => this.model.getNode(e));\n\t\t\tthis.selection.set(nodes, browserEvent);\n\n\t\t\tconst indexes = elements.map(e => this.model.getListIndex(e)).filter(i => i > -1);\n\t\t\tthis.view.setSelection(indexes, browserEvent, true);\n\t\t});\n\t}\n\n\tgetSelection(): T[] {\n\t\treturn this.selection.get();\n\t}\n\n\tsetFocus(elements: TRef[], browserEvent?: UIEvent): void {\n\t\tthis.eventBufferer.bufferEvents(() => {\n\t\t\tconst nodes = elements.map(e => this.model.getNode(e));\n\t\t\tthis.focus.set(nodes, browserEvent);\n\n\t\t\tconst indexes = elements.map(e => this.model.getListIndex(e)).filter(i => i > -1);\n\t\t\tthis.view.setFocus(indexes, browserEvent, true);\n\t\t});\n\t}\n\n\tfocusNext(n = 1, loop = false, browserEvent?: UIEvent, filter: ((node: ITreeNode) => boolean) | undefined = (isKeyboardEvent(browserEvent) && browserEvent.altKey) ? undefined : this.focusNavigationFilter): void {\n\t\tthis.view.focusNext(n, loop, browserEvent, filter);\n\t}\n\n\tfocusPrevious(n = 1, loop = false, browserEvent?: UIEvent, filter: ((node: ITreeNode) => boolean) | undefined = (isKeyboardEvent(browserEvent) && browserEvent.altKey) ? undefined : this.focusNavigationFilter): void {\n\t\tthis.view.focusPrevious(n, loop, browserEvent, filter);\n\t}\n\n\tfocusNextPage(browserEvent?: UIEvent, filter: ((node: ITreeNode) => boolean) | undefined = (isKeyboardEvent(browserEvent) && browserEvent.altKey) ? undefined : this.focusNavigationFilter): Promise {\n\t\treturn this.view.focusNextPage(browserEvent, filter);\n\t}\n\n\tfocusPreviousPage(browserEvent?: UIEvent, filter: ((node: ITreeNode) => boolean) | undefined = (isKeyboardEvent(browserEvent) && browserEvent.altKey) ? undefined : this.focusNavigationFilter): Promise {\n\t\treturn this.view.focusPreviousPage(browserEvent, filter, () => this.stickyScrollController?.height ?? 0);\n\t}\n\n\tfocusFirst(browserEvent?: UIEvent, filter: ((node: ITreeNode) => boolean) | undefined = (isKeyboardEvent(browserEvent) && browserEvent.altKey) ? undefined : this.focusNavigationFilter): void {\n\t\tthis.view.focusFirst(browserEvent, filter);\n\t}\n\n\tgetFocus(): T[] {\n\t\treturn this.focus.get();\n\t}\n\n\treveal(location: TRef, relativeTop?: number): void {\n\t\tthis.model.expandTo(location);\n\n\t\tconst index = this.model.getListIndex(location);\n\n\t\tif (index === -1) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (!this.stickyScrollController) {\n\t\t\tthis.view.reveal(index, relativeTop);\n\t\t} else {\n\t\t\tconst paddingTop = this.stickyScrollController.nodePositionTopBelowWidget(this.getNode(location));\n\t\t\tthis.view.reveal(index, relativeTop, paddingTop);\n\t\t}\n\t}\n\n\t// List\n\n\tprivate onLeftArrow(e: StandardKeyboardEvent): void {\n\t\te.preventDefault();\n\t\te.stopPropagation();\n\n\t\tconst nodes = this.view.getFocusedElements();\n\n\t\tif (nodes.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst node = nodes[0];\n\t\tconst location = this.model.getNodeLocation(node);\n\t\tconst didChange = this.model.setCollapsed(location, true);\n\n\t\tif (!didChange) {\n\t\t\tconst parentLocation = this.model.getParentNodeLocation(location);\n\n\t\t\tif (!parentLocation) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst parentListIndex = this.model.getListIndex(parentLocation);\n\n\t\t\tthis.view.reveal(parentListIndex);\n\t\t\tthis.view.setFocus([parentListIndex]);\n\t\t}\n\t}\n\n\tprivate onRightArrow(e: StandardKeyboardEvent): void {\n\t\te.preventDefault();\n\t\te.stopPropagation();\n\n\t\tconst nodes = this.view.getFocusedElements();\n\n\t\tif (nodes.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst node = nodes[0];\n\t\tconst location = this.model.getNodeLocation(node);\n\t\tconst didChange = this.model.setCollapsed(location, false);\n\n\t\tif (!didChange) {\n\t\t\tif (!node.children.some(child => child.visible)) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst [focusedIndex] = this.view.getFocus();\n\t\t\tconst firstChildIndex = focusedIndex + 1;\n\n\t\t\tthis.view.reveal(firstChildIndex);\n\t\t\tthis.view.setFocus([firstChildIndex]);\n\t\t}\n\t}\n\n\tprivate onSpace(e: StandardKeyboardEvent): void {\n\t\te.preventDefault();\n\t\te.stopPropagation();\n\n\t\tconst nodes = this.view.getFocusedElements();\n\n\t\tif (nodes.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst node = nodes[0];\n\t\tconst location = this.model.getNodeLocation(node);\n\t\tconst recursive = e.browserEvent.altKey;\n\n\t\tthis.model.setCollapsed(location, undefined, recursive);\n\t}\n\n\tprotected abstract createModel(user: string, view: ISpliceable>, options: IAbstractTreeOptions): ITreeModel;\n\n\tdispose(): void {\n\t\tdispose(this.disposables);\n\t\tthis.stickyScrollController?.dispose();\n\t\tthis.view.dispose();\n\t}\n}\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\nimport { IIdentityProvider, IListVirtualDelegate } from 'vs/base/browser/ui/list/list';\nimport { AbstractTree, IAbstractTreeOptions } from 'vs/base/browser/ui/tree/abstractTree';\nimport { IList } from 'vs/base/browser/ui/tree/indexTreeModel';\nimport { ObjectTreeModel } from 'vs/base/browser/ui/tree/objectTreeModel';\nimport { IDataSource, ITreeModel, ITreeNode, ITreeRenderer } from 'vs/base/browser/ui/tree/tree';\n\nexport interface IDataTreeOptions extends IAbstractTreeOptions {\n}\n\nexport class DataTree extends AbstractTree {\n\n\tprotected declare model: ObjectTreeModel;\n\n\tprivate identityProvider: IIdentityProvider | undefined;\n\n\tconstructor(\n\t\tprivate user: string,\n\t\tcontainer: HTMLElement,\n\t\tdelegate: IListVirtualDelegate,\n\t\trenderers: ITreeRenderer[],\n\t\tprivate dataSource: IDataSource,\n\t\toptions: IDataTreeOptions = {}\n\t) {\n\t\tsuper(user, container, delegate, renderers, options as IDataTreeOptions);\n\t\tthis.identityProvider = options.identityProvider;\n\t}\n\n\tprotected createModel(user: string, view: IList>, options: IDataTreeOptions): ITreeModel {\n\t\treturn new ObjectTreeModel(user, view, options);\n\t}\n}\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\nimport { IIdentityProvider, IKeyboardNavigationLabelProvider, IListVirtualDelegate } from 'vs/base/browser/ui/list/list';\nimport { AbstractTree, IAbstractTreeOptions, IAbstractTreeOptionsUpdate, IStickyScrollDelegate, StickyScrollNode } from 'vs/base/browser/ui/tree/abstractTree';\nimport { CompressibleObjectTreeModel, ICompressedTreeElement, ICompressedTreeNode } from 'vs/base/browser/ui/tree/compressedObjectTreeModel';\nimport { IList } from 'vs/base/browser/ui/tree/indexTreeModel';\nimport { IObjectTreeModel, ObjectTreeModel } from 'vs/base/browser/ui/tree/objectTreeModel';\nimport { ICollapseStateChangeEvent, IObjectTreeElement, ITreeModel, ITreeNode, ITreeRenderer, ITreeSorter } from 'vs/base/browser/ui/tree/tree';\nimport { memoize } from 'vs/base/common/decorators';\nimport { Event } from 'vs/base/common/event';\nimport { Iterable } from 'vs/base/common/iterator';\n\nexport interface IObjectTreeOptions extends IAbstractTreeOptions {\n\treadonly sorter?: ITreeSorter;\n}\n\nexport interface IObjectTreeSetChildrenOptions {\n\n\t/**\n\t * Identity provider used to optimize splice() calls in the IndexTree. If\n\t * this is not present, optimized splicing is not enabled.\n\t *\n\t * Warning: if this is present, calls to `setChildren()` will not replace\n\t * or update nodes if their identity is the same, even if the elements are\n\t * different. For this, you should call `rerender()`.\n\t */\n\treadonly diffIdentityProvider?: IIdentityProvider;\n}\n\nexport class ObjectTree, TFilterData = void> extends AbstractTree {\n\n\tprotected declare model: IObjectTreeModel;\n\n\toverride get onDidChangeCollapseState(): Event> { return this.model.onDidChangeCollapseState; }\n\n\tconstructor(\n\t\tprotected readonly user: string,\n\t\tcontainer: HTMLElement,\n\t\tdelegate: IListVirtualDelegate,\n\t\trenderers: ITreeRenderer[],\n\t\toptions: IObjectTreeOptions = {}\n\t) {\n\t\tsuper(user, container, delegate, renderers, options as IObjectTreeOptions);\n\t}\n\n\tsetChildren(element: T | null, children: Iterable> = Iterable.empty(), options?: IObjectTreeSetChildrenOptions): void {\n\t\tthis.model.setChildren(element, children, options);\n\t}\n\n\trerender(element?: T): void {\n\t\tif (element === undefined) {\n\t\t\tthis.view.rerender();\n\t\t\treturn;\n\t\t}\n\n\t\tthis.model.rerender(element);\n\t}\n\n\thasElement(element: T): boolean {\n\t\treturn this.model.has(element);\n\t}\n\n\tprotected createModel(user: string, view: IList>, options: IObjectTreeOptions): ITreeModel {\n\t\treturn new ObjectTreeModel(user, view, options);\n\t}\n}\n\ninterface ICompressedTreeNodeProvider {\n\tgetCompressedTreeNode(location: T | null): ITreeNode | null, TFilterData>;\n}\n\nexport interface ICompressibleTreeRenderer extends ITreeRenderer {\n\trenderCompressedElements(node: ITreeNode, TFilterData>, index: number, templateData: TTemplateData, height: number | undefined): void;\n\tdisposeCompressedElements?(node: ITreeNode, TFilterData>, index: number, templateData: TTemplateData, height: number | undefined): void;\n}\n\ninterface CompressibleTemplateData {\n\tcompressedTreeNode: ITreeNode, TFilterData> | undefined;\n\treadonly data: TTemplateData;\n}\n\nclass CompressibleRenderer, TFilterData, TTemplateData> implements ITreeRenderer> {\n\n\treadonly templateId: string;\n\treadonly onDidChangeTwistieState: Event | undefined;\n\n\t@memoize\n\tprivate get compressedTreeNodeProvider(): ICompressedTreeNodeProvider {\n\t\treturn this._compressedTreeNodeProvider();\n\t}\n\n\tconstructor(private _compressedTreeNodeProvider: () => ICompressedTreeNodeProvider, private stickyScrollDelegate: CompressibleStickyScrollDelegate, private renderer: ICompressibleTreeRenderer) {\n\t\tthis.templateId = renderer.templateId;\n\n\t\tif (renderer.onDidChangeTwistieState) {\n\t\t\tthis.onDidChangeTwistieState = renderer.onDidChangeTwistieState;\n\t\t}\n\t}\n\n\trenderTemplate(container: HTMLElement): CompressibleTemplateData {\n\t\tconst data = this.renderer.renderTemplate(container);\n\t\treturn { compressedTreeNode: undefined, data };\n\t}\n\n\trenderElement(node: ITreeNode, index: number, templateData: CompressibleTemplateData, height: number | undefined): void {\n\t\tlet compressedTreeNode = this.stickyScrollDelegate.getCompressedNode(node);\n\t\tif (!compressedTreeNode) {\n\t\t\tcompressedTreeNode = this.compressedTreeNodeProvider.getCompressedTreeNode(node.element) as ITreeNode, TFilterData>;\n\t\t}\n\n\t\tif (compressedTreeNode.element.elements.length === 1) {\n\t\t\ttemplateData.compressedTreeNode = undefined;\n\t\t\tthis.renderer.renderElement(node, index, templateData.data, height);\n\t\t} else {\n\t\t\ttemplateData.compressedTreeNode = compressedTreeNode;\n\t\t\tthis.renderer.renderCompressedElements(compressedTreeNode, index, templateData.data, height);\n\t\t}\n\t}\n\n\tdisposeElement(node: ITreeNode, index: number, templateData: CompressibleTemplateData, height: number | undefined): void {\n\t\tif (templateData.compressedTreeNode) {\n\t\t\tthis.renderer.disposeCompressedElements?.(templateData.compressedTreeNode, index, templateData.data, height);\n\t\t} else {\n\t\t\tthis.renderer.disposeElement?.(node, index, templateData.data, height);\n\t\t}\n\t}\n\n\tdisposeTemplate(templateData: CompressibleTemplateData): void {\n\t\tthis.renderer.disposeTemplate(templateData.data);\n\t}\n\n\trenderTwistie?(element: T, twistieElement: HTMLElement): boolean {\n\t\tif (this.renderer.renderTwistie) {\n\t\t\treturn this.renderer.renderTwistie(element, twistieElement);\n\t\t}\n\t\treturn false;\n\t}\n}\n\nclass CompressibleStickyScrollDelegate implements IStickyScrollDelegate {\n\n\tprivate readonly compressedStickyNodes = new Map, ITreeNode, TFilterData>>();\n\n\tconstructor(private readonly modelProvider: () => CompressibleObjectTreeModel) { }\n\n\tgetCompressedNode(node: ITreeNode): ITreeNode, TFilterData> | undefined {\n\t\treturn this.compressedStickyNodes.get(node);\n\t}\n\n\tconstrainStickyScrollNodes(stickyNodes: StickyScrollNode[], stickyScrollMaxItemCount: number, maxWidgetHeight: number): StickyScrollNode[] {\n\t\tthis.compressedStickyNodes.clear();\n\t\tif (stickyNodes.length === 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\tfor (let i = 0; i < stickyNodes.length; i++) {\n\t\t\tconst stickyNode = stickyNodes[i];\n\t\t\tconst stickyNodeBottom = stickyNode.position + stickyNode.height;\n\t\t\tconst followingReachesMaxHeight = i + 1 < stickyNodes.length && stickyNodeBottom + stickyNodes[i + 1].height > maxWidgetHeight;\n\n\t\t\tif (followingReachesMaxHeight || i >= stickyScrollMaxItemCount - 1 && stickyScrollMaxItemCount < stickyNodes.length) {\n\t\t\t\tconst uncompressedStickyNodes = stickyNodes.slice(0, i);\n\t\t\t\tconst overflowingStickyNodes = stickyNodes.slice(i);\n\t\t\t\tconst compressedStickyNode = this.compressStickyNodes(overflowingStickyNodes);\n\t\t\t\treturn [...uncompressedStickyNodes, compressedStickyNode];\n\t\t\t}\n\n\t\t}\n\n\t\treturn stickyNodes;\n\t}\n\n\tprivate compressStickyNodes(stickyNodes: StickyScrollNode[]): StickyScrollNode {\n\n\t\tif (stickyNodes.length === 0) {\n\t\t\tthrow new Error('Can\\'t compress empty sticky nodes');\n\t\t}\n\t\tconst compressionModel = this.modelProvider();\n\t\tif (!compressionModel.isCompressionEnabled()) {\n\t\t\treturn stickyNodes[0];\n\t\t}\n\n\t\t// Collect all elements to be compressed\n\t\tconst elements: T[] = [];\n\t\tfor (let i = 0; i < stickyNodes.length; i++) {\n\t\t\tconst stickyNode = stickyNodes[i];\n\t\t\tconst compressedNode = compressionModel.getCompressedTreeNode(stickyNode.node.element);\n\n\t\t\tif (compressedNode.element) {\n\t\t\t\t// if an element is incompressible, it can't be compressed with it's parent element\n\t\t\t\tif (i !== 0 && compressedNode.element.incompressible) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\telements.push(...compressedNode.element.elements);\n\t\t\t}\n\t\t}\n\n\t\tif (elements.length < 2) {\n\t\t\treturn stickyNodes[0];\n\t\t}\n\n\t\t// Compress the elements\n\t\tconst lastStickyNode = stickyNodes[stickyNodes.length - 1];\n\t\tconst compressedElement: ICompressedTreeNode = { elements, incompressible: false };\n\t\tconst compressedNode: ITreeNode, TFilterData> = { ...lastStickyNode.node, children: [], element: compressedElement };\n\n\t\tconst stickyTreeNode = new Proxy(stickyNodes[0].node, {});\n\n\t\tconst compressedStickyNode: StickyScrollNode = {\n\t\t\tnode: stickyTreeNode,\n\t\t\tstartIndex: stickyNodes[0].startIndex,\n\t\t\tendIndex: lastStickyNode.endIndex,\n\t\t\tposition: stickyNodes[0].position,\n\t\t\theight: stickyNodes[0].height,\n\t\t};\n\n\t\tthis.compressedStickyNodes.set(stickyTreeNode, compressedNode);\n\n\t\treturn compressedStickyNode;\n\t}\n}\n\nexport interface ICompressibleKeyboardNavigationLabelProvider extends IKeyboardNavigationLabelProvider {\n\tgetCompressedNodeKeyboardNavigationLabel(elements: T[]): { toString(): string | undefined } | undefined;\n}\n\nexport interface ICompressibleObjectTreeOptions extends IObjectTreeOptions {\n\treadonly keyboardNavigationLabelProvider?: ICompressibleKeyboardNavigationLabelProvider;\n}\n\nfunction asObjectTreeOptions(compressedTreeNodeProvider: () => ICompressedTreeNodeProvider, options?: ICompressibleObjectTreeOptions): IObjectTreeOptions | undefined {\n\treturn options && {\n\t\t...options,\n\t\tkeyboardNavigationLabelProvider: options.keyboardNavigationLabelProvider && {\n\t\t\tgetKeyboardNavigationLabel(e: T) {\n\t\t\t\tlet compressedTreeNode: ITreeNode, TFilterData>;\n\n\t\t\t\ttry {\n\t\t\t\t\tcompressedTreeNode = compressedTreeNodeProvider().getCompressedTreeNode(e) as ITreeNode, TFilterData>;\n\t\t\t\t} catch {\n\t\t\t\t\treturn options.keyboardNavigationLabelProvider!.getKeyboardNavigationLabel(e);\n\t\t\t\t}\n\n\t\t\t\tif (compressedTreeNode.element.elements.length === 1) {\n\t\t\t\t\treturn options.keyboardNavigationLabelProvider!.getKeyboardNavigationLabel(e);\n\t\t\t\t} else {\n\t\t\t\t\treturn options.keyboardNavigationLabelProvider!.getCompressedNodeKeyboardNavigationLabel(compressedTreeNode.element.elements);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n}\n\nexport interface ICompressibleObjectTreeOptionsUpdate extends IAbstractTreeOptionsUpdate {\n\treadonly compressionEnabled?: boolean;\n}\n\nexport class CompressibleObjectTree, TFilterData = void> extends ObjectTree implements ICompressedTreeNodeProvider {\n\n\tprotected declare model: CompressibleObjectTreeModel;\n\n\tconstructor(\n\t\tuser: string,\n\t\tcontainer: HTMLElement,\n\t\tdelegate: IListVirtualDelegate,\n\t\trenderers: ICompressibleTreeRenderer[],\n\t\toptions: ICompressibleObjectTreeOptions = {}\n\t) {\n\t\tconst compressedTreeNodeProvider = () => this;\n\t\tconst stickyScrollDelegate = new CompressibleStickyScrollDelegate(() => this.model);\n\t\tconst compressibleRenderers = renderers.map(r => new CompressibleRenderer(compressedTreeNodeProvider, stickyScrollDelegate, r));\n\n\t\tsuper(user, container, delegate, compressibleRenderers, { ...asObjectTreeOptions(compressedTreeNodeProvider, options), stickyScrollDelegate });\n\t}\n\n\toverride setChildren(element: T | null, children: Iterable> = Iterable.empty(), options?: IObjectTreeSetChildrenOptions): void {\n\t\tthis.model.setChildren(element, children, options);\n\t}\n\n\tprotected override createModel(user: string, view: IList>, options: ICompressibleObjectTreeOptions): ITreeModel {\n\t\treturn new CompressibleObjectTreeModel(user, view, options);\n\t}\n\n\toverride updateOptions(optionsUpdate: ICompressibleObjectTreeOptionsUpdate = {}): void {\n\t\tsuper.updateOptions(optionsUpdate);\n\n\t\tif (typeof optionsUpdate.compressionEnabled !== 'undefined') {\n\t\t\tthis.model.setCompressionEnabled(optionsUpdate.compressionEnabled);\n\t\t}\n\t}\n\n\tgetCompressedTreeNode(element: T | null = null): ITreeNode | null, TFilterData> {\n\t\treturn this.model.getCompressedTreeNode(element);\n\t}\n}\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\nimport { IDragAndDropData } from 'vs/base/browser/dnd';\nimport { IIdentityProvider, IListDragAndDrop, IListDragOverReaction, IListVirtualDelegate } from 'vs/base/browser/ui/list/list';\nimport { ElementsDragAndDropData, ListViewTargetSector } from 'vs/base/browser/ui/list/listView';\nimport { IListStyles } from 'vs/base/browser/ui/list/listWidget';\nimport { ComposedTreeDelegate, TreeFindMode as TreeFindMode, IAbstractTreeOptions, IAbstractTreeOptionsUpdate, TreeFindMatchType } from 'vs/base/browser/ui/tree/abstractTree';\nimport { ICompressedTreeElement, ICompressedTreeNode } from 'vs/base/browser/ui/tree/compressedObjectTreeModel';\nimport { getVisibleState, isFilterResult } from 'vs/base/browser/ui/tree/indexTreeModel';\nimport { CompressibleObjectTree, ICompressibleKeyboardNavigationLabelProvider, ICompressibleObjectTreeOptions, ICompressibleTreeRenderer, IObjectTreeOptions, IObjectTreeSetChildrenOptions, ObjectTree } from 'vs/base/browser/ui/tree/objectTree';\nimport { IAsyncDataSource, ICollapseStateChangeEvent, IObjectTreeElement, ITreeDragAndDrop, ITreeEvent, ITreeFilter, ITreeMouseEvent, ITreeNode, ITreeRenderer, ITreeSorter, ObjectTreeElementCollapseState, TreeError, TreeFilterResult, TreeVisibility, WeakMapper } from 'vs/base/browser/ui/tree/tree';\nimport { CancelablePromise, createCancelablePromise, Promises, timeout } from 'vs/base/common/async';\nimport { Codicon } from 'vs/base/common/codicons';\nimport { ThemeIcon } from 'vs/base/common/themables';\nimport { isCancellationError, onUnexpectedError } from 'vs/base/common/errors';\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { Iterable } from 'vs/base/common/iterator';\nimport { DisposableStore, dispose, IDisposable } from 'vs/base/common/lifecycle';\nimport { ScrollEvent } from 'vs/base/common/scrollable';\nimport { isIterable } from 'vs/base/common/types';\n\ninterface IAsyncDataTreeNode {\n\telement: TInput | T;\n\treadonly parent: IAsyncDataTreeNode | null;\n\treadonly children: IAsyncDataTreeNode[];\n\treadonly id?: string | null;\n\trefreshPromise: Promise | undefined;\n\thasChildren: boolean;\n\tstale: boolean;\n\tslow: boolean;\n\treadonly defaultCollapseState: undefined | ObjectTreeElementCollapseState.PreserveOrCollapsed | ObjectTreeElementCollapseState.PreserveOrExpanded;\n\tforceExpanded: boolean;\n}\n\ninterface IAsyncDataTreeNodeRequiredProps extends Partial> {\n\treadonly element: TInput | T;\n\treadonly parent: IAsyncDataTreeNode | null;\n\treadonly hasChildren: boolean;\n\treadonly defaultCollapseState: undefined | ObjectTreeElementCollapseState.PreserveOrCollapsed | ObjectTreeElementCollapseState.PreserveOrExpanded;\n}\n\nfunction createAsyncDataTreeNode(props: IAsyncDataTreeNodeRequiredProps): IAsyncDataTreeNode {\n\treturn {\n\t\t...props,\n\t\tchildren: [],\n\t\trefreshPromise: undefined,\n\t\tstale: true,\n\t\tslow: false,\n\t\tforceExpanded: false\n\t};\n}\n\nfunction isAncestor(ancestor: IAsyncDataTreeNode, descendant: IAsyncDataTreeNode): boolean {\n\tif (!descendant.parent) {\n\t\treturn false;\n\t} else if (descendant.parent === ancestor) {\n\t\treturn true;\n\t} else {\n\t\treturn isAncestor(ancestor, descendant.parent);\n\t}\n}\n\nfunction intersects(node: IAsyncDataTreeNode, other: IAsyncDataTreeNode): boolean {\n\treturn node === other || isAncestor(node, other) || isAncestor(other, node);\n}\n\ninterface IDataTreeListTemplateData {\n\ttemplateData: T;\n}\n\ntype AsyncDataTreeNodeMapper = WeakMapper | null, TFilterData>, ITreeNode>;\n\nclass AsyncDataTreeNodeWrapper implements ITreeNode {\n\n\tget element(): T { return this.node.element!.element as T; }\n\tget children(): ITreeNode[] { return this.node.children.map(node => new AsyncDataTreeNodeWrapper(node)); }\n\tget depth(): number { return this.node.depth; }\n\tget visibleChildrenCount(): number { return this.node.visibleChildrenCount; }\n\tget visibleChildIndex(): number { return this.node.visibleChildIndex; }\n\tget collapsible(): boolean { return this.node.collapsible; }\n\tget collapsed(): boolean { return this.node.collapsed; }\n\tget visible(): boolean { return this.node.visible; }\n\tget filterData(): TFilterData | undefined { return this.node.filterData; }\n\n\tconstructor(private node: ITreeNode | null, TFilterData>) { }\n}\n\nclass AsyncDataTreeRenderer implements ITreeRenderer, TFilterData, IDataTreeListTemplateData> {\n\n\treadonly templateId: string;\n\tprivate renderedNodes = new Map, IDataTreeListTemplateData>();\n\n\tconstructor(\n\t\tprotected renderer: ITreeRenderer,\n\t\tprotected nodeMapper: AsyncDataTreeNodeMapper,\n\t\treadonly onDidChangeTwistieState: Event>\n\t) {\n\t\tthis.templateId = renderer.templateId;\n\t}\n\n\trenderTemplate(container: HTMLElement): IDataTreeListTemplateData {\n\t\tconst templateData = this.renderer.renderTemplate(container);\n\t\treturn { templateData };\n\t}\n\n\trenderElement(node: ITreeNode, TFilterData>, index: number, templateData: IDataTreeListTemplateData, height: number | undefined): void {\n\t\tthis.renderer.renderElement(this.nodeMapper.map(node) as ITreeNode, index, templateData.templateData, height);\n\t}\n\n\trenderTwistie(element: IAsyncDataTreeNode, twistieElement: HTMLElement): boolean {\n\t\tif (element.slow) {\n\t\t\ttwistieElement.classList.add(...ThemeIcon.asClassNameArray(Codicon.treeItemLoading));\n\t\t\treturn true;\n\t\t} else {\n\t\t\ttwistieElement.classList.remove(...ThemeIcon.asClassNameArray(Codicon.treeItemLoading));\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tdisposeElement(node: ITreeNode, TFilterData>, index: number, templateData: IDataTreeListTemplateData, height: number | undefined): void {\n\t\tthis.renderer.disposeElement?.(this.nodeMapper.map(node) as ITreeNode, index, templateData.templateData, height);\n\t}\n\n\tdisposeTemplate(templateData: IDataTreeListTemplateData): void {\n\t\tthis.renderer.disposeTemplate(templateData.templateData);\n\t}\n\n\tdispose(): void {\n\t\tthis.renderedNodes.clear();\n\t}\n}\n\nfunction asTreeEvent(e: ITreeEvent | null>): ITreeEvent {\n\treturn {\n\t\tbrowserEvent: e.browserEvent,\n\t\telements: e.elements.map(e => e!.element as T)\n\t};\n}\n\nfunction asTreeMouseEvent(e: ITreeMouseEvent | null>): ITreeMouseEvent {\n\treturn {\n\t\tbrowserEvent: e.browserEvent,\n\t\telement: e.element && e.element.element as T,\n\t\ttarget: e.target\n\t};\n}\n\nclass AsyncDataTreeElementsDragAndDropData extends ElementsDragAndDropData {\n\n\tconstructor(private data: ElementsDragAndDropData, TContext>) {\n\t\tsuper(data.elements.map(node => node.element as T));\n\t}\n}\n\nfunction asAsyncDataTreeDragAndDropData(data: IDragAndDropData): IDragAndDropData {\n\tif (data instanceof ElementsDragAndDropData) {\n\t\treturn new AsyncDataTreeElementsDragAndDropData(data);\n\t}\n\n\treturn data;\n}\n\nclass AsyncDataTreeNodeListDragAndDrop implements IListDragAndDrop> {\n\n\tconstructor(private dnd: ITreeDragAndDrop) { }\n\n\tgetDragURI(node: IAsyncDataTreeNode): string | null {\n\t\treturn this.dnd.getDragURI(node.element as T);\n\t}\n\n\tgetDragLabel(nodes: IAsyncDataTreeNode[], originalEvent: DragEvent): string | undefined {\n\t\tif (this.dnd.getDragLabel) {\n\t\t\treturn this.dnd.getDragLabel(nodes.map(node => node.element as T), originalEvent);\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\tonDragStart(data: IDragAndDropData, originalEvent: DragEvent): void {\n\t\tthis.dnd.onDragStart?.(asAsyncDataTreeDragAndDropData(data), originalEvent);\n\t}\n\n\tonDragOver(data: IDragAndDropData, targetNode: IAsyncDataTreeNode | undefined, targetIndex: number | undefined, targetSector: ListViewTargetSector | undefined, originalEvent: DragEvent, raw = true): boolean | IListDragOverReaction {\n\t\treturn this.dnd.onDragOver(asAsyncDataTreeDragAndDropData(data), targetNode && targetNode.element as T, targetIndex, targetSector, originalEvent);\n\t}\n\n\tdrop(data: IDragAndDropData, targetNode: IAsyncDataTreeNode | undefined, targetIndex: number | undefined, targetSector: ListViewTargetSector | undefined, originalEvent: DragEvent): void {\n\t\tthis.dnd.drop(asAsyncDataTreeDragAndDropData(data), targetNode && targetNode.element as T, targetIndex, targetSector, originalEvent);\n\t}\n\n\tonDragEnd(originalEvent: DragEvent): void {\n\t\tthis.dnd.onDragEnd?.(originalEvent);\n\t}\n\n\tdispose(): void {\n\t\tthis.dnd.dispose();\n\t}\n}\n\nfunction asObjectTreeOptions(options?: IAsyncDataTreeOptions): IObjectTreeOptions, TFilterData> | undefined {\n\treturn options && {\n\t\t...options,\n\t\tcollapseByDefault: true,\n\t\tidentityProvider: options.identityProvider && {\n\t\t\tgetId(el) {\n\t\t\t\treturn options.identityProvider!.getId(el.element as T);\n\t\t\t}\n\t\t},\n\t\tdnd: options.dnd && new AsyncDataTreeNodeListDragAndDrop(options.dnd),\n\t\tmultipleSelectionController: options.multipleSelectionController && {\n\t\t\tisSelectionSingleChangeEvent(e) {\n\t\t\t\treturn options.multipleSelectionController!.isSelectionSingleChangeEvent({ ...e, element: e.element } as any);\n\t\t\t},\n\t\t\tisSelectionRangeChangeEvent(e) {\n\t\t\t\treturn options.multipleSelectionController!.isSelectionRangeChangeEvent({ ...e, element: e.element } as any);\n\t\t\t}\n\t\t},\n\t\taccessibilityProvider: options.accessibilityProvider && {\n\t\t\t...options.accessibilityProvider,\n\t\t\tgetPosInSet: undefined,\n\t\t\tgetSetSize: undefined,\n\t\t\tgetRole: options.accessibilityProvider.getRole ? (el) => {\n\t\t\t\treturn options.accessibilityProvider!.getRole!(el.element as T);\n\t\t\t} : () => 'treeitem',\n\t\t\tisChecked: options.accessibilityProvider.isChecked ? (e) => {\n\t\t\t\treturn !!(options.accessibilityProvider?.isChecked!(e.element as T));\n\t\t\t} : undefined,\n\t\t\tgetAriaLabel(e) {\n\t\t\t\treturn options.accessibilityProvider!.getAriaLabel(e.element as T);\n\t\t\t},\n\t\t\tgetWidgetAriaLabel() {\n\t\t\t\treturn options.accessibilityProvider!.getWidgetAriaLabel();\n\t\t\t},\n\t\t\tgetWidgetRole: options.accessibilityProvider.getWidgetRole ? () => options.accessibilityProvider!.getWidgetRole!() : () => 'tree',\n\t\t\tgetAriaLevel: options.accessibilityProvider.getAriaLevel && (node => {\n\t\t\t\treturn options.accessibilityProvider!.getAriaLevel!(node.element as T);\n\t\t\t}),\n\t\t\tgetActiveDescendantId: options.accessibilityProvider.getActiveDescendantId && (node => {\n\t\t\t\treturn options.accessibilityProvider!.getActiveDescendantId!(node.element as T);\n\t\t\t})\n\t\t},\n\t\tfilter: options.filter && {\n\t\t\tfilter(e, parentVisibility) {\n\t\t\t\treturn options.filter!.filter(e.element as T, parentVisibility);\n\t\t\t}\n\t\t},\n\t\tkeyboardNavigationLabelProvider: options.keyboardNavigationLabelProvider && {\n\t\t\t...options.keyboardNavigationLabelProvider,\n\t\t\tgetKeyboardNavigationLabel(e) {\n\t\t\t\treturn options.keyboardNavigationLabelProvider!.getKeyboardNavigationLabel(e.element as T);\n\t\t\t}\n\t\t},\n\t\tsorter: undefined,\n\t\texpandOnlyOnTwistieClick: typeof options.expandOnlyOnTwistieClick === 'undefined' ? undefined : (\n\t\t\ttypeof options.expandOnlyOnTwistieClick !== 'function' ? options.expandOnlyOnTwistieClick : (\n\t\t\t\te => (options.expandOnlyOnTwistieClick as ((e: T) => boolean))(e.element as T)\n\t\t\t)\n\t\t),\n\t\tdefaultFindVisibility: e => {\n\t\t\tif (e.hasChildren && e.stale) {\n\t\t\t\treturn TreeVisibility.Visible;\n\t\t\t} else if (typeof options.defaultFindVisibility === 'number') {\n\t\t\t\treturn options.defaultFindVisibility;\n\t\t\t} else if (typeof options.defaultFindVisibility === 'undefined') {\n\t\t\t\treturn TreeVisibility.Recurse;\n\t\t\t} else {\n\t\t\t\treturn (options.defaultFindVisibility as ((e: T) => TreeVisibility))(e.element as T);\n\t\t\t}\n\t\t}\n\t};\n}\n\nexport interface IAsyncDataTreeOptionsUpdate extends IAbstractTreeOptionsUpdate { }\nexport interface IAsyncDataTreeUpdateChildrenOptions extends IObjectTreeSetChildrenOptions { }\n\nexport interface IAsyncDataTreeOptions extends IAsyncDataTreeOptionsUpdate, Pick, Exclude, 'collapseByDefault'>> {\n\treadonly collapseByDefault?: { (e: T): boolean };\n\treadonly identityProvider?: IIdentityProvider;\n\treadonly sorter?: ITreeSorter;\n\treadonly autoExpandSingleChildren?: boolean;\n}\n\nexport interface IAsyncDataTreeViewState {\n\treadonly focus?: string[];\n\treadonly selection?: string[];\n\treadonly expanded?: string[];\n\treadonly scrollTop?: number;\n}\n\ninterface IAsyncDataTreeViewStateContext {\n\treadonly viewState: IAsyncDataTreeViewState;\n\treadonly selection: IAsyncDataTreeNode[];\n\treadonly focus: IAsyncDataTreeNode[];\n}\n\nfunction dfs(node: IAsyncDataTreeNode, fn: (node: IAsyncDataTreeNode) => void): void {\n\tfn(node);\n\tnode.children.forEach(child => dfs(child, fn));\n}\n\nexport class AsyncDataTree implements IDisposable {\n\n\tprotected readonly tree: ObjectTree, TFilterData>;\n\tprotected readonly root: IAsyncDataTreeNode;\n\tprivate readonly nodes = new Map>();\n\tprivate readonly sorter?: ITreeSorter;\n\tprivate readonly getDefaultCollapseState: { (e: T): undefined | ObjectTreeElementCollapseState.PreserveOrCollapsed | ObjectTreeElementCollapseState.PreserveOrExpanded };\n\n\tprivate readonly subTreeRefreshPromises = new Map, Promise>();\n\tprivate readonly refreshPromises = new Map, CancelablePromise>>();\n\n\tprotected readonly identityProvider?: IIdentityProvider;\n\tprivate readonly autoExpandSingleChildren: boolean;\n\n\tprivate readonly _onDidRender = new Emitter();\n\tprotected readonly _onDidChangeNodeSlowState = new Emitter>();\n\n\tprotected readonly nodeMapper: AsyncDataTreeNodeMapper = new WeakMapper(node => new AsyncDataTreeNodeWrapper(node));\n\n\tprotected readonly disposables = new DisposableStore();\n\n\tget onDidScroll(): Event { return this.tree.onDidScroll; }\n\n\tget onDidChangeFocus(): Event> { return Event.map(this.tree.onDidChangeFocus, asTreeEvent); }\n\tget onDidChangeSelection(): Event> { return Event.map(this.tree.onDidChangeSelection, asTreeEvent); }\n\tget onMouseDblClick(): Event> { return Event.map(this.tree.onMouseDblClick, asTreeMouseEvent); }\n\tget onPointer(): Event> { return Event.map(this.tree.onPointer, asTreeMouseEvent); }\n\tget onDidFocus(): Event { return this.tree.onDidFocus; }\n\n\t/**\n\t * To be used internally only!\n\t * @deprecated\n\t */\n\tget onDidChangeModel(): Event { return this.tree.onDidChangeModel; }\n\tget onDidChangeCollapseState(): Event | null, TFilterData>> { return this.tree.onDidChangeCollapseState; }\n\n\tget onDidChangeFindOpenState(): Event { return this.tree.onDidChangeFindOpenState; }\n\tget onDidChangeStickyScrollFocused(): Event { return this.tree.onDidChangeStickyScrollFocused; }\n\treadonly onDidChangeFindMode: Event;\n\treadonly onDidChangeFindMatchType: Event;\n\n\tget onDidDispose(): Event { return this.tree.onDidDispose; }\n\n\tconstructor(\n\t\tprotected user: string,\n\t\tcontainer: HTMLElement,\n\t\tdelegate: IListVirtualDelegate,\n\t\trenderers: ITreeRenderer[],\n\t\tprivate dataSource: IAsyncDataSource,\n\t\toptions: IAsyncDataTreeOptions = {}\n\t) {\n\t\tthis.identityProvider = options.identityProvider;\n\t\tthis.autoExpandSingleChildren = typeof options.autoExpandSingleChildren === 'undefined' ? false : options.autoExpandSingleChildren;\n\t\tthis.sorter = options.sorter;\n\t\tthis.getDefaultCollapseState = e => options.collapseByDefault ? (options.collapseByDefault(e) ? ObjectTreeElementCollapseState.PreserveOrCollapsed : ObjectTreeElementCollapseState.PreserveOrExpanded) : undefined;\n\n\t\tthis.tree = this.createTree(user, container, delegate, renderers, options);\n\t\tthis.onDidChangeFindMode = this.tree.onDidChangeFindMode;\n\t\tthis.onDidChangeFindMatchType = this.tree.onDidChangeFindMatchType;\n\n\t\tthis.root = createAsyncDataTreeNode({\n\t\t\telement: undefined!,\n\t\t\tparent: null,\n\t\t\thasChildren: true,\n\t\t\tdefaultCollapseState: undefined\n\t\t});\n\n\t\tif (this.identityProvider) {\n\t\t\tthis.root = {\n\t\t\t\t...this.root,\n\t\t\t\tid: null\n\t\t\t};\n\t\t}\n\n\t\tthis.nodes.set(null, this.root);\n\n\t\tthis.tree.onDidChangeCollapseState(this._onDidChangeCollapseState, this, this.disposables);\n\t}\n\n\tprotected createTree(\n\t\tuser: string,\n\t\tcontainer: HTMLElement,\n\t\tdelegate: IListVirtualDelegate,\n\t\trenderers: ITreeRenderer[],\n\t\toptions: IAsyncDataTreeOptions\n\t): ObjectTree, TFilterData> {\n\t\tconst objectTreeDelegate = new ComposedTreeDelegate>(delegate);\n\t\tconst objectTreeRenderers = renderers.map(r => new AsyncDataTreeRenderer(r, this.nodeMapper, this._onDidChangeNodeSlowState.event));\n\t\tconst objectTreeOptions = asObjectTreeOptions(options) || {};\n\n\t\treturn new ObjectTree(user, container, objectTreeDelegate, objectTreeRenderers, objectTreeOptions);\n\t}\n\n\tupdateOptions(options: IAsyncDataTreeOptionsUpdate = {}): void {\n\t\tthis.tree.updateOptions(options);\n\t}\n\n\t// Widget\n\n\tgetHTMLElement(): HTMLElement {\n\t\treturn this.tree.getHTMLElement();\n\t}\n\n\tget scrollTop(): number {\n\t\treturn this.tree.scrollTop;\n\t}\n\n\tset scrollTop(scrollTop: number) {\n\t\tthis.tree.scrollTop = scrollTop;\n\t}\n\n\tget scrollHeight(): number {\n\t\treturn this.tree.scrollHeight;\n\t}\n\n\tget renderHeight(): number {\n\t\treturn this.tree.renderHeight;\n\t}\n\n\tdomFocus(): void {\n\t\tthis.tree.domFocus();\n\t}\n\n\tlayout(height?: number, width?: number): void {\n\t\tthis.tree.layout(height, width);\n\t}\n\n\tstyle(styles: IListStyles): void {\n\t\tthis.tree.style(styles);\n\t}\n\n\t// Model\n\n\tgetInput(): TInput | undefined {\n\t\treturn this.root.element as TInput;\n\t}\n\n\tasync setInput(input: TInput, viewState?: IAsyncDataTreeViewState): Promise {\n\t\tthis.refreshPromises.forEach(promise => promise.cancel());\n\t\tthis.refreshPromises.clear();\n\n\t\tthis.root.element = input!;\n\n\t\tconst viewStateContext: IAsyncDataTreeViewStateContext | undefined = viewState && { viewState, focus: [], selection: [] };\n\n\t\tawait this._updateChildren(input, true, false, viewStateContext);\n\n\t\tif (viewStateContext) {\n\t\t\tthis.tree.setFocus(viewStateContext.focus);\n\t\t\tthis.tree.setSelection(viewStateContext.selection);\n\t\t}\n\n\t\tif (viewState && typeof viewState.scrollTop === 'number') {\n\t\t\tthis.scrollTop = viewState.scrollTop;\n\t\t}\n\t}\n\n\tprivate async _updateChildren(element: TInput | T = this.root.element, recursive = true, rerender = false, viewStateContext?: IAsyncDataTreeViewStateContext, options?: IAsyncDataTreeUpdateChildrenOptions): Promise {\n\t\tif (typeof this.root.element === 'undefined') {\n\t\t\tthrow new TreeError(this.user, 'Tree input not set');\n\t\t}\n\n\t\tif (this.root.refreshPromise) {\n\t\t\tawait this.root.refreshPromise;\n\t\t\tawait Event.toPromise(this._onDidRender.event);\n\t\t}\n\n\t\tconst node = this.getDataNode(element);\n\t\tawait this.refreshAndRenderNode(node, recursive, viewStateContext, options);\n\n\t\tif (rerender) {\n\t\t\ttry {\n\t\t\t\tthis.tree.rerender(node);\n\t\t\t} catch {\n\t\t\t\t// missing nodes are fine, this could've resulted from\n\t\t\t\t// parallel refresh calls, removing `node` altogether\n\t\t\t}\n\t\t}\n\t}\n\n\t// View\n\n\trerender(element?: T): void {\n\t\tif (element === undefined || element === this.root.element) {\n\t\t\tthis.tree.rerender();\n\t\t\treturn;\n\t\t}\n\n\t\tconst node = this.getDataNode(element);\n\t\tthis.tree.rerender(node);\n\t}\n\n\t// Tree\n\n\tgetNode(element: TInput | T = this.root.element): ITreeNode {\n\t\tconst dataNode = this.getDataNode(element);\n\t\tconst node = this.tree.getNode(dataNode === this.root ? null : dataNode);\n\t\treturn this.nodeMapper.map(node);\n\t}\n\n\tcollapse(element: T, recursive: boolean = false): boolean {\n\t\tconst node = this.getDataNode(element);\n\t\treturn this.tree.collapse(node === this.root ? null : node, recursive);\n\t}\n\n\tasync expand(element: T, recursive: boolean = false): Promise {\n\t\tif (typeof this.root.element === 'undefined') {\n\t\t\tthrow new TreeError(this.user, 'Tree input not set');\n\t\t}\n\n\t\tif (this.root.refreshPromise) {\n\t\t\tawait this.root.refreshPromise;\n\t\t\tawait Event.toPromise(this._onDidRender.event);\n\t\t}\n\n\t\tconst node = this.getDataNode(element);\n\n\t\tif (this.tree.hasElement(node) && !this.tree.isCollapsible(node)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (node.refreshPromise) {\n\t\t\tawait this.root.refreshPromise;\n\t\t\tawait Event.toPromise(this._onDidRender.event);\n\t\t}\n\n\t\tif (node !== this.root && !node.refreshPromise && !this.tree.isCollapsed(node)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst result = this.tree.expand(node === this.root ? null : node, recursive);\n\n\t\tif (node.refreshPromise) {\n\t\t\tawait this.root.refreshPromise;\n\t\t\tawait Event.toPromise(this._onDidRender.event);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tsetSelection(elements: T[], browserEvent?: UIEvent): void {\n\t\tconst nodes = elements.map(e => this.getDataNode(e));\n\t\tthis.tree.setSelection(nodes, browserEvent);\n\t}\n\n\tgetSelection(): T[] {\n\t\tconst nodes = this.tree.getSelection();\n\t\treturn nodes.map(n => n!.element as T);\n\t}\n\n\tsetFocus(elements: T[], browserEvent?: UIEvent): void {\n\t\tconst nodes = elements.map(e => this.getDataNode(e));\n\t\tthis.tree.setFocus(nodes, browserEvent);\n\t}\n\n\tgetFocus(): T[] {\n\t\tconst nodes = this.tree.getFocus();\n\t\treturn nodes.map(n => n!.element as T);\n\t}\n\n\treveal(element: T, relativeTop?: number): void {\n\t\tthis.tree.reveal(this.getDataNode(element), relativeTop);\n\t}\n\n\t// Tree navigation\n\n\tgetParentElement(element: T): TInput | T {\n\t\tconst node = this.tree.getParentElement(this.getDataNode(element));\n\t\treturn (node && node.element)!;\n\t}\n\n\tgetFirstElementChild(element: TInput | T = this.root.element): TInput | T | undefined {\n\t\tconst dataNode = this.getDataNode(element);\n\t\tconst node = this.tree.getFirstElementChild(dataNode === this.root ? null : dataNode);\n\t\treturn (node && node.element)!;\n\t}\n\n\t// Implementation\n\n\tprivate getDataNode(element: TInput | T): IAsyncDataTreeNode {\n\t\tconst node: IAsyncDataTreeNode | undefined = this.nodes.get((element === this.root.element ? null : element) as T);\n\n\t\tif (!node) {\n\t\t\tthrow new TreeError(this.user, `Data tree node not found: ${element}`);\n\t\t}\n\n\t\treturn node;\n\t}\n\n\tprivate async refreshAndRenderNode(node: IAsyncDataTreeNode, recursive: boolean, viewStateContext?: IAsyncDataTreeViewStateContext, options?: IAsyncDataTreeUpdateChildrenOptions): Promise {\n\t\tawait this.refreshNode(node, recursive, viewStateContext);\n\t\tif (this.disposables.isDisposed) {\n\t\t\treturn; // tree disposed during refresh (#199264)\n\t\t}\n\t\tthis.render(node, viewStateContext, options);\n\t}\n\n\tprivate async refreshNode(node: IAsyncDataTreeNode, recursive: boolean, viewStateContext?: IAsyncDataTreeViewStateContext): Promise {\n\t\tlet result: Promise | undefined;\n\n\t\tthis.subTreeRefreshPromises.forEach((refreshPromise, refreshNode) => {\n\t\t\tif (!result && intersects(refreshNode, node)) {\n\t\t\t\tresult = refreshPromise.then(() => this.refreshNode(node, recursive, viewStateContext));\n\t\t\t}\n\t\t});\n\n\t\tif (result) {\n\t\t\treturn result;\n\t\t}\n\n\t\tif (node !== this.root) {\n\t\t\tconst treeNode = this.tree.getNode(node);\n\n\t\t\tif (treeNode.collapsed) {\n\t\t\t\tnode.hasChildren = !!this.dataSource.hasChildren(node.element);\n\t\t\t\tnode.stale = true;\n\t\t\t\tthis.setChildren(node, [], recursive, viewStateContext);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\treturn this.doRefreshSubTree(node, recursive, viewStateContext);\n\t}\n\n\tprivate async doRefreshSubTree(node: IAsyncDataTreeNode, recursive: boolean, viewStateContext?: IAsyncDataTreeViewStateContext): Promise {\n\t\tlet done: () => void;\n\t\tnode.refreshPromise = new Promise(c => done = c);\n\t\tthis.subTreeRefreshPromises.set(node, node.refreshPromise);\n\n\t\tnode.refreshPromise.finally(() => {\n\t\t\tnode.refreshPromise = undefined;\n\t\t\tthis.subTreeRefreshPromises.delete(node);\n\t\t});\n\n\t\ttry {\n\t\t\tconst childrenToRefresh = await this.doRefreshNode(node, recursive, viewStateContext);\n\t\t\tnode.stale = false;\n\n\t\t\tawait Promises.settled(childrenToRefresh.map(child => this.doRefreshSubTree(child, recursive, viewStateContext)));\n\t\t} finally {\n\t\t\tdone!();\n\t\t}\n\t}\n\n\tprivate async doRefreshNode(node: IAsyncDataTreeNode, recursive: boolean, viewStateContext?: IAsyncDataTreeViewStateContext): Promise[]> {\n\t\tnode.hasChildren = !!this.dataSource.hasChildren(node.element);\n\n\t\tlet childrenPromise: Promise>;\n\n\t\tif (!node.hasChildren) {\n\t\t\tchildrenPromise = Promise.resolve(Iterable.empty());\n\t\t} else {\n\t\t\tconst children = this.doGetChildren(node);\n\t\t\tif (isIterable(children)) {\n\t\t\t\tchildrenPromise = Promise.resolve(children);\n\t\t\t} else {\n\t\t\t\tconst slowTimeout = timeout(800);\n\n\t\t\t\tslowTimeout.then(() => {\n\t\t\t\t\tnode.slow = true;\n\t\t\t\t\tthis._onDidChangeNodeSlowState.fire(node);\n\t\t\t\t}, _ => null);\n\n\t\t\t\tchildrenPromise = children.finally(() => slowTimeout.cancel());\n\t\t\t}\n\t\t}\n\n\t\ttry {\n\t\t\tconst children = await childrenPromise;\n\t\t\treturn this.setChildren(node, children, recursive, viewStateContext);\n\t\t} catch (err) {\n\t\t\tif (node !== this.root && this.tree.hasElement(node)) {\n\t\t\t\tthis.tree.collapse(node);\n\t\t\t}\n\n\t\t\tif (isCancellationError(err)) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tthrow err;\n\t\t} finally {\n\t\t\tif (node.slow) {\n\t\t\t\tnode.slow = false;\n\t\t\t\tthis._onDidChangeNodeSlowState.fire(node);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate doGetChildren(node: IAsyncDataTreeNode): Promise> | Iterable {\n\t\tlet result = this.refreshPromises.get(node);\n\n\t\tif (result) {\n\t\t\treturn result;\n\t\t}\n\t\tconst children = this.dataSource.getChildren(node.element);\n\t\tif (isIterable(children)) {\n\t\t\treturn this.processChildren(children);\n\t\t} else {\n\t\t\tresult = createCancelablePromise(async () => this.processChildren(await children));\n\t\t\tthis.refreshPromises.set(node, result);\n\t\t\treturn result.finally(() => { this.refreshPromises.delete(node); });\n\t\t}\n\t}\n\n\tprivate _onDidChangeCollapseState({ node, deep }: ICollapseStateChangeEvent | null, any>): void {\n\t\tif (node.element === null) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (!node.collapsed && node.element.stale) {\n\t\t\tif (deep) {\n\t\t\t\tthis.collapse(node.element.element as T);\n\t\t\t} else {\n\t\t\t\tthis.refreshAndRenderNode(node.element, false)\n\t\t\t\t\t.catch(onUnexpectedError);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate setChildren(node: IAsyncDataTreeNode, childrenElementsIterable: Iterable, recursive: boolean, viewStateContext?: IAsyncDataTreeViewStateContext): IAsyncDataTreeNode[] {\n\t\tconst childrenElements = [...childrenElementsIterable];\n\n\t\t// perf: if the node was and still is a leaf, avoid all this hassle\n\t\tif (node.children.length === 0 && childrenElements.length === 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst nodesToForget = new Map>();\n\t\tconst childrenTreeNodesById = new Map; collapsed: boolean }>();\n\n\t\tfor (const child of node.children) {\n\t\t\tnodesToForget.set(child.element as T, child);\n\n\t\t\tif (this.identityProvider) {\n\t\t\t\tchildrenTreeNodesById.set(child.id!, { node: child, collapsed: this.tree.hasElement(child) && this.tree.isCollapsed(child) });\n\t\t\t}\n\t\t}\n\n\t\tconst childrenToRefresh: IAsyncDataTreeNode[] = [];\n\n\t\tconst children = childrenElements.map>(element => {\n\t\t\tconst hasChildren = !!this.dataSource.hasChildren(element);\n\n\t\t\tif (!this.identityProvider) {\n\t\t\t\tconst asyncDataTreeNode = createAsyncDataTreeNode({ element, parent: node, hasChildren, defaultCollapseState: this.getDefaultCollapseState(element) });\n\n\t\t\t\tif (hasChildren && asyncDataTreeNode.defaultCollapseState === ObjectTreeElementCollapseState.PreserveOrExpanded) {\n\t\t\t\t\tchildrenToRefresh.push(asyncDataTreeNode);\n\t\t\t\t}\n\n\t\t\t\treturn asyncDataTreeNode;\n\t\t\t}\n\n\t\t\tconst id = this.identityProvider.getId(element).toString();\n\t\t\tconst result = childrenTreeNodesById.get(id);\n\n\t\t\tif (result) {\n\t\t\t\tconst asyncDataTreeNode = result.node;\n\n\t\t\t\tnodesToForget.delete(asyncDataTreeNode.element as T);\n\t\t\t\tthis.nodes.delete(asyncDataTreeNode.element as T);\n\t\t\t\tthis.nodes.set(element, asyncDataTreeNode);\n\n\t\t\t\tasyncDataTreeNode.element = element;\n\t\t\t\tasyncDataTreeNode.hasChildren = hasChildren;\n\n\t\t\t\tif (recursive) {\n\t\t\t\t\tif (result.collapsed) {\n\t\t\t\t\t\tasyncDataTreeNode.children.forEach(node => dfs(node, node => this.nodes.delete(node.element as T)));\n\t\t\t\t\t\tasyncDataTreeNode.children.splice(0, asyncDataTreeNode.children.length);\n\t\t\t\t\t\tasyncDataTreeNode.stale = true;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tchildrenToRefresh.push(asyncDataTreeNode);\n\t\t\t\t\t}\n\t\t\t\t} else if (hasChildren && !result.collapsed) {\n\t\t\t\t\tchildrenToRefresh.push(asyncDataTreeNode);\n\t\t\t\t}\n\n\t\t\t\treturn asyncDataTreeNode;\n\t\t\t}\n\n\t\t\tconst childAsyncDataTreeNode = createAsyncDataTreeNode({ element, parent: node, id, hasChildren, defaultCollapseState: this.getDefaultCollapseState(element) });\n\n\t\t\tif (viewStateContext && viewStateContext.viewState.focus && viewStateContext.viewState.focus.indexOf(id) > -1) {\n\t\t\t\tviewStateContext.focus.push(childAsyncDataTreeNode);\n\t\t\t}\n\n\t\t\tif (viewStateContext && viewStateContext.viewState.selection && viewStateContext.viewState.selection.indexOf(id) > -1) {\n\t\t\t\tviewStateContext.selection.push(childAsyncDataTreeNode);\n\t\t\t}\n\n\t\t\tif (viewStateContext && viewStateContext.viewState.expanded && viewStateContext.viewState.expanded.indexOf(id) > -1) {\n\t\t\t\tchildrenToRefresh.push(childAsyncDataTreeNode);\n\t\t\t} else if (hasChildren && childAsyncDataTreeNode.defaultCollapseState === ObjectTreeElementCollapseState.PreserveOrExpanded) {\n\t\t\t\tchildrenToRefresh.push(childAsyncDataTreeNode);\n\t\t\t}\n\n\t\t\treturn childAsyncDataTreeNode;\n\t\t});\n\n\t\tfor (const node of nodesToForget.values()) {\n\t\t\tdfs(node, node => this.nodes.delete(node.element as T));\n\t\t}\n\n\t\tfor (const child of children) {\n\t\t\tthis.nodes.set(child.element as T, child);\n\t\t}\n\n\t\tnode.children.splice(0, node.children.length, ...children);\n\n\t\t// TODO@joao this doesn't take filter into account\n\t\tif (node !== this.root && this.autoExpandSingleChildren && children.length === 1 && childrenToRefresh.length === 0) {\n\t\t\tchildren[0].forceExpanded = true;\n\t\t\tchildrenToRefresh.push(children[0]);\n\t\t}\n\n\t\treturn childrenToRefresh;\n\t}\n\n\tprotected render(node: IAsyncDataTreeNode, viewStateContext?: IAsyncDataTreeViewStateContext, options?: IAsyncDataTreeUpdateChildrenOptions): void {\n\t\tconst children = node.children.map(node => this.asTreeElement(node, viewStateContext));\n\t\tconst objectTreeOptions: IObjectTreeSetChildrenOptions> | undefined = options && {\n\t\t\t...options,\n\t\t\tdiffIdentityProvider: options.diffIdentityProvider && {\n\t\t\t\tgetId(node: IAsyncDataTreeNode): { toString(): string } {\n\t\t\t\t\treturn options.diffIdentityProvider!.getId(node.element as T);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tthis.tree.setChildren(node === this.root ? null : node, children, objectTreeOptions);\n\n\t\tif (node !== this.root) {\n\t\t\tthis.tree.setCollapsible(node, node.hasChildren);\n\t\t}\n\n\t\tthis._onDidRender.fire();\n\t}\n\n\tprotected asTreeElement(node: IAsyncDataTreeNode, viewStateContext?: IAsyncDataTreeViewStateContext): IObjectTreeElement> {\n\t\tif (node.stale) {\n\t\t\treturn {\n\t\t\t\telement: node,\n\t\t\t\tcollapsible: node.hasChildren,\n\t\t\t\tcollapsed: true\n\t\t\t};\n\t\t}\n\n\t\tlet collapsed: boolean | ObjectTreeElementCollapseState.PreserveOrCollapsed | ObjectTreeElementCollapseState.PreserveOrExpanded | undefined;\n\n\t\tif (viewStateContext && viewStateContext.viewState.expanded && node.id && viewStateContext.viewState.expanded.indexOf(node.id) > -1) {\n\t\t\tcollapsed = false;\n\t\t} else if (node.forceExpanded) {\n\t\t\tcollapsed = false;\n\t\t\tnode.forceExpanded = false;\n\t\t} else {\n\t\t\tcollapsed = node.defaultCollapseState;\n\t\t}\n\n\t\treturn {\n\t\t\telement: node,\n\t\t\tchildren: node.hasChildren ? Iterable.map(node.children, child => this.asTreeElement(child, viewStateContext)) : [],\n\t\t\tcollapsible: node.hasChildren,\n\t\t\tcollapsed\n\t\t};\n\t}\n\n\tprotected processChildren(children: Iterable): Iterable {\n\t\tif (this.sorter) {\n\t\t\tchildren = [...children].sort(this.sorter.compare.bind(this.sorter));\n\t\t}\n\n\t\treturn children;\n\t}\n\n\tdispose(): void {\n\t\tthis.disposables.dispose();\n\t\tthis.tree.dispose();\n\t}\n}\n\ntype CompressibleAsyncDataTreeNodeMapper = WeakMapper>, TFilterData>, ITreeNode, TFilterData>>;\n\nclass CompressibleAsyncDataTreeNodeWrapper implements ITreeNode, TFilterData> {\n\n\tget element(): ICompressedTreeNode {\n\t\treturn {\n\t\t\telements: this.node.element.elements.map(e => e.element),\n\t\t\tincompressible: this.node.element.incompressible\n\t\t};\n\t}\n\n\tget children(): ITreeNode, TFilterData>[] { return this.node.children.map(node => new CompressibleAsyncDataTreeNodeWrapper(node)); }\n\tget depth(): number { return this.node.depth; }\n\tget visibleChildrenCount(): number { return this.node.visibleChildrenCount; }\n\tget visibleChildIndex(): number { return this.node.visibleChildIndex; }\n\tget collapsible(): boolean { return this.node.collapsible; }\n\tget collapsed(): boolean { return this.node.collapsed; }\n\tget visible(): boolean { return this.node.visible; }\n\tget filterData(): TFilterData | undefined { return this.node.filterData; }\n\n\tconstructor(private node: ITreeNode>, TFilterData>) { }\n}\n\nclass CompressibleAsyncDataTreeRenderer implements ICompressibleTreeRenderer, TFilterData, IDataTreeListTemplateData> {\n\n\treadonly templateId: string;\n\tprivate renderedNodes = new Map, IDataTreeListTemplateData>();\n\tprivate disposables: IDisposable[] = [];\n\n\tconstructor(\n\t\tprotected renderer: ICompressibleTreeRenderer,\n\t\tprotected nodeMapper: AsyncDataTreeNodeMapper,\n\t\tprivate compressibleNodeMapperProvider: () => CompressibleAsyncDataTreeNodeMapper,\n\t\treadonly onDidChangeTwistieState: Event>\n\t) {\n\t\tthis.templateId = renderer.templateId;\n\t}\n\n\trenderTemplate(container: HTMLElement): IDataTreeListTemplateData {\n\t\tconst templateData = this.renderer.renderTemplate(container);\n\t\treturn { templateData };\n\t}\n\n\trenderElement(node: ITreeNode, TFilterData>, index: number, templateData: IDataTreeListTemplateData, height: number | undefined): void {\n\t\tthis.renderer.renderElement(this.nodeMapper.map(node) as ITreeNode, index, templateData.templateData, height);\n\t}\n\n\trenderCompressedElements(node: ITreeNode>, TFilterData>, index: number, templateData: IDataTreeListTemplateData, height: number | undefined): void {\n\t\tthis.renderer.renderCompressedElements(this.compressibleNodeMapperProvider().map(node) as ITreeNode, TFilterData>, index, templateData.templateData, height);\n\t}\n\n\trenderTwistie(element: IAsyncDataTreeNode, twistieElement: HTMLElement): boolean {\n\t\tif (element.slow) {\n\t\t\ttwistieElement.classList.add(...ThemeIcon.asClassNameArray(Codicon.treeItemLoading));\n\t\t\treturn true;\n\t\t} else {\n\t\t\ttwistieElement.classList.remove(...ThemeIcon.asClassNameArray(Codicon.treeItemLoading));\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tdisposeElement(node: ITreeNode, TFilterData>, index: number, templateData: IDataTreeListTemplateData, height: number | undefined): void {\n\t\tthis.renderer.disposeElement?.(this.nodeMapper.map(node) as ITreeNode, index, templateData.templateData, height);\n\t}\n\n\tdisposeCompressedElements(node: ITreeNode>, TFilterData>, index: number, templateData: IDataTreeListTemplateData, height: number | undefined): void {\n\t\tthis.renderer.disposeCompressedElements?.(this.compressibleNodeMapperProvider().map(node) as ITreeNode, TFilterData>, index, templateData.templateData, height);\n\t}\n\n\tdisposeTemplate(templateData: IDataTreeListTemplateData): void {\n\t\tthis.renderer.disposeTemplate(templateData.templateData);\n\t}\n\n\tdispose(): void {\n\t\tthis.renderedNodes.clear();\n\t\tthis.disposables = dispose(this.disposables);\n\t}\n}\n\nexport interface ITreeCompressionDelegate {\n\tisIncompressible(element: T): boolean;\n}\n\nfunction asCompressibleObjectTreeOptions(options?: ICompressibleAsyncDataTreeOptions): ICompressibleObjectTreeOptions, TFilterData> | undefined {\n\tconst objectTreeOptions = options && asObjectTreeOptions(options);\n\n\treturn objectTreeOptions && {\n\t\t...objectTreeOptions,\n\t\tkeyboardNavigationLabelProvider: objectTreeOptions.keyboardNavigationLabelProvider && {\n\t\t\t...objectTreeOptions.keyboardNavigationLabelProvider,\n\t\t\tgetCompressedNodeKeyboardNavigationLabel(els) {\n\t\t\t\treturn options.keyboardNavigationLabelProvider!.getCompressedNodeKeyboardNavigationLabel(els.map(e => e.element as T));\n\t\t\t}\n\t\t}\n\t};\n}\n\nexport interface ICompressibleAsyncDataTreeOptions extends IAsyncDataTreeOptions {\n\treadonly keyboardNavigationLabelProvider?: ICompressibleKeyboardNavigationLabelProvider;\n}\n\nexport interface ICompressibleAsyncDataTreeOptionsUpdate extends IAsyncDataTreeOptionsUpdate {\n}\n\nexport class CompressibleAsyncDataTree extends AsyncDataTree {\n\n\tprotected declare readonly tree: CompressibleObjectTree, TFilterData>;\n\tprotected readonly compressibleNodeMapper: CompressibleAsyncDataTreeNodeMapper = new WeakMapper(node => new CompressibleAsyncDataTreeNodeWrapper(node));\n\tprivate filter?: ITreeFilter;\n\n\tconstructor(\n\t\tuser: string,\n\t\tcontainer: HTMLElement,\n\t\tvirtualDelegate: IListVirtualDelegate,\n\t\tprivate compressionDelegate: ITreeCompressionDelegate,\n\t\trenderers: ICompressibleTreeRenderer[],\n\t\tdataSource: IAsyncDataSource,\n\t\toptions: ICompressibleAsyncDataTreeOptions = {}\n\t) {\n\t\tsuper(user, container, virtualDelegate, renderers, dataSource, options);\n\t\tthis.filter = options.filter;\n\t}\n\n\tprotected override createTree(\n\t\tuser: string,\n\t\tcontainer: HTMLElement,\n\t\tdelegate: IListVirtualDelegate,\n\t\trenderers: ICompressibleTreeRenderer[],\n\t\toptions: ICompressibleAsyncDataTreeOptions\n\t): ObjectTree, TFilterData> {\n\t\tconst objectTreeDelegate = new ComposedTreeDelegate>(delegate);\n\t\tconst objectTreeRenderers = renderers.map(r => new CompressibleAsyncDataTreeRenderer(r, this.nodeMapper, () => this.compressibleNodeMapper, this._onDidChangeNodeSlowState.event));\n\t\tconst objectTreeOptions = asCompressibleObjectTreeOptions(options) || {};\n\n\t\treturn new CompressibleObjectTree(user, container, objectTreeDelegate, objectTreeRenderers, objectTreeOptions);\n\t}\n\n\tprotected override asTreeElement(node: IAsyncDataTreeNode, viewStateContext?: IAsyncDataTreeViewStateContext): ICompressedTreeElement> {\n\t\treturn {\n\t\t\tincompressible: this.compressionDelegate.isIncompressible(node.element as T),\n\t\t\t...super.asTreeElement(node, viewStateContext)\n\t\t};\n\t}\n\n\toverride updateOptions(options: ICompressibleAsyncDataTreeOptionsUpdate = {}): void {\n\t\tthis.tree.updateOptions(options);\n\t}\n\n\tprotected override render(node: IAsyncDataTreeNode, viewStateContext?: IAsyncDataTreeViewStateContext, options?: IAsyncDataTreeUpdateChildrenOptions): void {\n\t\tif (!this.identityProvider) {\n\t\t\treturn super.render(node, viewStateContext);\n\t\t}\n\n\t\t// Preserve traits across compressions. Hacky but does the trick.\n\t\t// This is hard to fix properly since it requires rewriting the traits\n\t\t// across trees and lists. Let's just keep it this way for now.\n\t\tconst getId = (element: T) => this.identityProvider!.getId(element).toString();\n\t\tconst getUncompressedIds = (nodes: IAsyncDataTreeNode[]): Set => {\n\t\t\tconst result = new Set();\n\n\t\t\tfor (const node of nodes) {\n\t\t\t\tconst compressedNode = this.tree.getCompressedTreeNode(node === this.root ? null : node);\n\n\t\t\t\tif (!compressedNode.element) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tfor (const node of compressedNode.element.elements) {\n\t\t\t\t\tresult.add(getId(node.element as T));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn result;\n\t\t};\n\n\t\tconst oldSelection = getUncompressedIds(this.tree.getSelection() as IAsyncDataTreeNode[]);\n\t\tconst oldFocus = getUncompressedIds(this.tree.getFocus() as IAsyncDataTreeNode[]);\n\n\t\tsuper.render(node, viewStateContext, options);\n\n\t\tconst selection = this.getSelection();\n\t\tlet didChangeSelection = false;\n\n\t\tconst focus = this.getFocus();\n\t\tlet didChangeFocus = false;\n\n\t\tconst visit = (node: ITreeNode> | null, TFilterData>) => {\n\t\t\tconst compressedNode = node.element;\n\n\t\t\tif (compressedNode) {\n\t\t\t\tfor (let i = 0; i < compressedNode.elements.length; i++) {\n\t\t\t\t\tconst id = getId(compressedNode.elements[i].element as T);\n\t\t\t\t\tconst element = compressedNode.elements[compressedNode.elements.length - 1].element as T;\n\n\t\t\t\t\t// github.com/microsoft/vscode/issues/85938\n\t\t\t\t\tif (oldSelection.has(id) && selection.indexOf(element) === -1) {\n\t\t\t\t\t\tselection.push(element);\n\t\t\t\t\t\tdidChangeSelection = true;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (oldFocus.has(id) && focus.indexOf(element) === -1) {\n\t\t\t\t\t\tfocus.push(element);\n\t\t\t\t\t\tdidChangeFocus = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tnode.children.forEach(visit);\n\t\t};\n\n\t\tvisit(this.tree.getCompressedTreeNode(node === this.root ? null : node));\n\n\t\tif (didChangeSelection) {\n\t\t\tthis.setSelection(selection);\n\t\t}\n\n\t\tif (didChangeFocus) {\n\t\t\tthis.setFocus(focus);\n\t\t}\n\t}\n\n\t// For compressed async data trees, `TreeVisibility.Recurse` doesn't currently work\n\t// and we have to filter everything beforehand\n\t// Related to #85193 and #85835\n\tprotected override processChildren(children: Iterable): Iterable {\n\t\tif (this.filter) {\n\t\t\tchildren = Iterable.filter(children, e => {\n\t\t\t\tconst result = this.filter!.filter(e, TreeVisibility.Visible);\n\t\t\t\tconst visibility = getVisibility(result);\n\n\t\t\t\tif (visibility === TreeVisibility.Recurse) {\n\t\t\t\t\tthrow new Error('Recursive tree visibility not supported in async data compressed trees');\n\t\t\t\t}\n\n\t\t\t\treturn visibility === TreeVisibility.Visible;\n\t\t\t});\n\t\t}\n\n\t\treturn super.processChildren(children);\n\t}\n}\n\nfunction getVisibility(filterResult: TreeFilterResult): TreeVisibility {\n\tif (typeof filterResult === 'boolean') {\n\t\treturn filterResult ? TreeVisibility.Visible : TreeVisibility.Hidden;\n\t} else if (isFilterResult(filterResult)) {\n\t\treturn getVisibleState(filterResult.visibility);\n\t} else {\n\t\treturn getVisibleState(filterResult);\n\t}\n}\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\nimport { transformErrorForSerialization } from 'vs/base/common/errors';\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { Disposable, IDisposable } from 'vs/base/common/lifecycle';\nimport { getAllMethodNames } from 'vs/base/common/objects';\nimport { isWeb } from 'vs/base/common/platform';\nimport * as strings from 'vs/base/common/strings';\n\nconst INITIALIZE = '$initialize';\n\nexport interface IWorker extends IDisposable {\n\tgetId(): number;\n\tpostMessage(message: Message, transfer: ArrayBuffer[]): void;\n}\n\nexport interface IWorkerCallback {\n\t(message: Message): void;\n}\n\nexport interface IWorkerFactory {\n\tcreate(moduleId: string, callback: IWorkerCallback, onErrorCallback: (err: any) => void): IWorker;\n}\n\nlet webWorkerWarningLogged = false;\nexport function logOnceWebWorkerWarning(err: any): void {\n\tif (!isWeb) {\n\t\t// running tests\n\t\treturn;\n\t}\n\tif (!webWorkerWarningLogged) {\n\t\twebWorkerWarningLogged = true;\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');\n\t}\n\tconsole.warn(err.message);\n}\n\nconst enum MessageType {\n\tRequest,\n\tReply,\n\tSubscribeEvent,\n\tEvent,\n\tUnsubscribeEvent\n}\nclass RequestMessage {\n\tpublic readonly type = MessageType.Request;\n\tconstructor(\n\t\tpublic readonly vsWorker: number,\n\t\tpublic readonly req: string,\n\t\tpublic readonly method: string,\n\t\tpublic readonly args: any[]\n\t) { }\n}\nclass ReplyMessage {\n\tpublic readonly type = MessageType.Reply;\n\tconstructor(\n\t\tpublic readonly vsWorker: number,\n\t\tpublic readonly seq: string,\n\t\tpublic readonly res: any,\n\t\tpublic readonly err: any\n\t) { }\n}\nclass SubscribeEventMessage {\n\tpublic readonly type = MessageType.SubscribeEvent;\n\tconstructor(\n\t\tpublic readonly vsWorker: number,\n\t\tpublic readonly req: string,\n\t\tpublic readonly eventName: string,\n\t\tpublic readonly arg: any\n\t) { }\n}\nclass EventMessage {\n\tpublic readonly type = MessageType.Event;\n\tconstructor(\n\t\tpublic readonly vsWorker: number,\n\t\tpublic readonly req: string,\n\t\tpublic readonly event: any\n\t) { }\n}\nclass UnsubscribeEventMessage {\n\tpublic readonly type = MessageType.UnsubscribeEvent;\n\tconstructor(\n\t\tpublic readonly vsWorker: number,\n\t\tpublic readonly req: string\n\t) { }\n}\ntype Message = RequestMessage | ReplyMessage | SubscribeEventMessage | EventMessage | UnsubscribeEventMessage;\n\ninterface IMessageReply {\n\tresolve: (value?: any) => void;\n\treject: (error?: any) => void;\n}\n\ninterface IMessageHandler {\n\tsendMessage(msg: any, transfer?: ArrayBuffer[]): void;\n\thandleMessage(method: string, args: any[]): Promise;\n\thandleEvent(eventName: string, arg: any): Event;\n}\n\nclass SimpleWorkerProtocol {\n\n\tprivate _workerId: number;\n\tprivate _lastSentReq: number;\n\tprivate _pendingReplies: { [req: string]: IMessageReply };\n\tprivate _pendingEmitters: Map>;\n\tprivate _pendingEvents: Map;\n\tprivate _handler: IMessageHandler;\n\n\tconstructor(handler: IMessageHandler) {\n\t\tthis._workerId = -1;\n\t\tthis._handler = handler;\n\t\tthis._lastSentReq = 0;\n\t\tthis._pendingReplies = Object.create(null);\n\t\tthis._pendingEmitters = new Map>();\n\t\tthis._pendingEvents = new Map();\n\t}\n\n\tpublic setWorkerId(workerId: number): void {\n\t\tthis._workerId = workerId;\n\t}\n\n\tpublic sendMessage(method: string, args: any[]): Promise {\n\t\tconst req = String(++this._lastSentReq);\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tthis._pendingReplies[req] = {\n\t\t\t\tresolve: resolve,\n\t\t\t\treject: reject\n\t\t\t};\n\t\t\tthis._send(new RequestMessage(this._workerId, req, method, args));\n\t\t});\n\t}\n\n\tpublic listen(eventName: string, arg: any): Event {\n\t\tlet req: string | null = null;\n\t\tconst emitter = new Emitter({\n\t\t\tonWillAddFirstListener: () => {\n\t\t\t\treq = String(++this._lastSentReq);\n\t\t\t\tthis._pendingEmitters.set(req, emitter);\n\t\t\t\tthis._send(new SubscribeEventMessage(this._workerId, req, eventName, arg));\n\t\t\t},\n\t\t\tonDidRemoveLastListener: () => {\n\t\t\t\tthis._pendingEmitters.delete(req!);\n\t\t\t\tthis._send(new UnsubscribeEventMessage(this._workerId, req!));\n\t\t\t\treq = null;\n\t\t\t}\n\t\t});\n\t\treturn emitter.event;\n\t}\n\n\tpublic handleMessage(message: Message): void {\n\t\tif (!message || !message.vsWorker) {\n\t\t\treturn;\n\t\t}\n\t\tif (this._workerId !== -1 && message.vsWorker !== this._workerId) {\n\t\t\treturn;\n\t\t}\n\t\tthis._handleMessage(message);\n\t}\n\n\tprivate _handleMessage(msg: Message): void {\n\t\tswitch (msg.type) {\n\t\t\tcase MessageType.Reply:\n\t\t\t\treturn this._handleReplyMessage(msg);\n\t\t\tcase MessageType.Request:\n\t\t\t\treturn this._handleRequestMessage(msg);\n\t\t\tcase MessageType.SubscribeEvent:\n\t\t\t\treturn this._handleSubscribeEventMessage(msg);\n\t\t\tcase MessageType.Event:\n\t\t\t\treturn this._handleEventMessage(msg);\n\t\t\tcase MessageType.UnsubscribeEvent:\n\t\t\t\treturn this._handleUnsubscribeEventMessage(msg);\n\t\t}\n\t}\n\n\tprivate _handleReplyMessage(replyMessage: ReplyMessage): void {\n\t\tif (!this._pendingReplies[replyMessage.seq]) {\n\t\t\tconsole.warn('Got reply to unknown seq');\n\t\t\treturn;\n\t\t}\n\n\t\tconst reply = this._pendingReplies[replyMessage.seq];\n\t\tdelete this._pendingReplies[replyMessage.seq];\n\n\t\tif (replyMessage.err) {\n\t\t\tlet err = replyMessage.err;\n\t\t\tif (replyMessage.err.$isError) {\n\t\t\t\terr = new Error();\n\t\t\t\terr.name = replyMessage.err.name;\n\t\t\t\terr.message = replyMessage.err.message;\n\t\t\t\terr.stack = replyMessage.err.stack;\n\t\t\t}\n\t\t\treply.reject(err);\n\t\t\treturn;\n\t\t}\n\n\t\treply.resolve(replyMessage.res);\n\t}\n\n\tprivate _handleRequestMessage(requestMessage: RequestMessage): void {\n\t\tconst req = requestMessage.req;\n\t\tconst result = this._handler.handleMessage(requestMessage.method, requestMessage.args);\n\t\tresult.then((r) => {\n\t\t\tthis._send(new ReplyMessage(this._workerId, req, r, undefined));\n\t\t}, (e) => {\n\t\t\tif (e.detail instanceof Error) {\n\t\t\t\t// Loading errors have a detail property that points to the actual error\n\t\t\t\te.detail = transformErrorForSerialization(e.detail);\n\t\t\t}\n\t\t\tthis._send(new ReplyMessage(this._workerId, req, undefined, transformErrorForSerialization(e)));\n\t\t});\n\t}\n\n\tprivate _handleSubscribeEventMessage(msg: SubscribeEventMessage): void {\n\t\tconst req = msg.req;\n\t\tconst disposable = this._handler.handleEvent(msg.eventName, msg.arg)((event) => {\n\t\t\tthis._send(new EventMessage(this._workerId, req, event));\n\t\t});\n\t\tthis._pendingEvents.set(req, disposable);\n\t}\n\n\tprivate _handleEventMessage(msg: EventMessage): void {\n\t\tif (!this._pendingEmitters.has(msg.req)) {\n\t\t\tconsole.warn('Got event for unknown req');\n\t\t\treturn;\n\t\t}\n\t\tthis._pendingEmitters.get(msg.req)!.fire(msg.event);\n\t}\n\n\tprivate _handleUnsubscribeEventMessage(msg: UnsubscribeEventMessage): void {\n\t\tif (!this._pendingEvents.has(msg.req)) {\n\t\t\tconsole.warn('Got unsubscribe for unknown req');\n\t\t\treturn;\n\t\t}\n\t\tthis._pendingEvents.get(msg.req)!.dispose();\n\t\tthis._pendingEvents.delete(msg.req);\n\t}\n\n\tprivate _send(msg: Message): void {\n\t\tconst transfer: ArrayBuffer[] = [];\n\t\tif (msg.type === MessageType.Request) {\n\t\t\tfor (let i = 0; i < msg.args.length; i++) {\n\t\t\t\tif (msg.args[i] instanceof ArrayBuffer) {\n\t\t\t\t\ttransfer.push(msg.args[i]);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (msg.type === MessageType.Reply) {\n\t\t\tif (msg.res instanceof ArrayBuffer) {\n\t\t\t\ttransfer.push(msg.res);\n\t\t\t}\n\t\t}\n\t\tthis._handler.sendMessage(msg, transfer);\n\t}\n}\n\nexport interface IWorkerClient {\n\tgetProxyObject(): Promise;\n\tdispose(): void;\n}\n\n/**\n * Main thread side\n */\nexport class SimpleWorkerClient extends Disposable implements IWorkerClient {\n\n\tprivate readonly _worker: IWorker;\n\tprivate readonly _onModuleLoaded: Promise;\n\tprivate readonly _protocol: SimpleWorkerProtocol;\n\tprivate readonly _lazyProxy: Promise;\n\n\tconstructor(workerFactory: IWorkerFactory, moduleId: string, host: H) {\n\t\tsuper();\n\n\t\tlet lazyProxyReject: ((err: any) => void) | null = null;\n\n\t\tthis._worker = this._register(workerFactory.create(\n\t\t\t'vs/base/common/worker/simpleWorker',\n\t\t\t(msg: Message) => {\n\t\t\t\tthis._protocol.handleMessage(msg);\n\t\t\t},\n\t\t\t(err: any) => {\n\t\t\t\t// in Firefox, web workers fail lazily :(\n\t\t\t\t// we will reject the proxy\n\t\t\t\tlazyProxyReject?.(err);\n\t\t\t}\n\t\t));\n\n\t\tthis._protocol = new SimpleWorkerProtocol({\n\t\t\tsendMessage: (msg: any, transfer: ArrayBuffer[]): void => {\n\t\t\t\tthis._worker.postMessage(msg, transfer);\n\t\t\t},\n\t\t\thandleMessage: (method: string, args: any[]): Promise => {\n\t\t\t\tif (typeof (host as any)[method] !== 'function') {\n\t\t\t\t\treturn Promise.reject(new Error('Missing method ' + method + ' on main thread host.'));\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\treturn Promise.resolve((host as any)[method].apply(host, args));\n\t\t\t\t} catch (e) {\n\t\t\t\t\treturn Promise.reject(e);\n\t\t\t\t}\n\t\t\t},\n\t\t\thandleEvent: (eventName: string, arg: any): Event => {\n\t\t\t\tif (propertyIsDynamicEvent(eventName)) {\n\t\t\t\t\tconst event = (host as any)[eventName].call(host, arg);\n\t\t\t\t\tif (typeof event !== 'function') {\n\t\t\t\t\t\tthrow new Error(`Missing dynamic event ${eventName} on main thread host.`);\n\t\t\t\t\t}\n\t\t\t\t\treturn event;\n\t\t\t\t}\n\t\t\t\tif (propertyIsEvent(eventName)) {\n\t\t\t\t\tconst event = (host as any)[eventName];\n\t\t\t\t\tif (typeof event !== 'function') {\n\t\t\t\t\t\tthrow new Error(`Missing event ${eventName} on main thread host.`);\n\t\t\t\t\t}\n\t\t\t\t\treturn event;\n\t\t\t\t}\n\t\t\t\tthrow new Error(`Malformed event name ${eventName}`);\n\t\t\t}\n\t\t});\n\t\tthis._protocol.setWorkerId(this._worker.getId());\n\n\t\t// Gather loader configuration\n\t\tlet loaderConfiguration: any = null;\n\n\t\tconst globalRequire: { getConfig?(): object } | undefined = (globalThis as any).require;\n\t\tif (typeof globalRequire !== 'undefined' && typeof globalRequire.getConfig === 'function') {\n\t\t\t// Get the configuration from the Monaco AMD Loader\n\t\t\tloaderConfiguration = globalRequire.getConfig();\n\t\t} else if (typeof (globalThis as any).requirejs !== 'undefined') {\n\t\t\t// Get the configuration from requirejs\n\t\t\tloaderConfiguration = (globalThis as any).requirejs.s.contexts._.config;\n\t\t}\n\n\t\tconst hostMethods = getAllMethodNames(host);\n\n\t\t// Send initialize message\n\t\tthis._onModuleLoaded = this._protocol.sendMessage(INITIALIZE, [\n\t\t\tthis._worker.getId(),\n\t\t\tJSON.parse(JSON.stringify(loaderConfiguration)),\n\t\t\tmoduleId,\n\t\t\thostMethods,\n\t\t]);\n\n\t\t// Create proxy to loaded code\n\t\tconst proxyMethodRequest = (method: string, args: any[]): Promise => {\n\t\t\treturn this._request(method, args);\n\t\t};\n\t\tconst proxyListen = (eventName: string, arg: any): Event => {\n\t\t\treturn this._protocol.listen(eventName, arg);\n\t\t};\n\n\t\tthis._lazyProxy = new Promise((resolve, reject) => {\n\t\t\tlazyProxyReject = reject;\n\t\t\tthis._onModuleLoaded.then((availableMethods: string[]) => {\n\t\t\t\tresolve(createProxyObject(availableMethods, proxyMethodRequest, proxyListen));\n\t\t\t}, (e) => {\n\t\t\t\treject(e);\n\t\t\t\tthis._onError('Worker failed to load ' + moduleId, e);\n\t\t\t});\n\t\t});\n\t}\n\n\tpublic getProxyObject(): Promise {\n\t\treturn this._lazyProxy;\n\t}\n\n\tprivate _request(method: string, args: any[]): Promise {\n\t\treturn new Promise((resolve, reject) => {\n\t\t\tthis._onModuleLoaded.then(() => {\n\t\t\t\tthis._protocol.sendMessage(method, args).then(resolve, reject);\n\t\t\t}, reject);\n\t\t});\n\t}\n\n\tprivate _onError(message: string, error?: any): void {\n\t\tconsole.error(message);\n\t\tconsole.info(error);\n\t}\n}\n\nfunction propertyIsEvent(name: string): boolean {\n\t// Assume a property is an event if it has a form of \"onSomething\"\n\treturn name[0] === 'o' && name[1] === 'n' && strings.isUpperAsciiLetter(name.charCodeAt(2));\n}\n\nfunction propertyIsDynamicEvent(name: string): boolean {\n\t// Assume a property is a dynamic event (a method that returns an event) if it has a form of \"onDynamicSomething\"\n\treturn /^onDynamic/.test(name) && strings.isUpperAsciiLetter(name.charCodeAt(9));\n}\n\nfunction createProxyObject(\n\tmethodNames: string[],\n\tinvoke: (method: string, args: unknown[]) => unknown,\n\tproxyListen: (eventName: string, arg: any) => Event\n): T {\n\tconst createProxyMethod = (method: string): () => unknown => {\n\t\treturn function () {\n\t\t\tconst args = Array.prototype.slice.call(arguments, 0);\n\t\t\treturn invoke(method, args);\n\t\t};\n\t};\n\tconst createProxyDynamicEvent = (eventName: string): (arg: any) => Event => {\n\t\treturn function (arg) {\n\t\t\treturn proxyListen(eventName, arg);\n\t\t};\n\t};\n\n\tconst result = {} as T;\n\tfor (const methodName of methodNames) {\n\t\tif (propertyIsDynamicEvent(methodName)) {\n\t\t\t(result)[methodName] = createProxyDynamicEvent(methodName);\n\t\t\tcontinue;\n\t\t}\n\t\tif (propertyIsEvent(methodName)) {\n\t\t\t(result)[methodName] = proxyListen(methodName, undefined);\n\t\t\tcontinue;\n\t\t}\n\t\t(result)[methodName] = createProxyMethod(methodName);\n\t}\n\treturn result;\n}\n\nexport interface IRequestHandler {\n\t_requestHandlerBrand: any;\n\t[prop: string]: any;\n}\n\nexport interface IRequestHandlerFactory {\n\t(host: H): IRequestHandler;\n}\n\n/**\n * Worker side\n */\nexport class SimpleWorkerServer {\n\n\tprivate _requestHandlerFactory: IRequestHandlerFactory | null;\n\tprivate _requestHandler: IRequestHandler | null;\n\tprivate _protocol: SimpleWorkerProtocol;\n\n\tconstructor(postMessage: (msg: Message, transfer?: ArrayBuffer[]) => void, requestHandlerFactory: IRequestHandlerFactory | null) {\n\t\tthis._requestHandlerFactory = requestHandlerFactory;\n\t\tthis._requestHandler = null;\n\t\tthis._protocol = new SimpleWorkerProtocol({\n\t\t\tsendMessage: (msg: any, transfer: ArrayBuffer[]): void => {\n\t\t\t\tpostMessage(msg, transfer);\n\t\t\t},\n\t\t\thandleMessage: (method: string, args: any[]): Promise => this._handleMessage(method, args),\n\t\t\thandleEvent: (eventName: string, arg: any): Event => this._handleEvent(eventName, arg)\n\t\t});\n\t}\n\n\tpublic onmessage(msg: any): void {\n\t\tthis._protocol.handleMessage(msg);\n\t}\n\n\tprivate _handleMessage(method: string, args: any[]): Promise {\n\t\tif (method === INITIALIZE) {\n\t\t\treturn this.initialize(args[0], args[1], args[2], args[3]);\n\t\t}\n\n\t\tif (!this._requestHandler || typeof this._requestHandler[method] !== 'function') {\n\t\t\treturn Promise.reject(new Error('Missing requestHandler or method: ' + method));\n\t\t}\n\n\t\ttry {\n\t\t\treturn Promise.resolve(this._requestHandler[method].apply(this._requestHandler, args));\n\t\t} catch (e) {\n\t\t\treturn Promise.reject(e);\n\t\t}\n\t}\n\n\tprivate _handleEvent(eventName: string, arg: any): Event {\n\t\tif (!this._requestHandler) {\n\t\t\tthrow new Error(`Missing requestHandler`);\n\t\t}\n\t\tif (propertyIsDynamicEvent(eventName)) {\n\t\t\tconst event = (this._requestHandler as any)[eventName].call(this._requestHandler, arg);\n\t\t\tif (typeof event !== 'function') {\n\t\t\t\tthrow new Error(`Missing dynamic event ${eventName} on request handler.`);\n\t\t\t}\n\t\t\treturn event;\n\t\t}\n\t\tif (propertyIsEvent(eventName)) {\n\t\t\tconst event = (this._requestHandler as any)[eventName];\n\t\t\tif (typeof event !== 'function') {\n\t\t\t\tthrow new Error(`Missing event ${eventName} on request handler.`);\n\t\t\t}\n\t\t\treturn event;\n\t\t}\n\t\tthrow new Error(`Malformed event name ${eventName}`);\n\t}\n\n\tprivate initialize(workerId: number, loaderConfig: any, moduleId: string, hostMethods: string[]): Promise {\n\t\tthis._protocol.setWorkerId(workerId);\n\n\t\tconst proxyMethodRequest = (method: string, args: any[]): Promise => {\n\t\t\treturn this._protocol.sendMessage(method, args);\n\t\t};\n\t\tconst proxyListen = (eventName: string, arg: any): Event => {\n\t\t\treturn this._protocol.listen(eventName, arg);\n\t\t};\n\n\t\tconst hostProxy = createProxyObject(hostMethods, proxyMethodRequest, proxyListen);\n\n\t\tif (this._requestHandlerFactory) {\n\t\t\t// static request handler\n\t\t\tthis._requestHandler = this._requestHandlerFactory(hostProxy);\n\t\t\treturn Promise.resolve(getAllMethodNames(this._requestHandler));\n\t\t}\n\n\t\tif (loaderConfig) {\n\t\t\t// Remove 'baseUrl', handling it is beyond scope for now\n\t\t\tif (typeof loaderConfig.baseUrl !== 'undefined') {\n\t\t\t\tdelete loaderConfig['baseUrl'];\n\t\t\t}\n\t\t\tif (typeof loaderConfig.paths !== 'undefined') {\n\t\t\t\tif (typeof loaderConfig.paths.vs !== 'undefined') {\n\t\t\t\t\tdelete loaderConfig.paths['vs'];\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (typeof loaderConfig.trustedTypesPolicy !== 'undefined') {\n\t\t\t\t// don't use, it has been destroyed during serialize\n\t\t\t\tdelete loaderConfig['trustedTypesPolicy'];\n\t\t\t}\n\n\t\t\t// Since this is in a web worker, enable catching errors\n\t\t\tloaderConfig.catchError = true;\n\t\t\tglobalThis.require.config(loaderConfig);\n\t\t}\n\n\t\treturn new Promise((resolve, reject) => {\n\t\t\t// Use the global require to be sure to get the global config\n\n\t\t\t// ESM-comment-begin\n\t\t\tconst req = (globalThis.require || require);\n\t\t\t// ESM-comment-end\n\t\t\t// ESM-uncomment-begin\n\t\t\t// const req = globalThis.require;\n\t\t\t// ESM-uncomment-end\n\n\t\t\treq([moduleId], (module: { create: IRequestHandlerFactory }) => {\n\t\t\t\tthis._requestHandler = module.create(hostProxy);\n\n\t\t\t\tif (!this._requestHandler) {\n\t\t\t\t\treject(new Error(`No RequestHandler!`));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tresolve(getAllMethodNames(this._requestHandler));\n\t\t\t}, reject);\n\t\t});\n\t}\n}\n\n/**\n * Called on the worker side\n * @skipMangle\n */\nexport function create(postMessage: (msg: Message, transfer?: ArrayBuffer[]) => void): SimpleWorkerServer {\n\treturn new SimpleWorkerServer(postMessage, null);\n}\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\nimport { createTrustedTypesPolicy } from 'vs/base/browser/trustedTypes';\nimport { onUnexpectedError } from 'vs/base/common/errors';\nimport { COI } from 'vs/base/common/network';\nimport { IWorker, IWorkerCallback, IWorkerFactory, logOnceWebWorkerWarning } from 'vs/base/common/worker/simpleWorker';\nimport { Disposable, toDisposable } from 'vs/base/common/lifecycle';\n\nconst ttPolicy = createTrustedTypesPolicy('defaultWorkerFactory', { createScriptURL: value => value });\n\nfunction getWorker(label: string): Worker | Promise {\n\t// Option for hosts to overwrite the worker script (used in the standalone editor)\n\tinterface IMonacoEnvironment {\n\t\tgetWorker?(moduleId: string, label: string): Worker | Promise;\n\t\tgetWorkerUrl?(moduleId: string, label: string): string;\n\t}\n\tconst monacoEnvironment: IMonacoEnvironment | undefined = (globalThis as any).MonacoEnvironment;\n\tif (monacoEnvironment) {\n\t\tif (typeof monacoEnvironment.getWorker === 'function') {\n\t\t\treturn monacoEnvironment.getWorker('workerMain.js', label);\n\t\t}\n\t\tif (typeof monacoEnvironment.getWorkerUrl === 'function') {\n\t\t\tconst workerUrl = monacoEnvironment.getWorkerUrl('workerMain.js', label);\n\t\t\treturn new Worker(ttPolicy ? ttPolicy.createScriptURL(workerUrl) as unknown as string : workerUrl, { name: label });\n\t\t}\n\t}\n\t// ESM-comment-begin\n\tif (typeof require === 'function') {\n\t\t// check if the JS lives on a different origin\n\t\tconst workerMain = require.toUrl('vs/base/worker/workerMain.js'); // explicitly using require.toUrl(), see https://github.com/microsoft/vscode/issues/107440#issuecomment-698982321\n\t\tconst workerUrl = getWorkerBootstrapUrl(workerMain, label);\n\t\treturn new Worker(ttPolicy ? ttPolicy.createScriptURL(workerUrl) as unknown as string : workerUrl, { name: label });\n\t}\n\t// ESM-comment-end\n\tthrow new Error(`You must define a function MonacoEnvironment.getWorkerUrl or MonacoEnvironment.getWorker`);\n}\n\n// ESM-comment-begin\nexport function getWorkerBootstrapUrl(scriptPath: string, label: string): string {\n\tif (/^((http:)|(https:)|(file:))/.test(scriptPath) && scriptPath.substring(0, globalThis.origin.length) !== globalThis.origin) {\n\t\t// this is the cross-origin case\n\t\t// i.e. the webpage is running at a different origin than where the scripts are loaded from\n\t\tconst myPath = 'vs/base/worker/defaultWorkerFactory.js';\n\t\tconst workerBaseUrl = require.toUrl(myPath).slice(0, -myPath.length); // explicitly using require.toUrl(), see https://github.com/microsoft/vscode/issues/107440#issuecomment-698982321\n\t\tconst js = `/*${label}*/globalThis.MonacoEnvironment={baseUrl: '${workerBaseUrl}'};const ttPolicy = globalThis.trustedTypes?.createPolicy('defaultWorkerFactory', { createScriptURL: value => value });importScripts(ttPolicy?.createScriptURL('${scriptPath}') ?? '${scriptPath}');/*${label}*/`;\n\t\tconst blob = new Blob([js], { type: 'application/javascript' });\n\t\treturn URL.createObjectURL(blob);\n\t}\n\n\tconst start = scriptPath.lastIndexOf('?');\n\tconst end = scriptPath.lastIndexOf('#', start);\n\tconst params = start > 0\n\t\t? new URLSearchParams(scriptPath.substring(start + 1, ~end ? end : undefined))\n\t\t: new URLSearchParams();\n\n\tCOI.addSearchParam(params, true, true);\n\tconst search = params.toString();\n\n\tif (!search) {\n\t\treturn `${scriptPath}#${label}`;\n\t} else {\n\t\treturn `${scriptPath}?${params.toString()}#${label}`;\n\t}\n}\n// ESM-comment-end\n\nfunction isPromiseLike(obj: any): obj is PromiseLike {\n\tif (typeof obj.then === 'function') {\n\t\treturn true;\n\t}\n\treturn false;\n}\n\n/**\n * A worker that uses HTML5 web workers so that is has\n * its own global scope and its own thread.\n */\nclass WebWorker extends Disposable implements IWorker {\n\n\tprivate readonly id: number;\n\tprivate readonly label: string;\n\tprivate worker: Promise | null;\n\n\tconstructor(moduleId: string, id: number, label: string, onMessageCallback: IWorkerCallback, onErrorCallback: (err: any) => void) {\n\t\tsuper();\n\t\tthis.id = id;\n\t\tthis.label = label;\n\t\tconst workerOrPromise = getWorker(label);\n\t\tif (isPromiseLike(workerOrPromise)) {\n\t\t\tthis.worker = workerOrPromise;\n\t\t} else {\n\t\t\tthis.worker = Promise.resolve(workerOrPromise);\n\t\t}\n\t\tthis.postMessage(moduleId, []);\n\t\tthis.worker.then((w) => {\n\t\t\tw.onmessage = function (ev) {\n\t\t\t\tonMessageCallback(ev.data);\n\t\t\t};\n\t\t\tw.onmessageerror = onErrorCallback;\n\t\t\tif (typeof w.addEventListener === 'function') {\n\t\t\t\tw.addEventListener('error', onErrorCallback);\n\t\t\t}\n\t\t});\n\t\tthis._register(toDisposable(() => {\n\t\t\tthis.worker?.then(w => {\n\t\t\t\tw.onmessage = null;\n\t\t\t\tw.onmessageerror = null;\n\t\t\t\tw.removeEventListener('error', onErrorCallback);\n\t\t\t\tw.terminate();\n\t\t\t});\n\t\t\tthis.worker = null;\n\t\t}));\n\t}\n\n\tpublic getId(): number {\n\t\treturn this.id;\n\t}\n\n\tpublic postMessage(message: any, transfer: Transferable[]): void {\n\t\tthis.worker?.then(w => {\n\t\t\ttry {\n\t\t\t\tw.postMessage(message, transfer);\n\t\t\t} catch (err) {\n\t\t\t\tonUnexpectedError(err);\n\t\t\t\tonUnexpectedError(new Error(`FAILED to post message to '${this.label}'-worker`, { cause: err }));\n\t\t\t}\n\t\t});\n\t}\n\n\n}\n\nexport class DefaultWorkerFactory implements IWorkerFactory {\n\n\tprivate static LAST_WORKER_ID = 0;\n\n\tprivate _label: string | undefined;\n\tprivate _webWorkerFailedBeforeError: any;\n\n\tconstructor(label: string | undefined) {\n\t\tthis._label = label;\n\t\tthis._webWorkerFailedBeforeError = false;\n\t}\n\n\tpublic create(moduleId: string, onMessageCallback: IWorkerCallback, onErrorCallback: (err: any) => void): IWorker {\n\t\tconst workerId = (++DefaultWorkerFactory.LAST_WORKER_ID);\n\n\t\tif (this._webWorkerFailedBeforeError) {\n\t\t\tthrow this._webWorkerFailedBeforeError;\n\t\t}\n\n\t\treturn new WebWorker(moduleId, workerId, this._label || 'anonymous' + workerId, onMessageCallback, (err) => {\n\t\t\tlogOnceWebWorkerWarning(err);\n\t\t\tthis._webWorkerFailedBeforeError = err;\n\t\t\tonErrorCallback(err);\n\t\t});\n\t}\n}\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\nimport { ThrottledDelayer } from 'vs/base/common/async';\nimport { Event, PauseableEmitter } from 'vs/base/common/event';\nimport { Disposable, IDisposable } from 'vs/base/common/lifecycle';\nimport { stringify } from 'vs/base/common/marshalling';\nimport { isObject, isUndefinedOrNull } from 'vs/base/common/types';\n\nexport enum StorageHint {\n\n\t// A hint to the storage that the storage\n\t// does not exist on disk yet. This allows\n\t// the storage library to improve startup\n\t// time by not checking the storage for data.\n\tSTORAGE_DOES_NOT_EXIST,\n\n\t// A hint to the storage that the storage\n\t// is backed by an in-memory storage.\n\tSTORAGE_IN_MEMORY\n}\n\nexport interface IStorageOptions {\n\treadonly hint?: StorageHint;\n}\n\nexport interface IUpdateRequest {\n\treadonly insert?: Map;\n\treadonly delete?: Set;\n}\n\nexport interface IStorageItemsChangeEvent {\n\treadonly changed?: Map;\n\treadonly deleted?: Set;\n}\n\nexport interface IStorageDatabase {\n\n\treadonly onDidChangeItemsExternal: Event;\n\tupdateItems(request: IUpdateRequest): Promise;\n}\n\nexport interface IStorageChangeEvent {\n\n\t/**\n\t * The `key` of the storage entry that was changed\n\t * or was removed.\n\t */\n\treadonly key: string;\n\n\t/**\n\t * A hint how the storage change event was triggered. If\n\t * `true`, the storage change was triggered by an external\n\t * source, such as:\n\t * - another process (for example another window)\n\t * - operations such as settings sync or profiles change\n\t */\n\treadonly external?: boolean;\n}\n\nexport type StorageValue = string | boolean | number | undefined | null | object;\n\nexport interface IStorage extends IDisposable {\n\n\tget(key: string, fallbackValue: string): string;\n\tget(key: string, fallbackValue?: string): string | undefined;\n\n\tgetBoolean(key: string, fallbackValue: boolean): boolean;\n\tgetBoolean(key: string, fallbackValue?: boolean): boolean | undefined;\n\n\tgetNumber(key: string, fallbackValue: number): number;\n\tgetNumber(key: string, fallbackValue?: number): number | undefined;\n\n\tset(key: string, value: StorageValue, external?: boolean): Promise;\n\tdelete(key: string, external?: boolean): Promise;\n}\n\nexport enum StorageState {\n\tNone,\n\tInitialized,\n\tClosed\n}\n\nexport class Storage extends Disposable implements IStorage {\n\n\tprivate static readonly DEFAULT_FLUSH_DELAY = 100;\n\n\tprivate readonly _onDidChangeStorage = this._register(new PauseableEmitter());\n\treadonly onDidChangeStorage = this._onDidChangeStorage.event;\n\n\tprivate state = StorageState.None;\n\n\tprivate cache = new Map();\n\n\tprivate readonly flushDelayer = this._register(new ThrottledDelayer(Storage.DEFAULT_FLUSH_DELAY));\n\n\tprivate pendingDeletes = new Set();\n\tprivate pendingInserts = new Map();\n\n\tprivate readonly whenFlushedCallbacks: Function[] = [];\n\n\tconstructor(\n\t\tprotected readonly database: IStorageDatabase,\n\t\tprivate readonly options: IStorageOptions = Object.create(null)\n\t) {\n\t\tsuper();\n\n\t\tthis.registerListeners();\n\t}\n\n\tprivate registerListeners(): void {\n\t\tthis._register(this.database.onDidChangeItemsExternal(e => this.onDidChangeItemsExternal(e)));\n\t}\n\n\tprivate onDidChangeItemsExternal(e: IStorageItemsChangeEvent): void {\n\t\tthis._onDidChangeStorage.pause();\n\n\t\ttry {\n\t\t\t// items that change external require us to update our\n\t\t\t// caches with the values. we just accept the value and\n\t\t\t// emit an event if there is a change.\n\n\t\t\te.changed?.forEach((value, key) => this.acceptExternal(key, value));\n\t\t\te.deleted?.forEach(key => this.acceptExternal(key, undefined));\n\n\t\t} finally {\n\t\t\tthis._onDidChangeStorage.resume();\n\t\t}\n\t}\n\n\tprivate acceptExternal(key: string, value: string | undefined): void {\n\t\tif (this.state === StorageState.Closed) {\n\t\t\treturn; // Return early if we are already closed\n\t\t}\n\n\t\tlet changed = false;\n\n\t\t// Item got removed, check for deletion\n\t\tif (isUndefinedOrNull(value)) {\n\t\t\tchanged = this.cache.delete(key);\n\t\t}\n\n\t\t// Item got updated, check for change\n\t\telse {\n\t\t\tconst currentValue = this.cache.get(key);\n\t\t\tif (currentValue !== value) {\n\t\t\t\tthis.cache.set(key, value);\n\t\t\t\tchanged = true;\n\t\t\t}\n\t\t}\n\n\t\t// Signal to outside listeners\n\t\tif (changed) {\n\t\t\tthis._onDidChangeStorage.fire({ key, external: true });\n\t\t}\n\t}\n\n\tget(key: string, fallbackValue: string): string;\n\tget(key: string, fallbackValue?: string): string | undefined;\n\tget(key: string, fallbackValue?: string): string | undefined {\n\t\tconst value = this.cache.get(key);\n\n\t\tif (isUndefinedOrNull(value)) {\n\t\t\treturn fallbackValue;\n\t\t}\n\n\t\treturn value;\n\t}\n\n\tgetBoolean(key: string, fallbackValue: boolean): boolean;\n\tgetBoolean(key: string, fallbackValue?: boolean): boolean | undefined;\n\tgetBoolean(key: string, fallbackValue?: boolean): boolean | undefined {\n\t\tconst value = this.get(key);\n\n\t\tif (isUndefinedOrNull(value)) {\n\t\t\treturn fallbackValue;\n\t\t}\n\n\t\treturn value === 'true';\n\t}\n\n\tgetNumber(key: string, fallbackValue: number): number;\n\tgetNumber(key: string, fallbackValue?: number): number | undefined;\n\tgetNumber(key: string, fallbackValue?: number): number | undefined {\n\t\tconst value = this.get(key);\n\n\t\tif (isUndefinedOrNull(value)) {\n\t\t\treturn fallbackValue;\n\t\t}\n\n\t\treturn parseInt(value, 10);\n\t}\n\n\tasync set(key: string, value: string | boolean | number | null | undefined | object, external = false): Promise {\n\t\tif (this.state === StorageState.Closed) {\n\t\t\treturn; // Return early if we are already closed\n\t\t}\n\n\t\t// We remove the key for undefined/null values\n\t\tif (isUndefinedOrNull(value)) {\n\t\t\treturn this.delete(key, external);\n\t\t}\n\n\t\t// Otherwise, convert to String and store\n\t\tconst valueStr = isObject(value) || Array.isArray(value) ? stringify(value) : String(value);\n\n\t\t// Return early if value already set\n\t\tconst currentValue = this.cache.get(key);\n\t\tif (currentValue === valueStr) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Update in cache and pending\n\t\tthis.cache.set(key, valueStr);\n\t\tthis.pendingInserts.set(key, valueStr);\n\t\tthis.pendingDeletes.delete(key);\n\n\t\t// Event\n\t\tthis._onDidChangeStorage.fire({ key, external });\n\n\t\t// Accumulate work by scheduling after timeout\n\t\treturn this.doFlush();\n\t}\n\n\tasync delete(key: string, external = false): Promise {\n\t\tif (this.state === StorageState.Closed) {\n\t\t\treturn; // Return early if we are already closed\n\t\t}\n\n\t\t// Remove from cache and add to pending\n\t\tconst wasDeleted = this.cache.delete(key);\n\t\tif (!wasDeleted) {\n\t\t\treturn; // Return early if value already deleted\n\t\t}\n\n\t\tif (!this.pendingDeletes.has(key)) {\n\t\t\tthis.pendingDeletes.add(key);\n\t\t}\n\n\t\tthis.pendingInserts.delete(key);\n\n\t\t// Event\n\t\tthis._onDidChangeStorage.fire({ key, external });\n\n\t\t// Accumulate work by scheduling after timeout\n\t\treturn this.doFlush();\n\t}\n\n\tprivate get hasPending() {\n\t\treturn this.pendingInserts.size > 0 || this.pendingDeletes.size > 0;\n\t}\n\n\tprivate async flushPending(): Promise {\n\t\tif (!this.hasPending) {\n\t\t\treturn; // return early if nothing to do\n\t\t}\n\n\t\t// Get pending data\n\t\tconst updateRequest: IUpdateRequest = { insert: this.pendingInserts, delete: this.pendingDeletes };\n\n\t\t// Reset pending data for next run\n\t\tthis.pendingDeletes = new Set();\n\t\tthis.pendingInserts = new Map();\n\n\t\t// Update in storage and release any\n\t\t// waiters we have once done\n\t\treturn this.database.updateItems(updateRequest).finally(() => {\n\t\t\tif (!this.hasPending) {\n\t\t\t\twhile (this.whenFlushedCallbacks.length) {\n\t\t\t\t\tthis.whenFlushedCallbacks.pop()?.();\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate async doFlush(delay?: number): Promise {\n\t\tif (this.options.hint === StorageHint.STORAGE_IN_MEMORY) {\n\t\t\treturn this.flushPending(); // return early if in-memory\n\t\t}\n\n\t\treturn this.flushDelayer.trigger(() => this.flushPending(), delay);\n\t}\n}\n\nexport class InMemoryStorageDatabase implements IStorageDatabase {\n\n\treadonly onDidChangeItemsExternal = Event.None;\n\n\tprivate readonly items = new Map();\n\n\tasync updateItems(request: IUpdateRequest): Promise {\n\t\trequest.insert?.forEach((value, key) => this.items.set(key, value));\n\n\t\trequest.delete?.forEach(key => this.items.delete(key));\n\t}\n}\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\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport { IDimension } from 'vs/editor/common/core/dimension';\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { getWindow, scheduleAtNextAnimationFrame } from 'vs/base/browser/dom';\n\nexport class ElementSizeObserver extends Disposable {\n\n\tprivate _onDidChange = this._register(new Emitter());\n\tpublic readonly onDidChange: Event = this._onDidChange.event;\n\n\tprivate readonly _referenceDomElement: HTMLElement | null;\n\tprivate _width: number;\n\tprivate _height: number;\n\tprivate _resizeObserver: ResizeObserver | null;\n\n\tconstructor(referenceDomElement: HTMLElement | null, dimension: IDimension | undefined) {\n\t\tsuper();\n\t\tthis._referenceDomElement = referenceDomElement;\n\t\tthis._width = -1;\n\t\tthis._height = -1;\n\t\tthis._resizeObserver = null;\n\t\tthis.measureReferenceDomElement(false, dimension);\n\t}\n\n\tpublic override dispose(): void {\n\t\tthis.stopObserving();\n\t\tsuper.dispose();\n\t}\n\n\tpublic getWidth(): number {\n\t\treturn this._width;\n\t}\n\n\tpublic getHeight(): number {\n\t\treturn this._height;\n\t}\n\n\tpublic startObserving(): void {\n\t\tif (!this._resizeObserver && this._referenceDomElement) {\n\t\t\t// We want to react to the resize observer only once per animation frame\n\t\t\t// The first time the resize observer fires, we will react to it immediately.\n\t\t\t// Otherwise we will postpone to the next animation frame.\n\t\t\t// We'll use `observeContentRect` to store the content rect we received.\n\n\t\t\tlet observedDimenstion: IDimension | null = null;\n\t\t\tconst observeNow = () => {\n\t\t\t\tif (observedDimenstion) {\n\t\t\t\t\tthis.observe({ width: observedDimenstion.width, height: observedDimenstion.height });\n\t\t\t\t} else {\n\t\t\t\t\tthis.observe();\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tlet shouldObserve = false;\n\t\t\tlet alreadyObservedThisAnimationFrame = false;\n\n\t\t\tconst update = () => {\n\t\t\t\tif (shouldObserve && !alreadyObservedThisAnimationFrame) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tshouldObserve = false;\n\t\t\t\t\t\talreadyObservedThisAnimationFrame = true;\n\t\t\t\t\t\tobserveNow();\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tscheduleAtNextAnimationFrame(getWindow(this._referenceDomElement), () => {\n\t\t\t\t\t\t\talreadyObservedThisAnimationFrame = false;\n\t\t\t\t\t\t\tupdate();\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tthis._resizeObserver = new ResizeObserver((entries) => {\n\t\t\t\tif (entries && entries[0] && entries[0].contentRect) {\n\t\t\t\t\tobservedDimenstion = { width: entries[0].contentRect.width, height: entries[0].contentRect.height };\n\t\t\t\t} else {\n\t\t\t\t\tobservedDimenstion = null;\n\t\t\t\t}\n\t\t\t\tshouldObserve = true;\n\t\t\t\tupdate();\n\t\t\t});\n\t\t\tthis._resizeObserver.observe(this._referenceDomElement);\n\t\t}\n\t}\n\n\tpublic stopObserving(): void {\n\t\tif (this._resizeObserver) {\n\t\t\tthis._resizeObserver.disconnect();\n\t\t\tthis._resizeObserver = null;\n\t\t}\n\t}\n\n\tpublic observe(dimension?: IDimension): void {\n\t\tthis.measureReferenceDomElement(true, dimension);\n\t}\n\n\tprivate measureReferenceDomElement(emitEvent: boolean, dimension?: IDimension): void {\n\t\tlet observedWidth = 0;\n\t\tlet observedHeight = 0;\n\t\tif (dimension) {\n\t\t\tobservedWidth = dimension.width;\n\t\t\tobservedHeight = dimension.height;\n\t\t} else if (this._referenceDomElement) {\n\t\t\tobservedWidth = this._referenceDomElement.clientWidth;\n\t\t\tobservedHeight = this._referenceDomElement.clientHeight;\n\t\t}\n\t\tobservedWidth = Math.max(5, observedWidth);\n\t\tobservedHeight = Math.max(5, observedHeight);\n\t\tif (this._width !== observedWidth || this._height !== observedHeight) {\n\t\t\tthis._width = observedWidth;\n\t\t\tthis._height = observedHeight;\n\t\t\tif (emitEvent) {\n\t\t\t\tthis._onDidChange.fire();\n\t\t\t}\n\t\t}\n\t}\n}\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\nimport * as dom from 'vs/base/browser/dom';\nimport { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';\nimport { ContentWidgetPositionPreference, IContentWidget } from 'vs/editor/browser/editorBrowser';\nimport { PartFingerprint, PartFingerprints, ViewPart } from 'vs/editor/browser/view/viewPart';\nimport { RenderingContext, RestrictedRenderingContext } from 'vs/editor/browser/view/renderingContext';\nimport { ViewContext } from 'vs/editor/common/viewModel/viewContext';\nimport * as viewEvents from 'vs/editor/common/viewEvents';\nimport { ViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData';\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\nimport { IDimension } from 'vs/editor/common/core/dimension';\nimport { PositionAffinity } from 'vs/editor/common/model';\nimport { IPosition, Position } from 'vs/editor/common/core/position';\nimport { IViewModel } from 'vs/editor/common/viewModel';\n\nexport class ViewContentWidgets extends ViewPart {\n\n\tprivate readonly _viewDomNode: FastDomNode;\n\tprivate _widgets: { [key: string]: Widget };\n\n\tpublic domNode: FastDomNode;\n\tpublic overflowingContentWidgetsDomNode: FastDomNode;\n\n\tconstructor(context: ViewContext, viewDomNode: FastDomNode) {\n\t\tsuper(context);\n\t\tthis._viewDomNode = viewDomNode;\n\t\tthis._widgets = {};\n\n\t\tthis.domNode = createFastDomNode(document.createElement('div'));\n\t\tPartFingerprints.write(this.domNode, PartFingerprint.ContentWidgets);\n\t\tthis.domNode.setClassName('contentWidgets');\n\t\tthis.domNode.setPosition('absolute');\n\t\tthis.domNode.setTop(0);\n\n\t\tthis.overflowingContentWidgetsDomNode = createFastDomNode(document.createElement('div'));\n\t\tPartFingerprints.write(this.overflowingContentWidgetsDomNode, PartFingerprint.OverflowingContentWidgets);\n\t\tthis.overflowingContentWidgetsDomNode.setClassName('overflowingContentWidgets');\n\t}\n\n\tpublic override dispose(): void {\n\t\tsuper.dispose();\n\t\tthis._widgets = {};\n\t}\n\n\t// --- begin event handlers\n\n\tpublic override onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {\n\t\tconst keys = Object.keys(this._widgets);\n\t\tfor (const widgetId of keys) {\n\t\t\tthis._widgets[widgetId].onConfigurationChanged(e);\n\t\t}\n\t\treturn true;\n\t}\n\tpublic override onDecorationsChanged(e: viewEvents.ViewDecorationsChangedEvent): boolean {\n\t\t// true for inline decorations that can end up relayouting text\n\t\treturn true;\n\t}\n\tpublic override onFlushed(e: viewEvents.ViewFlushedEvent): boolean {\n\t\treturn true;\n\t}\n\tpublic override onLineMappingChanged(e: viewEvents.ViewLineMappingChangedEvent): boolean {\n\t\tthis._updateAnchorsViewPositions();\n\t\treturn true;\n\t}\n\tpublic override onLinesChanged(e: viewEvents.ViewLinesChangedEvent): boolean {\n\t\tthis._updateAnchorsViewPositions();\n\t\treturn true;\n\t}\n\tpublic override onLinesDeleted(e: viewEvents.ViewLinesDeletedEvent): boolean {\n\t\tthis._updateAnchorsViewPositions();\n\t\treturn true;\n\t}\n\tpublic override onLinesInserted(e: viewEvents.ViewLinesInsertedEvent): boolean {\n\t\tthis._updateAnchorsViewPositions();\n\t\treturn true;\n\t}\n\tpublic override onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean {\n\t\treturn true;\n\t}\n\tpublic override onZonesChanged(e: viewEvents.ViewZonesChangedEvent): boolean {\n\t\treturn true;\n\t}\n\n\t// ---- end view event handlers\n\n\tprivate _updateAnchorsViewPositions(): void {\n\t\tconst keys = Object.keys(this._widgets);\n\t\tfor (const widgetId of keys) {\n\t\t\tthis._widgets[widgetId].updateAnchorViewPosition();\n\t\t}\n\t}\n\n\tpublic addWidget(_widget: IContentWidget): void {\n\t\tconst myWidget = new Widget(this._context, this._viewDomNode, _widget);\n\t\tthis._widgets[myWidget.id] = myWidget;\n\n\t\tif (myWidget.allowEditorOverflow) {\n\t\t\tthis.overflowingContentWidgetsDomNode.appendChild(myWidget.domNode);\n\t\t} else {\n\t\t\tthis.domNode.appendChild(myWidget.domNode);\n\t\t}\n\n\t\tthis.setShouldRender();\n\t}\n\n\tpublic setWidgetPosition(widget: IContentWidget, primaryAnchor: IPosition | null, secondaryAnchor: IPosition | null, preference: ContentWidgetPositionPreference[] | null, affinity: PositionAffinity | null): void {\n\t\tconst myWidget = this._widgets[widget.getId()];\n\t\tmyWidget.setPosition(primaryAnchor, secondaryAnchor, preference, affinity);\n\n\t\tthis.setShouldRender();\n\t}\n\n\tpublic removeWidget(widget: IContentWidget): void {\n\t\tconst widgetId = widget.getId();\n\t\tif (this._widgets.hasOwnProperty(widgetId)) {\n\t\t\tconst myWidget = this._widgets[widgetId];\n\t\t\tdelete this._widgets[widgetId];\n\n\t\t\tconst domNode = myWidget.domNode.domNode;\n\t\t\tdomNode.parentNode!.removeChild(domNode);\n\t\t\tdomNode.removeAttribute('monaco-visible-content-widget');\n\n\t\t\tthis.setShouldRender();\n\t\t}\n\t}\n\n\tpublic shouldSuppressMouseDownOnWidget(widgetId: string): boolean {\n\t\tif (this._widgets.hasOwnProperty(widgetId)) {\n\t\t\treturn this._widgets[widgetId].suppressMouseDown;\n\t\t}\n\t\treturn false;\n\t}\n\n\tpublic onBeforeRender(viewportData: ViewportData): void {\n\t\tconst keys = Object.keys(this._widgets);\n\t\tfor (const widgetId of keys) {\n\t\t\tthis._widgets[widgetId].onBeforeRender(viewportData);\n\t\t}\n\t}\n\n\tpublic prepareRender(ctx: RenderingContext): void {\n\t\tconst keys = Object.keys(this._widgets);\n\t\tfor (const widgetId of keys) {\n\t\t\tthis._widgets[widgetId].prepareRender(ctx);\n\t\t}\n\t}\n\n\tpublic render(ctx: RestrictedRenderingContext): void {\n\t\tconst keys = Object.keys(this._widgets);\n\t\tfor (const widgetId of keys) {\n\t\t\tthis._widgets[widgetId].render(ctx);\n\t\t}\n\t}\n}\n\ninterface IBoxLayoutResult {\n\tfitsAbove: boolean;\n\taboveTop: number;\n\n\tfitsBelow: boolean;\n\tbelowTop: number;\n\n\tleft: number;\n}\n\ninterface IOffViewportRenderData {\n\tkind: 'offViewport';\n\tpreserveFocus: boolean;\n}\n\ninterface IInViewportRenderData {\n\tkind: 'inViewport';\n\tcoordinate: Coordinate;\n\tposition: ContentWidgetPositionPreference;\n}\n\ntype IRenderData = IInViewportRenderData | IOffViewportRenderData;\n\nclass Widget {\n\tprivate readonly _context: ViewContext;\n\tprivate readonly _viewDomNode: FastDomNode;\n\tprivate readonly _actual: IContentWidget;\n\n\tpublic readonly domNode: FastDomNode;\n\tpublic readonly id: string;\n\tpublic readonly allowEditorOverflow: boolean;\n\tpublic readonly suppressMouseDown: boolean;\n\n\tprivate readonly _fixedOverflowWidgets: boolean;\n\tprivate _contentWidth: number;\n\tprivate _contentLeft: number;\n\tprivate _lineHeight: number;\n\n\tprivate _primaryAnchor: PositionPair = new PositionPair(null, null);\n\tprivate _secondaryAnchor: PositionPair = new PositionPair(null, null);\n\tprivate _affinity: PositionAffinity | null;\n\tprivate _preference: ContentWidgetPositionPreference[] | null;\n\tprivate _cachedDomNodeOffsetWidth: number;\n\tprivate _cachedDomNodeOffsetHeight: number;\n\tprivate _maxWidth: number;\n\tprivate _isVisible: boolean;\n\n\tprivate _renderData: IRenderData | null;\n\n\tconstructor(context: ViewContext, viewDomNode: FastDomNode, actual: IContentWidget) {\n\t\tthis._context = context;\n\t\tthis._viewDomNode = viewDomNode;\n\t\tthis._actual = actual;\n\n\t\tthis.domNode = createFastDomNode(this._actual.getDomNode());\n\t\tthis.id = this._actual.getId();\n\t\tthis.allowEditorOverflow = this._actual.allowEditorOverflow || false;\n\t\tthis.suppressMouseDown = this._actual.suppressMouseDown || false;\n\n\t\tconst options = this._context.configuration.options;\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\n\n\t\tthis._fixedOverflowWidgets = options.get(EditorOption.fixedOverflowWidgets);\n\t\tthis._contentWidth = layoutInfo.contentWidth;\n\t\tthis._contentLeft = layoutInfo.contentLeft;\n\t\tthis._lineHeight = options.get(EditorOption.lineHeight);\n\n\t\tthis._affinity = null;\n\t\tthis._preference = [];\n\t\tthis._cachedDomNodeOffsetWidth = -1;\n\t\tthis._cachedDomNodeOffsetHeight = -1;\n\t\tthis._maxWidth = this._getMaxWidth();\n\t\tthis._isVisible = false;\n\t\tthis._renderData = null;\n\n\t\tthis.domNode.setPosition((this._fixedOverflowWidgets && this.allowEditorOverflow) ? 'fixed' : 'absolute');\n\t\tthis.domNode.setDisplay('none');\n\t\tthis.domNode.setVisibility('hidden');\n\t\tthis.domNode.setAttribute('widgetId', this.id);\n\t\tthis.domNode.setMaxWidth(this._maxWidth);\n\t}\n\n\tpublic onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): void {\n\t\tconst options = this._context.configuration.options;\n\t\tthis._lineHeight = options.get(EditorOption.lineHeight);\n\t\tif (e.hasChanged(EditorOption.layoutInfo)) {\n\t\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\n\t\t\tthis._contentLeft = layoutInfo.contentLeft;\n\t\t\tthis._contentWidth = layoutInfo.contentWidth;\n\t\t\tthis._maxWidth = this._getMaxWidth();\n\t\t}\n\t}\n\n\tpublic updateAnchorViewPosition(): void {\n\t\tthis._setPosition(this._affinity, this._primaryAnchor.modelPosition, this._secondaryAnchor.modelPosition);\n\t}\n\n\tprivate _setPosition(affinity: PositionAffinity | null, primaryAnchor: IPosition | null, secondaryAnchor: IPosition | null): void {\n\t\tthis._affinity = affinity;\n\t\tthis._primaryAnchor = getValidPositionPair(primaryAnchor, this._context.viewModel, this._affinity);\n\t\tthis._secondaryAnchor = getValidPositionPair(secondaryAnchor, this._context.viewModel, this._affinity);\n\n\t\tfunction getValidPositionPair(position: IPosition | null, viewModel: IViewModel, affinity: PositionAffinity | null): PositionPair {\n\t\t\tif (!position) {\n\t\t\t\treturn new PositionPair(null, null);\n\t\t\t}\n\t\t\t// Do not trust that widgets give a valid position\n\t\t\tconst validModelPosition = viewModel.model.validatePosition(position);\n\t\t\tif (viewModel.coordinatesConverter.modelPositionIsVisible(validModelPosition)) {\n\t\t\t\tconst viewPosition = viewModel.coordinatesConverter.convertModelPositionToViewPosition(validModelPosition, affinity ?? undefined);\n\t\t\t\treturn new PositionPair(position, viewPosition);\n\t\t\t}\n\t\t\treturn new PositionPair(position, null);\n\t\t}\n\t}\n\n\tprivate _getMaxWidth(): number {\n\t\tconst elDocument = this.domNode.domNode.ownerDocument;\n\t\tconst elWindow = elDocument.defaultView;\n\t\treturn (\n\t\t\tthis.allowEditorOverflow\n\t\t\t\t? elWindow?.innerWidth || elDocument.documentElement.offsetWidth || elDocument.body.offsetWidth\n\t\t\t\t: this._contentWidth\n\t\t);\n\t}\n\n\tpublic setPosition(primaryAnchor: IPosition | null, secondaryAnchor: IPosition | null, preference: ContentWidgetPositionPreference[] | null, affinity: PositionAffinity | null): void {\n\t\tthis._setPosition(affinity, primaryAnchor, secondaryAnchor);\n\t\tthis._preference = preference;\n\t\tif (this._primaryAnchor.viewPosition && this._preference && this._preference.length > 0) {\n\t\t\t// this content widget would like to be visible if possible\n\t\t\t// we change it from `display:none` to `display:block` even if it\n\t\t\t// might be outside the viewport such that we can measure its size\n\t\t\t// in `prepareRender`\n\t\t\tthis.domNode.setDisplay('block');\n\t\t} else {\n\t\t\tthis.domNode.setDisplay('none');\n\t\t}\n\t\tthis._cachedDomNodeOffsetWidth = -1;\n\t\tthis._cachedDomNodeOffsetHeight = -1;\n\t}\n\n\tprivate _layoutBoxInViewport(anchor: AnchorCoordinate, width: number, height: number, ctx: RenderingContext): IBoxLayoutResult {\n\t\t// Our visible box is split horizontally by the current line => 2 boxes\n\n\t\t// a) the box above the line\n\t\tconst aboveLineTop = anchor.top;\n\t\tconst heightAvailableAboveLine = aboveLineTop;\n\n\t\t// b) the box under the line\n\t\tconst underLineTop = anchor.top + anchor.height;\n\t\tconst heightAvailableUnderLine = ctx.viewportHeight - underLineTop;\n\n\t\tconst aboveTop = aboveLineTop - height;\n\t\tconst fitsAbove = (heightAvailableAboveLine >= height);\n\t\tconst belowTop = underLineTop;\n\t\tconst fitsBelow = (heightAvailableUnderLine >= height);\n\n\t\t// And its left\n\t\tlet left = anchor.left;\n\t\tif (left + width > ctx.scrollLeft + ctx.viewportWidth) {\n\t\t\tleft = ctx.scrollLeft + ctx.viewportWidth - width;\n\t\t}\n\t\tif (left < ctx.scrollLeft) {\n\t\t\tleft = ctx.scrollLeft;\n\t\t}\n\n\t\treturn { fitsAbove, aboveTop, fitsBelow, belowTop, left };\n\t}\n\n\tprivate _layoutHorizontalSegmentInPage(windowSize: dom.Dimension, domNodePosition: dom.IDomNodePagePosition, left: number, width: number): [number, number] {\n\t\t// Leave some clearance to the left/right\n\t\tconst LEFT_PADDING = 15;\n\t\tconst RIGHT_PADDING = 15;\n\n\t\t// Initially, the limits are defined as the dom node limits\n\t\tconst MIN_LIMIT = Math.max(LEFT_PADDING, domNodePosition.left - width);\n\t\tconst MAX_LIMIT = Math.min(domNodePosition.left + domNodePosition.width + width, windowSize.width - RIGHT_PADDING);\n\n\t\tconst elDocument = this._viewDomNode.domNode.ownerDocument;\n\t\tconst elWindow = elDocument.defaultView;\n\t\tlet absoluteLeft = domNodePosition.left + left - (elWindow?.scrollX ?? 0);\n\n\t\tif (absoluteLeft + width > MAX_LIMIT) {\n\t\t\tconst delta = absoluteLeft - (MAX_LIMIT - width);\n\t\t\tabsoluteLeft -= delta;\n\t\t\tleft -= delta;\n\t\t}\n\n\t\tif (absoluteLeft < MIN_LIMIT) {\n\t\t\tconst delta = absoluteLeft - MIN_LIMIT;\n\t\t\tabsoluteLeft -= delta;\n\t\t\tleft -= delta;\n\t\t}\n\n\t\treturn [left, absoluteLeft];\n\t}\n\n\tprivate _layoutBoxInPage(anchor: AnchorCoordinate, width: number, height: number, ctx: RenderingContext): IBoxLayoutResult | null {\n\t\tconst aboveTop = anchor.top - height;\n\t\tconst belowTop = anchor.top + anchor.height;\n\n\t\tconst domNodePosition = dom.getDomNodePagePosition(this._viewDomNode.domNode);\n\t\tconst elDocument = this._viewDomNode.domNode.ownerDocument;\n\t\tconst elWindow = elDocument.defaultView;\n\t\tconst absoluteAboveTop = domNodePosition.top + aboveTop - (elWindow?.scrollY ?? 0);\n\t\tconst absoluteBelowTop = domNodePosition.top + belowTop - (elWindow?.scrollY ?? 0);\n\n\t\tconst windowSize = dom.getClientArea(elDocument.body);\n\t\tconst [left, absoluteAboveLeft] = this._layoutHorizontalSegmentInPage(windowSize, domNodePosition, anchor.left - ctx.scrollLeft + this._contentLeft, width);\n\n\t\t// Leave some clearance to the top/bottom\n\t\tconst TOP_PADDING = 22;\n\t\tconst BOTTOM_PADDING = 22;\n\n\t\tconst fitsAbove = (absoluteAboveTop >= TOP_PADDING);\n\t\tconst fitsBelow = (absoluteBelowTop + height <= windowSize.height - BOTTOM_PADDING);\n\n\t\tif (this._fixedOverflowWidgets) {\n\t\t\treturn {\n\t\t\t\tfitsAbove,\n\t\t\t\taboveTop: Math.max(absoluteAboveTop, TOP_PADDING),\n\t\t\t\tfitsBelow,\n\t\t\t\tbelowTop: absoluteBelowTop,\n\t\t\t\tleft: absoluteAboveLeft\n\t\t\t};\n\t\t}\n\n\t\treturn { fitsAbove, aboveTop, fitsBelow, belowTop, left };\n\t}\n\n\tprivate _prepareRenderWidgetAtExactPositionOverflowing(topLeft: Coordinate): Coordinate {\n\t\treturn new Coordinate(topLeft.top, topLeft.left + this._contentLeft);\n\t}\n\n\t/**\n\t * Compute the coordinates above and below the primary and secondary anchors.\n\t * The content widget *must* touch the primary anchor.\n\t * The content widget should touch if possible the secondary anchor.\n\t */\n\tprivate _getAnchorsCoordinates(ctx: RenderingContext): { primary: AnchorCoordinate | null; secondary: AnchorCoordinate | null } {\n\t\tconst primary = getCoordinates(this._primaryAnchor.viewPosition, this._affinity, this._lineHeight);\n\t\tconst secondaryViewPosition = (this._secondaryAnchor.viewPosition?.lineNumber === this._primaryAnchor.viewPosition?.lineNumber ? this._secondaryAnchor.viewPosition : null);\n\t\tconst secondary = getCoordinates(secondaryViewPosition, this._affinity, this._lineHeight);\n\t\treturn { primary, secondary };\n\n\t\tfunction getCoordinates(position: Position | null, affinity: PositionAffinity | null, lineHeight: number): AnchorCoordinate | null {\n\t\t\tif (!position) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst horizontalPosition = ctx.visibleRangeForPosition(position);\n\t\t\tif (!horizontalPosition) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\t// Left-align widgets that should appear :before content\n\t\t\tconst left = (position.column === 1 && affinity === PositionAffinity.LeftOfInjectedText ? 0 : horizontalPosition.left);\n\t\t\tconst top = ctx.getVerticalOffsetForLineNumber(position.lineNumber) - ctx.scrollTop;\n\t\t\treturn new AnchorCoordinate(top, left, lineHeight);\n\t\t}\n\t}\n\n\tprivate _reduceAnchorCoordinates(primary: AnchorCoordinate, secondary: AnchorCoordinate | null, width: number): AnchorCoordinate {\n\t\tif (!secondary) {\n\t\t\treturn primary;\n\t\t}\n\n\t\tconst fontInfo = this._context.configuration.options.get(EditorOption.fontInfo);\n\n\t\tlet left = secondary.left;\n\t\tif (left < primary.left) {\n\t\t\tleft = Math.max(left, primary.left - width + fontInfo.typicalFullwidthCharacterWidth);\n\t\t} else {\n\t\t\tleft = Math.min(left, primary.left + width - fontInfo.typicalFullwidthCharacterWidth);\n\t\t}\n\t\treturn new AnchorCoordinate(primary.top, left, primary.height);\n\t}\n\n\tprivate _prepareRenderWidget(ctx: RenderingContext): IRenderData | null {\n\t\tif (!this._preference || this._preference.length === 0) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst { primary, secondary } = this._getAnchorsCoordinates(ctx);\n\t\tif (!primary) {\n\t\t\treturn {\n\t\t\t\tkind: 'offViewport',\n\t\t\t\tpreserveFocus: this.domNode.domNode.contains(this.domNode.domNode.ownerDocument.activeElement)\n\t\t\t};\n\t\t\t// return null;\n\t\t}\n\n\t\tif (this._cachedDomNodeOffsetWidth === -1 || this._cachedDomNodeOffsetHeight === -1) {\n\n\t\t\tlet preferredDimensions: IDimension | null = null;\n\t\t\tif (typeof this._actual.beforeRender === 'function') {\n\t\t\t\tpreferredDimensions = safeInvoke(this._actual.beforeRender, this._actual);\n\t\t\t}\n\t\t\tif (preferredDimensions) {\n\t\t\t\tthis._cachedDomNodeOffsetWidth = preferredDimensions.width;\n\t\t\t\tthis._cachedDomNodeOffsetHeight = preferredDimensions.height;\n\t\t\t} else {\n\t\t\t\tconst domNode = this.domNode.domNode;\n\t\t\t\tconst clientRect = domNode.getBoundingClientRect();\n\t\t\t\tthis._cachedDomNodeOffsetWidth = Math.round(clientRect.width);\n\t\t\t\tthis._cachedDomNodeOffsetHeight = Math.round(clientRect.height);\n\t\t\t}\n\t\t}\n\n\t\tconst anchor = this._reduceAnchorCoordinates(primary, secondary, this._cachedDomNodeOffsetWidth);\n\n\t\tlet placement: IBoxLayoutResult | null;\n\t\tif (this.allowEditorOverflow) {\n\t\t\tplacement = this._layoutBoxInPage(anchor, this._cachedDomNodeOffsetWidth, this._cachedDomNodeOffsetHeight, ctx);\n\t\t} else {\n\t\t\tplacement = this._layoutBoxInViewport(anchor, this._cachedDomNodeOffsetWidth, this._cachedDomNodeOffsetHeight, ctx);\n\t\t}\n\n\t\t// Do two passes, first for perfect fit, second picks first option\n\t\tfor (let pass = 1; pass <= 2; pass++) {\n\t\t\tfor (const pref of this._preference) {\n\t\t\t\t// placement\n\t\t\t\tif (pref === ContentWidgetPositionPreference.ABOVE) {\n\t\t\t\t\tif (!placement) {\n\t\t\t\t\t\t// Widget outside of viewport\n\t\t\t\t\t\treturn null;\n\t\t\t\t\t}\n\t\t\t\t\tif (pass === 2 || placement.fitsAbove) {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tkind: 'inViewport',\n\t\t\t\t\t\t\tcoordinate: new Coordinate(placement.aboveTop, placement.left),\n\t\t\t\t\t\t\tposition: ContentWidgetPositionPreference.ABOVE\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t} else if (pref === ContentWidgetPositionPreference.BELOW) {\n\t\t\t\t\tif (!placement) {\n\t\t\t\t\t\t// Widget outside of viewport\n\t\t\t\t\t\treturn null;\n\t\t\t\t\t}\n\t\t\t\t\tif (pass === 2 || placement.fitsBelow) {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tkind: 'inViewport',\n\t\t\t\t\t\t\tcoordinate: new Coordinate(placement.belowTop, placement.left),\n\t\t\t\t\t\t\tposition: ContentWidgetPositionPreference.BELOW\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif (this.allowEditorOverflow) {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tkind: 'inViewport',\n\t\t\t\t\t\t\tcoordinate: this._prepareRenderWidgetAtExactPositionOverflowing(new Coordinate(anchor.top, anchor.left)),\n\t\t\t\t\t\t\tposition: ContentWidgetPositionPreference.EXACT\n\t\t\t\t\t\t};\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tkind: 'inViewport',\n\t\t\t\t\t\t\tcoordinate: new Coordinate(anchor.top, anchor.left),\n\t\t\t\t\t\t\tposition: ContentWidgetPositionPreference.EXACT\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}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * On this first pass, we ensure that the content widget (if it is in the viewport) has the max width set correctly.\n\t */\n\tpublic onBeforeRender(viewportData: ViewportData): void {\n\t\tif (!this._primaryAnchor.viewPosition || !this._preference) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (this._primaryAnchor.viewPosition.lineNumber < viewportData.startLineNumber || this._primaryAnchor.viewPosition.lineNumber > viewportData.endLineNumber) {\n\t\t\t// Outside of viewport\n\t\t\treturn;\n\t\t}\n\n\t\tthis.domNode.setMaxWidth(this._maxWidth);\n\t}\n\n\tpublic prepareRender(ctx: RenderingContext): void {\n\t\tthis._renderData = this._prepareRenderWidget(ctx);\n\t}\n\n\tpublic render(ctx: RestrictedRenderingContext): void {\n\t\tif (!this._renderData || this._renderData.kind === 'offViewport') {\n\t\t\t// This widget should be invisible\n\t\t\tif (this._isVisible) {\n\t\t\t\tthis.domNode.removeAttribute('monaco-visible-content-widget');\n\t\t\t\tthis._isVisible = false;\n\n\t\t\t\tif (this._renderData?.kind === 'offViewport' && this._renderData.preserveFocus) {\n\t\t\t\t\t// widget wants to be shown, but it is outside of the viewport and it\n\t\t\t\t\t// has focus which we need to preserve\n\t\t\t\t\tthis.domNode.setTop(-1000);\n\t\t\t\t} else {\n\t\t\t\t\tthis.domNode.setVisibility('hidden');\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (typeof this._actual.afterRender === 'function') {\n\t\t\t\tsafeInvoke(this._actual.afterRender, this._actual, null);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// This widget should be visible\n\t\tif (this.allowEditorOverflow) {\n\t\t\tthis.domNode.setTop(this._renderData.coordinate.top);\n\t\t\tthis.domNode.setLeft(this._renderData.coordinate.left);\n\t\t} else {\n\t\t\tthis.domNode.setTop(this._renderData.coordinate.top + ctx.scrollTop - ctx.bigNumbersDelta);\n\t\t\tthis.domNode.setLeft(this._renderData.coordinate.left);\n\t\t}\n\n\t\tif (!this._isVisible) {\n\t\t\tthis.domNode.setVisibility('inherit');\n\t\t\tthis.domNode.setAttribute('monaco-visible-content-widget', 'true');\n\t\t\tthis._isVisible = true;\n\t\t}\n\n\t\tif (typeof this._actual.afterRender === 'function') {\n\t\t\tsafeInvoke(this._actual.afterRender, this._actual, this._renderData.position);\n\t\t}\n\t}\n}\n\nclass PositionPair {\n\tconstructor(\n\t\tpublic readonly modelPosition: IPosition | null,\n\t\tpublic readonly viewPosition: Position | null\n\t) { }\n}\n\nclass Coordinate {\n\t_coordinateBrand: void = undefined;\n\n\tconstructor(\n\t\tpublic readonly top: number,\n\t\tpublic readonly left: number\n\t) { }\n}\n\nclass AnchorCoordinate {\n\t_anchorCoordinateBrand: void = undefined;\n\n\tconstructor(\n\t\tpublic readonly top: number,\n\t\tpublic readonly left: number,\n\t\tpublic readonly height: number\n\t) { }\n}\n\nfunction safeInvoke any>(fn: T, thisArg: ThisParameterType, ...args: Parameters): ReturnType | null {\n\ttry {\n\t\treturn fn.call(thisArg, ...args);\n\t} catch {\n\t\t// ignore\n\t\treturn null;\n\t}\n}\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\nimport 'vs/css!./overlayWidgets';\nimport { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';\nimport { IOverlayWidget, IOverlayWidgetPosition, IOverlayWidgetPositionCoordinates, OverlayWidgetPositionPreference } from 'vs/editor/browser/editorBrowser';\nimport { PartFingerprint, PartFingerprints, ViewPart } from 'vs/editor/browser/view/viewPart';\nimport { RenderingContext, RestrictedRenderingContext } from 'vs/editor/browser/view/renderingContext';\nimport { ViewContext } from 'vs/editor/common/viewModel/viewContext';\nimport * as viewEvents from 'vs/editor/common/viewEvents';\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\nimport * as dom from 'vs/base/browser/dom';\n\n\ninterface IWidgetData {\n\twidget: IOverlayWidget;\n\tpreference: OverlayWidgetPositionPreference | IOverlayWidgetPositionCoordinates | null;\n\tstack?: number;\n\tdomNode: FastDomNode;\n}\n\ninterface IWidgetMap {\n\t[key: string]: IWidgetData;\n}\n\nexport class ViewOverlayWidgets extends ViewPart {\n\n\tprivate readonly _viewDomNode: FastDomNode;\n\tprivate _widgets: IWidgetMap;\n\tprivate _viewDomNodeRect: dom.IDomNodePagePosition;\n\tprivate readonly _domNode: FastDomNode;\n\tpublic readonly overflowingOverlayWidgetsDomNode: FastDomNode;\n\tprivate _verticalScrollbarWidth: number;\n\tprivate _minimapWidth: number;\n\tprivate _horizontalScrollbarHeight: number;\n\tprivate _editorHeight: number;\n\tprivate _editorWidth: number;\n\n\tconstructor(context: ViewContext, viewDomNode: FastDomNode) {\n\t\tsuper(context);\n\t\tthis._viewDomNode = viewDomNode;\n\n\t\tconst options = this._context.configuration.options;\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\n\n\t\tthis._widgets = {};\n\t\tthis._verticalScrollbarWidth = layoutInfo.verticalScrollbarWidth;\n\t\tthis._minimapWidth = layoutInfo.minimap.minimapWidth;\n\t\tthis._horizontalScrollbarHeight = layoutInfo.horizontalScrollbarHeight;\n\t\tthis._editorHeight = layoutInfo.height;\n\t\tthis._editorWidth = layoutInfo.width;\n\t\tthis._viewDomNodeRect = { top: 0, left: 0, width: 0, height: 0 };\n\n\t\tthis._domNode = createFastDomNode(document.createElement('div'));\n\t\tPartFingerprints.write(this._domNode, PartFingerprint.OverlayWidgets);\n\t\tthis._domNode.setClassName('overlayWidgets');\n\n\t\tthis.overflowingOverlayWidgetsDomNode = createFastDomNode(document.createElement('div'));\n\t\tPartFingerprints.write(this.overflowingOverlayWidgetsDomNode, PartFingerprint.OverflowingOverlayWidgets);\n\t\tthis.overflowingOverlayWidgetsDomNode.setClassName('overflowingOverlayWidgets');\n\t}\n\n\tpublic override dispose(): void {\n\t\tsuper.dispose();\n\t\tthis._widgets = {};\n\t}\n\n\tpublic getDomNode(): FastDomNode {\n\t\treturn this._domNode;\n\t}\n\n\t// ---- begin view event handlers\n\n\tpublic override onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {\n\t\tconst options = this._context.configuration.options;\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\n\n\t\tthis._verticalScrollbarWidth = layoutInfo.verticalScrollbarWidth;\n\t\tthis._minimapWidth = layoutInfo.minimap.minimapWidth;\n\t\tthis._horizontalScrollbarHeight = layoutInfo.horizontalScrollbarHeight;\n\t\tthis._editorHeight = layoutInfo.height;\n\t\tthis._editorWidth = layoutInfo.width;\n\t\treturn true;\n\t}\n\n\t// ---- end view event handlers\n\n\tpublic addWidget(widget: IOverlayWidget): void {\n\t\tconst domNode = createFastDomNode(widget.getDomNode());\n\n\t\tthis._widgets[widget.getId()] = {\n\t\t\twidget: widget,\n\t\t\tpreference: null,\n\t\t\tdomNode: domNode\n\t\t};\n\n\t\t// This is sync because a widget wants to be in the dom\n\t\tdomNode.setPosition('absolute');\n\t\tdomNode.setAttribute('widgetId', widget.getId());\n\n\t\tif (widget.allowEditorOverflow) {\n\t\t\tthis.overflowingOverlayWidgetsDomNode.appendChild(domNode);\n\t\t} else {\n\t\t\tthis._domNode.appendChild(domNode);\n\t\t}\n\n\t\tthis.setShouldRender();\n\t\tthis._updateMaxMinWidth();\n\t}\n\n\tpublic setWidgetPosition(widget: IOverlayWidget, position: IOverlayWidgetPosition | null): boolean {\n\t\tconst widgetData = this._widgets[widget.getId()];\n\t\tconst preference = position ? position.preference : null;\n\t\tconst stack = position?.stackOridinal;\n\t\tif (widgetData.preference === preference && widgetData.stack === stack) {\n\t\t\tthis._updateMaxMinWidth();\n\t\t\treturn false;\n\t\t}\n\n\t\twidgetData.preference = preference;\n\t\twidgetData.stack = stack;\n\t\tthis.setShouldRender();\n\t\tthis._updateMaxMinWidth();\n\n\t\treturn true;\n\t}\n\n\tpublic removeWidget(widget: IOverlayWidget): void {\n\t\tconst widgetId = widget.getId();\n\t\tif (this._widgets.hasOwnProperty(widgetId)) {\n\t\t\tconst widgetData = this._widgets[widgetId];\n\t\t\tconst domNode = widgetData.domNode.domNode;\n\t\t\tdelete this._widgets[widgetId];\n\n\t\t\tdomNode.remove();\n\t\t\tthis.setShouldRender();\n\t\t\tthis._updateMaxMinWidth();\n\t\t}\n\t}\n\n\tprivate _updateMaxMinWidth(): void {\n\t\tlet maxMinWidth = 0;\n\t\tconst keys = Object.keys(this._widgets);\n\t\tfor (let i = 0, len = keys.length; i < len; i++) {\n\t\t\tconst widgetId = keys[i];\n\t\t\tconst widget = this._widgets[widgetId];\n\t\t\tconst widgetMinWidthInPx = widget.widget.getMinContentWidthInPx?.();\n\t\t\tif (typeof widgetMinWidthInPx !== 'undefined') {\n\t\t\t\tmaxMinWidth = Math.max(maxMinWidth, widgetMinWidthInPx);\n\t\t\t}\n\t\t}\n\t\tthis._context.viewLayout.setOverlayWidgetsMinWidth(maxMinWidth);\n\t}\n\n\tprivate _renderWidget(widgetData: IWidgetData, stackCoordinates: number[]): void {\n\t\tconst domNode = widgetData.domNode;\n\n\t\tif (widgetData.preference === null) {\n\t\t\tdomNode.setTop('');\n\t\t\treturn;\n\t\t}\n\n\t\tconst maxRight = (2 * this._verticalScrollbarWidth) + this._minimapWidth;\n\t\tif (widgetData.preference === OverlayWidgetPositionPreference.TOP_RIGHT_CORNER || widgetData.preference === OverlayWidgetPositionPreference.BOTTOM_RIGHT_CORNER) {\n\t\t\tif (widgetData.preference === OverlayWidgetPositionPreference.BOTTOM_RIGHT_CORNER) {\n\t\t\t\tconst widgetHeight = domNode.domNode.clientHeight;\n\t\t\t\tdomNode.setTop((this._editorHeight - widgetHeight - 2 * this._horizontalScrollbarHeight));\n\t\t\t} else {\n\t\t\t\tdomNode.setTop(0);\n\t\t\t}\n\n\t\t\tif (widgetData.stack !== undefined) {\n\t\t\t\tdomNode.setTop(stackCoordinates[widgetData.preference]);\n\t\t\t\tstackCoordinates[widgetData.preference] += domNode.domNode.clientWidth;\n\t\t\t} else {\n\t\t\t\tdomNode.setRight(maxRight);\n\t\t\t}\n\t\t} else if (widgetData.preference === OverlayWidgetPositionPreference.TOP_CENTER) {\n\t\t\tdomNode.domNode.style.right = '50%';\n\t\t\tif (widgetData.stack !== undefined) {\n\t\t\t\tdomNode.setTop(stackCoordinates[OverlayWidgetPositionPreference.TOP_CENTER]);\n\t\t\t\tstackCoordinates[OverlayWidgetPositionPreference.TOP_CENTER] += domNode.domNode.clientHeight;\n\t\t\t} else {\n\t\t\t\tdomNode.setTop(0);\n\t\t\t}\n\t\t} else {\n\t\t\tconst { top, left } = widgetData.preference;\n\t\t\tconst fixedOverflowWidgets = this._context.configuration.options.get(EditorOption.fixedOverflowWidgets);\n\t\t\tif (fixedOverflowWidgets && widgetData.widget.allowEditorOverflow) {\n\t\t\t\t// top, left are computed relative to the editor and we need them relative to the page\n\t\t\t\tconst editorBoundingBox = this._viewDomNodeRect;\n\t\t\t\tdomNode.setTop(top + editorBoundingBox.top);\n\t\t\t\tdomNode.setLeft(left + editorBoundingBox.left);\n\t\t\t\tdomNode.setPosition('fixed');\n\n\t\t\t} else {\n\t\t\t\tdomNode.setTop(top);\n\t\t\t\tdomNode.setLeft(left);\n\t\t\t\tdomNode.setPosition('absolute');\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic prepareRender(ctx: RenderingContext): void {\n\t\tthis._viewDomNodeRect = dom.getDomNodePagePosition(this._viewDomNode.domNode);\n\t}\n\n\tpublic render(ctx: RestrictedRenderingContext): void {\n\t\tthis._domNode.setWidth(this._editorWidth);\n\n\t\tconst keys = Object.keys(this._widgets);\n\t\tconst stackCoordinates = Array.from({ length: OverlayWidgetPositionPreference.TOP_CENTER + 1 }, () => 0);\n\t\tkeys.sort((a, b) => (this._widgets[a].stack || 0) - (this._widgets[b].stack || 0));\n\n\t\tfor (let i = 0, len = keys.length; i < len; i++) {\n\t\t\tconst widgetId = keys[i];\n\t\t\tthis._renderWidget(this._widgets[widgetId], stackCoordinates);\n\t\t}\n\t}\n}\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\nimport { getWindow, runWhenWindowIdle } from 'vs/base/browser/dom';\nimport { onUnexpectedError } from 'vs/base/common/errors';\nimport { Disposable, DisposableMap, IDisposable } from 'vs/base/common/lifecycle';\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\nimport { EditorContributionInstantiation, IEditorContributionDescription } from 'vs/editor/browser/editorExtensions';\nimport { IEditorContribution } from 'vs/editor/common/editorCommon';\nimport { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';\n\nexport class CodeEditorContributions extends Disposable {\n\n\tprivate _editor: ICodeEditor | null = null;\n\tprivate _instantiationService: IInstantiationService | null = null;\n\n\t/**\n\t * Contains all instantiated contributions.\n\t */\n\tprivate readonly _instances = this._register(new DisposableMap());\n\t/**\n\t * Contains contributions which are not yet instantiated.\n\t */\n\tprivate readonly _pending = new Map();\n\t/**\n\t * Tracks which instantiation kinds are still left in `_pending`.\n\t */\n\tprivate readonly _finishedInstantiation: boolean[] = [];\n\n\tconstructor(\n\n\t) {\n\t\tsuper();\n\n\t\tthis._finishedInstantiation[EditorContributionInstantiation.Eager] = false;\n\t\tthis._finishedInstantiation[EditorContributionInstantiation.AfterFirstRender] = false;\n\t\tthis._finishedInstantiation[EditorContributionInstantiation.BeforeFirstInteraction] = false;\n\t\tthis._finishedInstantiation[EditorContributionInstantiation.Eventually] = false;\n\t}\n\n\tpublic initialize(editor: ICodeEditor, contributions: IEditorContributionDescription[], instantiationService: IInstantiationService) {\n\t\tthis._editor = editor;\n\t\tthis._instantiationService = instantiationService;\n\n\t\tfor (const desc of contributions) {\n\t\t\tif (this._pending.has(desc.id)) {\n\t\t\t\tonUnexpectedError(new Error(`Cannot have two contributions with the same id ${desc.id}`));\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tthis._pending.set(desc.id, desc);\n\t\t}\n\n\t\tthis._instantiateSome(EditorContributionInstantiation.Eager);\n\n\t\t// AfterFirstRender\n\t\t// - these extensions will be instantiated at the latest 50ms after the first render.\n\t\t// - but if there is idle time, we will instantiate them sooner.\n\t\tthis._register(runWhenWindowIdle(getWindow(this._editor.getDomNode()), () => {\n\t\t\tthis._instantiateSome(EditorContributionInstantiation.AfterFirstRender);\n\t\t}));\n\n\t\t// BeforeFirstInteraction\n\t\t// - these extensions will be instantiated at the latest before a mouse or a keyboard event.\n\t\t// - but if there is idle time, we will instantiate them sooner.\n\t\tthis._register(runWhenWindowIdle(getWindow(this._editor.getDomNode()), () => {\n\t\t\tthis._instantiateSome(EditorContributionInstantiation.BeforeFirstInteraction);\n\t\t}));\n\n\t\t// Eventually\n\t\t// - these extensions will only be instantiated when there is idle time.\n\t\t// - since there is no guarantee that there will ever be idle time, we set a timeout of 5s here.\n\t\tthis._register(runWhenWindowIdle(getWindow(this._editor.getDomNode()), () => {\n\t\t\tthis._instantiateSome(EditorContributionInstantiation.Eventually);\n\t\t}, 5000));\n\t}\n\n\tpublic saveViewState(): { [key: string]: any } {\n\t\tconst contributionsState: { [key: string]: any } = {};\n\t\tfor (const [id, contribution] of this._instances) {\n\t\t\tif (typeof contribution.saveViewState === 'function') {\n\t\t\t\tcontributionsState[id] = contribution.saveViewState();\n\t\t\t}\n\t\t}\n\t\treturn contributionsState;\n\t}\n\n\tpublic restoreViewState(contributionsState: { [key: string]: any }): void {\n\t\tfor (const [id, contribution] of this._instances) {\n\t\t\tif (typeof contribution.restoreViewState === 'function') {\n\t\t\t\tcontribution.restoreViewState(contributionsState[id]);\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic get(id: string): IEditorContribution | null {\n\t\tthis._instantiateById(id);\n\t\treturn this._instances.get(id) || null;\n\t}\n\n\tpublic onBeforeInteractionEvent(): void {\n\t\t// this method is called very often by the editor!\n\t\tthis._instantiateSome(EditorContributionInstantiation.BeforeFirstInteraction);\n\t}\n\n\tpublic onAfterModelAttached(): IDisposable {\n\t\treturn runWhenWindowIdle(getWindow(this._editor?.getDomNode()), () => {\n\t\t\tthis._instantiateSome(EditorContributionInstantiation.AfterFirstRender);\n\t\t}, 50);\n\t}\n\n\tprivate _instantiateSome(instantiation: EditorContributionInstantiation): void {\n\t\tif (this._finishedInstantiation[instantiation]) {\n\t\t\t// already done with this instantiation!\n\t\t\treturn;\n\t\t}\n\t\tthis._finishedInstantiation[instantiation] = true;\n\n\t\tconst contribs = this._findPendingContributionsByInstantiation(instantiation);\n\t\tfor (const contrib of contribs) {\n\t\t\tthis._instantiateById(contrib.id);\n\t\t}\n\t}\n\n\tprivate _findPendingContributionsByInstantiation(instantiation: EditorContributionInstantiation): readonly IEditorContributionDescription[] {\n\t\tconst result: IEditorContributionDescription[] = [];\n\t\tfor (const [, desc] of this._pending) {\n\t\t\tif (desc.instantiation === instantiation) {\n\t\t\t\tresult.push(desc);\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate _instantiateById(id: string): void {\n\t\tconst desc = this._pending.get(id);\n\t\tif (!desc) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._pending.delete(id);\n\n\t\tif (!this._instantiationService || !this._editor) {\n\t\t\tthrow new Error(`Cannot instantiate contributions before being initialized!`);\n\t\t}\n\n\t\ttry {\n\t\t\tconst instance = this._instantiationService.createInstance(desc.ctor, this._editor);\n\t\t\tthis._instances.set(desc.id, instance);\n\t\t\tif (typeof instance.restoreViewState === 'function' && desc.instantiation !== EditorContributionInstantiation.Eager) {\n\t\t\t\tconsole.warn(`Editor contribution '${desc.id}' should be eager instantiated because it uses saveViewState / restoreViewState.`);\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tonUnexpectedError(err);\n\t\t}\n\t}\n}\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\nimport { IBoundarySashes, ISashEvent, Orientation, Sash, SashState } from 'vs/base/browser/ui/sash/sash';\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport { IObservable, IReader, ISettableObservable, autorun, observableValue } from 'vs/base/common/observable';\nimport { DiffEditorOptions } from '../diffEditorOptions';\nimport { derivedWithSetter } from 'vs/base/common/observableInternal/derived';\n\nexport class SashLayout {\n\tpublic readonly sashLeft = derivedWithSetter(this, reader => {\n\t\tconst ratio = this._sashRatio.read(reader) ?? this._options.splitViewDefaultRatio.read(reader);\n\t\treturn this._computeSashLeft(ratio, reader);\n\t}, (value, tx) => {\n\t\tconst contentWidth = this.dimensions.width.get();\n\t\tthis._sashRatio.set(value / contentWidth, tx);\n\t});\n\n\tprivate readonly _sashRatio = observableValue(this, undefined);\n\n\tpublic resetSash(): void {\n\t\tthis._sashRatio.set(undefined, undefined);\n\t}\n\n\tconstructor(\n\t\tprivate readonly _options: DiffEditorOptions,\n\t\tpublic readonly dimensions: { height: IObservable; width: IObservable },\n\t) {\n\t}\n\n\t/** @pure */\n\tprivate _computeSashLeft(desiredRatio: number, reader: IReader | undefined): number {\n\t\tconst contentWidth = this.dimensions.width.read(reader);\n\t\tconst midPoint = Math.floor(this._options.splitViewDefaultRatio.read(reader) * contentWidth);\n\t\tconst sashLeft = this._options.enableSplitViewResizing.read(reader) ? Math.floor(desiredRatio * contentWidth) : midPoint;\n\n\t\tconst MINIMUM_EDITOR_WIDTH = 100;\n\t\tif (contentWidth <= MINIMUM_EDITOR_WIDTH * 2) {\n\t\t\treturn midPoint;\n\t\t}\n\t\tif (sashLeft < MINIMUM_EDITOR_WIDTH) {\n\t\t\treturn MINIMUM_EDITOR_WIDTH;\n\t\t}\n\t\tif (sashLeft > contentWidth - MINIMUM_EDITOR_WIDTH) {\n\t\t\treturn contentWidth - MINIMUM_EDITOR_WIDTH;\n\t\t}\n\t\treturn sashLeft;\n\t}\n}\n\nexport class DiffEditorSash extends Disposable {\n\tprivate readonly _sash = this._register(new Sash(this._domNode, {\n\t\tgetVerticalSashTop: (_sash: Sash): number => 0,\n\t\tgetVerticalSashLeft: (_sash: Sash): number => this.sashLeft.get(),\n\t\tgetVerticalSashHeight: (_sash: Sash): number => this._dimensions.height.get(),\n\t}, { orientation: Orientation.VERTICAL }));\n\n\tprivate _startSashPosition: number | undefined = undefined;\n\n\tconstructor(\n\t\tprivate readonly _domNode: HTMLElement,\n\t\tprivate readonly _dimensions: { height: IObservable; width: IObservable },\n\t\tprivate readonly _enabled: IObservable,\n\t\tprivate readonly _boundarySashes: IObservable,\n\t\tpublic readonly sashLeft: ISettableObservable,\n\t\tprivate readonly _resetSash: () => void,\n\t) {\n\t\tsuper();\n\n\t\tthis._register(this._sash.onDidStart(() => {\n\t\t\tthis._startSashPosition = this.sashLeft.get();\n\t\t}));\n\t\tthis._register(this._sash.onDidChange((e: ISashEvent) => {\n\t\t\tthis.sashLeft.set(this._startSashPosition! + (e.currentX - e.startX), undefined);\n\t\t}));\n\t\tthis._register(this._sash.onDidEnd(() => this._sash.layout()));\n\t\tthis._register(this._sash.onDidReset(() => this._resetSash()));\n\n\t\tthis._register(autorun(reader => {\n\t\t\tconst sashes = this._boundarySashes.read(reader);\n\t\t\tif (sashes) {\n\t\t\t\tthis._sash.orthogonalEndSash = sashes.bottom;\n\t\t\t}\n\t\t}));\n\n\t\tthis._register(autorun(reader => {\n\t\t\t/** @description DiffEditorSash.layoutSash */\n\t\t\tconst enabled = this._enabled.read(reader);\n\t\t\tthis._sash.state = enabled ? SashState.Enabled : SashState.Disabled;\n\t\t\tthis.sashLeft.read(reader);\n\t\t\tthis._dimensions.height.read(reader);\n\t\t\tthis._sash.layout();\n\t\t}));\n\t}\n}\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\nimport { IDimension } from 'vs/base/browser/dom';\nimport { findLast } from 'vs/base/common/arraysFind';\nimport { CancellationTokenSource } from 'vs/base/common/cancellation';\nimport { isHotReloadEnabled, registerHotReloadHandler } from 'vs/base/common/hotReload';\nimport { Disposable, DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle';\nimport { IObservable, IReader, ISettableObservable, autorun, autorunHandleChanges, autorunOpts, autorunWithStore, observableSignalFromEvent, observableValue, transaction } from 'vs/base/common/observable';\nimport { ElementSizeObserver } from 'vs/editor/browser/config/elementSizeObserver';\nimport { ICodeEditor, IOverlayWidget, IViewZone } from 'vs/editor/browser/editorBrowser';\nimport { Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\nimport { DetailedLineRangeMapping } from 'vs/editor/common/diff/rangeMapping';\nimport { IModelDeltaDecoration } from 'vs/editor/common/model';\nimport { TextLength } from 'vs/editor/common/core/textLength';\n\nexport function joinCombine(arr1: readonly T[], arr2: readonly T[], keySelector: (val: T) => number, combine: (v1: T, v2: T) => T): readonly T[] {\n\tif (arr1.length === 0) {\n\t\treturn arr2;\n\t}\n\tif (arr2.length === 0) {\n\t\treturn arr1;\n\t}\n\n\tconst result: T[] = [];\n\tlet i = 0;\n\tlet j = 0;\n\twhile (i < arr1.length && j < arr2.length) {\n\t\tconst val1 = arr1[i];\n\t\tconst val2 = arr2[j];\n\t\tconst key1 = keySelector(val1);\n\t\tconst key2 = keySelector(val2);\n\n\t\tif (key1 < key2) {\n\t\t\tresult.push(val1);\n\t\t\ti++;\n\t\t} else if (key1 > key2) {\n\t\t\tresult.push(val2);\n\t\t\tj++;\n\t\t} else {\n\t\t\tresult.push(combine(val1, val2));\n\t\t\ti++;\n\t\t\tj++;\n\t\t}\n\t}\n\twhile (i < arr1.length) {\n\t\tresult.push(arr1[i]);\n\t\ti++;\n\t}\n\twhile (j < arr2.length) {\n\t\tresult.push(arr2[j]);\n\t\tj++;\n\t}\n\treturn result;\n}\n\n// TODO make utility\nexport function applyObservableDecorations(editor: ICodeEditor, decorations: IObservable): IDisposable {\n\tconst d = new DisposableStore();\n\tconst decorationsCollection = editor.createDecorationsCollection();\n\td.add(autorunOpts({ debugName: () => `Apply decorations from ${decorations.debugName}` }, reader => {\n\t\tconst d = decorations.read(reader);\n\t\tdecorationsCollection.set(d);\n\t}));\n\td.add({\n\t\tdispose: () => {\n\t\t\tdecorationsCollection.clear();\n\t\t}\n\t});\n\treturn d;\n}\n\nexport function appendRemoveOnDispose(parent: HTMLElement, child: HTMLElement) {\n\tparent.appendChild(child);\n\treturn toDisposable(() => {\n\t\tparent.removeChild(child);\n\t});\n}\n\nexport function prependRemoveOnDispose(parent: HTMLElement, child: HTMLElement) {\n\tparent.prepend(child);\n\treturn toDisposable(() => {\n\t\tparent.removeChild(child);\n\t});\n}\n\nexport class ObservableElementSizeObserver extends Disposable {\n\tprivate readonly elementSizeObserver: ElementSizeObserver;\n\n\tprivate readonly _width: ISettableObservable;\n\tpublic get width(): IObservable { return this._width; }\n\n\tprivate readonly _height: ISettableObservable;\n\tpublic get height(): IObservable { return this._height; }\n\n\tconstructor(element: HTMLElement | null, dimension: IDimension | undefined) {\n\t\tsuper();\n\n\t\tthis.elementSizeObserver = this._register(new ElementSizeObserver(element, dimension));\n\t\tthis._width = observableValue(this, this.elementSizeObserver.getWidth());\n\t\tthis._height = observableValue(this, this.elementSizeObserver.getHeight());\n\n\t\tthis._register(this.elementSizeObserver.onDidChange(e => transaction(tx => {\n\t\t\t/** @description Set width/height from elementSizeObserver */\n\t\t\tthis._width.set(this.elementSizeObserver.getWidth(), tx);\n\t\t\tthis._height.set(this.elementSizeObserver.getHeight(), tx);\n\t\t})));\n\t}\n\n\tpublic observe(dimension?: IDimension): void {\n\t\tthis.elementSizeObserver.observe(dimension);\n\t}\n\n\tpublic setAutomaticLayout(automaticLayout: boolean): void {\n\t\tif (automaticLayout) {\n\t\t\tthis.elementSizeObserver.startObserving();\n\t\t} else {\n\t\t\tthis.elementSizeObserver.stopObserving();\n\t\t}\n\t}\n}\n\nexport function animatedObservable(targetWindow: Window, base: IObservable, store: DisposableStore): IObservable {\n\tlet targetVal = base.get();\n\tlet startVal = targetVal;\n\tlet curVal = targetVal;\n\tconst result = observableValue('animatedValue', targetVal);\n\n\tlet animationStartMs: number = -1;\n\tconst durationMs = 300;\n\tlet animationFrame: number | undefined = undefined;\n\n\tstore.add(autorunHandleChanges({\n\t\tcreateEmptyChangeSummary: () => ({ animate: false }),\n\t\thandleChange: (ctx, s) => {\n\t\t\tif (ctx.didChange(base)) {\n\t\t\t\ts.animate = s.animate || ctx.change;\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\t}, (reader, s) => {\n\t\t/** @description update value */\n\t\tif (animationFrame !== undefined) {\n\t\t\ttargetWindow.cancelAnimationFrame(animationFrame);\n\t\t\tanimationFrame = undefined;\n\t\t}\n\n\t\tstartVal = curVal;\n\t\ttargetVal = base.read(reader);\n\t\tanimationStartMs = Date.now() - (s.animate ? 0 : durationMs);\n\n\t\tupdate();\n\t}));\n\n\tfunction update() {\n\t\tconst passedMs = Date.now() - animationStartMs;\n\t\tcurVal = Math.floor(easeOutExpo(passedMs, startVal, targetVal - startVal, durationMs));\n\n\t\tif (passedMs < durationMs) {\n\t\t\tanimationFrame = targetWindow.requestAnimationFrame(update);\n\t\t} else {\n\t\t\tcurVal = targetVal;\n\t\t}\n\n\t\tresult.set(curVal, undefined);\n\t}\n\n\treturn result;\n}\n\nfunction easeOutExpo(t: number, b: number, c: number, d: number): number {\n\treturn t === d ? b + c : c * (-Math.pow(2, -10 * t / d) + 1) + b;\n}\n\nexport abstract class ViewZoneOverlayWidget extends Disposable {\n\tconstructor(\n\t\teditor: ICodeEditor,\n\t\tviewZone: PlaceholderViewZone,\n\t\thtmlElement: HTMLElement,\n\t) {\n\t\tsuper();\n\n\t\tthis._register(new ManagedOverlayWidget(editor, htmlElement));\n\t\tthis._register(applyStyle(htmlElement, {\n\t\t\theight: viewZone.actualHeight,\n\t\t\ttop: viewZone.actualTop,\n\t\t}));\n\t}\n}\n\nexport interface IObservableViewZone extends IViewZone {\n\t// Causes the view zone to relayout.\n\tonChange?: IObservable;\n\n\t// Tells a view zone its id.\n\tsetZoneId?(zoneId: string): void;\n}\n\nexport class PlaceholderViewZone implements IObservableViewZone {\n\tpublic readonly domNode = document.createElement('div');\n\n\tprivate readonly _actualTop = observableValue(this, undefined);\n\tprivate readonly _actualHeight = observableValue(this, undefined);\n\n\tpublic readonly actualTop: IObservable = this._actualTop;\n\tpublic readonly actualHeight: IObservable = this._actualHeight;\n\n\tpublic readonly showInHiddenAreas = true;\n\n\tpublic get afterLineNumber(): number { return this._afterLineNumber.get(); }\n\n\tpublic readonly onChange?: IObservable = this._afterLineNumber;\n\n\tconstructor(\n\t\tprivate readonly _afterLineNumber: IObservable,\n\t\tpublic readonly heightInPx: number,\n\t) {\n\t}\n\n\tonDomNodeTop = (top: number) => {\n\t\tthis._actualTop.set(top, undefined);\n\t};\n\n\tonComputedHeight = (height: number) => {\n\t\tthis._actualHeight.set(height, undefined);\n\t};\n}\n\n\nexport class ManagedOverlayWidget implements IDisposable {\n\tprivate static _counter = 0;\n\tprivate readonly _overlayWidgetId = `managedOverlayWidget-${ManagedOverlayWidget._counter++}`;\n\n\tprivate readonly _overlayWidget: IOverlayWidget = {\n\t\tgetId: () => this._overlayWidgetId,\n\t\tgetDomNode: () => this._domElement,\n\t\tgetPosition: () => null\n\t};\n\n\tconstructor(\n\t\tprivate readonly _editor: ICodeEditor,\n\t\tprivate readonly _domElement: HTMLElement,\n\t) {\n\t\tthis._editor.addOverlayWidget(this._overlayWidget);\n\t}\n\n\tdispose(): void {\n\t\tthis._editor.removeOverlayWidget(this._overlayWidget);\n\t}\n}\n\nexport interface CSSStyle {\n\theight: number | string;\n\twidth: number | string;\n\ttop: number | string;\n\tvisibility: 'visible' | 'hidden' | 'collapse';\n\tdisplay: 'block' | 'inline' | 'inline-block' | 'flex' | 'none';\n\tpaddingRight: number | string;\n}\n\nexport function applyStyle(domNode: HTMLElement, style: Partial<{ [TKey in keyof CSSStyle]: CSSStyle[TKey] | IObservable | undefined }>) {\n\treturn autorun(reader => {\n\t\t/** @description applyStyle */\n\t\tfor (let [key, val] of Object.entries(style)) {\n\t\t\tif (val && typeof val === 'object' && 'read' in val) {\n\t\t\t\tval = val.read(reader) as any;\n\t\t\t}\n\t\t\tif (typeof val === 'number') {\n\t\t\t\tval = `${val}px`;\n\t\t\t}\n\t\t\tkey = key.replace(/[A-Z]/g, m => '-' + m.toLowerCase());\n\t\t\tdomNode.style[key as any] = val as any;\n\t\t}\n\t});\n}\n\nexport function readHotReloadableExport(value: T, reader: IReader | undefined): T {\n\tobserveHotReloadableExports([value], reader);\n\treturn value;\n}\n\nexport function observeHotReloadableExports(values: any[], reader: IReader | undefined): void {\n\tif (isHotReloadEnabled()) {\n\t\tconst o = observableSignalFromEvent(\n\t\t\t'reload',\n\t\t\tevent => registerHotReloadHandler(({ oldExports }) => {\n\t\t\t\tif (![...Object.values(oldExports)].some(v => values.includes(v))) {\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\t\t\t\treturn (_newExports) => {\n\t\t\t\t\tevent(undefined);\n\t\t\t\t\treturn true;\n\t\t\t\t};\n\t\t\t})\n\t\t);\n\t\to.read(reader);\n\t}\n}\n\nexport function applyViewZones(editor: ICodeEditor, viewZones: IObservable, setIsUpdating?: (isUpdatingViewZones: boolean) => void, zoneIds?: Set): IDisposable {\n\tconst store = new DisposableStore();\n\tconst lastViewZoneIds: string[] = [];\n\n\tstore.add(autorunWithStore((reader, store) => {\n\t\t/** @description applyViewZones */\n\t\tconst curViewZones = viewZones.read(reader);\n\n\t\tconst viewZonIdsPerViewZone = new Map();\n\t\tconst viewZoneIdPerOnChangeObservable = new Map, string>();\n\n\t\t// Add/remove view zones\n\t\tif (setIsUpdating) { setIsUpdating(true); }\n\t\teditor.changeViewZones(a => {\n\t\t\tfor (const id of lastViewZoneIds) { a.removeZone(id); zoneIds?.delete(id); }\n\t\t\tlastViewZoneIds.length = 0;\n\n\t\t\tfor (const z of curViewZones) {\n\t\t\t\tconst id = a.addZone(z);\n\t\t\t\tif (z.setZoneId) {\n\t\t\t\t\tz.setZoneId(id);\n\t\t\t\t}\n\t\t\t\tlastViewZoneIds.push(id);\n\t\t\t\tzoneIds?.add(id);\n\t\t\t\tviewZonIdsPerViewZone.set(z, id);\n\t\t\t}\n\t\t});\n\t\tif (setIsUpdating) { setIsUpdating(false); }\n\n\t\t// Layout zone on change\n\t\tstore.add(autorunHandleChanges({\n\t\t\tcreateEmptyChangeSummary() {\n\t\t\t\treturn { zoneIds: [] as string[] };\n\t\t\t},\n\t\t\thandleChange(context, changeSummary) {\n\t\t\t\tconst id = viewZoneIdPerOnChangeObservable.get(context.changedObservable);\n\t\t\t\tif (id !== undefined) { changeSummary.zoneIds.push(id); }\n\t\t\t\treturn true;\n\t\t\t},\n\t\t}, (reader, changeSummary) => {\n\t\t\t/** @description layoutZone on change */\n\t\t\tfor (const vz of curViewZones) {\n\t\t\t\tif (vz.onChange) {\n\t\t\t\t\tviewZoneIdPerOnChangeObservable.set(vz.onChange, viewZonIdsPerViewZone.get(vz)!);\n\t\t\t\t\tvz.onChange.read(reader);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (setIsUpdating) { setIsUpdating(true); }\n\t\t\teditor.changeViewZones(a => { for (const id of changeSummary.zoneIds) { a.layoutZone(id); } });\n\t\t\tif (setIsUpdating) { setIsUpdating(false); }\n\t\t}));\n\t}));\n\n\tstore.add({\n\t\tdispose() {\n\t\t\tif (setIsUpdating) { setIsUpdating(true); }\n\t\t\teditor.changeViewZones(a => { for (const id of lastViewZoneIds) { a.removeZone(id); } });\n\t\t\tzoneIds?.clear();\n\t\t\tif (setIsUpdating) { setIsUpdating(false); }\n\t\t}\n\t});\n\n\treturn store;\n}\n\nexport class DisposableCancellationTokenSource extends CancellationTokenSource {\n\tpublic override dispose() {\n\t\tsuper.dispose(true);\n\t}\n}\n\nexport function translatePosition(posInOriginal: Position, mappings: DetailedLineRangeMapping[]): Range {\n\tconst mapping = findLast(mappings, m => m.original.startLineNumber <= posInOriginal.lineNumber);\n\tif (!mapping) {\n\t\t// No changes before the position\n\t\treturn Range.fromPositions(posInOriginal);\n\t}\n\n\tif (mapping.original.endLineNumberExclusive <= posInOriginal.lineNumber) {\n\t\tconst newLineNumber = posInOriginal.lineNumber - mapping.original.endLineNumberExclusive + mapping.modified.endLineNumberExclusive;\n\t\treturn Range.fromPositions(new Position(newLineNumber, posInOriginal.column));\n\t}\n\n\tif (!mapping.innerChanges) {\n\t\t// Only for legacy algorithm\n\t\treturn Range.fromPositions(new Position(mapping.modified.startLineNumber, 1));\n\t}\n\n\tconst innerMapping = findLast(mapping.innerChanges, m => m.originalRange.getStartPosition().isBeforeOrEqual(posInOriginal));\n\tif (!innerMapping) {\n\t\tconst newLineNumber = posInOriginal.lineNumber - mapping.original.startLineNumber + mapping.modified.startLineNumber;\n\t\treturn Range.fromPositions(new Position(newLineNumber, posInOriginal.column));\n\t}\n\n\tif (innerMapping.originalRange.containsPosition(posInOriginal)) {\n\t\treturn innerMapping.modifiedRange;\n\t} else {\n\t\tconst l = lengthBetweenPositions(innerMapping.originalRange.getEndPosition(), posInOriginal);\n\t\treturn Range.fromPositions(l.addToPosition(innerMapping.modifiedRange.getEndPosition()));\n\t}\n}\n\nfunction lengthBetweenPositions(position1: Position, position2: Position): TextLength {\n\tif (position1.lineNumber === position2.lineNumber) {\n\t\treturn new TextLength(0, position2.column - position1.column);\n\t} else {\n\t\treturn new TextLength(position2.lineNumber - position1.lineNumber, position2.column - 1);\n\t}\n}\n\nexport function filterWithPrevious(arr: T[], filter: (cur: T, prev: T | undefined) => boolean): T[] {\n\tlet prev: T | undefined;\n\treturn arr.filter(cur => {\n\t\tconst result = filter(cur, prev);\n\t\tprev = cur;\n\t\treturn result;\n\t});\n}\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\nimport { h, reset } from 'vs/base/browser/dom';\nimport { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle';\nimport { autorun, IObservable, IReader, ISettableObservable, observableFromEvent, observableSignal, observableSignalFromEvent, observableValue, transaction } from 'vs/base/common/observable';\nimport { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditor/codeEditorWidget';\nimport { LineRange } from 'vs/editor/common/core/lineRange';\nimport { OffsetRange } from 'vs/editor/common/core/offsetRange';\n\nexport class EditorGutter extends Disposable {\n\tprivate readonly scrollTop = observableFromEvent(\n\t\tthis._editor.onDidScrollChange,\n\t\t(e) => /** @description editor.onDidScrollChange */ this._editor.getScrollTop()\n\t);\n\tprivate readonly isScrollTopZero = this.scrollTop.map((scrollTop) => /** @description isScrollTopZero */ scrollTop === 0);\n\tprivate readonly modelAttached = observableFromEvent(\n\t\tthis._editor.onDidChangeModel,\n\t\t(e) => /** @description editor.onDidChangeModel */ this._editor.hasModel()\n\t);\n\n\tprivate readonly editorOnDidChangeViewZones = observableSignalFromEvent('onDidChangeViewZones', this._editor.onDidChangeViewZones);\n\tprivate readonly editorOnDidContentSizeChange = observableSignalFromEvent('onDidContentSizeChange', this._editor.onDidContentSizeChange);\n\tprivate readonly domNodeSizeChanged = observableSignal('domNodeSizeChanged');\n\n\tconstructor(\n\t\tprivate readonly _editor: CodeEditorWidget,\n\t\tprivate readonly _domNode: HTMLElement,\n\t\tprivate readonly itemProvider: IGutterItemProvider\n\t) {\n\t\tsuper();\n\t\tthis._domNode.className = 'gutter monaco-editor';\n\t\tconst scrollDecoration = this._domNode.appendChild(\n\t\t\th('div.scroll-decoration', { role: 'presentation', ariaHidden: 'true', style: { width: '100%' } })\n\t\t\t\t.root\n\t\t);\n\n\t\tconst o = new ResizeObserver(() => {\n\t\t\ttransaction(tx => {\n\t\t\t\t/** @description ResizeObserver: size changed */\n\t\t\t\tthis.domNodeSizeChanged.trigger(tx);\n\t\t\t});\n\t\t});\n\t\to.observe(this._domNode);\n\t\tthis._register(toDisposable(() => o.disconnect()));\n\n\t\tthis._register(autorun(reader => {\n\t\t\t/** @description update scroll decoration */\n\t\t\tscrollDecoration.className = this.isScrollTopZero.read(reader) ? '' : 'scroll-decoration';\n\t\t}));\n\n\t\tthis._register(autorun(reader => /** @description EditorGutter.Render */ this.render(reader)));\n\t}\n\n\toverride dispose(): void {\n\t\tsuper.dispose();\n\n\t\treset(this._domNode);\n\t}\n\n\tprivate readonly views = new Map();\n\n\tprivate render(reader: IReader): void {\n\t\tif (!this.modelAttached.read(reader)) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.domNodeSizeChanged.read(reader);\n\t\tthis.editorOnDidChangeViewZones.read(reader);\n\t\tthis.editorOnDidContentSizeChange.read(reader);\n\n\t\tconst scrollTop = this.scrollTop.read(reader);\n\n\t\tconst visibleRanges = this._editor.getVisibleRanges();\n\t\tconst unusedIds = new Set(this.views.keys());\n\n\t\tconst viewRange = OffsetRange.ofStartAndLength(0, this._domNode.clientHeight);\n\n\t\tif (!viewRange.isEmpty) {\n\t\t\tfor (const visibleRange of visibleRanges) {\n\t\t\t\tconst visibleRange2 = new LineRange(\n\t\t\t\t\tvisibleRange.startLineNumber,\n\t\t\t\t\tvisibleRange.endLineNumber + 1\n\t\t\t\t);\n\n\t\t\t\tconst gutterItems = this.itemProvider.getIntersectingGutterItems(\n\t\t\t\t\tvisibleRange2,\n\t\t\t\t\treader\n\t\t\t\t);\n\n\t\t\t\ttransaction(tx => {\n\t\t\t\t\t/** EditorGutter.render */\n\n\t\t\t\t\tfor (const gutterItem of gutterItems) {\n\t\t\t\t\t\tif (!gutterItem.range.intersect(visibleRange2)) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tunusedIds.delete(gutterItem.id);\n\t\t\t\t\t\tlet view = this.views.get(gutterItem.id);\n\t\t\t\t\t\tif (!view) {\n\t\t\t\t\t\t\tconst viewDomNode = document.createElement('div');\n\t\t\t\t\t\t\tthis._domNode.appendChild(viewDomNode);\n\t\t\t\t\t\t\tconst gutterItemObs = observableValue('item', gutterItem);\n\t\t\t\t\t\t\tconst itemView = this.itemProvider.createView(\n\t\t\t\t\t\t\t\tgutterItemObs,\n\t\t\t\t\t\t\t\tviewDomNode\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tview = new ManagedGutterItemView(gutterItemObs, itemView, viewDomNode);\n\t\t\t\t\t\t\tthis.views.set(gutterItem.id, view);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tview.item.set(gutterItem, tx);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst top =\n\t\t\t\t\t\t\tgutterItem.range.startLineNumber <= this._editor.getModel()!.getLineCount()\n\t\t\t\t\t\t\t\t? this._editor.getTopForLineNumber(gutterItem.range.startLineNumber, true) - scrollTop\n\t\t\t\t\t\t\t\t: this._editor.getBottomForLineNumber(gutterItem.range.startLineNumber - 1, false) - scrollTop;\n\t\t\t\t\t\tconst bottom = gutterItem.range.isEmpty\n\t\t\t\t\t\t\t// Don't trust that `getBottomForLineNumber` for the previous line equals `getTopForLineNumber` for the current one.\n\t\t\t\t\t\t\t? top\n\t\t\t\t\t\t\t: (this._editor.getBottomForLineNumber(gutterItem.range.endLineNumberExclusive - 1, true) - scrollTop);\n\n\t\t\t\t\t\tconst height = bottom - top;\n\t\t\t\t\t\tview.domNode.style.top = `${top}px`;\n\t\t\t\t\t\tview.domNode.style.height = `${height}px`;\n\n\t\t\t\t\t\tview.gutterItemView.layout(OffsetRange.ofStartAndLength(top, height), viewRange);\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tfor (const id of unusedIds) {\n\t\t\tconst view = this.views.get(id)!;\n\t\t\tview.gutterItemView.dispose();\n\t\t\tthis._domNode.removeChild(view.domNode);\n\t\t\tthis.views.delete(id);\n\t\t}\n\t}\n}\n\nclass ManagedGutterItemView {\n\tconstructor(\n\t\tpublic readonly item: ISettableObservable,\n\t\tpublic readonly gutterItemView: IGutterItemView,\n\t\tpublic readonly domNode: HTMLDivElement,\n\t) { }\n}\n\nexport interface IGutterItemProvider {\n\tgetIntersectingGutterItems(range: LineRange, reader: IReader): TItem[];\n\n\tcreateView(item: IObservable, target: HTMLElement): IGutterItemView;\n}\n\nexport interface IGutterItemInfo {\n\tid: string;\n\trange: LineRange;\n}\n\nexport interface IGutterItemView extends IDisposable {\n\tlayout(itemRange: OffsetRange, viewRange: OffsetRange): void;\n}\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\nimport * as strings from 'vs/base/common/strings';\nimport * as platform from 'vs/base/common/platform';\nimport * as buffer from 'vs/base/common/buffer';\n\nlet _utf16LE_TextDecoder: TextDecoder | null;\nfunction getUTF16LE_TextDecoder(): TextDecoder {\n\tif (!_utf16LE_TextDecoder) {\n\t\t_utf16LE_TextDecoder = new TextDecoder('UTF-16LE');\n\t}\n\treturn _utf16LE_TextDecoder;\n}\n\nlet _utf16BE_TextDecoder: TextDecoder | null;\nfunction getUTF16BE_TextDecoder(): TextDecoder {\n\tif (!_utf16BE_TextDecoder) {\n\t\t_utf16BE_TextDecoder = new TextDecoder('UTF-16BE');\n\t}\n\treturn _utf16BE_TextDecoder;\n}\n\nlet _platformTextDecoder: TextDecoder | null;\nexport function getPlatformTextDecoder(): TextDecoder {\n\tif (!_platformTextDecoder) {\n\t\t_platformTextDecoder = platform.isLittleEndian() ? getUTF16LE_TextDecoder() : getUTF16BE_TextDecoder();\n\t}\n\treturn _platformTextDecoder;\n}\n\nexport function decodeUTF16LE(source: Uint8Array, offset: number, len: number): string {\n\tconst view = new Uint16Array(source.buffer, offset, len);\n\tif (len > 0 && (view[0] === 0xFEFF || view[0] === 0xFFFE)) {\n\t\t// UTF16 sometimes starts with a BOM https://de.wikipedia.org/wiki/Byte_Order_Mark\n\t\t// It looks like TextDecoder.decode will eat up a leading BOM (0xFEFF or 0xFFFE)\n\t\t// We don't want that behavior because we know the string is UTF16LE and the BOM should be maintained\n\t\t// So we use the manual decoder\n\t\treturn compatDecodeUTF16LE(source, offset, len);\n\t}\n\treturn getUTF16LE_TextDecoder().decode(view);\n}\n\nfunction compatDecodeUTF16LE(source: Uint8Array, offset: number, len: number): string {\n\tconst result: string[] = [];\n\tlet resultLen = 0;\n\tfor (let i = 0; i < len; i++) {\n\t\tconst charCode = buffer.readUInt16LE(source, offset); offset += 2;\n\t\tresult[resultLen++] = String.fromCharCode(charCode);\n\t}\n\treturn result.join('');\n}\n\nexport class StringBuilder {\n\n\tprivate readonly _capacity: number;\n\tprivate readonly _buffer: Uint16Array;\n\n\tprivate _completedStrings: string[] | null;\n\tprivate _bufferLength: number;\n\n\tconstructor(capacity: number) {\n\t\tthis._capacity = capacity | 0;\n\t\tthis._buffer = new Uint16Array(this._capacity);\n\n\t\tthis._completedStrings = null;\n\t\tthis._bufferLength = 0;\n\t}\n\n\tpublic reset(): void {\n\t\tthis._completedStrings = null;\n\t\tthis._bufferLength = 0;\n\t}\n\n\tpublic build(): string {\n\t\tif (this._completedStrings !== null) {\n\t\t\tthis._flushBuffer();\n\t\t\treturn this._completedStrings.join('');\n\t\t}\n\t\treturn this._buildBuffer();\n\t}\n\n\tprivate _buildBuffer(): string {\n\t\tif (this._bufferLength === 0) {\n\t\t\treturn '';\n\t\t}\n\n\t\tconst view = new Uint16Array(this._buffer.buffer, 0, this._bufferLength);\n\t\treturn getPlatformTextDecoder().decode(view);\n\t}\n\n\tprivate _flushBuffer(): void {\n\t\tconst bufferString = this._buildBuffer();\n\t\tthis._bufferLength = 0;\n\n\t\tif (this._completedStrings === null) {\n\t\t\tthis._completedStrings = [bufferString];\n\t\t} else {\n\t\t\tthis._completedStrings[this._completedStrings.length] = bufferString;\n\t\t}\n\t}\n\n\t/**\n\t * Append a char code (<2^16)\n\t */\n\tpublic appendCharCode(charCode: number): void {\n\t\tconst remainingSpace = this._capacity - this._bufferLength;\n\n\t\tif (remainingSpace <= 1) {\n\t\t\tif (remainingSpace === 0 || strings.isHighSurrogate(charCode)) {\n\t\t\t\tthis._flushBuffer();\n\t\t\t}\n\t\t}\n\n\t\tthis._buffer[this._bufferLength++] = charCode;\n\t}\n\n\t/**\n\t * Append an ASCII char code (<2^8)\n\t */\n\tpublic appendASCIICharCode(charCode: number): void {\n\t\tif (this._bufferLength === this._capacity) {\n\t\t\t// buffer is full\n\t\t\tthis._flushBuffer();\n\t\t}\n\t\tthis._buffer[this._bufferLength++] = charCode;\n\t}\n\n\tpublic appendString(str: string): void {\n\t\tconst strLen = str.length;\n\n\t\tif (this._bufferLength + strLen >= this._capacity) {\n\t\t\t// This string does not fit in the remaining buffer space\n\n\t\t\tthis._flushBuffer();\n\t\t\tthis._completedStrings![this._completedStrings!.length] = str;\n\t\t\treturn;\n\t\t}\n\n\t\tfor (let i = 0; i < strLen; i++) {\n\t\t\tthis._buffer[this._bufferLength++] = str.charCodeAt(i);\n\t\t}\n\t}\n}\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\nimport { createTrustedTypesPolicy } from 'vs/base/browser/trustedTypes';\nimport { CharCode } from 'vs/base/common/charCode';\nimport * as strings from 'vs/base/common/strings';\nimport { assertIsDefined } from 'vs/base/common/types';\nimport { applyFontInfo } from 'vs/editor/browser/config/domFontInfo';\nimport { WrappingIndent } from 'vs/editor/common/config/editorOptions';\nimport { FontInfo } from 'vs/editor/common/config/fontInfo';\nimport { StringBuilder } from 'vs/editor/common/core/stringBuilder';\nimport { InjectedTextOptions } from 'vs/editor/common/model';\nimport { ILineBreaksComputer, ILineBreaksComputerFactory, ModelLineProjectionData } from 'vs/editor/common/modelLineProjectionData';\nimport { LineInjectedText } from 'vs/editor/common/textModelEvents';\n\nconst ttPolicy = createTrustedTypesPolicy('domLineBreaksComputer', { createHTML: value => value });\n\nexport class DOMLineBreaksComputerFactory implements ILineBreaksComputerFactory {\n\n\tpublic static create(targetWindow: Window): DOMLineBreaksComputerFactory {\n\t\treturn new DOMLineBreaksComputerFactory(new WeakRef(targetWindow));\n\t}\n\n\tconstructor(private targetWindow: WeakRef) {\n\t}\n\n\tpublic createLineBreaksComputer(fontInfo: FontInfo, tabSize: number, wrappingColumn: number, wrappingIndent: WrappingIndent, wordBreak: 'normal' | 'keepAll'): ILineBreaksComputer {\n\t\tconst requests: string[] = [];\n\t\tconst injectedTexts: (LineInjectedText[] | null)[] = [];\n\t\treturn {\n\t\t\taddRequest: (lineText: string, injectedText: LineInjectedText[] | null, previousLineBreakData: ModelLineProjectionData | null) => {\n\t\t\t\trequests.push(lineText);\n\t\t\t\tinjectedTexts.push(injectedText);\n\t\t\t},\n\t\t\tfinalize: () => {\n\t\t\t\treturn createLineBreaks(assertIsDefined(this.targetWindow.deref()), requests, fontInfo, tabSize, wrappingColumn, wrappingIndent, wordBreak, injectedTexts);\n\t\t\t}\n\t\t};\n\t}\n}\n\nfunction createLineBreaks(targetWindow: Window, requests: string[], fontInfo: FontInfo, tabSize: number, firstLineBreakColumn: number, wrappingIndent: WrappingIndent, wordBreak: 'normal' | 'keepAll', injectedTextsPerLine: (LineInjectedText[] | null)[]): (ModelLineProjectionData | null)[] {\n\tfunction createEmptyLineBreakWithPossiblyInjectedText(requestIdx: number): ModelLineProjectionData | null {\n\t\tconst injectedTexts = injectedTextsPerLine[requestIdx];\n\t\tif (injectedTexts) {\n\t\t\tconst lineText = LineInjectedText.applyInjectedText(requests[requestIdx], injectedTexts);\n\n\t\t\tconst injectionOptions = injectedTexts.map(t => t.options);\n\t\t\tconst injectionOffsets = injectedTexts.map(text => text.column - 1);\n\n\t\t\t// creating a `LineBreakData` with an invalid `breakOffsetsVisibleColumn` is OK\n\t\t\t// because `breakOffsetsVisibleColumn` will never be used because it contains injected text\n\t\t\treturn new ModelLineProjectionData(injectionOffsets, injectionOptions, [lineText.length], [], 0);\n\t\t} else {\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tif (firstLineBreakColumn === -1) {\n\t\tconst result: (ModelLineProjectionData | null)[] = [];\n\t\tfor (let i = 0, len = requests.length; i < len; i++) {\n\t\t\tresult[i] = createEmptyLineBreakWithPossiblyInjectedText(i);\n\t\t}\n\t\treturn result;\n\t}\n\n\tconst overallWidth = Math.round(firstLineBreakColumn * fontInfo.typicalHalfwidthCharacterWidth);\n\tconst additionalIndent = (wrappingIndent === WrappingIndent.DeepIndent ? 2 : wrappingIndent === WrappingIndent.Indent ? 1 : 0);\n\tconst additionalIndentSize = Math.round(tabSize * additionalIndent);\n\tconst additionalIndentLength = Math.ceil(fontInfo.spaceWidth * additionalIndentSize);\n\n\tconst containerDomNode = document.createElement('div');\n\tapplyFontInfo(containerDomNode, fontInfo);\n\n\tconst sb = new StringBuilder(10000);\n\tconst firstNonWhitespaceIndices: number[] = [];\n\tconst wrappedTextIndentLengths: number[] = [];\n\tconst renderLineContents: string[] = [];\n\tconst allCharOffsets: number[][] = [];\n\tconst allVisibleColumns: number[][] = [];\n\tfor (let i = 0; i < requests.length; i++) {\n\t\tconst lineContent = LineInjectedText.applyInjectedText(requests[i], injectedTextsPerLine[i]);\n\n\t\tlet firstNonWhitespaceIndex = 0;\n\t\tlet wrappedTextIndentLength = 0;\n\t\tlet width = overallWidth;\n\n\t\tif (wrappingIndent !== WrappingIndent.None) {\n\t\t\tfirstNonWhitespaceIndex = strings.firstNonWhitespaceIndex(lineContent);\n\t\t\tif (firstNonWhitespaceIndex === -1) {\n\t\t\t\t// all whitespace line\n\t\t\t\tfirstNonWhitespaceIndex = 0;\n\n\t\t\t} else {\n\t\t\t\t// Track existing indent\n\n\t\t\t\tfor (let i = 0; i < firstNonWhitespaceIndex; i++) {\n\t\t\t\t\tconst charWidth = (\n\t\t\t\t\t\tlineContent.charCodeAt(i) === CharCode.Tab\n\t\t\t\t\t\t\t? (tabSize - (wrappedTextIndentLength % tabSize))\n\t\t\t\t\t\t\t: 1\n\t\t\t\t\t);\n\t\t\t\t\twrappedTextIndentLength += charWidth;\n\t\t\t\t}\n\n\t\t\t\tconst indentWidth = Math.ceil(fontInfo.spaceWidth * wrappedTextIndentLength);\n\n\t\t\t\t// Force sticking to beginning of line if no character would fit except for the indentation\n\t\t\t\tif (indentWidth + fontInfo.typicalFullwidthCharacterWidth > overallWidth) {\n\t\t\t\t\tfirstNonWhitespaceIndex = 0;\n\t\t\t\t\twrappedTextIndentLength = 0;\n\t\t\t\t} else {\n\t\t\t\t\twidth = overallWidth - indentWidth;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst renderLineContent = lineContent.substr(firstNonWhitespaceIndex);\n\t\tconst tmp = renderLine(renderLineContent, wrappedTextIndentLength, tabSize, width, sb, additionalIndentLength);\n\t\tfirstNonWhitespaceIndices[i] = firstNonWhitespaceIndex;\n\t\twrappedTextIndentLengths[i] = wrappedTextIndentLength;\n\t\trenderLineContents[i] = renderLineContent;\n\t\tallCharOffsets[i] = tmp[0];\n\t\tallVisibleColumns[i] = tmp[1];\n\t}\n\tconst html = sb.build();\n\tconst trustedhtml = ttPolicy?.createHTML(html) ?? html;\n\tcontainerDomNode.innerHTML = trustedhtml as string;\n\n\tcontainerDomNode.style.position = 'absolute';\n\tcontainerDomNode.style.top = '10000';\n\tif (wordBreak === 'keepAll') {\n\t\t// word-break: keep-all; overflow-wrap: anywhere\n\t\tcontainerDomNode.style.wordBreak = 'keep-all';\n\t\tcontainerDomNode.style.overflowWrap = 'anywhere';\n\t} else {\n\t\t// overflow-wrap: break-word\n\t\tcontainerDomNode.style.wordBreak = 'inherit';\n\t\tcontainerDomNode.style.overflowWrap = 'break-word';\n\t}\n\ttargetWindow.document.body.appendChild(containerDomNode);\n\n\tconst range = document.createRange();\n\tconst lineDomNodes = Array.prototype.slice.call(containerDomNode.children, 0);\n\n\tconst result: (ModelLineProjectionData | null)[] = [];\n\tfor (let i = 0; i < requests.length; i++) {\n\t\tconst lineDomNode = lineDomNodes[i];\n\t\tconst breakOffsets: number[] | null = readLineBreaks(range, lineDomNode, renderLineContents[i], allCharOffsets[i]);\n\t\tif (breakOffsets === null) {\n\t\t\tresult[i] = createEmptyLineBreakWithPossiblyInjectedText(i);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst firstNonWhitespaceIndex = firstNonWhitespaceIndices[i];\n\t\tconst wrappedTextIndentLength = wrappedTextIndentLengths[i] + additionalIndentSize;\n\t\tconst visibleColumns = allVisibleColumns[i];\n\n\t\tconst breakOffsetsVisibleColumn: number[] = [];\n\t\tfor (let j = 0, len = breakOffsets.length; j < len; j++) {\n\t\t\tbreakOffsetsVisibleColumn[j] = visibleColumns[breakOffsets[j]];\n\t\t}\n\n\t\tif (firstNonWhitespaceIndex !== 0) {\n\t\t\t// All break offsets are relative to the renderLineContent, make them absolute again\n\t\t\tfor (let j = 0, len = breakOffsets.length; j < len; j++) {\n\t\t\t\tbreakOffsets[j] += firstNonWhitespaceIndex;\n\t\t\t}\n\t\t}\n\n\t\tlet injectionOptions: InjectedTextOptions[] | null;\n\t\tlet injectionOffsets: number[] | null;\n\t\tconst curInjectedTexts = injectedTextsPerLine[i];\n\t\tif (curInjectedTexts) {\n\t\t\tinjectionOptions = curInjectedTexts.map(t => t.options);\n\t\t\tinjectionOffsets = curInjectedTexts.map(text => text.column - 1);\n\t\t} else {\n\t\t\tinjectionOptions = null;\n\t\t\tinjectionOffsets = null;\n\t\t}\n\n\t\tresult[i] = new ModelLineProjectionData(injectionOffsets, injectionOptions, breakOffsets, breakOffsetsVisibleColumn, wrappedTextIndentLength);\n\t}\n\n\ttargetWindow.document.body.removeChild(containerDomNode);\n\treturn result;\n}\n\nconst enum Constants {\n\tSPAN_MODULO_LIMIT = 16384\n}\n\nfunction renderLine(lineContent: string, initialVisibleColumn: number, tabSize: number, width: number, sb: StringBuilder, wrappingIndentLength: number): [number[], number[]] {\n\n\tif (wrappingIndentLength !== 0) {\n\t\tconst hangingOffset = String(wrappingIndentLength);\n\t\tsb.appendString('

    ');\n\t// if (containsRTL) {\n\t// \tsb.appendASCIIString('\" dir=\"ltr');\n\t// }\n\n\tconst len = lineContent.length;\n\tlet visibleColumn = initialVisibleColumn;\n\tlet charOffset = 0;\n\tconst charOffsets: number[] = [];\n\tconst visibleColumns: number[] = [];\n\tlet nextCharCode = (0 < len ? lineContent.charCodeAt(0) : CharCode.Null);\n\n\tsb.appendString('');\n\tfor (let charIndex = 0; charIndex < len; charIndex++) {\n\t\tif (charIndex !== 0 && charIndex % Constants.SPAN_MODULO_LIMIT === 0) {\n\t\t\tsb.appendString('');\n\t\t}\n\t\tcharOffsets[charIndex] = charOffset;\n\t\tvisibleColumns[charIndex] = visibleColumn;\n\t\tconst charCode = nextCharCode;\n\t\tnextCharCode = (charIndex + 1 < len ? lineContent.charCodeAt(charIndex + 1) : CharCode.Null);\n\t\tlet producedCharacters = 1;\n\t\tlet charWidth = 1;\n\t\tswitch (charCode) {\n\t\t\tcase CharCode.Tab:\n\t\t\t\tproducedCharacters = (tabSize - (visibleColumn % tabSize));\n\t\t\t\tcharWidth = producedCharacters;\n\t\t\t\tfor (let space = 1; space <= producedCharacters; space++) {\n\t\t\t\t\tif (space < producedCharacters) {\n\t\t\t\t\t\tsb.appendCharCode(0xA0); //  \n\t\t\t\t\t} else {\n\t\t\t\t\t\tsb.appendASCIICharCode(CharCode.Space);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase CharCode.Space:\n\t\t\t\tif (nextCharCode === CharCode.Space) {\n\t\t\t\t\tsb.appendCharCode(0xA0); //  \n\t\t\t\t} else {\n\t\t\t\t\tsb.appendASCIICharCode(CharCode.Space);\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase CharCode.LessThan:\n\t\t\t\tsb.appendString('<');\n\t\t\t\tbreak;\n\n\t\t\tcase CharCode.GreaterThan:\n\t\t\t\tsb.appendString('>');\n\t\t\t\tbreak;\n\n\t\t\tcase CharCode.Ampersand:\n\t\t\t\tsb.appendString('&');\n\t\t\t\tbreak;\n\n\t\t\tcase CharCode.Null:\n\t\t\t\tsb.appendString('�');\n\t\t\t\tbreak;\n\n\t\t\tcase CharCode.UTF8_BOM:\n\t\t\tcase CharCode.LINE_SEPARATOR:\n\t\t\tcase CharCode.PARAGRAPH_SEPARATOR:\n\t\t\tcase CharCode.NEXT_LINE:\n\t\t\t\tsb.appendCharCode(0xFFFD);\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tif (strings.isFullWidthCharacter(charCode)) {\n\t\t\t\t\tcharWidth++;\n\t\t\t\t}\n\t\t\t\tif (charCode < 32) {\n\t\t\t\t\tsb.appendCharCode(9216 + charCode);\n\t\t\t\t} else {\n\t\t\t\t\tsb.appendCharCode(charCode);\n\t\t\t\t}\n\t\t}\n\n\t\tcharOffset += producedCharacters;\n\t\tvisibleColumn += charWidth;\n\t}\n\tsb.appendString('');\n\n\tcharOffsets[lineContent.length] = charOffset;\n\tvisibleColumns[lineContent.length] = visibleColumn;\n\n\tsb.appendString('
    ');\n\n\treturn [charOffsets, visibleColumns];\n}\n\nfunction readLineBreaks(range: Range, lineDomNode: HTMLDivElement, lineContent: string, charOffsets: number[]): number[] | null {\n\tif (lineContent.length <= 1) {\n\t\treturn null;\n\t}\n\tconst spans = Array.prototype.slice.call(lineDomNode.children, 0);\n\n\tconst breakOffsets: number[] = [];\n\ttry {\n\t\tdiscoverBreaks(range, spans, charOffsets, 0, null, lineContent.length - 1, null, breakOffsets);\n\t} catch (err) {\n\t\tconsole.log(err);\n\t\treturn null;\n\t}\n\n\tif (breakOffsets.length === 0) {\n\t\treturn null;\n\t}\n\n\tbreakOffsets.push(lineContent.length);\n\treturn breakOffsets;\n}\n\nfunction discoverBreaks(range: Range, spans: HTMLSpanElement[], charOffsets: number[], low: number, lowRects: DOMRectList | null, high: number, highRects: DOMRectList | null, result: number[]): void {\n\tif (low === high) {\n\t\treturn;\n\t}\n\n\tlowRects = lowRects || readClientRect(range, spans, charOffsets[low], charOffsets[low + 1]);\n\thighRects = highRects || readClientRect(range, spans, charOffsets[high], charOffsets[high + 1]);\n\n\tif (Math.abs(lowRects[0].top - highRects[0].top) <= 0.1) {\n\t\t// same line\n\t\treturn;\n\t}\n\n\t// there is at least one line break between these two offsets\n\tif (low + 1 === high) {\n\t\t// the two characters are adjacent, so the line break must be exactly between them\n\t\tresult.push(high);\n\t\treturn;\n\t}\n\n\tconst mid = low + ((high - low) / 2) | 0;\n\tconst midRects = readClientRect(range, spans, charOffsets[mid], charOffsets[mid + 1]);\n\tdiscoverBreaks(range, spans, charOffsets, low, lowRects, mid, midRects, result);\n\tdiscoverBreaks(range, spans, charOffsets, mid, midRects, high, highRects, result);\n}\n\nfunction readClientRect(range: Range, spans: HTMLSpanElement[], startOffset: number, endOffset: number): DOMRectList {\n\trange.setStart(spans[(startOffset / Constants.SPAN_MODULO_LIMIT) | 0].firstChild!, startOffset % Constants.SPAN_MODULO_LIMIT);\n\trange.setEnd(spans[(endOffset / Constants.SPAN_MODULO_LIMIT) | 0].firstChild!, endOffset % Constants.SPAN_MODULO_LIMIT);\n\treturn range.getClientRects();\n}\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\nimport { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';\nimport { createTrustedTypesPolicy } from 'vs/base/browser/trustedTypes';\nimport { BugIndicatingError } from 'vs/base/common/errors';\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\nimport { StringBuilder } from 'vs/editor/common/core/stringBuilder';\nimport * as viewEvents from 'vs/editor/common/viewEvents';\nimport { ViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData';\n\n/**\n * Represents a visible line\n */\nexport interface IVisibleLine extends ILine {\n\tgetDomNode(): HTMLElement | null;\n\tsetDomNode(domNode: HTMLElement): void;\n\n\t/**\n\t * Return null if the HTML should not be touched.\n\t * Return the new HTML otherwise.\n\t */\n\trenderLine(lineNumber: number, deltaTop: number, lineHeight: number, viewportData: ViewportData, sb: StringBuilder): boolean;\n\n\t/**\n\t * Layout the line.\n\t */\n\tlayoutLine(lineNumber: number, deltaTop: number, lineHeight: number): void;\n}\n\nexport interface ILine {\n\tonContentChanged(): void;\n\tonTokensChanged(): void;\n}\n\nexport class RenderedLinesCollection {\n\tprivate readonly _createLine: () => T;\n\tprivate _lines!: T[];\n\tprivate _rendLineNumberStart!: number;\n\n\tconstructor(createLine: () => T) {\n\t\tthis._createLine = createLine;\n\t\tthis._set(1, []);\n\t}\n\n\tpublic flush(): void {\n\t\tthis._set(1, []);\n\t}\n\n\t_set(rendLineNumberStart: number, lines: T[]): void {\n\t\tthis._lines = lines;\n\t\tthis._rendLineNumberStart = rendLineNumberStart;\n\t}\n\n\t_get(): { rendLineNumberStart: number; lines: T[] } {\n\t\treturn {\n\t\t\trendLineNumberStart: this._rendLineNumberStart,\n\t\t\tlines: this._lines\n\t\t};\n\t}\n\n\t/**\n\t * @returns Inclusive line number that is inside this collection\n\t */\n\tpublic getStartLineNumber(): number {\n\t\treturn this._rendLineNumberStart;\n\t}\n\n\t/**\n\t * @returns Inclusive line number that is inside this collection\n\t */\n\tpublic getEndLineNumber(): number {\n\t\treturn this._rendLineNumberStart + this._lines.length - 1;\n\t}\n\n\tpublic getCount(): number {\n\t\treturn this._lines.length;\n\t}\n\n\tpublic getLine(lineNumber: number): T {\n\t\tconst lineIndex = lineNumber - this._rendLineNumberStart;\n\t\tif (lineIndex < 0 || lineIndex >= this._lines.length) {\n\t\t\tthrow new BugIndicatingError('Illegal value for lineNumber');\n\t\t}\n\t\treturn this._lines[lineIndex];\n\t}\n\n\t/**\n\t * @returns Lines that were removed from this collection\n\t */\n\tpublic onLinesDeleted(deleteFromLineNumber: number, deleteToLineNumber: number): T[] | null {\n\t\tif (this.getCount() === 0) {\n\t\t\t// no lines\n\t\t\treturn null;\n\t\t}\n\n\t\tconst startLineNumber = this.getStartLineNumber();\n\t\tconst endLineNumber = this.getEndLineNumber();\n\n\t\tif (deleteToLineNumber < startLineNumber) {\n\t\t\t// deleting above the viewport\n\t\t\tconst deleteCnt = deleteToLineNumber - deleteFromLineNumber + 1;\n\t\t\tthis._rendLineNumberStart -= deleteCnt;\n\t\t\treturn null;\n\t\t}\n\n\t\tif (deleteFromLineNumber > endLineNumber) {\n\t\t\t// deleted below the viewport\n\t\t\treturn null;\n\t\t}\n\n\t\t// Record what needs to be deleted\n\t\tlet deleteStartIndex = 0;\n\t\tlet deleteCount = 0;\n\t\tfor (let lineNumber = startLineNumber; lineNumber <= endLineNumber; lineNumber++) {\n\t\t\tconst lineIndex = lineNumber - this._rendLineNumberStart;\n\n\t\t\tif (deleteFromLineNumber <= lineNumber && lineNumber <= deleteToLineNumber) {\n\t\t\t\t// this is a line to be deleted\n\t\t\t\tif (deleteCount === 0) {\n\t\t\t\t\t// this is the first line to be deleted\n\t\t\t\t\tdeleteStartIndex = lineIndex;\n\t\t\t\t\tdeleteCount = 1;\n\t\t\t\t} else {\n\t\t\t\t\tdeleteCount++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Adjust this._rendLineNumberStart for lines deleted above\n\t\tif (deleteFromLineNumber < startLineNumber) {\n\t\t\t// Something was deleted above\n\t\t\tlet deleteAboveCount = 0;\n\n\t\t\tif (deleteToLineNumber < startLineNumber) {\n\t\t\t\t// the entire deleted lines are above\n\t\t\t\tdeleteAboveCount = deleteToLineNumber - deleteFromLineNumber + 1;\n\t\t\t} else {\n\t\t\t\tdeleteAboveCount = startLineNumber - deleteFromLineNumber;\n\t\t\t}\n\n\t\t\tthis._rendLineNumberStart -= deleteAboveCount;\n\t\t}\n\n\t\tconst deleted = this._lines.splice(deleteStartIndex, deleteCount);\n\t\treturn deleted;\n\t}\n\n\tpublic onLinesChanged(changeFromLineNumber: number, changeCount: number): boolean {\n\t\tconst changeToLineNumber = changeFromLineNumber + changeCount - 1;\n\t\tif (this.getCount() === 0) {\n\t\t\t// no lines\n\t\t\treturn false;\n\t\t}\n\n\t\tconst startLineNumber = this.getStartLineNumber();\n\t\tconst endLineNumber = this.getEndLineNumber();\n\n\t\tlet someoneNotified = false;\n\n\t\tfor (let changedLineNumber = changeFromLineNumber; changedLineNumber <= changeToLineNumber; changedLineNumber++) {\n\t\t\tif (changedLineNumber >= startLineNumber && changedLineNumber <= endLineNumber) {\n\t\t\t\t// Notify the line\n\t\t\t\tthis._lines[changedLineNumber - this._rendLineNumberStart].onContentChanged();\n\t\t\t\tsomeoneNotified = true;\n\t\t\t}\n\t\t}\n\n\t\treturn someoneNotified;\n\t}\n\n\tpublic onLinesInserted(insertFromLineNumber: number, insertToLineNumber: number): T[] | null {\n\t\tif (this.getCount() === 0) {\n\t\t\t// no lines\n\t\t\treturn null;\n\t\t}\n\n\t\tconst insertCnt = insertToLineNumber - insertFromLineNumber + 1;\n\t\tconst startLineNumber = this.getStartLineNumber();\n\t\tconst endLineNumber = this.getEndLineNumber();\n\n\t\tif (insertFromLineNumber <= startLineNumber) {\n\t\t\t// inserting above the viewport\n\t\t\tthis._rendLineNumberStart += insertCnt;\n\t\t\treturn null;\n\t\t}\n\n\t\tif (insertFromLineNumber > endLineNumber) {\n\t\t\t// inserting below the viewport\n\t\t\treturn null;\n\t\t}\n\n\t\tif (insertCnt + insertFromLineNumber > endLineNumber) {\n\t\t\t// insert inside the viewport in such a way that all remaining lines are pushed outside\n\t\t\tconst deleted = this._lines.splice(insertFromLineNumber - this._rendLineNumberStart, endLineNumber - insertFromLineNumber + 1);\n\t\t\treturn deleted;\n\t\t}\n\n\t\t// insert inside the viewport, push out some lines, but not all remaining lines\n\t\tconst newLines: T[] = [];\n\t\tfor (let i = 0; i < insertCnt; i++) {\n\t\t\tnewLines[i] = this._createLine();\n\t\t}\n\t\tconst insertIndex = insertFromLineNumber - this._rendLineNumberStart;\n\t\tconst beforeLines = this._lines.slice(0, insertIndex);\n\t\tconst afterLines = this._lines.slice(insertIndex, this._lines.length - insertCnt);\n\t\tconst deletedLines = this._lines.slice(this._lines.length - insertCnt, this._lines.length);\n\n\t\tthis._lines = beforeLines.concat(newLines).concat(afterLines);\n\n\t\treturn deletedLines;\n\t}\n\n\tpublic onTokensChanged(ranges: { fromLineNumber: number; toLineNumber: number }[]): boolean {\n\t\tif (this.getCount() === 0) {\n\t\t\t// no lines\n\t\t\treturn false;\n\t\t}\n\n\t\tconst startLineNumber = this.getStartLineNumber();\n\t\tconst endLineNumber = this.getEndLineNumber();\n\n\t\tlet notifiedSomeone = false;\n\t\tfor (let i = 0, len = ranges.length; i < len; i++) {\n\t\t\tconst rng = ranges[i];\n\n\t\t\tif (rng.toLineNumber < startLineNumber || rng.fromLineNumber > endLineNumber) {\n\t\t\t\t// range outside viewport\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst from = Math.max(startLineNumber, rng.fromLineNumber);\n\t\t\tconst to = Math.min(endLineNumber, rng.toLineNumber);\n\n\t\t\tfor (let lineNumber = from; lineNumber <= to; lineNumber++) {\n\t\t\t\tconst lineIndex = lineNumber - this._rendLineNumberStart;\n\t\t\t\tthis._lines[lineIndex].onTokensChanged();\n\t\t\t\tnotifiedSomeone = true;\n\t\t\t}\n\t\t}\n\n\t\treturn notifiedSomeone;\n\t}\n}\n\nexport interface IVisibleLinesHost {\n\tcreateVisibleLine(): T;\n}\n\nexport class VisibleLinesCollection {\n\n\tprivate readonly _host: IVisibleLinesHost;\n\tpublic readonly domNode: FastDomNode;\n\tprivate readonly _linesCollection: RenderedLinesCollection;\n\n\tconstructor(host: IVisibleLinesHost) {\n\t\tthis._host = host;\n\t\tthis.domNode = this._createDomNode();\n\t\tthis._linesCollection = new RenderedLinesCollection(() => this._host.createVisibleLine());\n\t}\n\n\tprivate _createDomNode(): FastDomNode {\n\t\tconst domNode = createFastDomNode(document.createElement('div'));\n\t\tdomNode.setClassName('view-layer');\n\t\tdomNode.setPosition('absolute');\n\t\tdomNode.domNode.setAttribute('role', 'presentation');\n\t\tdomNode.domNode.setAttribute('aria-hidden', 'true');\n\t\treturn domNode;\n\t}\n\n\t// ---- begin view event handlers\n\n\tpublic onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {\n\t\tif (e.hasChanged(EditorOption.layoutInfo)) {\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tpublic onFlushed(e: viewEvents.ViewFlushedEvent): boolean {\n\t\tthis._linesCollection.flush();\n\t\t// No need to clear the dom node because a full .innerHTML will occur in ViewLayerRenderer._render\n\t\treturn true;\n\t}\n\n\tpublic onLinesChanged(e: viewEvents.ViewLinesChangedEvent): boolean {\n\t\treturn this._linesCollection.onLinesChanged(e.fromLineNumber, e.count);\n\t}\n\n\tpublic onLinesDeleted(e: viewEvents.ViewLinesDeletedEvent): boolean {\n\t\tconst deleted = this._linesCollection.onLinesDeleted(e.fromLineNumber, e.toLineNumber);\n\t\tif (deleted) {\n\t\t\t// Remove from DOM\n\t\t\tfor (let i = 0, len = deleted.length; i < len; i++) {\n\t\t\t\tconst lineDomNode = deleted[i].getDomNode();\n\t\t\t\tif (lineDomNode) {\n\t\t\t\t\tthis.domNode.domNode.removeChild(lineDomNode);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tpublic onLinesInserted(e: viewEvents.ViewLinesInsertedEvent): boolean {\n\t\tconst deleted = this._linesCollection.onLinesInserted(e.fromLineNumber, e.toLineNumber);\n\t\tif (deleted) {\n\t\t\t// Remove from DOM\n\t\t\tfor (let i = 0, len = deleted.length; i < len; i++) {\n\t\t\t\tconst lineDomNode = deleted[i].getDomNode();\n\t\t\t\tif (lineDomNode) {\n\t\t\t\t\tthis.domNode.domNode.removeChild(lineDomNode);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tpublic onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean {\n\t\treturn e.scrollTopChanged;\n\t}\n\n\tpublic onTokensChanged(e: viewEvents.ViewTokensChangedEvent): boolean {\n\t\treturn this._linesCollection.onTokensChanged(e.ranges);\n\t}\n\n\tpublic onZonesChanged(e: viewEvents.ViewZonesChangedEvent): boolean {\n\t\treturn true;\n\t}\n\n\t// ---- end view event handlers\n\n\tpublic getStartLineNumber(): number {\n\t\treturn this._linesCollection.getStartLineNumber();\n\t}\n\n\tpublic getEndLineNumber(): number {\n\t\treturn this._linesCollection.getEndLineNumber();\n\t}\n\n\tpublic getVisibleLine(lineNumber: number): T {\n\t\treturn this._linesCollection.getLine(lineNumber);\n\t}\n\n\tpublic renderLines(viewportData: ViewportData): void {\n\n\t\tconst inp = this._linesCollection._get();\n\n\t\tconst renderer = new ViewLayerRenderer(this.domNode.domNode, this._host, viewportData);\n\n\t\tconst ctx: IRendererContext = {\n\t\t\trendLineNumberStart: inp.rendLineNumberStart,\n\t\t\tlines: inp.lines,\n\t\t\tlinesLength: inp.lines.length\n\t\t};\n\n\t\t// Decide if this render will do a single update (single large .innerHTML) or many updates (inserting/removing dom nodes)\n\t\tconst resCtx = renderer.render(ctx, viewportData.startLineNumber, viewportData.endLineNumber, viewportData.relativeVerticalOffset);\n\n\t\tthis._linesCollection._set(resCtx.rendLineNumberStart, resCtx.lines);\n\t}\n}\n\ninterface IRendererContext {\n\trendLineNumberStart: number;\n\tlines: T[];\n\tlinesLength: number;\n}\n\nclass ViewLayerRenderer {\n\n\tprivate static _ttPolicy = createTrustedTypesPolicy('editorViewLayer', { createHTML: value => value });\n\n\treadonly domNode: HTMLElement;\n\treadonly host: IVisibleLinesHost;\n\treadonly viewportData: ViewportData;\n\n\tconstructor(domNode: HTMLElement, host: IVisibleLinesHost, viewportData: ViewportData) {\n\t\tthis.domNode = domNode;\n\t\tthis.host = host;\n\t\tthis.viewportData = viewportData;\n\t}\n\n\tpublic render(inContext: IRendererContext, startLineNumber: number, stopLineNumber: number, deltaTop: number[]): IRendererContext {\n\n\t\tconst ctx: IRendererContext = {\n\t\t\trendLineNumberStart: inContext.rendLineNumberStart,\n\t\t\tlines: inContext.lines.slice(0),\n\t\t\tlinesLength: inContext.linesLength\n\t\t};\n\n\t\tif ((ctx.rendLineNumberStart + ctx.linesLength - 1 < startLineNumber) || (stopLineNumber < ctx.rendLineNumberStart)) {\n\t\t\t// There is no overlap whatsoever\n\t\t\tctx.rendLineNumberStart = startLineNumber;\n\t\t\tctx.linesLength = stopLineNumber - startLineNumber + 1;\n\t\t\tctx.lines = [];\n\t\t\tfor (let x = startLineNumber; x <= stopLineNumber; x++) {\n\t\t\t\tctx.lines[x - startLineNumber] = this.host.createVisibleLine();\n\t\t\t}\n\t\t\tthis._finishRendering(ctx, true, deltaTop);\n\t\t\treturn ctx;\n\t\t}\n\n\t\t// Update lines which will remain untouched\n\t\tthis._renderUntouchedLines(\n\t\t\tctx,\n\t\t\tMath.max(startLineNumber - ctx.rendLineNumberStart, 0),\n\t\t\tMath.min(stopLineNumber - ctx.rendLineNumberStart, ctx.linesLength - 1),\n\t\t\tdeltaTop,\n\t\t\tstartLineNumber\n\t\t);\n\n\t\tif (ctx.rendLineNumberStart > startLineNumber) {\n\t\t\t// Insert lines before\n\t\t\tconst fromLineNumber = startLineNumber;\n\t\t\tconst toLineNumber = Math.min(stopLineNumber, ctx.rendLineNumberStart - 1);\n\t\t\tif (fromLineNumber <= toLineNumber) {\n\t\t\t\tthis._insertLinesBefore(ctx, fromLineNumber, toLineNumber, deltaTop, startLineNumber);\n\t\t\t\tctx.linesLength += toLineNumber - fromLineNumber + 1;\n\t\t\t}\n\t\t} else if (ctx.rendLineNumberStart < startLineNumber) {\n\t\t\t// Remove lines before\n\t\t\tconst removeCnt = Math.min(ctx.linesLength, startLineNumber - ctx.rendLineNumberStart);\n\t\t\tif (removeCnt > 0) {\n\t\t\t\tthis._removeLinesBefore(ctx, removeCnt);\n\t\t\t\tctx.linesLength -= removeCnt;\n\t\t\t}\n\t\t}\n\n\t\tctx.rendLineNumberStart = startLineNumber;\n\n\t\tif (ctx.rendLineNumberStart + ctx.linesLength - 1 < stopLineNumber) {\n\t\t\t// Insert lines after\n\t\t\tconst fromLineNumber = ctx.rendLineNumberStart + ctx.linesLength;\n\t\t\tconst toLineNumber = stopLineNumber;\n\n\t\t\tif (fromLineNumber <= toLineNumber) {\n\t\t\t\tthis._insertLinesAfter(ctx, fromLineNumber, toLineNumber, deltaTop, startLineNumber);\n\t\t\t\tctx.linesLength += toLineNumber - fromLineNumber + 1;\n\t\t\t}\n\n\t\t} else if (ctx.rendLineNumberStart + ctx.linesLength - 1 > stopLineNumber) {\n\t\t\t// Remove lines after\n\t\t\tconst fromLineNumber = Math.max(0, stopLineNumber - ctx.rendLineNumberStart + 1);\n\t\t\tconst toLineNumber = ctx.linesLength - 1;\n\t\t\tconst removeCnt = toLineNumber - fromLineNumber + 1;\n\n\t\t\tif (removeCnt > 0) {\n\t\t\t\tthis._removeLinesAfter(ctx, removeCnt);\n\t\t\t\tctx.linesLength -= removeCnt;\n\t\t\t}\n\t\t}\n\n\t\tthis._finishRendering(ctx, false, deltaTop);\n\n\t\treturn ctx;\n\t}\n\n\tprivate _renderUntouchedLines(ctx: IRendererContext, startIndex: number, endIndex: number, deltaTop: number[], deltaLN: number): void {\n\t\tconst rendLineNumberStart = ctx.rendLineNumberStart;\n\t\tconst lines = ctx.lines;\n\n\t\tfor (let i = startIndex; i <= endIndex; i++) {\n\t\t\tconst lineNumber = rendLineNumberStart + i;\n\t\t\tlines[i].layoutLine(lineNumber, deltaTop[lineNumber - deltaLN], this.viewportData.lineHeight);\n\t\t}\n\t}\n\n\tprivate _insertLinesBefore(ctx: IRendererContext, fromLineNumber: number, toLineNumber: number, deltaTop: number[], deltaLN: number): void {\n\t\tconst newLines: T[] = [];\n\t\tlet newLinesLen = 0;\n\t\tfor (let lineNumber = fromLineNumber; lineNumber <= toLineNumber; lineNumber++) {\n\t\t\tnewLines[newLinesLen++] = this.host.createVisibleLine();\n\t\t}\n\t\tctx.lines = newLines.concat(ctx.lines);\n\t}\n\n\tprivate _removeLinesBefore(ctx: IRendererContext, removeCount: number): void {\n\t\tfor (let i = 0; i < removeCount; i++) {\n\t\t\tconst lineDomNode = ctx.lines[i].getDomNode();\n\t\t\tif (lineDomNode) {\n\t\t\t\tthis.domNode.removeChild(lineDomNode);\n\t\t\t}\n\t\t}\n\t\tctx.lines.splice(0, removeCount);\n\t}\n\n\tprivate _insertLinesAfter(ctx: IRendererContext, fromLineNumber: number, toLineNumber: number, deltaTop: number[], deltaLN: number): void {\n\t\tconst newLines: T[] = [];\n\t\tlet newLinesLen = 0;\n\t\tfor (let lineNumber = fromLineNumber; lineNumber <= toLineNumber; lineNumber++) {\n\t\t\tnewLines[newLinesLen++] = this.host.createVisibleLine();\n\t\t}\n\t\tctx.lines = ctx.lines.concat(newLines);\n\t}\n\n\tprivate _removeLinesAfter(ctx: IRendererContext, removeCount: number): void {\n\t\tconst removeIndex = ctx.linesLength - removeCount;\n\n\t\tfor (let i = 0; i < removeCount; i++) {\n\t\t\tconst lineDomNode = ctx.lines[removeIndex + i].getDomNode();\n\t\t\tif (lineDomNode) {\n\t\t\t\tthis.domNode.removeChild(lineDomNode);\n\t\t\t}\n\t\t}\n\t\tctx.lines.splice(removeIndex, removeCount);\n\t}\n\n\tprivate _finishRenderingNewLines(ctx: IRendererContext, domNodeIsEmpty: boolean, newLinesHTML: string | TrustedHTML, wasNew: boolean[]): void {\n\t\tif (ViewLayerRenderer._ttPolicy) {\n\t\t\tnewLinesHTML = ViewLayerRenderer._ttPolicy.createHTML(newLinesHTML as string);\n\t\t}\n\t\tconst lastChild = this.domNode.lastChild;\n\t\tif (domNodeIsEmpty || !lastChild) {\n\t\t\tthis.domNode.innerHTML = newLinesHTML as string; // explains the ugly casts -> https://github.com/microsoft/vscode/issues/106396#issuecomment-692625393;\n\t\t} else {\n\t\t\tlastChild.insertAdjacentHTML('afterend', newLinesHTML as string);\n\t\t}\n\n\t\tlet currChild = this.domNode.lastChild;\n\t\tfor (let i = ctx.linesLength - 1; i >= 0; i--) {\n\t\t\tconst line = ctx.lines[i];\n\t\t\tif (wasNew[i]) {\n\t\t\t\tline.setDomNode(currChild);\n\t\t\t\tcurrChild = currChild.previousSibling;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate _finishRenderingInvalidLines(ctx: IRendererContext, invalidLinesHTML: string | TrustedHTML, wasInvalid: boolean[]): void {\n\t\tconst hugeDomNode = document.createElement('div');\n\n\t\tif (ViewLayerRenderer._ttPolicy) {\n\t\t\tinvalidLinesHTML = ViewLayerRenderer._ttPolicy.createHTML(invalidLinesHTML as string);\n\t\t}\n\t\thugeDomNode.innerHTML = invalidLinesHTML as string;\n\n\t\tfor (let i = 0; i < ctx.linesLength; i++) {\n\t\t\tconst line = ctx.lines[i];\n\t\t\tif (wasInvalid[i]) {\n\t\t\t\tconst source = hugeDomNode.firstChild;\n\t\t\t\tconst lineDomNode = line.getDomNode()!;\n\t\t\t\tlineDomNode.parentNode!.replaceChild(source, lineDomNode);\n\t\t\t\tline.setDomNode(source);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate static readonly _sb = new StringBuilder(100000);\n\n\tprivate _finishRendering(ctx: IRendererContext, domNodeIsEmpty: boolean, deltaTop: number[]): void {\n\n\t\tconst sb = ViewLayerRenderer._sb;\n\t\tconst linesLength = ctx.linesLength;\n\t\tconst lines = ctx.lines;\n\t\tconst rendLineNumberStart = ctx.rendLineNumberStart;\n\n\t\tconst wasNew: boolean[] = [];\n\t\t{\n\t\t\tsb.reset();\n\t\t\tlet hadNewLine = false;\n\n\t\t\tfor (let i = 0; i < linesLength; i++) {\n\t\t\t\tconst line = lines[i];\n\t\t\t\twasNew[i] = false;\n\n\t\t\t\tconst lineDomNode = line.getDomNode();\n\t\t\t\tif (lineDomNode) {\n\t\t\t\t\t// line is not new\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst renderResult = line.renderLine(i + rendLineNumberStart, deltaTop[i], this.viewportData.lineHeight, this.viewportData, sb);\n\t\t\t\tif (!renderResult) {\n\t\t\t\t\t// line does not need rendering\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\twasNew[i] = true;\n\t\t\t\thadNewLine = true;\n\t\t\t}\n\n\t\t\tif (hadNewLine) {\n\t\t\t\tthis._finishRenderingNewLines(ctx, domNodeIsEmpty, sb.build(), wasNew);\n\t\t\t}\n\t\t}\n\n\t\t{\n\t\t\tsb.reset();\n\n\t\t\tlet hadInvalidLine = false;\n\t\t\tconst wasInvalid: boolean[] = [];\n\n\t\t\tfor (let i = 0; i < linesLength; i++) {\n\t\t\t\tconst line = lines[i];\n\t\t\t\twasInvalid[i] = false;\n\n\t\t\t\tif (wasNew[i]) {\n\t\t\t\t\t// line was new\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst renderResult = line.renderLine(i + rendLineNumberStart, deltaTop[i], this.viewportData.lineHeight, this.viewportData, sb);\n\t\t\t\tif (!renderResult) {\n\t\t\t\t\t// line does not need rendering\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\twasInvalid[i] = true;\n\t\t\t\thadInvalidLine = true;\n\t\t\t}\n\n\t\t\tif (hadInvalidLine) {\n\t\t\t\tthis._finishRenderingInvalidLines(ctx, sb.build(), wasInvalid);\n\t\t\t}\n\t\t}\n\t}\n}\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\nimport { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';\nimport { applyFontInfo } from 'vs/editor/browser/config/domFontInfo';\nimport { DynamicViewOverlay } from 'vs/editor/browser/view/dynamicViewOverlay';\nimport { IVisibleLine, IVisibleLinesHost, VisibleLinesCollection } from 'vs/editor/browser/view/viewLayer';\nimport { ViewPart } from 'vs/editor/browser/view/viewPart';\nimport { StringBuilder } from 'vs/editor/common/core/stringBuilder';\nimport { RenderingContext, RestrictedRenderingContext } from 'vs/editor/browser/view/renderingContext';\nimport { ViewContext } from 'vs/editor/common/viewModel/viewContext';\nimport * as viewEvents from 'vs/editor/common/viewEvents';\nimport { ViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData';\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\n\nexport class ViewOverlays extends ViewPart implements IVisibleLinesHost {\n\n\tprivate readonly _visibleLines: VisibleLinesCollection;\n\tprotected readonly domNode: FastDomNode;\n\tprivate _dynamicOverlays: DynamicViewOverlay[];\n\tprivate _isFocused: boolean;\n\n\tconstructor(context: ViewContext) {\n\t\tsuper(context);\n\n\t\tthis._visibleLines = new VisibleLinesCollection(this);\n\t\tthis.domNode = this._visibleLines.domNode;\n\n\t\tconst options = this._context.configuration.options;\n\t\tconst fontInfo = options.get(EditorOption.fontInfo);\n\t\tapplyFontInfo(this.domNode, fontInfo);\n\n\t\tthis._dynamicOverlays = [];\n\t\tthis._isFocused = false;\n\n\t\tthis.domNode.setClassName('view-overlays');\n\t}\n\n\tpublic override shouldRender(): boolean {\n\t\tif (super.shouldRender()) {\n\t\t\treturn true;\n\t\t}\n\n\t\tfor (let i = 0, len = this._dynamicOverlays.length; i < len; i++) {\n\t\t\tconst dynamicOverlay = this._dynamicOverlays[i];\n\t\t\tif (dynamicOverlay.shouldRender()) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tpublic override dispose(): void {\n\t\tsuper.dispose();\n\n\t\tfor (let i = 0, len = this._dynamicOverlays.length; i < len; i++) {\n\t\t\tconst dynamicOverlay = this._dynamicOverlays[i];\n\t\t\tdynamicOverlay.dispose();\n\t\t}\n\t\tthis._dynamicOverlays = [];\n\t}\n\n\tpublic getDomNode(): FastDomNode {\n\t\treturn this.domNode;\n\t}\n\n\t// ---- begin IVisibleLinesHost\n\n\tpublic createVisibleLine(): ViewOverlayLine {\n\t\treturn new ViewOverlayLine(this._dynamicOverlays);\n\t}\n\n\t// ---- end IVisibleLinesHost\n\n\tpublic addDynamicOverlay(overlay: DynamicViewOverlay): void {\n\t\tthis._dynamicOverlays.push(overlay);\n\t}\n\n\t// ----- event handlers\n\n\tpublic override onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {\n\t\tthis._visibleLines.onConfigurationChanged(e);\n\n\t\tconst options = this._context.configuration.options;\n\t\tconst fontInfo = options.get(EditorOption.fontInfo);\n\t\tapplyFontInfo(this.domNode, fontInfo);\n\n\t\treturn true;\n\t}\n\tpublic override onFlushed(e: viewEvents.ViewFlushedEvent): boolean {\n\t\treturn this._visibleLines.onFlushed(e);\n\t}\n\tpublic override onFocusChanged(e: viewEvents.ViewFocusChangedEvent): boolean {\n\t\tthis._isFocused = e.isFocused;\n\t\treturn true;\n\t}\n\tpublic override onLinesChanged(e: viewEvents.ViewLinesChangedEvent): boolean {\n\t\treturn this._visibleLines.onLinesChanged(e);\n\t}\n\tpublic override onLinesDeleted(e: viewEvents.ViewLinesDeletedEvent): boolean {\n\t\treturn this._visibleLines.onLinesDeleted(e);\n\t}\n\tpublic override onLinesInserted(e: viewEvents.ViewLinesInsertedEvent): boolean {\n\t\treturn this._visibleLines.onLinesInserted(e);\n\t}\n\tpublic override onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean {\n\t\treturn this._visibleLines.onScrollChanged(e) || true;\n\t}\n\tpublic override onTokensChanged(e: viewEvents.ViewTokensChangedEvent): boolean {\n\t\treturn this._visibleLines.onTokensChanged(e);\n\t}\n\tpublic override onZonesChanged(e: viewEvents.ViewZonesChangedEvent): boolean {\n\t\treturn this._visibleLines.onZonesChanged(e);\n\t}\n\n\t// ----- end event handlers\n\n\tpublic prepareRender(ctx: RenderingContext): void {\n\t\tconst toRender = this._dynamicOverlays.filter(overlay => overlay.shouldRender());\n\n\t\tfor (let i = 0, len = toRender.length; i < len; i++) {\n\t\t\tconst dynamicOverlay = toRender[i];\n\t\t\tdynamicOverlay.prepareRender(ctx);\n\t\t\tdynamicOverlay.onDidRender();\n\t\t}\n\t}\n\n\tpublic render(ctx: RestrictedRenderingContext): void {\n\t\t// Overwriting to bypass `shouldRender` flag\n\t\tthis._viewOverlaysRender(ctx);\n\n\t\tthis.domNode.toggleClassName('focused', this._isFocused);\n\t}\n\n\t_viewOverlaysRender(ctx: RestrictedRenderingContext): void {\n\t\tthis._visibleLines.renderLines(ctx.viewportData);\n\t}\n}\n\nexport class ViewOverlayLine implements IVisibleLine {\n\n\tprivate readonly _dynamicOverlays: DynamicViewOverlay[];\n\tprivate _domNode: FastDomNode | null;\n\tprivate _renderedContent: string | null;\n\n\tconstructor(dynamicOverlays: DynamicViewOverlay[]) {\n\t\tthis._dynamicOverlays = dynamicOverlays;\n\n\t\tthis._domNode = null;\n\t\tthis._renderedContent = null;\n\t}\n\n\tpublic getDomNode(): HTMLElement | null {\n\t\tif (!this._domNode) {\n\t\t\treturn null;\n\t\t}\n\t\treturn this._domNode.domNode;\n\t}\n\tpublic setDomNode(domNode: HTMLElement): void {\n\t\tthis._domNode = createFastDomNode(domNode);\n\t}\n\n\tpublic onContentChanged(): void {\n\t\t// Nothing\n\t}\n\tpublic onTokensChanged(): void {\n\t\t// Nothing\n\t}\n\n\tpublic renderLine(lineNumber: number, deltaTop: number, lineHeight: number, viewportData: ViewportData, sb: StringBuilder): boolean {\n\t\tlet result = '';\n\t\tfor (let i = 0, len = this._dynamicOverlays.length; i < len; i++) {\n\t\t\tconst dynamicOverlay = this._dynamicOverlays[i];\n\t\t\tresult += dynamicOverlay.render(viewportData.startLineNumber, lineNumber);\n\t\t}\n\n\t\tif (this._renderedContent === result) {\n\t\t\t// No rendering needed\n\t\t\treturn false;\n\t\t}\n\n\t\tthis._renderedContent = result;\n\n\t\tsb.appendString('
    ');\n\t\tsb.appendString(result);\n\t\tsb.appendString('
    ');\n\n\t\treturn true;\n\t}\n\n\tpublic layoutLine(lineNumber: number, deltaTop: number, lineHeight: number): void {\n\t\tif (this._domNode) {\n\t\t\tthis._domNode.setTop(deltaTop);\n\t\t\tthis._domNode.setHeight(lineHeight);\n\t\t}\n\t}\n}\n\nexport class ContentViewOverlays extends ViewOverlays {\n\n\tprivate _contentWidth: number;\n\n\tconstructor(context: ViewContext) {\n\t\tsuper(context);\n\t\tconst options = this._context.configuration.options;\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\n\t\tthis._contentWidth = layoutInfo.contentWidth;\n\n\t\tthis.domNode.setHeight(0);\n\t}\n\n\t// --- begin event handlers\n\n\tpublic override onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {\n\t\tconst options = this._context.configuration.options;\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\n\t\tthis._contentWidth = layoutInfo.contentWidth;\n\t\treturn super.onConfigurationChanged(e) || true;\n\t}\n\tpublic override onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean {\n\t\treturn super.onScrollChanged(e) || e.scrollWidthChanged;\n\t}\n\n\t// --- end event handlers\n\n\toverride _viewOverlaysRender(ctx: RestrictedRenderingContext): void {\n\t\tsuper._viewOverlaysRender(ctx);\n\n\t\tthis.domNode.setWidth(Math.max(ctx.scrollWidth, this._contentWidth));\n\t}\n}\n\nexport class MarginViewOverlays extends ViewOverlays {\n\n\tprivate _contentLeft: number;\n\n\tconstructor(context: ViewContext) {\n\t\tsuper(context);\n\n\t\tconst options = this._context.configuration.options;\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\n\t\tthis._contentLeft = layoutInfo.contentLeft;\n\n\t\tthis.domNode.setClassName('margin-view-overlays');\n\t\tthis.domNode.setWidth(1);\n\n\t\tapplyFontInfo(this.domNode, options.get(EditorOption.fontInfo));\n\t}\n\n\tpublic override onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {\n\t\tconst options = this._context.configuration.options;\n\t\tapplyFontInfo(this.domNode, options.get(EditorOption.fontInfo));\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\n\t\tthis._contentLeft = layoutInfo.contentLeft;\n\t\treturn super.onConfigurationChanged(e) || true;\n\t}\n\n\tpublic override onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean {\n\t\treturn super.onScrollChanged(e) || e.scrollHeightChanged;\n\t}\n\n\toverride _viewOverlaysRender(ctx: RestrictedRenderingContext): void {\n\t\tsuper._viewOverlaysRender(ctx);\n\t\tconst height = Math.min(ctx.scrollHeight, 1000000);\n\t\tthis.domNode.setHeight(height);\n\t\tthis.domNode.setWidth(this._contentLeft);\n\t}\n}\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\nimport * as buffer from 'vs/base/common/buffer';\nimport { decodeUTF16LE } from 'vs/editor/common/core/stringBuilder';\n\nfunction escapeNewLine(str: string): string {\n\treturn (\n\t\tstr\n\t\t\t.replace(/\\n/g, '\\\\n')\n\t\t\t.replace(/\\r/g, '\\\\r')\n\t);\n}\n\nexport class TextChange {\n\n\tpublic get oldLength(): number {\n\t\treturn this.oldText.length;\n\t}\n\n\tpublic get oldEnd(): number {\n\t\treturn this.oldPosition + this.oldText.length;\n\t}\n\n\tpublic get newLength(): number {\n\t\treturn this.newText.length;\n\t}\n\n\tpublic get newEnd(): number {\n\t\treturn this.newPosition + this.newText.length;\n\t}\n\n\tconstructor(\n\t\tpublic readonly oldPosition: number,\n\t\tpublic readonly oldText: string,\n\t\tpublic readonly newPosition: number,\n\t\tpublic readonly newText: string\n\t) { }\n\n\tpublic toString(): string {\n\t\tif (this.oldText.length === 0) {\n\t\t\treturn `(insert@${this.oldPosition} \"${escapeNewLine(this.newText)}\")`;\n\t\t}\n\t\tif (this.newText.length === 0) {\n\t\t\treturn `(delete@${this.oldPosition} \"${escapeNewLine(this.oldText)}\")`;\n\t\t}\n\t\treturn `(replace@${this.oldPosition} \"${escapeNewLine(this.oldText)}\" with \"${escapeNewLine(this.newText)}\")`;\n\t}\n\n\tprivate static _writeStringSize(str: string): number {\n\t\treturn (\n\t\t\t4 + 2 * str.length\n\t\t);\n\t}\n\n\tprivate static _writeString(b: Uint8Array, str: string, offset: number): number {\n\t\tconst len = str.length;\n\t\tbuffer.writeUInt32BE(b, len, offset); offset += 4;\n\t\tfor (let i = 0; i < len; i++) {\n\t\t\tbuffer.writeUInt16LE(b, str.charCodeAt(i), offset); offset += 2;\n\t\t}\n\t\treturn offset;\n\t}\n\n\tprivate static _readString(b: Uint8Array, offset: number): string {\n\t\tconst len = buffer.readUInt32BE(b, offset); offset += 4;\n\t\treturn decodeUTF16LE(b, offset, len);\n\t}\n\n\tpublic writeSize(): number {\n\t\treturn (\n\t\t\t+ 4 // oldPosition\n\t\t\t+ 4 // newPosition\n\t\t\t+ TextChange._writeStringSize(this.oldText)\n\t\t\t+ TextChange._writeStringSize(this.newText)\n\t\t);\n\t}\n\n\tpublic write(b: Uint8Array, offset: number): number {\n\t\tbuffer.writeUInt32BE(b, this.oldPosition, offset); offset += 4;\n\t\tbuffer.writeUInt32BE(b, this.newPosition, offset); offset += 4;\n\t\toffset = TextChange._writeString(b, this.oldText, offset);\n\t\toffset = TextChange._writeString(b, this.newText, offset);\n\t\treturn offset;\n\t}\n\n\tpublic static read(b: Uint8Array, offset: number, dest: TextChange[]): number {\n\t\tconst oldPosition = buffer.readUInt32BE(b, offset); offset += 4;\n\t\tconst newPosition = buffer.readUInt32BE(b, offset); offset += 4;\n\t\tconst oldText = TextChange._readString(b, offset); offset += TextChange._writeStringSize(oldText);\n\t\tconst newText = TextChange._readString(b, offset); offset += TextChange._writeStringSize(newText);\n\t\tdest.push(new TextChange(oldPosition, oldText, newPosition, newText));\n\t\treturn offset;\n\t}\n}\n\nexport function compressConsecutiveTextChanges(prevEdits: TextChange[] | null, currEdits: TextChange[]): TextChange[] {\n\tif (prevEdits === null || prevEdits.length === 0) {\n\t\treturn currEdits;\n\t}\n\tconst compressor = new TextChangeCompressor(prevEdits, currEdits);\n\treturn compressor.compress();\n}\n\nclass TextChangeCompressor {\n\n\tprivate _prevEdits: TextChange[];\n\tprivate _currEdits: TextChange[];\n\n\tprivate _result: TextChange[];\n\tprivate _resultLen: number;\n\n\tprivate _prevLen: number;\n\tprivate _prevDeltaOffset: number;\n\n\tprivate _currLen: number;\n\tprivate _currDeltaOffset: number;\n\n\tconstructor(prevEdits: TextChange[], currEdits: TextChange[]) {\n\t\tthis._prevEdits = prevEdits;\n\t\tthis._currEdits = currEdits;\n\n\t\tthis._result = [];\n\t\tthis._resultLen = 0;\n\n\t\tthis._prevLen = this._prevEdits.length;\n\t\tthis._prevDeltaOffset = 0;\n\n\t\tthis._currLen = this._currEdits.length;\n\t\tthis._currDeltaOffset = 0;\n\t}\n\n\tpublic compress(): TextChange[] {\n\t\tlet prevIndex = 0;\n\t\tlet currIndex = 0;\n\n\t\tlet prevEdit = this._getPrev(prevIndex);\n\t\tlet currEdit = this._getCurr(currIndex);\n\n\t\twhile (prevIndex < this._prevLen || currIndex < this._currLen) {\n\n\t\t\tif (prevEdit === null) {\n\t\t\t\tthis._acceptCurr(currEdit!);\n\t\t\t\tcurrEdit = this._getCurr(++currIndex);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (currEdit === null) {\n\t\t\t\tthis._acceptPrev(prevEdit);\n\t\t\t\tprevEdit = this._getPrev(++prevIndex);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (currEdit.oldEnd <= prevEdit.newPosition) {\n\t\t\t\tthis._acceptCurr(currEdit);\n\t\t\t\tcurrEdit = this._getCurr(++currIndex);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (prevEdit.newEnd <= currEdit.oldPosition) {\n\t\t\t\tthis._acceptPrev(prevEdit);\n\t\t\t\tprevEdit = this._getPrev(++prevIndex);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (currEdit.oldPosition < prevEdit.newPosition) {\n\t\t\t\tconst [e1, e2] = TextChangeCompressor._splitCurr(currEdit, prevEdit.newPosition - currEdit.oldPosition);\n\t\t\t\tthis._acceptCurr(e1);\n\t\t\t\tcurrEdit = e2;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (prevEdit.newPosition < currEdit.oldPosition) {\n\t\t\t\tconst [e1, e2] = TextChangeCompressor._splitPrev(prevEdit, currEdit.oldPosition - prevEdit.newPosition);\n\t\t\t\tthis._acceptPrev(e1);\n\t\t\t\tprevEdit = e2;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// At this point, currEdit.oldPosition === prevEdit.newPosition\n\n\t\t\tlet mergePrev: TextChange;\n\t\t\tlet mergeCurr: TextChange;\n\n\t\t\tif (currEdit.oldEnd === prevEdit.newEnd) {\n\t\t\t\tmergePrev = prevEdit;\n\t\t\t\tmergeCurr = currEdit;\n\t\t\t\tprevEdit = this._getPrev(++prevIndex);\n\t\t\t\tcurrEdit = this._getCurr(++currIndex);\n\t\t\t} else if (currEdit.oldEnd < prevEdit.newEnd) {\n\t\t\t\tconst [e1, e2] = TextChangeCompressor._splitPrev(prevEdit, currEdit.oldLength);\n\t\t\t\tmergePrev = e1;\n\t\t\t\tmergeCurr = currEdit;\n\t\t\t\tprevEdit = e2;\n\t\t\t\tcurrEdit = this._getCurr(++currIndex);\n\t\t\t} else {\n\t\t\t\tconst [e1, e2] = TextChangeCompressor._splitCurr(currEdit, prevEdit.newLength);\n\t\t\t\tmergePrev = prevEdit;\n\t\t\t\tmergeCurr = e1;\n\t\t\t\tprevEdit = this._getPrev(++prevIndex);\n\t\t\t\tcurrEdit = e2;\n\t\t\t}\n\n\t\t\tthis._result[this._resultLen++] = new TextChange(\n\t\t\t\tmergePrev.oldPosition,\n\t\t\t\tmergePrev.oldText,\n\t\t\t\tmergeCurr.newPosition,\n\t\t\t\tmergeCurr.newText\n\t\t\t);\n\t\t\tthis._prevDeltaOffset += mergePrev.newLength - mergePrev.oldLength;\n\t\t\tthis._currDeltaOffset += mergeCurr.newLength - mergeCurr.oldLength;\n\t\t}\n\n\t\tconst merged = TextChangeCompressor._merge(this._result);\n\t\tconst cleaned = TextChangeCompressor._removeNoOps(merged);\n\t\treturn cleaned;\n\t}\n\n\tprivate _acceptCurr(currEdit: TextChange): void {\n\t\tthis._result[this._resultLen++] = TextChangeCompressor._rebaseCurr(this._prevDeltaOffset, currEdit);\n\t\tthis._currDeltaOffset += currEdit.newLength - currEdit.oldLength;\n\t}\n\n\tprivate _getCurr(currIndex: number): TextChange | null {\n\t\treturn (currIndex < this._currLen ? this._currEdits[currIndex] : null);\n\t}\n\n\tprivate _acceptPrev(prevEdit: TextChange): void {\n\t\tthis._result[this._resultLen++] = TextChangeCompressor._rebasePrev(this._currDeltaOffset, prevEdit);\n\t\tthis._prevDeltaOffset += prevEdit.newLength - prevEdit.oldLength;\n\t}\n\n\tprivate _getPrev(prevIndex: number): TextChange | null {\n\t\treturn (prevIndex < this._prevLen ? this._prevEdits[prevIndex] : null);\n\t}\n\n\tprivate static _rebaseCurr(prevDeltaOffset: number, currEdit: TextChange): TextChange {\n\t\treturn new TextChange(\n\t\t\tcurrEdit.oldPosition - prevDeltaOffset,\n\t\t\tcurrEdit.oldText,\n\t\t\tcurrEdit.newPosition,\n\t\t\tcurrEdit.newText\n\t\t);\n\t}\n\n\tprivate static _rebasePrev(currDeltaOffset: number, prevEdit: TextChange): TextChange {\n\t\treturn new TextChange(\n\t\t\tprevEdit.oldPosition,\n\t\t\tprevEdit.oldText,\n\t\t\tprevEdit.newPosition + currDeltaOffset,\n\t\t\tprevEdit.newText\n\t\t);\n\t}\n\n\tprivate static _splitPrev(edit: TextChange, offset: number): [TextChange, TextChange] {\n\t\tconst preText = edit.newText.substr(0, offset);\n\t\tconst postText = edit.newText.substr(offset);\n\n\t\treturn [\n\t\t\tnew TextChange(\n\t\t\t\tedit.oldPosition,\n\t\t\t\tedit.oldText,\n\t\t\t\tedit.newPosition,\n\t\t\t\tpreText\n\t\t\t),\n\t\t\tnew TextChange(\n\t\t\t\tedit.oldEnd,\n\t\t\t\t'',\n\t\t\t\tedit.newPosition + offset,\n\t\t\t\tpostText\n\t\t\t)\n\t\t];\n\t}\n\n\tprivate static _splitCurr(edit: TextChange, offset: number): [TextChange, TextChange] {\n\t\tconst preText = edit.oldText.substr(0, offset);\n\t\tconst postText = edit.oldText.substr(offset);\n\n\t\treturn [\n\t\t\tnew TextChange(\n\t\t\t\tedit.oldPosition,\n\t\t\t\tpreText,\n\t\t\t\tedit.newPosition,\n\t\t\t\tedit.newText\n\t\t\t),\n\t\t\tnew TextChange(\n\t\t\t\tedit.oldPosition + offset,\n\t\t\t\tpostText,\n\t\t\t\tedit.newEnd,\n\t\t\t\t''\n\t\t\t)\n\t\t];\n\t}\n\n\tprivate static _merge(edits: TextChange[]): TextChange[] {\n\t\tif (edits.length === 0) {\n\t\t\treturn edits;\n\t\t}\n\n\t\tconst result: TextChange[] = [];\n\t\tlet resultLen = 0;\n\n\t\tlet prev = edits[0];\n\t\tfor (let i = 1; i < edits.length; i++) {\n\t\t\tconst curr = edits[i];\n\n\t\t\tif (prev.oldEnd === curr.oldPosition) {\n\t\t\t\t// Merge into `prev`\n\t\t\t\tprev = new TextChange(\n\t\t\t\t\tprev.oldPosition,\n\t\t\t\t\tprev.oldText + curr.oldText,\n\t\t\t\t\tprev.newPosition,\n\t\t\t\t\tprev.newText + curr.newText\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tresult[resultLen++] = prev;\n\t\t\t\tprev = curr;\n\t\t\t}\n\t\t}\n\t\tresult[resultLen++] = prev;\n\n\t\treturn result;\n\t}\n\n\tprivate static _removeNoOps(edits: TextChange[]): TextChange[] {\n\t\tif (edits.length === 0) {\n\t\t\treturn edits;\n\t\t}\n\n\t\tconst result: TextChange[] = [];\n\t\tlet resultLen = 0;\n\n\t\tfor (let i = 0; i < edits.length; i++) {\n\t\t\tconst edit = edits[i];\n\n\t\t\tif (edit.oldText === edit.newText) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tresult[resultLen++] = edit;\n\t\t}\n\n\t\treturn result;\n\t}\n}\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\nimport { IRelativePattern, match as matchGlobPattern } from 'vs/base/common/glob';\nimport { URI } from 'vs/base/common/uri';\nimport { normalize } from 'vs/base/common/path';\n\nexport interface LanguageFilter {\n\treadonly language?: string;\n\treadonly scheme?: string;\n\treadonly pattern?: string | IRelativePattern;\n\treadonly notebookType?: string;\n\t/**\n\t * This provider is implemented in the UI thread.\n\t */\n\treadonly hasAccessToAllModels?: boolean;\n\treadonly exclusive?: boolean;\n\n\t/**\n\t * This provider comes from a builtin extension.\n\t */\n\treadonly isBuiltin?: boolean;\n}\n\nexport type LanguageSelector = string | LanguageFilter | ReadonlyArray;\n\nexport function score(selector: LanguageSelector | undefined, candidateUri: URI, candidateLanguage: string, candidateIsSynchronized: boolean, candidateNotebookUri: URI | undefined, candidateNotebookType: string | undefined): number {\n\n\tif (Array.isArray(selector)) {\n\t\t// array -> take max individual value\n\t\tlet ret = 0;\n\t\tfor (const filter of selector) {\n\t\t\tconst value = score(filter, candidateUri, candidateLanguage, candidateIsSynchronized, candidateNotebookUri, candidateNotebookType);\n\t\t\tif (value === 10) {\n\t\t\t\treturn value; // already at the highest\n\t\t\t}\n\t\t\tif (value > ret) {\n\t\t\t\tret = value;\n\t\t\t}\n\t\t}\n\t\treturn ret;\n\n\t} else if (typeof selector === 'string') {\n\n\t\tif (!candidateIsSynchronized) {\n\t\t\treturn 0;\n\t\t}\n\n\t\t// short-hand notion, desugars to\n\t\t// 'fooLang' -> { language: 'fooLang'}\n\t\t// '*' -> { language: '*' }\n\t\tif (selector === '*') {\n\t\t\treturn 5;\n\t\t} else if (selector === candidateLanguage) {\n\t\t\treturn 10;\n\t\t} else {\n\t\t\treturn 0;\n\t\t}\n\n\t} else if (selector) {\n\t\t// filter -> select accordingly, use defaults for scheme\n\t\tconst { language, pattern, scheme, hasAccessToAllModels, notebookType } = selector as LanguageFilter; // TODO: microsoft/TypeScript#42768\n\n\t\tif (!candidateIsSynchronized && !hasAccessToAllModels) {\n\t\t\treturn 0;\n\t\t}\n\n\t\t// selector targets a notebook -> use the notebook uri instead\n\t\t// of the \"normal\" document uri.\n\t\tif (notebookType && candidateNotebookUri) {\n\t\t\tcandidateUri = candidateNotebookUri;\n\t\t}\n\n\t\tlet ret = 0;\n\n\t\tif (scheme) {\n\t\t\tif (scheme === candidateUri.scheme) {\n\t\t\t\tret = 10;\n\t\t\t} else if (scheme === '*') {\n\t\t\t\tret = 5;\n\t\t\t} else {\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t}\n\n\t\tif (language) {\n\t\t\tif (language === candidateLanguage) {\n\t\t\t\tret = 10;\n\t\t\t} else if (language === '*') {\n\t\t\t\tret = Math.max(ret, 5);\n\t\t\t} else {\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t}\n\n\t\tif (notebookType) {\n\t\t\tif (notebookType === candidateNotebookType) {\n\t\t\t\tret = 10;\n\t\t\t} else if (notebookType === '*' && candidateNotebookType !== undefined) {\n\t\t\t\tret = Math.max(ret, 5);\n\t\t\t} else {\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t}\n\n\t\tif (pattern) {\n\t\t\tlet normalizedPattern: string | IRelativePattern;\n\t\t\tif (typeof pattern === 'string') {\n\t\t\t\tnormalizedPattern = pattern;\n\t\t\t} else {\n\t\t\t\t// Since this pattern has a `base` property, we need\n\t\t\t\t// to normalize this path first before passing it on\n\t\t\t\t// because we will compare it against `Uri.fsPath`\n\t\t\t\t// which uses platform specific separators.\n\t\t\t\t// Refs: https://github.com/microsoft/vscode/issues/99938\n\t\t\t\tnormalizedPattern = { ...pattern, base: normalize(pattern.base) };\n\t\t\t}\n\n\t\t\tif (normalizedPattern === candidateUri.fsPath || matchGlobPattern(normalizedPattern, candidateUri.fsPath)) {\n\t\t\t\tret = 10;\n\t\t\t} else {\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t}\n\n\t\treturn ret;\n\n\t} else {\n\t\treturn 0;\n\t}\n}\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\nimport { Emitter } from 'vs/base/common/event';\nimport { IDisposable, toDisposable } from 'vs/base/common/lifecycle';\nimport { ITextModel, shouldSynchronizeModel } from 'vs/editor/common/model';\nimport { LanguageFilter, LanguageSelector, score } from 'vs/editor/common/languageSelector';\nimport { URI } from 'vs/base/common/uri';\n\ninterface Entry {\n\tselector: LanguageSelector;\n\tprovider: T;\n\t_score: number;\n\t_time: number;\n}\n\nfunction isExclusive(selector: LanguageSelector): boolean {\n\tif (typeof selector === 'string') {\n\t\treturn false;\n\t} else if (Array.isArray(selector)) {\n\t\treturn selector.every(isExclusive);\n\t} else {\n\t\treturn !!(selector as LanguageFilter).exclusive; // TODO: microsoft/TypeScript#42768\n\t}\n}\n\nexport interface NotebookInfo {\n\treadonly uri: URI;\n\treadonly type: string;\n}\n\nexport interface NotebookInfoResolver {\n\t(uri: URI): NotebookInfo | undefined;\n}\n\nclass MatchCandidate {\n\tconstructor(\n\t\treadonly uri: URI,\n\t\treadonly languageId: string,\n\t\treadonly notebookUri: URI | undefined,\n\t\treadonly notebookType: string | undefined\n\t) { }\n\n\tequals(other: MatchCandidate): boolean {\n\t\treturn this.notebookType === other.notebookType\n\t\t\t&& this.languageId === other.languageId\n\t\t\t&& this.uri.toString() === other.uri.toString()\n\t\t\t&& this.notebookUri?.toString() === other.notebookUri?.toString();\n\t}\n}\n\nexport class LanguageFeatureRegistry {\n\n\tprivate _clock: number = 0;\n\tprivate readonly _entries: Entry[] = [];\n\n\tprivate readonly _onDidChange = new Emitter();\n\treadonly onDidChange = this._onDidChange.event;\n\n\tconstructor(private readonly _notebookInfoResolver?: NotebookInfoResolver) { }\n\n\tregister(selector: LanguageSelector, provider: T): IDisposable {\n\n\t\tlet entry: Entry | undefined = {\n\t\t\tselector,\n\t\t\tprovider,\n\t\t\t_score: -1,\n\t\t\t_time: this._clock++\n\t\t};\n\n\t\tthis._entries.push(entry);\n\t\tthis._lastCandidate = undefined;\n\t\tthis._onDidChange.fire(this._entries.length);\n\n\t\treturn toDisposable(() => {\n\t\t\tif (entry) {\n\t\t\t\tconst idx = this._entries.indexOf(entry);\n\t\t\t\tif (idx >= 0) {\n\t\t\t\t\tthis._entries.splice(idx, 1);\n\t\t\t\t\tthis._lastCandidate = undefined;\n\t\t\t\t\tthis._onDidChange.fire(this._entries.length);\n\t\t\t\t\tentry = undefined;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\thas(model: ITextModel): boolean {\n\t\treturn this.all(model).length > 0;\n\t}\n\n\tall(model: ITextModel): T[] {\n\t\tif (!model) {\n\t\t\treturn [];\n\t\t}\n\n\t\tthis._updateScores(model);\n\t\tconst result: T[] = [];\n\n\t\t// from registry\n\t\tfor (const entry of this._entries) {\n\t\t\tif (entry._score > 0) {\n\t\t\t\tresult.push(entry.provider);\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tordered(model: ITextModel): T[] {\n\t\tconst result: T[] = [];\n\t\tthis._orderedForEach(model, entry => result.push(entry.provider));\n\t\treturn result;\n\t}\n\n\torderedGroups(model: ITextModel): T[][] {\n\t\tconst result: T[][] = [];\n\t\tlet lastBucket: T[];\n\t\tlet lastBucketScore: number;\n\n\t\tthis._orderedForEach(model, entry => {\n\t\t\tif (lastBucket && lastBucketScore === entry._score) {\n\t\t\t\tlastBucket.push(entry.provider);\n\t\t\t} else {\n\t\t\t\tlastBucketScore = entry._score;\n\t\t\t\tlastBucket = [entry.provider];\n\t\t\t\tresult.push(lastBucket);\n\t\t\t}\n\t\t});\n\n\t\treturn result;\n\t}\n\n\tprivate _orderedForEach(model: ITextModel, callback: (provider: Entry) => any): void {\n\n\t\tthis._updateScores(model);\n\n\t\tfor (const entry of this._entries) {\n\t\t\tif (entry._score > 0) {\n\t\t\t\tcallback(entry);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate _lastCandidate: MatchCandidate | undefined;\n\n\tprivate _updateScores(model: ITextModel): void {\n\n\t\tconst notebookInfo = this._notebookInfoResolver?.(model.uri);\n\n\t\t// use the uri (scheme, pattern) of the notebook info iff we have one\n\t\t// otherwise it's the model's/document's uri\n\t\tconst candidate = notebookInfo\n\t\t\t? new MatchCandidate(model.uri, model.getLanguageId(), notebookInfo.uri, notebookInfo.type)\n\t\t\t: new MatchCandidate(model.uri, model.getLanguageId(), undefined, undefined);\n\n\t\tif (this._lastCandidate?.equals(candidate)) {\n\t\t\t// nothing has changed\n\t\t\treturn;\n\t\t}\n\n\t\tthis._lastCandidate = candidate;\n\n\t\tfor (const entry of this._entries) {\n\t\t\tentry._score = score(entry.selector, candidate.uri, candidate.languageId, shouldSynchronizeModel(model), candidate.notebookUri, candidate.notebookType);\n\n\t\t\tif (isExclusive(entry.selector) && entry._score > 0) {\n\t\t\t\t// support for one exclusive selector that overwrites\n\t\t\t\t// any other selector\n\t\t\t\tfor (const entry of this._entries) {\n\t\t\t\t\tentry._score = 0;\n\t\t\t\t}\n\t\t\t\tentry._score = 1000;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// needs sorting\n\t\tthis._entries.sort(LanguageFeatureRegistry._compareByScoreAndTime);\n\t}\n\n\tprivate static _compareByScoreAndTime(a: Entry, b: Entry): number {\n\t\tif (a._score < b._score) {\n\t\t\treturn 1;\n\t\t} else if (a._score > b._score) {\n\t\t\treturn -1;\n\t\t}\n\n\t\t// De-prioritize built-in providers\n\t\tif (isBuiltinSelector(a.selector) && !isBuiltinSelector(b.selector)) {\n\t\t\treturn 1;\n\t\t} else if (!isBuiltinSelector(a.selector) && isBuiltinSelector(b.selector)) {\n\t\t\treturn -1;\n\t\t}\n\n\t\tif (a._time < b._time) {\n\t\t\treturn 1;\n\t\t} else if (a._time > b._time) {\n\t\t\treturn -1;\n\t\t} else {\n\t\t\treturn 0;\n\t\t}\n\t}\n}\n\nfunction isBuiltinSelector(selector: LanguageSelector): boolean {\n\tif (typeof selector === 'string') {\n\t\treturn false;\n\t}\n\n\tif (Array.isArray(selector)) {\n\t\treturn selector.some(isBuiltinSelector);\n\t}\n\n\treturn Boolean((selector as LanguageFilter).isBuiltin);\n}\n\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\nimport * as strings from 'vs/base/common/strings';\nimport * as stringBuilder from 'vs/editor/common/core/stringBuilder';\nimport { Range } from 'vs/editor/common/core/range';\nimport { CharacterPair } from 'vs/editor/common/languages/languageConfiguration';\n\ninterface InternalBracket {\n\topen: string[];\n\tclose: string[];\n}\n\n/**\n * Represents a grouping of colliding bracket pairs.\n *\n * Most of the times this contains a single bracket pair,\n * but sometimes this contains multiple bracket pairs in cases\n * where the same string appears as a closing bracket for multiple\n * bracket pairs, or the same string appears an opening bracket for\n * multiple bracket pairs.\n *\n * e.g. of a group containing a single pair:\n * open: ['{'], close: ['}']\n *\n * e.g. of a group containing multiple pairs:\n * open: ['if', 'for'], close: ['end', 'end']\n */\nexport class RichEditBracket {\n\t_richEditBracketBrand: void = undefined;\n\n\treadonly languageId: string;\n\t/**\n\t * A 0-based consecutive unique identifier for this bracket pair.\n\t * If a language has 5 bracket pairs, out of which 2 are grouped together,\n\t * it is expected that the `index` goes from 0 to 4.\n\t */\n\treadonly index: number;\n\t/**\n\t * The open sequence for each bracket pair contained in this group.\n\t *\n\t * The open sequence at a specific index corresponds to the\n\t * closing sequence at the same index.\n\t *\n\t * [ open[i], closed[i] ] represent a bracket pair.\n\t */\n\treadonly open: string[];\n\t/**\n\t * The close sequence for each bracket pair contained in this group.\n\t *\n\t * The close sequence at a specific index corresponds to the\n\t * opening sequence at the same index.\n\t *\n\t * [ open[i], closed[i] ] represent a bracket pair.\n\t */\n\treadonly close: string[];\n\t/**\n\t * A regular expression that is useful to search for this bracket pair group in a string.\n\t *\n\t * This regular expression is built in a way that it is aware of the other bracket\n\t * pairs defined for the language, so it might match brackets from other groups.\n\t *\n\t * See the fine details in `getRegexForBracketPair`.\n\t */\n\treadonly forwardRegex: RegExp;\n\t/**\n\t * A regular expression that is useful to search for this bracket pair group in a string backwards.\n\t *\n\t * This regular expression is built in a way that it is aware of the other bracket\n\t * pairs defined for the language, so it might match brackets from other groups.\n\t *\n\t * See the fine defails in `getReversedRegexForBracketPair`.\n\t */\n\treadonly reversedRegex: RegExp;\n\tprivate readonly _openSet: Set;\n\tprivate readonly _closeSet: Set;\n\n\tconstructor(languageId: string, index: number, open: string[], close: string[], forwardRegex: RegExp, reversedRegex: RegExp) {\n\t\tthis.languageId = languageId;\n\t\tthis.index = index;\n\t\tthis.open = open;\n\t\tthis.close = close;\n\t\tthis.forwardRegex = forwardRegex;\n\t\tthis.reversedRegex = reversedRegex;\n\t\tthis._openSet = RichEditBracket._toSet(this.open);\n\t\tthis._closeSet = RichEditBracket._toSet(this.close);\n\t}\n\n\t/**\n\t * Check if the provided `text` is an open bracket in this group.\n\t */\n\tpublic isOpen(text: string) {\n\t\treturn this._openSet.has(text);\n\t}\n\n\t/**\n\t * Check if the provided `text` is a close bracket in this group.\n\t */\n\tpublic isClose(text: string) {\n\t\treturn this._closeSet.has(text);\n\t}\n\n\tprivate static _toSet(arr: string[]): Set {\n\t\tconst result = new Set();\n\t\tfor (const element of arr) {\n\t\t\tresult.add(element);\n\t\t}\n\t\treturn result;\n\t}\n}\n\n/**\n * Groups together brackets that have equal open or close sequences.\n *\n * For example, if the following brackets are defined:\n * ['IF','END']\n * ['for','end']\n * ['{','}']\n *\n * Then the grouped brackets would be:\n * { open: ['if', 'for'], close: ['end', 'end'] }\n * { open: ['{'], close: ['}'] }\n *\n */\nfunction groupFuzzyBrackets(brackets: readonly CharacterPair[]): InternalBracket[] {\n\tconst N = brackets.length;\n\n\tbrackets = brackets.map(b => [b[0].toLowerCase(), b[1].toLowerCase()]);\n\n\tconst group: number[] = [];\n\tfor (let i = 0; i < N; i++) {\n\t\tgroup[i] = i;\n\t}\n\n\tconst areOverlapping = (a: CharacterPair, b: CharacterPair) => {\n\t\tconst [aOpen, aClose] = a;\n\t\tconst [bOpen, bClose] = b;\n\t\treturn (aOpen === bOpen || aOpen === bClose || aClose === bOpen || aClose === bClose);\n\t};\n\n\tconst mergeGroups = (g1: number, g2: number) => {\n\t\tconst newG = Math.min(g1, g2);\n\t\tconst oldG = Math.max(g1, g2);\n\t\tfor (let i = 0; i < N; i++) {\n\t\t\tif (group[i] === oldG) {\n\t\t\t\tgroup[i] = newG;\n\t\t\t}\n\t\t}\n\t};\n\n\t// group together brackets that have the same open or the same close sequence\n\tfor (let i = 0; i < N; i++) {\n\t\tconst a = brackets[i];\n\t\tfor (let j = i + 1; j < N; j++) {\n\t\t\tconst b = brackets[j];\n\t\t\tif (areOverlapping(a, b)) {\n\t\t\t\tmergeGroups(group[i], group[j]);\n\t\t\t}\n\t\t}\n\t}\n\n\tconst result: InternalBracket[] = [];\n\tfor (let g = 0; g < N; g++) {\n\t\tconst currentOpen: string[] = [];\n\t\tconst currentClose: string[] = [];\n\t\tfor (let i = 0; i < N; i++) {\n\t\t\tif (group[i] === g) {\n\t\t\t\tconst [open, close] = brackets[i];\n\t\t\t\tcurrentOpen.push(open);\n\t\t\t\tcurrentClose.push(close);\n\t\t\t}\n\t\t}\n\t\tif (currentOpen.length > 0) {\n\t\t\tresult.push({\n\t\t\t\topen: currentOpen,\n\t\t\t\tclose: currentClose\n\t\t\t});\n\t\t}\n\t}\n\treturn result;\n}\n\nexport class RichEditBrackets {\n\t_richEditBracketsBrand: void = undefined;\n\n\t/**\n\t * All groups of brackets defined for this language.\n\t */\n\tpublic readonly brackets: RichEditBracket[];\n\t/**\n\t * A regular expression that is useful to search for all bracket pairs in a string.\n\t *\n\t * See the fine details in `getRegexForBrackets`.\n\t */\n\tpublic readonly forwardRegex: RegExp;\n\t/**\n\t * A regular expression that is useful to search for all bracket pairs in a string backwards.\n\t *\n\t * See the fine details in `getReversedRegexForBrackets`.\n\t */\n\tpublic readonly reversedRegex: RegExp;\n\t/**\n\t * The length (i.e. str.length) for the longest bracket pair.\n\t */\n\tpublic readonly maxBracketLength: number;\n\t/**\n\t * A map useful for decoding a regex match and finding which bracket group was matched.\n\t */\n\tpublic readonly textIsBracket: { [text: string]: RichEditBracket };\n\t/**\n\t * A set useful for decoding if a regex match is the open bracket of a bracket pair.\n\t */\n\tpublic readonly textIsOpenBracket: { [text: string]: boolean };\n\n\tconstructor(languageId: string, _brackets: readonly CharacterPair[]) {\n\t\tconst brackets = groupFuzzyBrackets(_brackets);\n\n\t\tthis.brackets = brackets.map((b, index) => {\n\t\t\treturn new RichEditBracket(\n\t\t\t\tlanguageId,\n\t\t\t\tindex,\n\t\t\t\tb.open,\n\t\t\t\tb.close,\n\t\t\t\tgetRegexForBracketPair(b.open, b.close, brackets, index),\n\t\t\t\tgetReversedRegexForBracketPair(b.open, b.close, brackets, index)\n\t\t\t);\n\t\t});\n\n\t\tthis.forwardRegex = getRegexForBrackets(this.brackets);\n\t\tthis.reversedRegex = getReversedRegexForBrackets(this.brackets);\n\n\t\tthis.textIsBracket = {};\n\t\tthis.textIsOpenBracket = {};\n\n\t\tthis.maxBracketLength = 0;\n\t\tfor (const bracket of this.brackets) {\n\t\t\tfor (const open of bracket.open) {\n\t\t\t\tthis.textIsBracket[open] = bracket;\n\t\t\t\tthis.textIsOpenBracket[open] = true;\n\t\t\t\tthis.maxBracketLength = Math.max(this.maxBracketLength, open.length);\n\t\t\t}\n\t\t\tfor (const close of bracket.close) {\n\t\t\t\tthis.textIsBracket[close] = bracket;\n\t\t\t\tthis.textIsOpenBracket[close] = false;\n\t\t\t\tthis.maxBracketLength = Math.max(this.maxBracketLength, close.length);\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction collectSuperstrings(str: string, brackets: InternalBracket[], currentIndex: number, dest: string[]): void {\n\tfor (let i = 0, len = brackets.length; i < len; i++) {\n\t\tif (i === currentIndex) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst bracket = brackets[i];\n\t\tfor (const open of bracket.open) {\n\t\t\tif (open.indexOf(str) >= 0) {\n\t\t\t\tdest.push(open);\n\t\t\t}\n\t\t}\n\t\tfor (const close of bracket.close) {\n\t\t\tif (close.indexOf(str) >= 0) {\n\t\t\t\tdest.push(close);\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction lengthcmp(a: string, b: string) {\n\treturn a.length - b.length;\n}\n\nfunction unique(arr: string[]): string[] {\n\tif (arr.length <= 1) {\n\t\treturn arr;\n\t}\n\tconst result: string[] = [];\n\tconst seen = new Set();\n\tfor (const element of arr) {\n\t\tif (seen.has(element)) {\n\t\t\tcontinue;\n\t\t}\n\t\tresult.push(element);\n\t\tseen.add(element);\n\t}\n\treturn result;\n}\n\n/**\n * Create a regular expression that can be used to search forward in a piece of text\n * for a group of bracket pairs. But this regex must be built in a way in which\n * it is aware of the other bracket pairs defined for the language.\n *\n * For example, if a language contains the following bracket pairs:\n * ['begin', 'end']\n * ['if', 'end if']\n * The two bracket pairs do not collide because no open or close brackets are equal.\n * So the function getRegexForBracketPair is called twice, once with\n * the ['begin'], ['end'] group consisting of one bracket pair, and once with\n * the ['if'], ['end if'] group consiting of the other bracket pair.\n *\n * But there could be a situation where an occurrence of 'end if' is mistaken\n * for an occurrence of 'end'.\n *\n * Therefore, for the bracket pair ['begin', 'end'], the regex will also\n * target 'end if'. The regex will be something like:\n * /(\\bend if\\b)|(\\bend\\b)|(\\bif\\b)/\n *\n * The regex also searches for \"superstrings\" (other brackets that might be mistaken with the current bracket).\n *\n */\nfunction getRegexForBracketPair(open: string[], close: string[], brackets: InternalBracket[], currentIndex: number): RegExp {\n\t// search in all brackets for other brackets that are a superstring of these brackets\n\tlet pieces: string[] = [];\n\tpieces = pieces.concat(open);\n\tpieces = pieces.concat(close);\n\tfor (let i = 0, len = pieces.length; i < len; i++) {\n\t\tcollectSuperstrings(pieces[i], brackets, currentIndex, pieces);\n\t}\n\tpieces = unique(pieces);\n\tpieces.sort(lengthcmp);\n\tpieces.reverse();\n\treturn createBracketOrRegExp(pieces);\n}\n\n/**\n * Matching a regular expression in JS can only be done \"forwards\". So JS offers natively only\n * methods to find the first match of a regex in a string. But sometimes, it is useful to\n * find the last match of a regex in a string. For such a situation, a nice solution is to\n * simply reverse the string and then search for a reversed regex.\n *\n * This function also has the fine details of `getRegexForBracketPair`. For the same example\n * given above, the regex produced here would look like:\n * /(\\bfi dne\\b)|(\\bdne\\b)|(\\bfi\\b)/\n */\nfunction getReversedRegexForBracketPair(open: string[], close: string[], brackets: InternalBracket[], currentIndex: number): RegExp {\n\t// search in all brackets for other brackets that are a superstring of these brackets\n\tlet pieces: string[] = [];\n\tpieces = pieces.concat(open);\n\tpieces = pieces.concat(close);\n\tfor (let i = 0, len = pieces.length; i < len; i++) {\n\t\tcollectSuperstrings(pieces[i], brackets, currentIndex, pieces);\n\t}\n\tpieces = unique(pieces);\n\tpieces.sort(lengthcmp);\n\tpieces.reverse();\n\treturn createBracketOrRegExp(pieces.map(toReversedString));\n}\n\n/**\n * Creates a regular expression that targets all bracket pairs.\n *\n * e.g. for the bracket pairs:\n * ['{','}']\n * ['begin,'end']\n * ['for','end']\n * the regex would look like:\n * /(\\{)|(\\})|(\\bbegin\\b)|(\\bend\\b)|(\\bfor\\b)/\n */\nfunction getRegexForBrackets(brackets: RichEditBracket[]): RegExp {\n\tlet pieces: string[] = [];\n\tfor (const bracket of brackets) {\n\t\tfor (const open of bracket.open) {\n\t\t\tpieces.push(open);\n\t\t}\n\t\tfor (const close of bracket.close) {\n\t\t\tpieces.push(close);\n\t\t}\n\t}\n\tpieces = unique(pieces);\n\treturn createBracketOrRegExp(pieces);\n}\n\n/**\n * Matching a regular expression in JS can only be done \"forwards\". So JS offers natively only\n * methods to find the first match of a regex in a string. But sometimes, it is useful to\n * find the last match of a regex in a string. For such a situation, a nice solution is to\n * simply reverse the string and then search for a reversed regex.\n *\n * e.g. for the bracket pairs:\n * ['{','}']\n * ['begin,'end']\n * ['for','end']\n * the regex would look like:\n * /(\\{)|(\\})|(\\bnigeb\\b)|(\\bdne\\b)|(\\brof\\b)/\n */\nfunction getReversedRegexForBrackets(brackets: RichEditBracket[]): RegExp {\n\tlet pieces: string[] = [];\n\tfor (const bracket of brackets) {\n\t\tfor (const open of bracket.open) {\n\t\t\tpieces.push(open);\n\t\t}\n\t\tfor (const close of bracket.close) {\n\t\t\tpieces.push(close);\n\t\t}\n\t}\n\tpieces = unique(pieces);\n\treturn createBracketOrRegExp(pieces.map(toReversedString));\n}\n\nfunction prepareBracketForRegExp(str: string): string {\n\t// This bracket pair uses letters like e.g. \"begin\" - \"end\"\n\tconst insertWordBoundaries = (/^[\\w ]+$/.test(str));\n\tstr = strings.escapeRegExpCharacters(str);\n\treturn (insertWordBoundaries ? `\\\\b${str}\\\\b` : str);\n}\n\nfunction createBracketOrRegExp(pieces: string[]): RegExp {\n\tconst regexStr = `(${pieces.map(prepareBracketForRegExp).join(')|(')})`;\n\treturn strings.createRegExp(regexStr, true);\n}\n\nconst toReversedString = (function () {\n\n\tfunction reverse(str: string): string {\n\t\t// create a Uint16Array and then use a TextDecoder to create a string\n\t\tconst arr = new Uint16Array(str.length);\n\t\tlet offset = 0;\n\t\tfor (let i = str.length - 1; i >= 0; i--) {\n\t\t\tarr[offset++] = str.charCodeAt(i);\n\t\t}\n\t\treturn stringBuilder.getPlatformTextDecoder().decode(arr);\n\t}\n\n\tlet lastInput: string | null = null;\n\tlet lastOutput: string | null = null;\n\treturn function toReversedString(str: string): string {\n\t\tif (lastInput !== str) {\n\t\t\tlastInput = str;\n\t\t\tlastOutput = reverse(lastInput);\n\t\t}\n\t\treturn lastOutput!;\n\t};\n})();\n\nexport class BracketsUtils {\n\n\tprivate static _findPrevBracketInText(reversedBracketRegex: RegExp, lineNumber: number, reversedText: string, offset: number): Range | null {\n\t\tconst m = reversedText.match(reversedBracketRegex);\n\n\t\tif (!m) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst matchOffset = reversedText.length - (m.index || 0);\n\t\tconst matchLength = m[0].length;\n\t\tconst absoluteMatchOffset = offset + matchOffset;\n\n\t\treturn new Range(lineNumber, absoluteMatchOffset - matchLength + 1, lineNumber, absoluteMatchOffset + 1);\n\t}\n\n\tpublic static findPrevBracketInRange(reversedBracketRegex: RegExp, lineNumber: number, lineText: string, startOffset: number, endOffset: number): Range | null {\n\t\t// Because JS does not support backwards regex search, we search forwards in a reversed string with a reversed regex ;)\n\t\tconst reversedLineText = toReversedString(lineText);\n\t\tconst reversedSubstr = reversedLineText.substring(lineText.length - endOffset, lineText.length - startOffset);\n\t\treturn this._findPrevBracketInText(reversedBracketRegex, lineNumber, reversedSubstr, startOffset);\n\t}\n\n\tpublic static findNextBracketInText(bracketRegex: RegExp, lineNumber: number, text: string, offset: number): Range | null {\n\t\tconst m = text.match(bracketRegex);\n\n\t\tif (!m) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst matchOffset = m.index || 0;\n\t\tconst matchLength = m[0].length;\n\t\tif (matchLength === 0) {\n\t\t\treturn null;\n\t\t}\n\t\tconst absoluteMatchOffset = offset + matchOffset;\n\n\t\treturn new Range(lineNumber, absoluteMatchOffset + 1, lineNumber, absoluteMatchOffset + 1 + matchLength);\n\t}\n\n\tpublic static findNextBracketInRange(bracketRegex: RegExp, lineNumber: number, lineText: string, startOffset: number, endOffset: number): Range | null {\n\t\tconst substr = lineText.substring(startOffset, endOffset);\n\t\treturn this.findNextBracketInText(bracketRegex, lineNumber, substr, startOffset);\n\t}\n}\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\nimport { distinct } from 'vs/base/common/arrays';\nimport { ScopedLineTokens, ignoreBracketsInToken } from 'vs/editor/common/languages/supports';\nimport { BracketsUtils, RichEditBrackets } from 'vs/editor/common/languages/supports/richEditBrackets';\n\n/**\n * Interface used to support electric characters\n * @internal\n */\nexport interface IElectricAction {\n\t// The line will be indented at the same level of the line\n\t// which contains the matching given bracket type.\n\tmatchOpenBracket: string;\n}\n\nexport class BracketElectricCharacterSupport {\n\n\tprivate readonly _richEditBrackets: RichEditBrackets | null;\n\n\tconstructor(richEditBrackets: RichEditBrackets | null) {\n\t\tthis._richEditBrackets = richEditBrackets;\n\t}\n\n\tpublic getElectricCharacters(): string[] {\n\t\tconst result: string[] = [];\n\n\t\tif (this._richEditBrackets) {\n\t\t\tfor (const bracket of this._richEditBrackets.brackets) {\n\t\t\t\tfor (const close of bracket.close) {\n\t\t\t\t\tconst lastChar = close.charAt(close.length - 1);\n\t\t\t\t\tresult.push(lastChar);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn distinct(result);\n\t}\n\n\tpublic onElectricCharacter(character: string, context: ScopedLineTokens, column: number): IElectricAction | null {\n\t\tif (!this._richEditBrackets || this._richEditBrackets.brackets.length === 0) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst tokenIndex = context.findTokenIndexAtOffset(column - 1);\n\t\tif (ignoreBracketsInToken(context.getStandardTokenType(tokenIndex))) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst reversedBracketRegex = this._richEditBrackets.reversedRegex;\n\t\tconst text = context.getLineContent().substring(0, column - 1) + character;\n\n\t\tconst r = BracketsUtils.findPrevBracketInRange(reversedBracketRegex, 1, text, 0, text.length);\n\t\tif (!r) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst bracketText = text.substring(r.startColumn - 1, r.endColumn - 1).toLowerCase();\n\n\t\tconst isOpen = this._richEditBrackets.textIsOpenBracket[bracketText];\n\t\tif (isOpen) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst textBeforeBracket = context.getActualLineContentBefore(r.startColumn - 1);\n\t\tif (!/^\\s*$/.test(textBeforeBracket)) {\n\t\t\t// There is other text on the line before the bracket\n\t\t\treturn null;\n\t\t}\n\n\t\treturn {\n\t\t\tmatchOpenBracket: bracketText\n\t\t};\n\t}\n}\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\nimport { CallbackIterable, compareBy } from 'vs/base/common/arrays';\nimport { Emitter } from 'vs/base/common/event';\nimport { Disposable, DisposableStore, IDisposable, IReference, MutableDisposable } from 'vs/base/common/lifecycle';\nimport { IPosition, Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\nimport { ILanguageConfigurationService } from 'vs/editor/common/languages/languageConfigurationRegistry';\nimport { ignoreBracketsInToken } from 'vs/editor/common/languages/supports';\nimport { LanguageBracketsConfiguration } from 'vs/editor/common/languages/supports/languageBracketsConfiguration';\nimport { BracketsUtils, RichEditBracket, RichEditBrackets } from 'vs/editor/common/languages/supports/richEditBrackets';\nimport { BracketPairsTree } from 'vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/bracketPairsTree';\nimport { TextModel } from 'vs/editor/common/model/textModel';\nimport { BracketInfo, BracketPairInfo, BracketPairWithMinIndentationInfo, IBracketPairsTextModelPart, IFoundBracket } from 'vs/editor/common/textModelBracketPairs';\nimport { IModelContentChangedEvent, IModelLanguageChangedEvent, IModelOptionsChangedEvent, IModelTokensChangedEvent } from 'vs/editor/common/textModelEvents';\nimport { LineTokens } from 'vs/editor/common/tokens/lineTokens';\n\nexport class BracketPairsTextModelPart extends Disposable implements IBracketPairsTextModelPart {\n\tprivate readonly bracketPairsTree = this._register(new MutableDisposable>());\n\n\tprivate readonly onDidChangeEmitter = new Emitter();\n\tpublic readonly onDidChange = this.onDidChangeEmitter.event;\n\n\tprivate get canBuildAST() {\n\t\tconst maxSupportedDocumentLength = /* max lines */ 50_000 * /* average column count */ 100;\n\t\treturn this.textModel.getValueLength() <= maxSupportedDocumentLength;\n\t}\n\n\tprivate bracketsRequested = false;\n\n\tpublic constructor(\n\t\tprivate readonly textModel: TextModel,\n\t\tprivate readonly languageConfigurationService: ILanguageConfigurationService\n\t) {\n\t\tsuper();\n\n\t\tthis._register(\n\t\t\tthis.languageConfigurationService.onDidChange(e => {\n\t\t\t\tif (!e.languageId || this.bracketPairsTree.value?.object.didLanguageChange(e.languageId)) {\n\t\t\t\t\tthis.bracketPairsTree.clear();\n\t\t\t\t\tthis.updateBracketPairsTree();\n\t\t\t\t}\n\t\t\t})\n\t\t);\n\t}\n\n\t//#region TextModel events\n\n\tpublic handleDidChangeOptions(e: IModelOptionsChangedEvent): void {\n\t\tthis.bracketPairsTree.clear();\n\t\tthis.updateBracketPairsTree();\n\t}\n\n\tpublic handleDidChangeLanguage(e: IModelLanguageChangedEvent): void {\n\t\tthis.bracketPairsTree.clear();\n\t\tthis.updateBracketPairsTree();\n\t}\n\n\tpublic handleDidChangeContent(change: IModelContentChangedEvent) {\n\t\tthis.bracketPairsTree.value?.object.handleContentChanged(change);\n\t}\n\n\tpublic handleDidChangeBackgroundTokenizationState(): void {\n\t\tthis.bracketPairsTree.value?.object.handleDidChangeBackgroundTokenizationState();\n\t}\n\n\tpublic handleDidChangeTokens(e: IModelTokensChangedEvent): void {\n\t\tthis.bracketPairsTree.value?.object.handleDidChangeTokens(e);\n\t}\n\n\t//#endregion\n\n\tprivate updateBracketPairsTree() {\n\t\tif (this.bracketsRequested && this.canBuildAST) {\n\t\t\tif (!this.bracketPairsTree.value) {\n\t\t\t\tconst store = new DisposableStore();\n\n\t\t\t\tthis.bracketPairsTree.value = createDisposableRef(\n\t\t\t\t\tstore.add(\n\t\t\t\t\t\tnew BracketPairsTree(this.textModel, (languageId) => {\n\t\t\t\t\t\t\treturn this.languageConfigurationService.getLanguageConfiguration(languageId);\n\t\t\t\t\t\t})\n\t\t\t\t\t),\n\t\t\t\t\tstore\n\t\t\t\t);\n\t\t\t\tstore.add(this.bracketPairsTree.value.object.onDidChange(e => this.onDidChangeEmitter.fire(e)));\n\t\t\t\tthis.onDidChangeEmitter.fire();\n\t\t\t}\n\t\t} else {\n\t\t\tif (this.bracketPairsTree.value) {\n\t\t\t\tthis.bracketPairsTree.clear();\n\t\t\t\t// Important: Don't call fire if there was no change!\n\t\t\t\tthis.onDidChangeEmitter.fire();\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Returns all bracket pairs that intersect the given range.\n\t * The result is sorted by the start position.\n\t*/\n\tpublic getBracketPairsInRange(range: Range): CallbackIterable {\n\t\tthis.bracketsRequested = true;\n\t\tthis.updateBracketPairsTree();\n\t\treturn this.bracketPairsTree.value?.object.getBracketPairsInRange(range, false) || CallbackIterable.empty;\n\t}\n\n\tpublic getBracketPairsInRangeWithMinIndentation(range: Range): CallbackIterable {\n\t\tthis.bracketsRequested = true;\n\t\tthis.updateBracketPairsTree();\n\t\treturn this.bracketPairsTree.value?.object.getBracketPairsInRange(range, true) || CallbackIterable.empty;\n\t}\n\n\tpublic getBracketsInRange(range: Range, onlyColorizedBrackets: boolean = false): CallbackIterable {\n\t\tthis.bracketsRequested = true;\n\t\tthis.updateBracketPairsTree();\n\t\treturn this.bracketPairsTree.value?.object.getBracketsInRange(range, onlyColorizedBrackets) || CallbackIterable.empty;\n\t}\n\n\tpublic findMatchingBracketUp(_bracket: string, _position: IPosition, maxDuration?: number): Range | null {\n\t\tconst position = this.textModel.validatePosition(_position);\n\t\tconst languageId = this.textModel.getLanguageIdAtPosition(position.lineNumber, position.column);\n\n\t\tif (this.canBuildAST) {\n\t\t\tconst closingBracketInfo = this.languageConfigurationService\n\t\t\t\t.getLanguageConfiguration(languageId)\n\t\t\t\t.bracketsNew.getClosingBracketInfo(_bracket);\n\n\t\t\tif (!closingBracketInfo) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst bracketPair = this.getBracketPairsInRange(Range.fromPositions(_position, _position)).findLast((b) =>\n\t\t\t\tclosingBracketInfo.closes(b.openingBracketInfo)\n\t\t\t);\n\n\t\t\tif (bracketPair) {\n\t\t\t\treturn bracketPair.openingBracketRange;\n\t\t\t}\n\t\t\treturn null;\n\t\t} else {\n\t\t\t// Fallback to old bracket matching code:\n\t\t\tconst bracket = _bracket.toLowerCase();\n\n\t\t\tconst bracketsSupport = this.languageConfigurationService.getLanguageConfiguration(languageId).brackets;\n\n\t\t\tif (!bracketsSupport) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst data = bracketsSupport.textIsBracket[bracket];\n\n\t\t\tif (!data) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\treturn stripBracketSearchCanceled(this._findMatchingBracketUp(data, position, createTimeBasedContinueBracketSearchPredicate(maxDuration)));\n\t\t}\n\t}\n\n\tpublic matchBracket(position: IPosition, maxDuration?: number): [Range, Range] | null {\n\t\tif (this.canBuildAST) {\n\t\t\tconst bracketPair =\n\t\t\t\tthis.getBracketPairsInRange(\n\t\t\t\t\tRange.fromPositions(position, position)\n\t\t\t\t).filter(\n\t\t\t\t\t(item) =>\n\t\t\t\t\t\titem.closingBracketRange !== undefined &&\n\t\t\t\t\t\t(item.openingBracketRange.containsPosition(position) ||\n\t\t\t\t\t\t\titem.closingBracketRange.containsPosition(position))\n\t\t\t\t).findLastMaxBy(\n\t\t\t\t\tcompareBy(\n\t\t\t\t\t\t(item) =>\n\t\t\t\t\t\t\titem.openingBracketRange.containsPosition(position)\n\t\t\t\t\t\t\t\t? item.openingBracketRange\n\t\t\t\t\t\t\t\t: item.closingBracketRange,\n\t\t\t\t\t\tRange.compareRangesUsingStarts\n\t\t\t\t\t)\n\t\t\t\t);\n\t\t\tif (bracketPair) {\n\t\t\t\treturn [bracketPair.openingBracketRange, bracketPair.closingBracketRange!];\n\t\t\t}\n\t\t\treturn null;\n\t\t} else {\n\t\t\t// Fallback to old bracket matching code:\n\t\t\tconst continueSearchPredicate = createTimeBasedContinueBracketSearchPredicate(maxDuration);\n\t\t\treturn this._matchBracket(this.textModel.validatePosition(position), continueSearchPredicate);\n\t\t}\n\t}\n\n\tprivate _establishBracketSearchOffsets(position: Position, lineTokens: LineTokens, modeBrackets: RichEditBrackets, tokenIndex: number) {\n\t\tconst tokenCount = lineTokens.getCount();\n\t\tconst currentLanguageId = lineTokens.getLanguageId(tokenIndex);\n\n\t\t// limit search to not go before `maxBracketLength`\n\t\tlet searchStartOffset = Math.max(0, position.column - 1 - modeBrackets.maxBracketLength);\n\t\tfor (let i = tokenIndex - 1; i >= 0; i--) {\n\t\t\tconst tokenEndOffset = lineTokens.getEndOffset(i);\n\t\t\tif (tokenEndOffset <= searchStartOffset) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (ignoreBracketsInToken(lineTokens.getStandardTokenType(i)) || lineTokens.getLanguageId(i) !== currentLanguageId) {\n\t\t\t\tsearchStartOffset = tokenEndOffset;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t// limit search to not go after `maxBracketLength`\n\t\tlet searchEndOffset = Math.min(lineTokens.getLineContent().length, position.column - 1 + modeBrackets.maxBracketLength);\n\t\tfor (let i = tokenIndex + 1; i < tokenCount; i++) {\n\t\t\tconst tokenStartOffset = lineTokens.getStartOffset(i);\n\t\t\tif (tokenStartOffset >= searchEndOffset) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (ignoreBracketsInToken(lineTokens.getStandardTokenType(i)) || lineTokens.getLanguageId(i) !== currentLanguageId) {\n\t\t\t\tsearchEndOffset = tokenStartOffset;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn { searchStartOffset, searchEndOffset };\n\t}\n\n\tprivate _matchBracket(position: Position, continueSearchPredicate: ContinueBracketSearchPredicate): [Range, Range] | null {\n\t\tconst lineNumber = position.lineNumber;\n\t\tconst lineTokens = this.textModel.tokenization.getLineTokens(lineNumber);\n\t\tconst lineText = this.textModel.getLineContent(lineNumber);\n\n\t\tconst tokenIndex = lineTokens.findTokenIndexAtOffset(position.column - 1);\n\t\tif (tokenIndex < 0) {\n\t\t\treturn null;\n\t\t}\n\t\tconst currentModeBrackets = this.languageConfigurationService.getLanguageConfiguration(lineTokens.getLanguageId(tokenIndex)).brackets;\n\n\t\t// check that the token is not to be ignored\n\t\tif (currentModeBrackets && !ignoreBracketsInToken(lineTokens.getStandardTokenType(tokenIndex))) {\n\n\t\t\tlet { searchStartOffset, searchEndOffset } = this._establishBracketSearchOffsets(position, lineTokens, currentModeBrackets, tokenIndex);\n\n\t\t\t// it might be the case that [currentTokenStart -> currentTokenEnd] contains multiple brackets\n\t\t\t// `bestResult` will contain the most right-side result\n\t\t\tlet bestResult: [Range, Range] | null = null;\n\t\t\twhile (true) {\n\t\t\t\tconst foundBracket = BracketsUtils.findNextBracketInRange(currentModeBrackets.forwardRegex, lineNumber, lineText, searchStartOffset, searchEndOffset);\n\t\t\t\tif (!foundBracket) {\n\t\t\t\t\t// there are no more brackets in this text\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\t// check that we didn't hit a bracket too far away from position\n\t\t\t\tif (foundBracket.startColumn <= position.column && position.column <= foundBracket.endColumn) {\n\t\t\t\t\tconst foundBracketText = lineText.substring(foundBracket.startColumn - 1, foundBracket.endColumn - 1).toLowerCase();\n\t\t\t\t\tconst r = this._matchFoundBracket(foundBracket, currentModeBrackets.textIsBracket[foundBracketText], currentModeBrackets.textIsOpenBracket[foundBracketText], continueSearchPredicate);\n\t\t\t\t\tif (r) {\n\t\t\t\t\t\tif (r instanceof BracketSearchCanceled) {\n\t\t\t\t\t\t\treturn null;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbestResult = r;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tsearchStartOffset = foundBracket.endColumn - 1;\n\t\t\t}\n\n\t\t\tif (bestResult) {\n\t\t\t\treturn bestResult;\n\t\t\t}\n\t\t}\n\n\t\t// If position is in between two tokens, try also looking in the previous token\n\t\tif (tokenIndex > 0 && lineTokens.getStartOffset(tokenIndex) === position.column - 1) {\n\t\t\tconst prevTokenIndex = tokenIndex - 1;\n\t\t\tconst prevModeBrackets = this.languageConfigurationService.getLanguageConfiguration(lineTokens.getLanguageId(prevTokenIndex)).brackets;\n\n\t\t\t// check that previous token is not to be ignored\n\t\t\tif (prevModeBrackets && !ignoreBracketsInToken(lineTokens.getStandardTokenType(prevTokenIndex))) {\n\n\t\t\t\tconst { searchStartOffset, searchEndOffset } = this._establishBracketSearchOffsets(position, lineTokens, prevModeBrackets, prevTokenIndex);\n\n\t\t\t\tconst foundBracket = BracketsUtils.findPrevBracketInRange(prevModeBrackets.reversedRegex, lineNumber, lineText, searchStartOffset, searchEndOffset);\n\n\t\t\t\t// check that we didn't hit a bracket too far away from position\n\t\t\t\tif (foundBracket && foundBracket.startColumn <= position.column && position.column <= foundBracket.endColumn) {\n\t\t\t\t\tconst foundBracketText = lineText.substring(foundBracket.startColumn - 1, foundBracket.endColumn - 1).toLowerCase();\n\t\t\t\t\tconst r = this._matchFoundBracket(foundBracket, prevModeBrackets.textIsBracket[foundBracketText], prevModeBrackets.textIsOpenBracket[foundBracketText], continueSearchPredicate);\n\t\t\t\t\tif (r) {\n\t\t\t\t\t\tif (r instanceof BracketSearchCanceled) {\n\t\t\t\t\t\t\treturn null;\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn r;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tprivate _matchFoundBracket(foundBracket: Range, data: RichEditBracket, isOpen: boolean, continueSearchPredicate: ContinueBracketSearchPredicate): [Range, Range] | null | BracketSearchCanceled {\n\t\tif (!data) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst matched = (\n\t\t\tisOpen\n\t\t\t\t? this._findMatchingBracketDown(data, foundBracket.getEndPosition(), continueSearchPredicate)\n\t\t\t\t: this._findMatchingBracketUp(data, foundBracket.getStartPosition(), continueSearchPredicate)\n\t\t);\n\n\t\tif (!matched) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif (matched instanceof BracketSearchCanceled) {\n\t\t\treturn matched;\n\t\t}\n\n\t\treturn [foundBracket, matched];\n\t}\n\n\tprivate _findMatchingBracketUp(bracket: RichEditBracket, position: Position, continueSearchPredicate: ContinueBracketSearchPredicate): Range | null | BracketSearchCanceled {\n\t\t// console.log('_findMatchingBracketUp: ', 'bracket: ', JSON.stringify(bracket), 'startPosition: ', String(position));\n\n\t\tconst languageId = bracket.languageId;\n\t\tconst reversedBracketRegex = bracket.reversedRegex;\n\t\tlet count = -1;\n\n\t\tlet totalCallCount = 0;\n\t\tconst searchPrevMatchingBracketInRange = (lineNumber: number, lineText: string, searchStartOffset: number, searchEndOffset: number): Range | null | BracketSearchCanceled => {\n\t\t\twhile (true) {\n\t\t\t\tif (continueSearchPredicate && (++totalCallCount) % 100 === 0 && !continueSearchPredicate()) {\n\t\t\t\t\treturn BracketSearchCanceled.INSTANCE;\n\t\t\t\t}\n\t\t\t\tconst r = BracketsUtils.findPrevBracketInRange(reversedBracketRegex, lineNumber, lineText, searchStartOffset, searchEndOffset);\n\t\t\t\tif (!r) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tconst hitText = lineText.substring(r.startColumn - 1, r.endColumn - 1).toLowerCase();\n\t\t\t\tif (bracket.isOpen(hitText)) {\n\t\t\t\t\tcount++;\n\t\t\t\t} else if (bracket.isClose(hitText)) {\n\t\t\t\t\tcount--;\n\t\t\t\t}\n\n\t\t\t\tif (count === 0) {\n\t\t\t\t\treturn r;\n\t\t\t\t}\n\n\t\t\t\tsearchEndOffset = r.startColumn - 1;\n\t\t\t}\n\n\t\t\treturn null;\n\t\t};\n\n\t\tfor (let lineNumber = position.lineNumber; lineNumber >= 1; lineNumber--) {\n\t\t\tconst lineTokens = this.textModel.tokenization.getLineTokens(lineNumber);\n\t\t\tconst tokenCount = lineTokens.getCount();\n\t\t\tconst lineText = this.textModel.getLineContent(lineNumber);\n\n\t\t\tlet tokenIndex = tokenCount - 1;\n\t\t\tlet searchStartOffset = lineText.length;\n\t\t\tlet searchEndOffset = lineText.length;\n\t\t\tif (lineNumber === position.lineNumber) {\n\t\t\t\ttokenIndex = lineTokens.findTokenIndexAtOffset(position.column - 1);\n\t\t\t\tsearchStartOffset = position.column - 1;\n\t\t\t\tsearchEndOffset = position.column - 1;\n\t\t\t}\n\n\t\t\tlet prevSearchInToken = true;\n\t\t\tfor (; tokenIndex >= 0; tokenIndex--) {\n\t\t\t\tconst searchInToken = (lineTokens.getLanguageId(tokenIndex) === languageId && !ignoreBracketsInToken(lineTokens.getStandardTokenType(tokenIndex)));\n\n\t\t\t\tif (searchInToken) {\n\t\t\t\t\t// this token should be searched\n\t\t\t\t\tif (prevSearchInToken) {\n\t\t\t\t\t\t// the previous token should be searched, simply extend searchStartOffset\n\t\t\t\t\t\tsearchStartOffset = lineTokens.getStartOffset(tokenIndex);\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// the previous token should not be searched\n\t\t\t\t\t\tsearchStartOffset = lineTokens.getStartOffset(tokenIndex);\n\t\t\t\t\t\tsearchEndOffset = lineTokens.getEndOffset(tokenIndex);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// this token should not be searched\n\t\t\t\t\tif (prevSearchInToken && searchStartOffset !== searchEndOffset) {\n\t\t\t\t\t\tconst r = searchPrevMatchingBracketInRange(lineNumber, lineText, searchStartOffset, searchEndOffset);\n\t\t\t\t\t\tif (r) {\n\t\t\t\t\t\t\treturn r;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tprevSearchInToken = searchInToken;\n\t\t\t}\n\n\t\t\tif (prevSearchInToken && searchStartOffset !== searchEndOffset) {\n\t\t\t\tconst r = searchPrevMatchingBracketInRange(lineNumber, lineText, searchStartOffset, searchEndOffset);\n\t\t\t\tif (r) {\n\t\t\t\t\treturn r;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tprivate _findMatchingBracketDown(bracket: RichEditBracket, position: Position, continueSearchPredicate: ContinueBracketSearchPredicate): Range | null | BracketSearchCanceled {\n\t\t// console.log('_findMatchingBracketDown: ', 'bracket: ', JSON.stringify(bracket), 'startPosition: ', String(position));\n\n\t\tconst languageId = bracket.languageId;\n\t\tconst bracketRegex = bracket.forwardRegex;\n\t\tlet count = 1;\n\n\t\tlet totalCallCount = 0;\n\t\tconst searchNextMatchingBracketInRange = (lineNumber: number, lineText: string, searchStartOffset: number, searchEndOffset: number): Range | null | BracketSearchCanceled => {\n\t\t\twhile (true) {\n\t\t\t\tif (continueSearchPredicate && (++totalCallCount) % 100 === 0 && !continueSearchPredicate()) {\n\t\t\t\t\treturn BracketSearchCanceled.INSTANCE;\n\t\t\t\t}\n\t\t\t\tconst r = BracketsUtils.findNextBracketInRange(bracketRegex, lineNumber, lineText, searchStartOffset, searchEndOffset);\n\t\t\t\tif (!r) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tconst hitText = lineText.substring(r.startColumn - 1, r.endColumn - 1).toLowerCase();\n\t\t\t\tif (bracket.isOpen(hitText)) {\n\t\t\t\t\tcount++;\n\t\t\t\t} else if (bracket.isClose(hitText)) {\n\t\t\t\t\tcount--;\n\t\t\t\t}\n\n\t\t\t\tif (count === 0) {\n\t\t\t\t\treturn r;\n\t\t\t\t}\n\n\t\t\t\tsearchStartOffset = r.endColumn - 1;\n\t\t\t}\n\n\t\t\treturn null;\n\t\t};\n\n\t\tconst lineCount = this.textModel.getLineCount();\n\t\tfor (let lineNumber = position.lineNumber; lineNumber <= lineCount; lineNumber++) {\n\t\t\tconst lineTokens = this.textModel.tokenization.getLineTokens(lineNumber);\n\t\t\tconst tokenCount = lineTokens.getCount();\n\t\t\tconst lineText = this.textModel.getLineContent(lineNumber);\n\n\t\t\tlet tokenIndex = 0;\n\t\t\tlet searchStartOffset = 0;\n\t\t\tlet searchEndOffset = 0;\n\t\t\tif (lineNumber === position.lineNumber) {\n\t\t\t\ttokenIndex = lineTokens.findTokenIndexAtOffset(position.column - 1);\n\t\t\t\tsearchStartOffset = position.column - 1;\n\t\t\t\tsearchEndOffset = position.column - 1;\n\t\t\t}\n\n\t\t\tlet prevSearchInToken = true;\n\t\t\tfor (; tokenIndex < tokenCount; tokenIndex++) {\n\t\t\t\tconst searchInToken = (lineTokens.getLanguageId(tokenIndex) === languageId && !ignoreBracketsInToken(lineTokens.getStandardTokenType(tokenIndex)));\n\n\t\t\t\tif (searchInToken) {\n\t\t\t\t\t// this token should be searched\n\t\t\t\t\tif (prevSearchInToken) {\n\t\t\t\t\t\t// the previous token should be searched, simply extend searchEndOffset\n\t\t\t\t\t\tsearchEndOffset = lineTokens.getEndOffset(tokenIndex);\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// the previous token should not be searched\n\t\t\t\t\t\tsearchStartOffset = lineTokens.getStartOffset(tokenIndex);\n\t\t\t\t\t\tsearchEndOffset = lineTokens.getEndOffset(tokenIndex);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// this token should not be searched\n\t\t\t\t\tif (prevSearchInToken && searchStartOffset !== searchEndOffset) {\n\t\t\t\t\t\tconst r = searchNextMatchingBracketInRange(lineNumber, lineText, searchStartOffset, searchEndOffset);\n\t\t\t\t\t\tif (r) {\n\t\t\t\t\t\t\treturn r;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tprevSearchInToken = searchInToken;\n\t\t\t}\n\n\t\t\tif (prevSearchInToken && searchStartOffset !== searchEndOffset) {\n\t\t\t\tconst r = searchNextMatchingBracketInRange(lineNumber, lineText, searchStartOffset, searchEndOffset);\n\t\t\t\tif (r) {\n\t\t\t\t\treturn r;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tpublic findPrevBracket(_position: IPosition): IFoundBracket | null {\n\t\tconst position = this.textModel.validatePosition(_position);\n\n\t\tif (this.canBuildAST) {\n\t\t\tthis.bracketsRequested = true;\n\t\t\tthis.updateBracketPairsTree();\n\t\t\treturn this.bracketPairsTree.value?.object.getFirstBracketBefore(position) || null;\n\t\t}\n\n\t\tlet languageId: string | null = null;\n\t\tlet modeBrackets: RichEditBrackets | null = null;\n\t\tlet bracketConfig: LanguageBracketsConfiguration | null = null;\n\t\tfor (let lineNumber = position.lineNumber; lineNumber >= 1; lineNumber--) {\n\t\t\tconst lineTokens = this.textModel.tokenization.getLineTokens(lineNumber);\n\t\t\tconst tokenCount = lineTokens.getCount();\n\t\t\tconst lineText = this.textModel.getLineContent(lineNumber);\n\n\t\t\tlet tokenIndex = tokenCount - 1;\n\t\t\tlet searchStartOffset = lineText.length;\n\t\t\tlet searchEndOffset = lineText.length;\n\t\t\tif (lineNumber === position.lineNumber) {\n\t\t\t\ttokenIndex = lineTokens.findTokenIndexAtOffset(position.column - 1);\n\t\t\t\tsearchStartOffset = position.column - 1;\n\t\t\t\tsearchEndOffset = position.column - 1;\n\t\t\t\tconst tokenLanguageId = lineTokens.getLanguageId(tokenIndex);\n\t\t\t\tif (languageId !== tokenLanguageId) {\n\t\t\t\t\tlanguageId = tokenLanguageId;\n\t\t\t\t\tmodeBrackets = this.languageConfigurationService.getLanguageConfiguration(languageId).brackets;\n\t\t\t\t\tbracketConfig = this.languageConfigurationService.getLanguageConfiguration(languageId).bracketsNew;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet prevSearchInToken = true;\n\t\t\tfor (; tokenIndex >= 0; tokenIndex--) {\n\t\t\t\tconst tokenLanguageId = lineTokens.getLanguageId(tokenIndex);\n\n\t\t\t\tif (languageId !== tokenLanguageId) {\n\t\t\t\t\t// language id change!\n\t\t\t\t\tif (modeBrackets && bracketConfig && prevSearchInToken && searchStartOffset !== searchEndOffset) {\n\t\t\t\t\t\tconst r = BracketsUtils.findPrevBracketInRange(modeBrackets.reversedRegex, lineNumber, lineText, searchStartOffset, searchEndOffset);\n\t\t\t\t\t\tif (r) {\n\t\t\t\t\t\t\treturn this._toFoundBracket(bracketConfig, r);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tprevSearchInToken = false;\n\t\t\t\t\t}\n\t\t\t\t\tlanguageId = tokenLanguageId;\n\t\t\t\t\tmodeBrackets = this.languageConfigurationService.getLanguageConfiguration(languageId).brackets;\n\t\t\t\t\tbracketConfig = this.languageConfigurationService.getLanguageConfiguration(languageId).bracketsNew;\n\t\t\t\t}\n\n\t\t\t\tconst searchInToken = (!!modeBrackets && !ignoreBracketsInToken(lineTokens.getStandardTokenType(tokenIndex)));\n\n\t\t\t\tif (searchInToken) {\n\t\t\t\t\t// this token should be searched\n\t\t\t\t\tif (prevSearchInToken) {\n\t\t\t\t\t\t// the previous token should be searched, simply extend searchStartOffset\n\t\t\t\t\t\tsearchStartOffset = lineTokens.getStartOffset(tokenIndex);\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// the previous token should not be searched\n\t\t\t\t\t\tsearchStartOffset = lineTokens.getStartOffset(tokenIndex);\n\t\t\t\t\t\tsearchEndOffset = lineTokens.getEndOffset(tokenIndex);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// this token should not be searched\n\t\t\t\t\tif (bracketConfig && modeBrackets && prevSearchInToken && searchStartOffset !== searchEndOffset) {\n\t\t\t\t\t\tconst r = BracketsUtils.findPrevBracketInRange(modeBrackets.reversedRegex, lineNumber, lineText, searchStartOffset, searchEndOffset);\n\t\t\t\t\t\tif (r) {\n\t\t\t\t\t\t\treturn this._toFoundBracket(bracketConfig, r);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tprevSearchInToken = searchInToken;\n\t\t\t}\n\n\t\t\tif (bracketConfig && modeBrackets && prevSearchInToken && searchStartOffset !== searchEndOffset) {\n\t\t\t\tconst r = BracketsUtils.findPrevBracketInRange(modeBrackets.reversedRegex, lineNumber, lineText, searchStartOffset, searchEndOffset);\n\t\t\t\tif (r) {\n\t\t\t\t\treturn this._toFoundBracket(bracketConfig, r);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tpublic findNextBracket(_position: IPosition): IFoundBracket | null {\n\t\tconst position = this.textModel.validatePosition(_position);\n\n\t\tif (this.canBuildAST) {\n\t\t\tthis.bracketsRequested = true;\n\t\t\tthis.updateBracketPairsTree();\n\t\t\treturn this.bracketPairsTree.value?.object.getFirstBracketAfter(position) || null;\n\t\t}\n\n\t\tconst lineCount = this.textModel.getLineCount();\n\n\t\tlet languageId: string | null = null;\n\t\tlet modeBrackets: RichEditBrackets | null = null;\n\t\tlet bracketConfig: LanguageBracketsConfiguration | null = null;\n\t\tfor (let lineNumber = position.lineNumber; lineNumber <= lineCount; lineNumber++) {\n\t\t\tconst lineTokens = this.textModel.tokenization.getLineTokens(lineNumber);\n\t\t\tconst tokenCount = lineTokens.getCount();\n\t\t\tconst lineText = this.textModel.getLineContent(lineNumber);\n\n\t\t\tlet tokenIndex = 0;\n\t\t\tlet searchStartOffset = 0;\n\t\t\tlet searchEndOffset = 0;\n\t\t\tif (lineNumber === position.lineNumber) {\n\t\t\t\ttokenIndex = lineTokens.findTokenIndexAtOffset(position.column - 1);\n\t\t\t\tsearchStartOffset = position.column - 1;\n\t\t\t\tsearchEndOffset = position.column - 1;\n\t\t\t\tconst tokenLanguageId = lineTokens.getLanguageId(tokenIndex);\n\t\t\t\tif (languageId !== tokenLanguageId) {\n\t\t\t\t\tlanguageId = tokenLanguageId;\n\t\t\t\t\tmodeBrackets = this.languageConfigurationService.getLanguageConfiguration(languageId).brackets;\n\t\t\t\t\tbracketConfig = this.languageConfigurationService.getLanguageConfiguration(languageId).bracketsNew;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet prevSearchInToken = true;\n\t\t\tfor (; tokenIndex < tokenCount; tokenIndex++) {\n\t\t\t\tconst tokenLanguageId = lineTokens.getLanguageId(tokenIndex);\n\n\t\t\t\tif (languageId !== tokenLanguageId) {\n\t\t\t\t\t// language id change!\n\t\t\t\t\tif (bracketConfig && modeBrackets && prevSearchInToken && searchStartOffset !== searchEndOffset) {\n\t\t\t\t\t\tconst r = BracketsUtils.findNextBracketInRange(modeBrackets.forwardRegex, lineNumber, lineText, searchStartOffset, searchEndOffset);\n\t\t\t\t\t\tif (r) {\n\t\t\t\t\t\t\treturn this._toFoundBracket(bracketConfig, r);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tprevSearchInToken = false;\n\t\t\t\t\t}\n\t\t\t\t\tlanguageId = tokenLanguageId;\n\t\t\t\t\tmodeBrackets = this.languageConfigurationService.getLanguageConfiguration(languageId).brackets;\n\t\t\t\t\tbracketConfig = this.languageConfigurationService.getLanguageConfiguration(languageId).bracketsNew;\n\t\t\t\t}\n\n\t\t\t\tconst searchInToken = (!!modeBrackets && !ignoreBracketsInToken(lineTokens.getStandardTokenType(tokenIndex)));\n\t\t\t\tif (searchInToken) {\n\t\t\t\t\t// this token should be searched\n\t\t\t\t\tif (prevSearchInToken) {\n\t\t\t\t\t\t// the previous token should be searched, simply extend searchEndOffset\n\t\t\t\t\t\tsearchEndOffset = lineTokens.getEndOffset(tokenIndex);\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// the previous token should not be searched\n\t\t\t\t\t\tsearchStartOffset = lineTokens.getStartOffset(tokenIndex);\n\t\t\t\t\t\tsearchEndOffset = lineTokens.getEndOffset(tokenIndex);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// this token should not be searched\n\t\t\t\t\tif (bracketConfig && modeBrackets && prevSearchInToken && searchStartOffset !== searchEndOffset) {\n\t\t\t\t\t\tconst r = BracketsUtils.findNextBracketInRange(modeBrackets.forwardRegex, lineNumber, lineText, searchStartOffset, searchEndOffset);\n\t\t\t\t\t\tif (r) {\n\t\t\t\t\t\t\treturn this._toFoundBracket(bracketConfig, r);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tprevSearchInToken = searchInToken;\n\t\t\t}\n\n\t\t\tif (bracketConfig && modeBrackets && prevSearchInToken && searchStartOffset !== searchEndOffset) {\n\t\t\t\tconst r = BracketsUtils.findNextBracketInRange(modeBrackets.forwardRegex, lineNumber, lineText, searchStartOffset, searchEndOffset);\n\t\t\t\tif (r) {\n\t\t\t\t\treturn this._toFoundBracket(bracketConfig, r);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tpublic findEnclosingBrackets(_position: IPosition, maxDuration?: number): [Range, Range] | null {\n\t\tconst position = this.textModel.validatePosition(_position);\n\n\t\tif (this.canBuildAST) {\n\t\t\tconst range = Range.fromPositions(position);\n\t\t\tconst bracketPair =\n\t\t\t\tthis.getBracketPairsInRange(Range.fromPositions(position, position)).findLast(\n\t\t\t\t\t(item) => item.closingBracketRange !== undefined && item.range.strictContainsRange(range)\n\t\t\t\t);\n\t\t\tif (bracketPair) {\n\t\t\t\treturn [bracketPair.openingBracketRange, bracketPair.closingBracketRange!];\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t\tconst continueSearchPredicate = createTimeBasedContinueBracketSearchPredicate(maxDuration);\n\t\tconst lineCount = this.textModel.getLineCount();\n\t\tconst savedCounts = new Map();\n\n\t\tlet counts: number[] = [];\n\t\tconst resetCounts = (languageId: string, modeBrackets: RichEditBrackets | null) => {\n\t\t\tif (!savedCounts.has(languageId)) {\n\t\t\t\tconst tmp = [];\n\t\t\t\tfor (let i = 0, len = modeBrackets ? modeBrackets.brackets.length : 0; i < len; i++) {\n\t\t\t\t\ttmp[i] = 0;\n\t\t\t\t}\n\t\t\t\tsavedCounts.set(languageId, tmp);\n\t\t\t}\n\t\t\tcounts = savedCounts.get(languageId)!;\n\t\t};\n\n\t\tlet totalCallCount = 0;\n\t\tconst searchInRange = (modeBrackets: RichEditBrackets, lineNumber: number, lineText: string, searchStartOffset: number, searchEndOffset: number): [Range, Range] | null | BracketSearchCanceled => {\n\t\t\twhile (true) {\n\t\t\t\tif (continueSearchPredicate && (++totalCallCount) % 100 === 0 && !continueSearchPredicate()) {\n\t\t\t\t\treturn BracketSearchCanceled.INSTANCE;\n\t\t\t\t}\n\t\t\t\tconst r = BracketsUtils.findNextBracketInRange(modeBrackets.forwardRegex, lineNumber, lineText, searchStartOffset, searchEndOffset);\n\t\t\t\tif (!r) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tconst hitText = lineText.substring(r.startColumn - 1, r.endColumn - 1).toLowerCase();\n\t\t\t\tconst bracket = modeBrackets.textIsBracket[hitText];\n\t\t\t\tif (bracket) {\n\t\t\t\t\tif (bracket.isOpen(hitText)) {\n\t\t\t\t\t\tcounts[bracket.index]++;\n\t\t\t\t\t} else if (bracket.isClose(hitText)) {\n\t\t\t\t\t\tcounts[bracket.index]--;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (counts[bracket.index] === -1) {\n\t\t\t\t\t\treturn this._matchFoundBracket(r, bracket, false, continueSearchPredicate);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tsearchStartOffset = r.endColumn - 1;\n\t\t\t}\n\t\t\treturn null;\n\t\t};\n\n\t\tlet languageId: string | null = null;\n\t\tlet modeBrackets: RichEditBrackets | null = null;\n\t\tfor (let lineNumber = position.lineNumber; lineNumber <= lineCount; lineNumber++) {\n\t\t\tconst lineTokens = this.textModel.tokenization.getLineTokens(lineNumber);\n\t\t\tconst tokenCount = lineTokens.getCount();\n\t\t\tconst lineText = this.textModel.getLineContent(lineNumber);\n\n\t\t\tlet tokenIndex = 0;\n\t\t\tlet searchStartOffset = 0;\n\t\t\tlet searchEndOffset = 0;\n\t\t\tif (lineNumber === position.lineNumber) {\n\t\t\t\ttokenIndex = lineTokens.findTokenIndexAtOffset(position.column - 1);\n\t\t\t\tsearchStartOffset = position.column - 1;\n\t\t\t\tsearchEndOffset = position.column - 1;\n\t\t\t\tconst tokenLanguageId = lineTokens.getLanguageId(tokenIndex);\n\t\t\t\tif (languageId !== tokenLanguageId) {\n\t\t\t\t\tlanguageId = tokenLanguageId;\n\t\t\t\t\tmodeBrackets = this.languageConfigurationService.getLanguageConfiguration(languageId).brackets;\n\t\t\t\t\tresetCounts(languageId, modeBrackets);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet prevSearchInToken = true;\n\t\t\tfor (; tokenIndex < tokenCount; tokenIndex++) {\n\t\t\t\tconst tokenLanguageId = lineTokens.getLanguageId(tokenIndex);\n\n\t\t\t\tif (languageId !== tokenLanguageId) {\n\t\t\t\t\t// language id change!\n\t\t\t\t\tif (modeBrackets && prevSearchInToken && searchStartOffset !== searchEndOffset) {\n\t\t\t\t\t\tconst r = searchInRange(modeBrackets, lineNumber, lineText, searchStartOffset, searchEndOffset);\n\t\t\t\t\t\tif (r) {\n\t\t\t\t\t\t\treturn stripBracketSearchCanceled(r);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tprevSearchInToken = false;\n\t\t\t\t\t}\n\t\t\t\t\tlanguageId = tokenLanguageId;\n\t\t\t\t\tmodeBrackets = this.languageConfigurationService.getLanguageConfiguration(languageId).brackets;\n\t\t\t\t\tresetCounts(languageId, modeBrackets);\n\t\t\t\t}\n\n\t\t\t\tconst searchInToken = (!!modeBrackets && !ignoreBracketsInToken(lineTokens.getStandardTokenType(tokenIndex)));\n\t\t\t\tif (searchInToken) {\n\t\t\t\t\t// this token should be searched\n\t\t\t\t\tif (prevSearchInToken) {\n\t\t\t\t\t\t// the previous token should be searched, simply extend searchEndOffset\n\t\t\t\t\t\tsearchEndOffset = lineTokens.getEndOffset(tokenIndex);\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// the previous token should not be searched\n\t\t\t\t\t\tsearchStartOffset = lineTokens.getStartOffset(tokenIndex);\n\t\t\t\t\t\tsearchEndOffset = lineTokens.getEndOffset(tokenIndex);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// this token should not be searched\n\t\t\t\t\tif (modeBrackets && prevSearchInToken && searchStartOffset !== searchEndOffset) {\n\t\t\t\t\t\tconst r = searchInRange(modeBrackets, lineNumber, lineText, searchStartOffset, searchEndOffset);\n\t\t\t\t\t\tif (r) {\n\t\t\t\t\t\t\treturn stripBracketSearchCanceled(r);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tprevSearchInToken = searchInToken;\n\t\t\t}\n\n\t\t\tif (modeBrackets && prevSearchInToken && searchStartOffset !== searchEndOffset) {\n\t\t\t\tconst r = searchInRange(modeBrackets, lineNumber, lineText, searchStartOffset, searchEndOffset);\n\t\t\t\tif (r) {\n\t\t\t\t\treturn stripBracketSearchCanceled(r);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tprivate _toFoundBracket(bracketConfig: LanguageBracketsConfiguration, r: Range): IFoundBracket | null {\n\t\tif (!r) {\n\t\t\treturn null;\n\t\t}\n\n\t\tlet text = this.textModel.getValueInRange(r);\n\t\ttext = text.toLowerCase();\n\n\t\tconst bracketInfo = bracketConfig.getBracketInfo(text);\n\t\tif (!bracketInfo) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn {\n\t\t\trange: r,\n\t\t\tbracketInfo\n\t\t};\n\t}\n}\n\nfunction createDisposableRef(object: T, disposable?: IDisposable): IReference {\n\treturn {\n\t\tobject,\n\t\tdispose: () => disposable?.dispose(),\n\t};\n}\n\ntype ContinueBracketSearchPredicate = (() => boolean);\n\nfunction createTimeBasedContinueBracketSearchPredicate(maxDuration: number | undefined): ContinueBracketSearchPredicate {\n\tif (typeof maxDuration === 'undefined') {\n\t\treturn () => true;\n\t} else {\n\t\tconst startTime = Date.now();\n\t\treturn () => {\n\t\t\treturn (Date.now() - startTime <= maxDuration);\n\t\t};\n\t}\n}\n\nclass BracketSearchCanceled {\n\tpublic static INSTANCE = new BracketSearchCanceled();\n\t_searchCanceledBrand = undefined;\n\tprivate constructor() { }\n}\n\nfunction stripBracketSearchCanceled(result: T | null | BracketSearchCanceled): T | null {\n\tif (result instanceof BracketSearchCanceled) {\n\t\treturn null;\n\t}\n\treturn result;\n}\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\nimport { Emitter } from 'vs/base/common/event';\nimport * as strings from 'vs/base/common/strings';\nimport { Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\nimport { ApplyEditsResult, EndOfLinePreference, FindMatch, IInternalModelContentChange, ISingleEditOperationIdentifier, ITextBuffer, ITextSnapshot, ValidAnnotatedEditOperation, IValidEditOperation, SearchData } from 'vs/editor/common/model';\nimport { PieceTreeBase, StringBuffer } from 'vs/editor/common/model/pieceTreeTextBuffer/pieceTreeBase';\nimport { countEOL, StringEOL } from 'vs/editor/common/core/eolCounter';\nimport { TextChange } from 'vs/editor/common/core/textChange';\nimport { Disposable } from 'vs/base/common/lifecycle';\n\nexport interface IValidatedEditOperation {\n\tsortIndex: number;\n\tidentifier: ISingleEditOperationIdentifier | null;\n\trange: Range;\n\trangeOffset: number;\n\trangeLength: number;\n\ttext: string;\n\teolCount: number;\n\tfirstLineLength: number;\n\tlastLineLength: number;\n\tforceMoveMarkers: boolean;\n\tisAutoWhitespaceEdit: boolean;\n}\n\ninterface IReverseSingleEditOperation extends IValidEditOperation {\n\tsortIndex: number;\n}\n\nexport class PieceTreeTextBuffer extends Disposable implements ITextBuffer {\n\tprivate _pieceTree: PieceTreeBase;\n\tprivate readonly _BOM: string;\n\tprivate _mightContainRTL: boolean;\n\tprivate _mightContainUnusualLineTerminators: boolean;\n\tprivate _mightContainNonBasicASCII: boolean;\n\n\tprivate readonly _onDidChangeContent: Emitter = this._register(new Emitter());\n\n\tconstructor(chunks: StringBuffer[], BOM: string, eol: '\\r\\n' | '\\n', containsRTL: boolean, containsUnusualLineTerminators: boolean, isBasicASCII: boolean, eolNormalized: boolean) {\n\t\tsuper();\n\t\tthis._BOM = BOM;\n\t\tthis._mightContainNonBasicASCII = !isBasicASCII;\n\t\tthis._mightContainRTL = containsRTL;\n\t\tthis._mightContainUnusualLineTerminators = containsUnusualLineTerminators;\n\t\tthis._pieceTree = new PieceTreeBase(chunks, eol, eolNormalized);\n\t}\n\tpublic mightContainRTL(): boolean {\n\t\treturn this._mightContainRTL;\n\t}\n\tpublic mightContainUnusualLineTerminators(): boolean {\n\t\treturn this._mightContainUnusualLineTerminators;\n\t}\n\tpublic resetMightContainUnusualLineTerminators(): void {\n\t\tthis._mightContainUnusualLineTerminators = false;\n\t}\n\tpublic mightContainNonBasicASCII(): boolean {\n\t\treturn this._mightContainNonBasicASCII;\n\t}\n\tpublic getBOM(): string {\n\t\treturn this._BOM;\n\t}\n\tpublic getEOL(): '\\r\\n' | '\\n' {\n\t\treturn this._pieceTree.getEOL();\n\t}\n\n\tpublic createSnapshot(preserveBOM: boolean): ITextSnapshot {\n\t\treturn this._pieceTree.createSnapshot(preserveBOM ? this._BOM : '');\n\t}\n\n\tpublic getOffsetAt(lineNumber: number, column: number): number {\n\t\treturn this._pieceTree.getOffsetAt(lineNumber, column);\n\t}\n\n\tpublic getPositionAt(offset: number): Position {\n\t\treturn this._pieceTree.getPositionAt(offset);\n\t}\n\n\tpublic getRangeAt(start: number, length: number): Range {\n\t\tconst end = start + length;\n\t\tconst startPosition = this.getPositionAt(start);\n\t\tconst endPosition = this.getPositionAt(end);\n\t\treturn new Range(startPosition.lineNumber, startPosition.column, endPosition.lineNumber, endPosition.column);\n\t}\n\n\tpublic getValueInRange(range: Range, eol: EndOfLinePreference = EndOfLinePreference.TextDefined): string {\n\t\tif (range.isEmpty()) {\n\t\t\treturn '';\n\t\t}\n\n\t\tconst lineEnding = this._getEndOfLine(eol);\n\t\treturn this._pieceTree.getValueInRange(range, lineEnding);\n\t}\n\n\tpublic getValueLengthInRange(range: Range, eol: EndOfLinePreference = EndOfLinePreference.TextDefined): number {\n\t\tif (range.isEmpty()) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tif (range.startLineNumber === range.endLineNumber) {\n\t\t\treturn (range.endColumn - range.startColumn);\n\t\t}\n\n\t\tconst startOffset = this.getOffsetAt(range.startLineNumber, range.startColumn);\n\t\tconst endOffset = this.getOffsetAt(range.endLineNumber, range.endColumn);\n\n\t\t// offsets use the text EOL, so we need to compensate for length differences\n\t\t// if the requested EOL doesn't match the text EOL\n\t\tlet eolOffsetCompensation = 0;\n\t\tconst desiredEOL = this._getEndOfLine(eol);\n\t\tconst actualEOL = this.getEOL();\n\t\tif (desiredEOL.length !== actualEOL.length) {\n\t\t\tconst delta = desiredEOL.length - actualEOL.length;\n\t\t\tconst eolCount = range.endLineNumber - range.startLineNumber;\n\t\t\teolOffsetCompensation = delta * eolCount;\n\t\t}\n\n\t\treturn endOffset - startOffset + eolOffsetCompensation;\n\t}\n\n\tpublic getCharacterCountInRange(range: Range, eol: EndOfLinePreference = EndOfLinePreference.TextDefined): number {\n\t\tif (this._mightContainNonBasicASCII) {\n\t\t\t// we must count by iterating\n\n\t\t\tlet result = 0;\n\n\t\t\tconst fromLineNumber = range.startLineNumber;\n\t\t\tconst toLineNumber = range.endLineNumber;\n\t\t\tfor (let lineNumber = fromLineNumber; lineNumber <= toLineNumber; lineNumber++) {\n\t\t\t\tconst lineContent = this.getLineContent(lineNumber);\n\t\t\t\tconst fromOffset = (lineNumber === fromLineNumber ? range.startColumn - 1 : 0);\n\t\t\t\tconst toOffset = (lineNumber === toLineNumber ? range.endColumn - 1 : lineContent.length);\n\n\t\t\t\tfor (let offset = fromOffset; offset < toOffset; offset++) {\n\t\t\t\t\tif (strings.isHighSurrogate(lineContent.charCodeAt(offset))) {\n\t\t\t\t\t\tresult = result + 1;\n\t\t\t\t\t\toffset = offset + 1;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tresult = result + 1;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tresult += this._getEndOfLine(eol).length * (toLineNumber - fromLineNumber);\n\n\t\t\treturn result;\n\t\t}\n\n\t\treturn this.getValueLengthInRange(range, eol);\n\t}\n\n\tpublic getLength(): number {\n\t\treturn this._pieceTree.getLength();\n\t}\n\n\tpublic getLineCount(): number {\n\t\treturn this._pieceTree.getLineCount();\n\t}\n\n\tpublic getLinesContent(): string[] {\n\t\treturn this._pieceTree.getLinesContent();\n\t}\n\n\tpublic getLineContent(lineNumber: number): string {\n\t\treturn this._pieceTree.getLineContent(lineNumber);\n\t}\n\n\tpublic getLineCharCode(lineNumber: number, index: number): number {\n\t\treturn this._pieceTree.getLineCharCode(lineNumber, index);\n\t}\n\n\tpublic getLineLength(lineNumber: number): number {\n\t\treturn this._pieceTree.getLineLength(lineNumber);\n\t}\n\n\tpublic getLineFirstNonWhitespaceColumn(lineNumber: number): number {\n\t\tconst result = strings.firstNonWhitespaceIndex(this.getLineContent(lineNumber));\n\t\tif (result === -1) {\n\t\t\treturn 0;\n\t\t}\n\t\treturn result + 1;\n\t}\n\n\tpublic getLineLastNonWhitespaceColumn(lineNumber: number): number {\n\t\tconst result = strings.lastNonWhitespaceIndex(this.getLineContent(lineNumber));\n\t\tif (result === -1) {\n\t\t\treturn 0;\n\t\t}\n\t\treturn result + 2;\n\t}\n\n\tprivate _getEndOfLine(eol: EndOfLinePreference): string {\n\t\tswitch (eol) {\n\t\t\tcase EndOfLinePreference.LF:\n\t\t\t\treturn '\\n';\n\t\t\tcase EndOfLinePreference.CRLF:\n\t\t\t\treturn '\\r\\n';\n\t\t\tcase EndOfLinePreference.TextDefined:\n\t\t\t\treturn this.getEOL();\n\t\t\tdefault:\n\t\t\t\tthrow new Error('Unknown EOL preference');\n\t\t}\n\t}\n\n\tpublic setEOL(newEOL: '\\r\\n' | '\\n'): void {\n\t\tthis._pieceTree.setEOL(newEOL);\n\t}\n\n\tpublic applyEdits(rawOperations: ValidAnnotatedEditOperation[], recordTrimAutoWhitespace: boolean, computeUndoEdits: boolean): ApplyEditsResult {\n\t\tlet mightContainRTL = this._mightContainRTL;\n\t\tlet mightContainUnusualLineTerminators = this._mightContainUnusualLineTerminators;\n\t\tlet mightContainNonBasicASCII = this._mightContainNonBasicASCII;\n\t\tlet canReduceOperations = true;\n\n\t\tlet operations: IValidatedEditOperation[] = [];\n\t\tfor (let i = 0; i < rawOperations.length; i++) {\n\t\t\tconst op = rawOperations[i];\n\t\t\tif (canReduceOperations && op._isTracked) {\n\t\t\t\tcanReduceOperations = false;\n\t\t\t}\n\t\t\tconst validatedRange = op.range;\n\t\t\tif (op.text) {\n\t\t\t\tlet textMightContainNonBasicASCII = true;\n\t\t\t\tif (!mightContainNonBasicASCII) {\n\t\t\t\t\ttextMightContainNonBasicASCII = !strings.isBasicASCII(op.text);\n\t\t\t\t\tmightContainNonBasicASCII = textMightContainNonBasicASCII;\n\t\t\t\t}\n\t\t\t\tif (!mightContainRTL && textMightContainNonBasicASCII) {\n\t\t\t\t\t// check if the new inserted text contains RTL\n\t\t\t\t\tmightContainRTL = strings.containsRTL(op.text);\n\t\t\t\t}\n\t\t\t\tif (!mightContainUnusualLineTerminators && textMightContainNonBasicASCII) {\n\t\t\t\t\t// check if the new inserted text contains unusual line terminators\n\t\t\t\t\tmightContainUnusualLineTerminators = strings.containsUnusualLineTerminators(op.text);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet validText = '';\n\t\t\tlet eolCount = 0;\n\t\t\tlet firstLineLength = 0;\n\t\t\tlet lastLineLength = 0;\n\t\t\tif (op.text) {\n\t\t\t\tlet strEOL: StringEOL;\n\t\t\t\t[eolCount, firstLineLength, lastLineLength, strEOL] = countEOL(op.text);\n\n\t\t\t\tconst bufferEOL = this.getEOL();\n\t\t\t\tconst expectedStrEOL = (bufferEOL === '\\r\\n' ? StringEOL.CRLF : StringEOL.LF);\n\t\t\t\tif (strEOL === StringEOL.Unknown || strEOL === expectedStrEOL) {\n\t\t\t\t\tvalidText = op.text;\n\t\t\t\t} else {\n\t\t\t\t\tvalidText = op.text.replace(/\\r\\n|\\r|\\n/g, bufferEOL);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\toperations[i] = {\n\t\t\t\tsortIndex: i,\n\t\t\t\tidentifier: op.identifier || null,\n\t\t\t\trange: validatedRange,\n\t\t\t\trangeOffset: this.getOffsetAt(validatedRange.startLineNumber, validatedRange.startColumn),\n\t\t\t\trangeLength: this.getValueLengthInRange(validatedRange),\n\t\t\t\ttext: validText,\n\t\t\t\teolCount: eolCount,\n\t\t\t\tfirstLineLength: firstLineLength,\n\t\t\t\tlastLineLength: lastLineLength,\n\t\t\t\tforceMoveMarkers: Boolean(op.forceMoveMarkers),\n\t\t\t\tisAutoWhitespaceEdit: op.isAutoWhitespaceEdit || false\n\t\t\t};\n\t\t}\n\n\t\t// Sort operations ascending\n\t\toperations.sort(PieceTreeTextBuffer._sortOpsAscending);\n\n\t\tlet hasTouchingRanges = false;\n\t\tfor (let i = 0, count = operations.length - 1; i < count; i++) {\n\t\t\tconst rangeEnd = operations[i].range.getEndPosition();\n\t\t\tconst nextRangeStart = operations[i + 1].range.getStartPosition();\n\n\t\t\tif (nextRangeStart.isBeforeOrEqual(rangeEnd)) {\n\t\t\t\tif (nextRangeStart.isBefore(rangeEnd)) {\n\t\t\t\t\t// overlapping ranges\n\t\t\t\t\tthrow new Error('Overlapping ranges are not allowed!');\n\t\t\t\t}\n\t\t\t\thasTouchingRanges = true;\n\t\t\t}\n\t\t}\n\n\t\tif (canReduceOperations) {\n\t\t\toperations = this._reduceOperations(operations);\n\t\t}\n\n\t\t// Delta encode operations\n\t\tconst reverseRanges = (computeUndoEdits || recordTrimAutoWhitespace ? PieceTreeTextBuffer._getInverseEditRanges(operations) : []);\n\t\tconst newTrimAutoWhitespaceCandidates: { lineNumber: number; oldContent: string }[] = [];\n\t\tif (recordTrimAutoWhitespace) {\n\t\t\tfor (let i = 0; i < operations.length; i++) {\n\t\t\t\tconst op = operations[i];\n\t\t\t\tconst reverseRange = reverseRanges[i];\n\n\t\t\t\tif (op.isAutoWhitespaceEdit && op.range.isEmpty()) {\n\t\t\t\t\t// Record already the future line numbers that might be auto whitespace removal candidates on next edit\n\t\t\t\t\tfor (let lineNumber = reverseRange.startLineNumber; lineNumber <= reverseRange.endLineNumber; lineNumber++) {\n\t\t\t\t\t\tlet currentLineContent = '';\n\t\t\t\t\t\tif (lineNumber === reverseRange.startLineNumber) {\n\t\t\t\t\t\t\tcurrentLineContent = this.getLineContent(op.range.startLineNumber);\n\t\t\t\t\t\t\tif (strings.firstNonWhitespaceIndex(currentLineContent) !== -1) {\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tnewTrimAutoWhitespaceCandidates.push({ lineNumber: lineNumber, oldContent: currentLineContent });\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tlet reverseOperations: IReverseSingleEditOperation[] | null = null;\n\t\tif (computeUndoEdits) {\n\n\t\t\tlet reverseRangeDeltaOffset = 0;\n\t\t\treverseOperations = [];\n\t\t\tfor (let i = 0; i < operations.length; i++) {\n\t\t\t\tconst op = operations[i];\n\t\t\t\tconst reverseRange = reverseRanges[i];\n\t\t\t\tconst bufferText = this.getValueInRange(op.range);\n\t\t\t\tconst reverseRangeOffset = op.rangeOffset + reverseRangeDeltaOffset;\n\t\t\t\treverseRangeDeltaOffset += (op.text.length - bufferText.length);\n\n\t\t\t\treverseOperations[i] = {\n\t\t\t\t\tsortIndex: op.sortIndex,\n\t\t\t\t\tidentifier: op.identifier,\n\t\t\t\t\trange: reverseRange,\n\t\t\t\t\ttext: bufferText,\n\t\t\t\t\ttextChange: new TextChange(op.rangeOffset, bufferText, reverseRangeOffset, op.text)\n\t\t\t\t};\n\t\t\t}\n\n\t\t\t// Can only sort reverse operations when the order is not significant\n\t\t\tif (!hasTouchingRanges) {\n\t\t\t\treverseOperations.sort((a, b) => a.sortIndex - b.sortIndex);\n\t\t\t}\n\t\t}\n\n\n\t\tthis._mightContainRTL = mightContainRTL;\n\t\tthis._mightContainUnusualLineTerminators = mightContainUnusualLineTerminators;\n\t\tthis._mightContainNonBasicASCII = mightContainNonBasicASCII;\n\n\t\tconst contentChanges = this._doApplyEdits(operations);\n\n\t\tlet trimAutoWhitespaceLineNumbers: number[] | null = null;\n\t\tif (recordTrimAutoWhitespace && newTrimAutoWhitespaceCandidates.length > 0) {\n\t\t\t// sort line numbers auto whitespace removal candidates for next edit descending\n\t\t\tnewTrimAutoWhitespaceCandidates.sort((a, b) => b.lineNumber - a.lineNumber);\n\n\t\t\ttrimAutoWhitespaceLineNumbers = [];\n\t\t\tfor (let i = 0, len = newTrimAutoWhitespaceCandidates.length; i < len; i++) {\n\t\t\t\tconst lineNumber = newTrimAutoWhitespaceCandidates[i].lineNumber;\n\t\t\t\tif (i > 0 && newTrimAutoWhitespaceCandidates[i - 1].lineNumber === lineNumber) {\n\t\t\t\t\t// Do not have the same line number twice\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst prevContent = newTrimAutoWhitespaceCandidates[i].oldContent;\n\t\t\t\tconst lineContent = this.getLineContent(lineNumber);\n\n\t\t\t\tif (lineContent.length === 0 || lineContent === prevContent || strings.firstNonWhitespaceIndex(lineContent) !== -1) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\ttrimAutoWhitespaceLineNumbers.push(lineNumber);\n\t\t\t}\n\t\t}\n\n\t\tthis._onDidChangeContent.fire();\n\n\t\treturn new ApplyEditsResult(\n\t\t\treverseOperations,\n\t\t\tcontentChanges,\n\t\t\ttrimAutoWhitespaceLineNumbers\n\t\t);\n\t}\n\n\t/**\n\t * Transform operations such that they represent the same logic edit,\n\t * but that they also do not cause OOM crashes.\n\t */\n\tprivate _reduceOperations(operations: IValidatedEditOperation[]): IValidatedEditOperation[] {\n\t\tif (operations.length < 1000) {\n\t\t\t// We know from empirical testing that a thousand edits work fine regardless of their shape.\n\t\t\treturn operations;\n\t\t}\n\n\t\t// At one point, due to how events are emitted and how each operation is handled,\n\t\t// some operations can trigger a high amount of temporary string allocations,\n\t\t// that will immediately get edited again.\n\t\t// e.g. a formatter inserting ridiculous ammounts of \\n on a model with a single line\n\t\t// Therefore, the strategy is to collapse all the operations into a huge single edit operation\n\t\treturn [this._toSingleEditOperation(operations)];\n\t}\n\n\t_toSingleEditOperation(operations: IValidatedEditOperation[]): IValidatedEditOperation {\n\t\tlet forceMoveMarkers = false;\n\t\tconst firstEditRange = operations[0].range;\n\t\tconst lastEditRange = operations[operations.length - 1].range;\n\t\tconst entireEditRange = new Range(firstEditRange.startLineNumber, firstEditRange.startColumn, lastEditRange.endLineNumber, lastEditRange.endColumn);\n\t\tlet lastEndLineNumber = firstEditRange.startLineNumber;\n\t\tlet lastEndColumn = firstEditRange.startColumn;\n\t\tconst result: string[] = [];\n\n\t\tfor (let i = 0, len = operations.length; i < len; i++) {\n\t\t\tconst operation = operations[i];\n\t\t\tconst range = operation.range;\n\n\t\t\tforceMoveMarkers = forceMoveMarkers || operation.forceMoveMarkers;\n\n\t\t\t// (1) -- Push old text\n\t\t\tresult.push(this.getValueInRange(new Range(lastEndLineNumber, lastEndColumn, range.startLineNumber, range.startColumn)));\n\n\t\t\t// (2) -- Push new text\n\t\t\tif (operation.text.length > 0) {\n\t\t\t\tresult.push(operation.text);\n\t\t\t}\n\n\t\t\tlastEndLineNumber = range.endLineNumber;\n\t\t\tlastEndColumn = range.endColumn;\n\t\t}\n\n\t\tconst text = result.join('');\n\t\tconst [eolCount, firstLineLength, lastLineLength] = countEOL(text);\n\n\t\treturn {\n\t\t\tsortIndex: 0,\n\t\t\tidentifier: operations[0].identifier,\n\t\t\trange: entireEditRange,\n\t\t\trangeOffset: this.getOffsetAt(entireEditRange.startLineNumber, entireEditRange.startColumn),\n\t\t\trangeLength: this.getValueLengthInRange(entireEditRange, EndOfLinePreference.TextDefined),\n\t\t\ttext: text,\n\t\t\teolCount: eolCount,\n\t\t\tfirstLineLength: firstLineLength,\n\t\t\tlastLineLength: lastLineLength,\n\t\t\tforceMoveMarkers: forceMoveMarkers,\n\t\t\tisAutoWhitespaceEdit: false\n\t\t};\n\t}\n\n\tprivate _doApplyEdits(operations: IValidatedEditOperation[]): IInternalModelContentChange[] {\n\t\toperations.sort(PieceTreeTextBuffer._sortOpsDescending);\n\n\t\tconst contentChanges: IInternalModelContentChange[] = [];\n\n\t\t// operations are from bottom to top\n\t\tfor (let i = 0; i < operations.length; i++) {\n\t\t\tconst op = operations[i];\n\n\t\t\tconst startLineNumber = op.range.startLineNumber;\n\t\t\tconst startColumn = op.range.startColumn;\n\t\t\tconst endLineNumber = op.range.endLineNumber;\n\t\t\tconst endColumn = op.range.endColumn;\n\n\t\t\tif (startLineNumber === endLineNumber && startColumn === endColumn && op.text.length === 0) {\n\t\t\t\t// no-op\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (op.text) {\n\t\t\t\t// replacement\n\t\t\t\tthis._pieceTree.delete(op.rangeOffset, op.rangeLength);\n\t\t\t\tthis._pieceTree.insert(op.rangeOffset, op.text, true);\n\n\t\t\t} else {\n\t\t\t\t// deletion\n\t\t\t\tthis._pieceTree.delete(op.rangeOffset, op.rangeLength);\n\t\t\t}\n\n\t\t\tconst contentChangeRange = new Range(startLineNumber, startColumn, endLineNumber, endColumn);\n\t\t\tcontentChanges.push({\n\t\t\t\trange: contentChangeRange,\n\t\t\t\trangeLength: op.rangeLength,\n\t\t\t\ttext: op.text,\n\t\t\t\trangeOffset: op.rangeOffset,\n\t\t\t\tforceMoveMarkers: op.forceMoveMarkers\n\t\t\t});\n\t\t}\n\t\treturn contentChanges;\n\t}\n\n\tfindMatchesLineByLine(searchRange: Range, searchData: SearchData, captureMatches: boolean, limitResultCount: number): FindMatch[] {\n\t\treturn this._pieceTree.findMatchesLineByLine(searchRange, searchData, captureMatches, limitResultCount);\n\t}\n\n\t/**\n\t * Assumes `operations` are validated and sorted ascending\n\t */\n\tpublic static _getInverseEditRanges(operations: IValidatedEditOperation[]): Range[] {\n\t\tconst result: Range[] = [];\n\n\t\tlet prevOpEndLineNumber: number = 0;\n\t\tlet prevOpEndColumn: number = 0;\n\t\tlet prevOp: IValidatedEditOperation | null = null;\n\t\tfor (let i = 0, len = operations.length; i < len; i++) {\n\t\t\tconst op = operations[i];\n\n\t\t\tlet startLineNumber: number;\n\t\t\tlet startColumn: number;\n\n\t\t\tif (prevOp) {\n\t\t\t\tif (prevOp.range.endLineNumber === op.range.startLineNumber) {\n\t\t\t\t\tstartLineNumber = prevOpEndLineNumber;\n\t\t\t\t\tstartColumn = prevOpEndColumn + (op.range.startColumn - prevOp.range.endColumn);\n\t\t\t\t} else {\n\t\t\t\t\tstartLineNumber = prevOpEndLineNumber + (op.range.startLineNumber - prevOp.range.endLineNumber);\n\t\t\t\t\tstartColumn = op.range.startColumn;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tstartLineNumber = op.range.startLineNumber;\n\t\t\t\tstartColumn = op.range.startColumn;\n\t\t\t}\n\n\t\t\tlet resultRange: Range;\n\n\t\t\tif (op.text.length > 0) {\n\t\t\t\t// the operation inserts something\n\t\t\t\tconst lineCount = op.eolCount + 1;\n\n\t\t\t\tif (lineCount === 1) {\n\t\t\t\t\t// single line insert\n\t\t\t\t\tresultRange = new Range(startLineNumber, startColumn, startLineNumber, startColumn + op.firstLineLength);\n\t\t\t\t} else {\n\t\t\t\t\t// multi line insert\n\t\t\t\t\tresultRange = new Range(startLineNumber, startColumn, startLineNumber + lineCount - 1, op.lastLineLength + 1);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// There is nothing to insert\n\t\t\t\tresultRange = new Range(startLineNumber, startColumn, startLineNumber, startColumn);\n\t\t\t}\n\n\t\t\tprevOpEndLineNumber = resultRange.endLineNumber;\n\t\t\tprevOpEndColumn = resultRange.endColumn;\n\n\t\t\tresult.push(resultRange);\n\t\t\tprevOp = op;\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tprivate static _sortOpsAscending(a: IValidatedEditOperation, b: IValidatedEditOperation): number {\n\t\tconst r = Range.compareRangesUsingEnds(a.range, b.range);\n\t\tif (r === 0) {\n\t\t\treturn a.sortIndex - b.sortIndex;\n\t\t}\n\t\treturn r;\n\t}\n\n\tprivate static _sortOpsDescending(a: IValidatedEditOperation, b: IValidatedEditOperation): number {\n\t\tconst r = Range.compareRangesUsingEnds(a.range, b.range);\n\t\tif (r === 0) {\n\t\t\treturn b.sortIndex - a.sortIndex;\n\t\t}\n\t\treturn -r;\n\t}\n\t// #endregion\n}\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\nimport { CharCode } from 'vs/base/common/charCode';\nimport { IDisposable } from 'vs/base/common/lifecycle';\nimport * as strings from 'vs/base/common/strings';\nimport { DefaultEndOfLine, ITextBuffer, ITextBufferBuilder, ITextBufferFactory } from 'vs/editor/common/model';\nimport { StringBuffer, createLineStarts, createLineStartsFast } from 'vs/editor/common/model/pieceTreeTextBuffer/pieceTreeBase';\nimport { PieceTreeTextBuffer } from 'vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBuffer';\n\nclass PieceTreeTextBufferFactory implements ITextBufferFactory {\n\n\tconstructor(\n\t\tprivate readonly _chunks: StringBuffer[],\n\t\tprivate readonly _bom: string,\n\t\tprivate readonly _cr: number,\n\t\tprivate readonly _lf: number,\n\t\tprivate readonly _crlf: number,\n\t\tprivate readonly _containsRTL: boolean,\n\t\tprivate readonly _containsUnusualLineTerminators: boolean,\n\t\tprivate readonly _isBasicASCII: boolean,\n\t\tprivate readonly _normalizeEOL: boolean\n\t) { }\n\n\tprivate _getEOL(defaultEOL: DefaultEndOfLine): '\\r\\n' | '\\n' {\n\t\tconst totalEOLCount = this._cr + this._lf + this._crlf;\n\t\tconst totalCRCount = this._cr + this._crlf;\n\t\tif (totalEOLCount === 0) {\n\t\t\t// This is an empty file or a file with precisely one line\n\t\t\treturn (defaultEOL === DefaultEndOfLine.LF ? '\\n' : '\\r\\n');\n\t\t}\n\t\tif (totalCRCount > totalEOLCount / 2) {\n\t\t\t// More than half of the file contains \\r\\n ending lines\n\t\t\treturn '\\r\\n';\n\t\t}\n\t\t// At least one line more ends in \\n\n\t\treturn '\\n';\n\t}\n\n\tpublic create(defaultEOL: DefaultEndOfLine): { textBuffer: ITextBuffer; disposable: IDisposable } {\n\t\tconst eol = this._getEOL(defaultEOL);\n\t\tconst chunks = this._chunks;\n\n\t\tif (this._normalizeEOL &&\n\t\t\t((eol === '\\r\\n' && (this._cr > 0 || this._lf > 0))\n\t\t\t\t|| (eol === '\\n' && (this._cr > 0 || this._crlf > 0)))\n\t\t) {\n\t\t\t// Normalize pieces\n\t\t\tfor (let i = 0, len = chunks.length; i < len; i++) {\n\t\t\t\tconst str = chunks[i].buffer.replace(/\\r\\n|\\r|\\n/g, eol);\n\t\t\t\tconst newLineStart = createLineStartsFast(str);\n\t\t\t\tchunks[i] = new StringBuffer(str, newLineStart);\n\t\t\t}\n\t\t}\n\n\t\tconst textBuffer = new PieceTreeTextBuffer(chunks, this._bom, eol, this._containsRTL, this._containsUnusualLineTerminators, this._isBasicASCII, this._normalizeEOL);\n\t\treturn { textBuffer: textBuffer, disposable: textBuffer };\n\t}\n}\n\nexport class PieceTreeTextBufferBuilder implements ITextBufferBuilder {\n\tprivate readonly chunks: StringBuffer[];\n\tprivate BOM: string;\n\n\tprivate _hasPreviousChar: boolean;\n\tprivate _previousChar: number;\n\tprivate readonly _tmpLineStarts: number[];\n\n\tprivate cr: number;\n\tprivate lf: number;\n\tprivate crlf: number;\n\tprivate containsRTL: boolean;\n\tprivate containsUnusualLineTerminators: boolean;\n\tprivate isBasicASCII: boolean;\n\n\tconstructor() {\n\t\tthis.chunks = [];\n\t\tthis.BOM = '';\n\n\t\tthis._hasPreviousChar = false;\n\t\tthis._previousChar = 0;\n\t\tthis._tmpLineStarts = [];\n\n\t\tthis.cr = 0;\n\t\tthis.lf = 0;\n\t\tthis.crlf = 0;\n\t\tthis.containsRTL = false;\n\t\tthis.containsUnusualLineTerminators = false;\n\t\tthis.isBasicASCII = true;\n\t}\n\n\tpublic acceptChunk(chunk: string): void {\n\t\tif (chunk.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.chunks.length === 0) {\n\t\t\tif (strings.startsWithUTF8BOM(chunk)) {\n\t\t\t\tthis.BOM = strings.UTF8_BOM_CHARACTER;\n\t\t\t\tchunk = chunk.substr(1);\n\t\t\t}\n\t\t}\n\n\t\tconst lastChar = chunk.charCodeAt(chunk.length - 1);\n\t\tif (lastChar === CharCode.CarriageReturn || (lastChar >= 0xD800 && lastChar <= 0xDBFF)) {\n\t\t\t// last character is \\r or a high surrogate => keep it back\n\t\t\tthis._acceptChunk1(chunk.substr(0, chunk.length - 1), false);\n\t\t\tthis._hasPreviousChar = true;\n\t\t\tthis._previousChar = lastChar;\n\t\t} else {\n\t\t\tthis._acceptChunk1(chunk, false);\n\t\t\tthis._hasPreviousChar = false;\n\t\t\tthis._previousChar = lastChar;\n\t\t}\n\t}\n\n\tprivate _acceptChunk1(chunk: string, allowEmptyStrings: boolean): void {\n\t\tif (!allowEmptyStrings && chunk.length === 0) {\n\t\t\t// Nothing to do\n\t\t\treturn;\n\t\t}\n\n\t\tif (this._hasPreviousChar) {\n\t\t\tthis._acceptChunk2(String.fromCharCode(this._previousChar) + chunk);\n\t\t} else {\n\t\t\tthis._acceptChunk2(chunk);\n\t\t}\n\t}\n\n\tprivate _acceptChunk2(chunk: string): void {\n\t\tconst lineStarts = createLineStarts(this._tmpLineStarts, chunk);\n\n\t\tthis.chunks.push(new StringBuffer(chunk, lineStarts.lineStarts));\n\t\tthis.cr += lineStarts.cr;\n\t\tthis.lf += lineStarts.lf;\n\t\tthis.crlf += lineStarts.crlf;\n\n\t\tif (!lineStarts.isBasicASCII) {\n\t\t\t// this chunk contains non basic ASCII characters\n\t\t\tthis.isBasicASCII = false;\n\t\t\tif (!this.containsRTL) {\n\t\t\t\tthis.containsRTL = strings.containsRTL(chunk);\n\t\t\t}\n\t\t\tif (!this.containsUnusualLineTerminators) {\n\t\t\t\tthis.containsUnusualLineTerminators = strings.containsUnusualLineTerminators(chunk);\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic finish(normalizeEOL: boolean = true): PieceTreeTextBufferFactory {\n\t\tthis._finish();\n\t\treturn new PieceTreeTextBufferFactory(\n\t\t\tthis.chunks,\n\t\t\tthis.BOM,\n\t\t\tthis.cr,\n\t\t\tthis.lf,\n\t\t\tthis.crlf,\n\t\t\tthis.containsRTL,\n\t\t\tthis.containsUnusualLineTerminators,\n\t\t\tthis.isBasicASCII,\n\t\t\tnormalizeEOL\n\t\t);\n\t}\n\n\tprivate _finish(): void {\n\t\tif (this.chunks.length === 0) {\n\t\t\tthis._acceptChunk1('', true);\n\t\t}\n\n\t\tif (this._hasPreviousChar) {\n\t\t\tthis._hasPreviousChar = false;\n\t\t\t// recreate last chunk\n\t\t\tconst lastChunk = this.chunks[this.chunks.length - 1];\n\t\t\tlastChunk.buffer += String.fromCharCode(this._previousChar);\n\t\t\tconst newLineStarts = createLineStartsFast(lastChunk.buffer);\n\t\t\tlastChunk.lineStarts = newLineStarts;\n\t\t\tif (this._previousChar === CharCode.CarriageReturn) {\n\t\t\t\tthis.cr++;\n\t\t\t}\n\t\t}\n\t}\n}\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\nimport { VSBuffer } from 'vs/base/common/buffer';\nimport * as platform from 'vs/base/common/platform';\n\nexport interface IFullSemanticTokensDto {\n\tid: number;\n\ttype: 'full';\n\tdata: Uint32Array;\n}\n\nexport interface IDeltaSemanticTokensDto {\n\tid: number;\n\ttype: 'delta';\n\tdeltas: { start: number; deleteCount: number; data?: Uint32Array }[];\n}\n\nexport type ISemanticTokensDto = IFullSemanticTokensDto | IDeltaSemanticTokensDto;\n\nconst enum EncodedSemanticTokensType {\n\tFull = 1,\n\tDelta = 2\n}\n\nfunction reverseEndianness(arr: Uint8Array): void {\n\tfor (let i = 0, len = arr.length; i < len; i += 4) {\n\t\t// flip bytes 0<->3 and 1<->2\n\t\tconst b0 = arr[i + 0];\n\t\tconst b1 = arr[i + 1];\n\t\tconst b2 = arr[i + 2];\n\t\tconst b3 = arr[i + 3];\n\t\tarr[i + 0] = b3;\n\t\tarr[i + 1] = b2;\n\t\tarr[i + 2] = b1;\n\t\tarr[i + 3] = b0;\n\t}\n}\n\nfunction toLittleEndianBuffer(arr: Uint32Array): VSBuffer {\n\tconst uint8Arr = new Uint8Array(arr.buffer, arr.byteOffset, arr.length * 4);\n\tif (!platform.isLittleEndian()) {\n\t\t// the byte order must be changed\n\t\treverseEndianness(uint8Arr);\n\t}\n\treturn VSBuffer.wrap(uint8Arr);\n}\n\nexport function encodeSemanticTokensDto(semanticTokens: ISemanticTokensDto): VSBuffer {\n\tconst dest = new Uint32Array(encodeSemanticTokensDtoSize(semanticTokens));\n\tlet offset = 0;\n\tdest[offset++] = semanticTokens.id;\n\tif (semanticTokens.type === 'full') {\n\t\tdest[offset++] = EncodedSemanticTokensType.Full;\n\t\tdest[offset++] = semanticTokens.data.length;\n\t\tdest.set(semanticTokens.data, offset); offset += semanticTokens.data.length;\n\t} else {\n\t\tdest[offset++] = EncodedSemanticTokensType.Delta;\n\t\tdest[offset++] = semanticTokens.deltas.length;\n\t\tfor (const delta of semanticTokens.deltas) {\n\t\t\tdest[offset++] = delta.start;\n\t\t\tdest[offset++] = delta.deleteCount;\n\t\t\tif (delta.data) {\n\t\t\t\tdest[offset++] = delta.data.length;\n\t\t\t\tdest.set(delta.data, offset); offset += delta.data.length;\n\t\t\t} else {\n\t\t\t\tdest[offset++] = 0;\n\t\t\t}\n\t\t}\n\t}\n\treturn toLittleEndianBuffer(dest);\n}\n\nfunction encodeSemanticTokensDtoSize(semanticTokens: ISemanticTokensDto): number {\n\tlet result = 0;\n\tresult += (\n\t\t+ 1 // id\n\t\t+ 1 // type\n\t);\n\tif (semanticTokens.type === 'full') {\n\t\tresult += (\n\t\t\t+ 1 // data length\n\t\t\t+ semanticTokens.data.length\n\t\t);\n\t} else {\n\t\tresult += (\n\t\t\t+ 1 // delta count\n\t\t);\n\t\tresult += (\n\t\t\t+ 1 // start\n\t\t\t+ 1 // deleteCount\n\t\t\t+ 1 // data length\n\t\t) * semanticTokens.deltas.length;\n\t\tfor (const delta of semanticTokens.deltas) {\n\t\t\tif (delta.data) {\n\t\t\t\tresult += delta.data.length;\n\t\t\t}\n\t\t}\n\t}\n\treturn result;\n}\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\nimport { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { KeyCode } from 'vs/base/common/keyCodes';\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport * as platform from 'vs/base/common/platform';\nimport { ICodeEditor, IEditorMouseEvent, IMouseTarget } from 'vs/editor/browser/editorBrowser';\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\nimport { ICursorSelectionChangedEvent } from 'vs/editor/common/cursorEvents';\n\nfunction hasModifier(e: { ctrlKey: boolean; shiftKey: boolean; altKey: boolean; metaKey: boolean }, modifier: 'ctrlKey' | 'shiftKey' | 'altKey' | 'metaKey'): boolean {\n\treturn !!e[modifier];\n}\n\n/**\n * An event that encapsulates the various trigger modifiers logic needed for go to definition.\n */\nexport class ClickLinkMouseEvent {\n\n\tpublic readonly target: IMouseTarget;\n\tpublic readonly hasTriggerModifier: boolean;\n\tpublic readonly hasSideBySideModifier: boolean;\n\tpublic readonly isNoneOrSingleMouseDown: boolean;\n\tpublic readonly isLeftClick: boolean;\n\tpublic readonly isMiddleClick: boolean;\n\tpublic readonly isRightClick: boolean;\n\n\tconstructor(source: IEditorMouseEvent, opts: ClickLinkOptions) {\n\t\tthis.target = source.target;\n\t\tthis.isLeftClick = source.event.leftButton;\n\t\tthis.isMiddleClick = source.event.middleButton;\n\t\tthis.isRightClick = source.event.rightButton;\n\t\tthis.hasTriggerModifier = hasModifier(source.event, opts.triggerModifier);\n\t\tthis.hasSideBySideModifier = hasModifier(source.event, opts.triggerSideBySideModifier);\n\t\tthis.isNoneOrSingleMouseDown = (source.event.detail <= 1);\n\t}\n}\n\n/**\n * An event that encapsulates the various trigger modifiers logic needed for go to definition.\n */\nexport class ClickLinkKeyboardEvent {\n\n\tpublic readonly keyCodeIsTriggerKey: boolean;\n\tpublic readonly keyCodeIsSideBySideKey: boolean;\n\tpublic readonly hasTriggerModifier: boolean;\n\n\tconstructor(source: IKeyboardEvent, opts: ClickLinkOptions) {\n\t\tthis.keyCodeIsTriggerKey = (source.keyCode === opts.triggerKey);\n\t\tthis.keyCodeIsSideBySideKey = (source.keyCode === opts.triggerSideBySideKey);\n\t\tthis.hasTriggerModifier = hasModifier(source, opts.triggerModifier);\n\t}\n}\nexport type TriggerModifier = 'ctrlKey' | 'shiftKey' | 'altKey' | 'metaKey';\n\nexport class ClickLinkOptions {\n\n\tpublic readonly triggerKey: KeyCode;\n\tpublic readonly triggerModifier: TriggerModifier;\n\tpublic readonly triggerSideBySideKey: KeyCode;\n\tpublic readonly triggerSideBySideModifier: TriggerModifier;\n\n\tconstructor(\n\t\ttriggerKey: KeyCode,\n\t\ttriggerModifier: TriggerModifier,\n\t\ttriggerSideBySideKey: KeyCode,\n\t\ttriggerSideBySideModifier: TriggerModifier\n\t) {\n\t\tthis.triggerKey = triggerKey;\n\t\tthis.triggerModifier = triggerModifier;\n\t\tthis.triggerSideBySideKey = triggerSideBySideKey;\n\t\tthis.triggerSideBySideModifier = triggerSideBySideModifier;\n\t}\n\n\tpublic equals(other: ClickLinkOptions): boolean {\n\t\treturn (\n\t\t\tthis.triggerKey === other.triggerKey\n\t\t\t&& this.triggerModifier === other.triggerModifier\n\t\t\t&& this.triggerSideBySideKey === other.triggerSideBySideKey\n\t\t\t&& this.triggerSideBySideModifier === other.triggerSideBySideModifier\n\t\t);\n\t}\n}\n\nfunction createOptions(multiCursorModifier: 'altKey' | 'ctrlKey' | 'metaKey'): ClickLinkOptions {\n\tif (multiCursorModifier === 'altKey') {\n\t\tif (platform.isMacintosh) {\n\t\t\treturn new ClickLinkOptions(KeyCode.Meta, 'metaKey', KeyCode.Alt, 'altKey');\n\t\t}\n\t\treturn new ClickLinkOptions(KeyCode.Ctrl, 'ctrlKey', KeyCode.Alt, 'altKey');\n\t}\n\n\tif (platform.isMacintosh) {\n\t\treturn new ClickLinkOptions(KeyCode.Alt, 'altKey', KeyCode.Meta, 'metaKey');\n\t}\n\treturn new ClickLinkOptions(KeyCode.Alt, 'altKey', KeyCode.Ctrl, 'ctrlKey');\n}\n\nexport interface IClickLinkGestureOptions {\n\t/**\n\t * Return 0 if the mouse event should not be considered.\n\t */\n\textractLineNumberFromMouseEvent?: (e: ClickLinkMouseEvent) => number;\n}\n\nexport class ClickLinkGesture extends Disposable {\n\n\tprivate readonly _onMouseMoveOrRelevantKeyDown: Emitter<[ClickLinkMouseEvent, ClickLinkKeyboardEvent | null]> = this._register(new Emitter<[ClickLinkMouseEvent, ClickLinkKeyboardEvent | null]>());\n\tpublic readonly onMouseMoveOrRelevantKeyDown: Event<[ClickLinkMouseEvent, ClickLinkKeyboardEvent | null]> = this._onMouseMoveOrRelevantKeyDown.event;\n\n\tprivate readonly _onExecute: Emitter = this._register(new Emitter());\n\tpublic readonly onExecute: Event = this._onExecute.event;\n\n\tprivate readonly _onCancel: Emitter = this._register(new Emitter());\n\tpublic readonly onCancel: Event = this._onCancel.event;\n\n\tprivate readonly _editor: ICodeEditor;\n\tprivate readonly _extractLineNumberFromMouseEvent: (e: ClickLinkMouseEvent) => number;\n\tprivate _opts: ClickLinkOptions;\n\n\tprivate _lastMouseMoveEvent: ClickLinkMouseEvent | null;\n\tprivate _hasTriggerKeyOnMouseDown: boolean;\n\tprivate _lineNumberOnMouseDown: number;\n\n\tconstructor(editor: ICodeEditor, opts?: IClickLinkGestureOptions) {\n\t\tsuper();\n\n\t\tthis._editor = editor;\n\t\tthis._extractLineNumberFromMouseEvent = opts?.extractLineNumberFromMouseEvent ?? ((e) => e.target.position ? e.target.position.lineNumber : 0);\n\t\tthis._opts = createOptions(this._editor.getOption(EditorOption.multiCursorModifier));\n\n\t\tthis._lastMouseMoveEvent = null;\n\t\tthis._hasTriggerKeyOnMouseDown = false;\n\t\tthis._lineNumberOnMouseDown = 0;\n\n\t\tthis._register(this._editor.onDidChangeConfiguration((e) => {\n\t\t\tif (e.hasChanged(EditorOption.multiCursorModifier)) {\n\t\t\t\tconst newOpts = createOptions(this._editor.getOption(EditorOption.multiCursorModifier));\n\t\t\t\tif (this._opts.equals(newOpts)) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tthis._opts = newOpts;\n\t\t\t\tthis._lastMouseMoveEvent = null;\n\t\t\t\tthis._hasTriggerKeyOnMouseDown = false;\n\t\t\t\tthis._lineNumberOnMouseDown = 0;\n\t\t\t\tthis._onCancel.fire();\n\t\t\t}\n\t\t}));\n\t\tthis._register(this._editor.onMouseMove((e: IEditorMouseEvent) => this._onEditorMouseMove(new ClickLinkMouseEvent(e, this._opts))));\n\t\tthis._register(this._editor.onMouseDown((e: IEditorMouseEvent) => this._onEditorMouseDown(new ClickLinkMouseEvent(e, this._opts))));\n\t\tthis._register(this._editor.onMouseUp((e: IEditorMouseEvent) => this._onEditorMouseUp(new ClickLinkMouseEvent(e, this._opts))));\n\t\tthis._register(this._editor.onKeyDown((e: IKeyboardEvent) => this._onEditorKeyDown(new ClickLinkKeyboardEvent(e, this._opts))));\n\t\tthis._register(this._editor.onKeyUp((e: IKeyboardEvent) => this._onEditorKeyUp(new ClickLinkKeyboardEvent(e, this._opts))));\n\t\tthis._register(this._editor.onMouseDrag(() => this._resetHandler()));\n\n\t\tthis._register(this._editor.onDidChangeCursorSelection((e) => this._onDidChangeCursorSelection(e)));\n\t\tthis._register(this._editor.onDidChangeModel((e) => this._resetHandler()));\n\t\tthis._register(this._editor.onDidChangeModelContent(() => this._resetHandler()));\n\t\tthis._register(this._editor.onDidScrollChange((e) => {\n\t\t\tif (e.scrollTopChanged || e.scrollLeftChanged) {\n\t\t\t\tthis._resetHandler();\n\t\t\t}\n\t\t}));\n\t}\n\n\tprivate _onDidChangeCursorSelection(e: ICursorSelectionChangedEvent): void {\n\t\tif (e.selection && e.selection.startColumn !== e.selection.endColumn) {\n\t\t\tthis._resetHandler(); // immediately stop this feature if the user starts to select (https://github.com/microsoft/vscode/issues/7827)\n\t\t}\n\t}\n\n\tprivate _onEditorMouseMove(mouseEvent: ClickLinkMouseEvent): void {\n\t\tthis._lastMouseMoveEvent = mouseEvent;\n\n\t\tthis._onMouseMoveOrRelevantKeyDown.fire([mouseEvent, null]);\n\t}\n\n\tprivate _onEditorMouseDown(mouseEvent: ClickLinkMouseEvent): void {\n\t\t// We need to record if we had the trigger key on mouse down because someone might select something in the editor\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\n\t\t// release the mouse button without wanting to do the navigation.\n\t\t// With this flag we prevent goto definition if the mouse was down before the trigger key was pressed.\n\t\tthis._hasTriggerKeyOnMouseDown = mouseEvent.hasTriggerModifier;\n\t\tthis._lineNumberOnMouseDown = this._extractLineNumberFromMouseEvent(mouseEvent);\n\t}\n\n\tprivate _onEditorMouseUp(mouseEvent: ClickLinkMouseEvent): void {\n\t\tconst currentLineNumber = this._extractLineNumberFromMouseEvent(mouseEvent);\n\t\tif (this._hasTriggerKeyOnMouseDown && this._lineNumberOnMouseDown && this._lineNumberOnMouseDown === currentLineNumber) {\n\t\t\tthis._onExecute.fire(mouseEvent);\n\t\t}\n\t}\n\n\tprivate _onEditorKeyDown(e: ClickLinkKeyboardEvent): void {\n\t\tif (\n\t\t\tthis._lastMouseMoveEvent\n\t\t\t&& (\n\t\t\t\te.keyCodeIsTriggerKey // User just pressed Ctrl/Cmd (normal goto definition)\n\t\t\t\t|| (e.keyCodeIsSideBySideKey && e.hasTriggerModifier) // User pressed Ctrl/Cmd+Alt (goto definition to the side)\n\t\t\t)\n\t\t) {\n\t\t\tthis._onMouseMoveOrRelevantKeyDown.fire([this._lastMouseMoveEvent, e]);\n\t\t} else if (e.hasTriggerModifier) {\n\t\t\tthis._onCancel.fire(); // remove decorations if user holds another key with ctrl/cmd to prevent accident goto declaration\n\t\t}\n\t}\n\n\tprivate _onEditorKeyUp(e: ClickLinkKeyboardEvent): void {\n\t\tif (e.keyCodeIsTriggerKey) {\n\t\t\tthis._onCancel.fire();\n\t\t}\n\t}\n\n\tprivate _resetHandler(): void {\n\t\tthis._lastMouseMoveEvent = null;\n\t\tthis._hasTriggerKeyOnMouseDown = false;\n\t\tthis._onCancel.fire();\n\t}\n}\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\nimport { coalesce } from 'vs/base/common/arrays';\nimport { CancellationToken } from 'vs/base/common/cancellation';\nimport { IActiveCodeEditor, ICodeEditor } from 'vs/editor/browser/editorBrowser';\nimport { IModelDecoration } from 'vs/editor/common/model';\nimport { HoverStartSource, IHoverComputer } from 'vs/editor/contrib/hover/browser/hoverOperation';\nimport { HoverAnchor, HoverAnchorType, IEditorHoverParticipant, IHoverPart } from 'vs/editor/contrib/hover/browser/hoverTypes';\nimport { AsyncIterableObject } from 'vs/base/common/async';\n\nexport class ContentHoverComputer implements IHoverComputer {\n\n\tprivate _anchor: HoverAnchor | null = null;\n\tpublic get anchor(): HoverAnchor | null { return this._anchor; }\n\tpublic set anchor(value: HoverAnchor | null) { this._anchor = value; }\n\n\tprivate _shouldFocus: boolean = false;\n\tpublic get shouldFocus(): boolean { return this._shouldFocus; }\n\tpublic set shouldFocus(value: boolean) { this._shouldFocus = value; }\n\n\tprivate _source: HoverStartSource = HoverStartSource.Mouse;\n\tpublic get source(): HoverStartSource { return this._source; }\n\tpublic set source(value: HoverStartSource) { this._source = value; }\n\n\tprivate _insistOnKeepingHoverVisible: boolean = false;\n\tpublic get insistOnKeepingHoverVisible(): boolean { return this._insistOnKeepingHoverVisible; }\n\tpublic set insistOnKeepingHoverVisible(value: boolean) { this._insistOnKeepingHoverVisible = value; }\n\n\tconstructor(\n\t\tprivate readonly _editor: ICodeEditor,\n\t\tprivate readonly _participants: readonly IEditorHoverParticipant[]\n\t) {\n\t}\n\n\tprivate static _getLineDecorations(editor: IActiveCodeEditor, anchor: HoverAnchor): IModelDecoration[] {\n\t\tif (anchor.type !== HoverAnchorType.Range && !anchor.supportsMarkerHover) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst model = editor.getModel();\n\t\tconst lineNumber = anchor.range.startLineNumber;\n\n\t\tif (lineNumber > model.getLineCount()) {\n\t\t\t// invalid line\n\t\t\treturn [];\n\t\t}\n\n\t\tconst maxColumn = model.getLineMaxColumn(lineNumber);\n\n\t\treturn editor.getLineDecorations(lineNumber).filter((d) => {\n\t\t\tif (d.options.isWholeLine) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tconst startColumn = (d.range.startLineNumber === lineNumber) ? d.range.startColumn : 1;\n\t\t\tconst endColumn = (d.range.endLineNumber === lineNumber) ? d.range.endColumn : maxColumn;\n\n\t\t\tif (d.options.showIfCollapsed) {\n\t\t\t\t// Relax check around `showIfCollapsed` decorations to also include +/- 1 character\n\t\t\t\tif (startColumn > anchor.range.startColumn + 1 || anchor.range.endColumn - 1 > endColumn) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (startColumn > anchor.range.startColumn || anchor.range.endColumn > endColumn) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn true;\n\t\t});\n\t}\n\n\tpublic computeAsync(token: CancellationToken): AsyncIterableObject {\n\t\tconst anchor = this._anchor;\n\n\t\tif (!this._editor.hasModel() || !anchor) {\n\t\t\treturn AsyncIterableObject.EMPTY;\n\t\t}\n\n\t\tconst lineDecorations = ContentHoverComputer._getLineDecorations(this._editor, anchor);\n\n\t\treturn AsyncIterableObject.merge(\n\t\t\tthis._participants.map((participant) => {\n\t\t\t\tif (!participant.computeAsync) {\n\t\t\t\t\treturn AsyncIterableObject.EMPTY;\n\t\t\t\t}\n\t\t\t\treturn participant.computeAsync(anchor, lineDecorations, token);\n\t\t\t})\n\t\t);\n\t}\n\n\tpublic computeSync(): IHoverPart[] {\n\t\tif (!this._editor.hasModel() || !this._anchor) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst lineDecorations = ContentHoverComputer._getLineDecorations(this._editor, this._anchor);\n\n\t\tlet result: IHoverPart[] = [];\n\t\tfor (const participant of this._participants) {\n\t\t\tresult = result.concat(participant.computeSync(this._anchor, lineDecorations));\n\t\t}\n\n\t\treturn coalesce(result);\n\t}\n}\n\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\nimport { AsyncIterableObject, CancelableAsyncIterableObject, createCancelableAsyncIterable, RunOnceScheduler } from 'vs/base/common/async';\nimport { CancellationToken } from 'vs/base/common/cancellation';\nimport { onUnexpectedError } from 'vs/base/common/errors';\nimport { Emitter } from 'vs/base/common/event';\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\n\nexport interface IHoverComputer {\n\t/**\n\t * This is called after half the hover time\n\t */\n\tcomputeAsync?: (token: CancellationToken) => AsyncIterableObject;\n\t/**\n\t * This is called after all the hover time\n\t */\n\tcomputeSync?: () => T[];\n}\n\nconst enum HoverOperationState {\n\tIdle,\n\tFirstWait,\n\tSecondWait,\n\tWaitingForAsync = 3,\n\tWaitingForAsyncShowingLoading = 4,\n}\n\nexport const enum HoverStartMode {\n\tDelayed = 0,\n\tImmediate = 1\n}\n\nexport const enum HoverStartSource {\n\tMouse = 0,\n\tKeyboard = 1\n}\n\nexport class HoverResult {\n\tconstructor(\n\t\tpublic readonly value: T[],\n\t\tpublic readonly isComplete: boolean,\n\t\tpublic readonly hasLoadingMessage: boolean,\n\t) { }\n}\n\n/**\n * Computing the hover is very fine tuned.\n *\n * Suppose the hover delay is 300ms (the default). Then, when resting the mouse at an anchor:\n * - at 150ms, the async computation is triggered (i.e. semantic hover)\n * - if async results already come in, they are not rendered yet.\n * - at 300ms, the sync computation is triggered (i.e. decorations, markers)\n * - if there are sync or async results, they are rendered.\n * - at 900ms, if the async computation hasn't finished, a \"Loading...\" result is added.\n */\nexport class HoverOperation extends Disposable {\n\n\tprivate readonly _onResult = this._register(new Emitter>());\n\tpublic readonly onResult = this._onResult.event;\n\n\tprivate readonly _firstWaitScheduler = this._register(new RunOnceScheduler(() => this._triggerAsyncComputation(), 0));\n\tprivate readonly _secondWaitScheduler = this._register(new RunOnceScheduler(() => this._triggerSyncComputation(), 0));\n\tprivate readonly _loadingMessageScheduler = this._register(new RunOnceScheduler(() => this._triggerLoadingMessage(), 0));\n\n\tprivate _state = HoverOperationState.Idle;\n\tprivate _asyncIterable: CancelableAsyncIterableObject | null = null;\n\tprivate _asyncIterableDone: boolean = false;\n\tprivate _result: T[] = [];\n\n\tconstructor(\n\t\tprivate readonly _editor: ICodeEditor,\n\t\tprivate readonly _computer: IHoverComputer\n\t) {\n\t\tsuper();\n\t}\n\n\tpublic override dispose(): void {\n\t\tif (this._asyncIterable) {\n\t\t\tthis._asyncIterable.cancel();\n\t\t\tthis._asyncIterable = null;\n\t\t}\n\t\tsuper.dispose();\n\t}\n\n\tprivate get _hoverTime(): number {\n\t\treturn this._editor.getOption(EditorOption.hover).delay;\n\t}\n\n\tprivate get _firstWaitTime(): number {\n\t\treturn this._hoverTime / 2;\n\t}\n\n\tprivate get _secondWaitTime(): number {\n\t\treturn this._hoverTime - this._firstWaitTime;\n\t}\n\n\tprivate get _loadingMessageTime(): number {\n\t\treturn 3 * this._hoverTime;\n\t}\n\n\tprivate _setState(state: HoverOperationState, fireResult: boolean = true): void {\n\t\tthis._state = state;\n\t\tif (fireResult) {\n\t\t\tthis._fireResult();\n\t\t}\n\t}\n\n\tprivate _triggerAsyncComputation(): void {\n\t\tthis._setState(HoverOperationState.SecondWait);\n\t\tthis._secondWaitScheduler.schedule(this._secondWaitTime);\n\n\t\tif (this._computer.computeAsync) {\n\t\t\tthis._asyncIterableDone = false;\n\t\t\tthis._asyncIterable = createCancelableAsyncIterable(token => this._computer.computeAsync!(token));\n\n\t\t\t(async () => {\n\t\t\t\ttry {\n\t\t\t\t\tfor await (const item of this._asyncIterable!) {\n\t\t\t\t\t\tif (item) {\n\t\t\t\t\t\t\tthis._result.push(item);\n\t\t\t\t\t\t\tthis._fireResult();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tthis._asyncIterableDone = true;\n\n\t\t\t\t\tif (this._state === HoverOperationState.WaitingForAsync || this._state === HoverOperationState.WaitingForAsyncShowingLoading) {\n\t\t\t\t\t\tthis._setState(HoverOperationState.Idle);\n\t\t\t\t\t}\n\n\t\t\t\t} catch (e) {\n\t\t\t\t\tonUnexpectedError(e);\n\t\t\t\t}\n\t\t\t})();\n\n\t\t} else {\n\t\t\tthis._asyncIterableDone = true;\n\t\t}\n\t}\n\n\tprivate _triggerSyncComputation(): void {\n\t\tif (this._computer.computeSync) {\n\t\t\tthis._result = this._result.concat(this._computer.computeSync());\n\t\t}\n\t\tthis._setState(this._asyncIterableDone ? HoverOperationState.Idle : HoverOperationState.WaitingForAsync);\n\t}\n\n\tprivate _triggerLoadingMessage(): void {\n\t\tif (this._state === HoverOperationState.WaitingForAsync) {\n\t\t\tthis._setState(HoverOperationState.WaitingForAsyncShowingLoading);\n\t\t}\n\t}\n\n\tprivate _fireResult(): void {\n\t\tif (this._state === HoverOperationState.FirstWait || this._state === HoverOperationState.SecondWait) {\n\t\t\t// Do not send out results before the hover time\n\t\t\treturn;\n\t\t}\n\t\tconst isComplete = (this._state === HoverOperationState.Idle);\n\t\tconst hasLoadingMessage = (this._state === HoverOperationState.WaitingForAsyncShowingLoading);\n\t\tthis._onResult.fire(new HoverResult(this._result.slice(0), isComplete, hasLoadingMessage));\n\t}\n\n\tpublic start(mode: HoverStartMode): void {\n\t\tif (mode === HoverStartMode.Delayed) {\n\t\t\tif (this._state === HoverOperationState.Idle) {\n\t\t\t\tthis._setState(HoverOperationState.FirstWait);\n\t\t\t\tthis._firstWaitScheduler.schedule(this._firstWaitTime);\n\t\t\t\tthis._loadingMessageScheduler.schedule(this._loadingMessageTime);\n\t\t\t}\n\t\t} else {\n\t\t\tswitch (this._state) {\n\t\t\t\tcase HoverOperationState.Idle:\n\t\t\t\t\tthis._triggerAsyncComputation();\n\t\t\t\t\tthis._secondWaitScheduler.cancel();\n\t\t\t\t\tthis._triggerSyncComputation();\n\t\t\t\t\tbreak;\n\t\t\t\tcase HoverOperationState.SecondWait:\n\t\t\t\t\tthis._secondWaitScheduler.cancel();\n\t\t\t\t\tthis._triggerSyncComputation();\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic cancel(): void {\n\t\tthis._firstWaitScheduler.cancel();\n\t\tthis._secondWaitScheduler.cancel();\n\t\tthis._loadingMessageScheduler.cancel();\n\t\tif (this._asyncIterable) {\n\t\t\tthis._asyncIterable.cancel();\n\t\t\tthis._asyncIterable = null;\n\t\t}\n\t\tthis._result = [];\n\t\tthis._setState(HoverOperationState.Idle, false);\n\t}\n\n}\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\nimport { asArray } from 'vs/base/common/arrays';\nimport { IMarkdownString, isEmptyMarkdownString } from 'vs/base/common/htmlContent';\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\nimport { IHoverComputer } from 'vs/editor/contrib/hover/browser/hoverOperation';\nimport { GlyphMarginLane } from 'vs/editor/common/model';\n\nexport type LaneOrLineNumber = GlyphMarginLane | 'lineNo';\n\nexport interface IHoverMessage {\n\tvalue: IMarkdownString;\n}\n\nexport class MarginHoverComputer implements IHoverComputer {\n\n\tprivate _lineNumber: number = -1;\n\tprivate _laneOrLine: LaneOrLineNumber = GlyphMarginLane.Center;\n\n\tpublic get lineNumber(): number {\n\t\treturn this._lineNumber;\n\t}\n\n\tpublic set lineNumber(value: number) {\n\t\tthis._lineNumber = value;\n\t}\n\n\tpublic get lane(): LaneOrLineNumber {\n\t\treturn this._laneOrLine;\n\t}\n\n\tpublic set lane(value: LaneOrLineNumber) {\n\t\tthis._laneOrLine = value;\n\t}\n\n\tconstructor(\n\t\tprivate readonly _editor: ICodeEditor\n\t) {\n\t}\n\n\tpublic computeSync(): IHoverMessage[] {\n\n\t\tconst toHoverMessage = (contents: IMarkdownString): IHoverMessage => {\n\t\t\treturn {\n\t\t\t\tvalue: contents\n\t\t\t};\n\t\t};\n\n\t\tconst lineDecorations = this._editor.getLineDecorations(this._lineNumber);\n\n\t\tconst result: IHoverMessage[] = [];\n\t\tconst isLineHover = this._laneOrLine === 'lineNo';\n\t\tif (!lineDecorations) {\n\t\t\treturn result;\n\t\t}\n\n\t\tfor (const d of lineDecorations) {\n\t\t\tconst lane = d.options.glyphMargin?.position ?? GlyphMarginLane.Center;\n\t\t\tif (!isLineHover && lane !== this._laneOrLine) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst hoverMessage = isLineHover ? d.options.lineNumberHoverMessage : d.options.glyphMarginHoverMessage;\n\t\t\tif (!hoverMessage || isEmptyMarkdownString(hoverMessage)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tresult.push(...asArray(hoverMessage).map(toHoverMessage));\n\t\t}\n\n\t\treturn result;\n\t}\n}\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\nimport { ResizableHTMLElement } from 'vs/base/browser/ui/resizable/resizable';\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser';\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\nimport { IPosition, Position } from 'vs/editor/common/core/position';\nimport * as dom from 'vs/base/browser/dom';\n\nconst TOP_HEIGHT = 30;\nconst BOTTOM_HEIGHT = 24;\n\nexport abstract class ResizableContentWidget extends Disposable implements IContentWidget {\n\n\treadonly allowEditorOverflow: boolean = true;\n\treadonly suppressMouseDown: boolean = false;\n\n\tprotected readonly _resizableNode = this._register(new ResizableHTMLElement());\n\tprotected _contentPosition: IContentWidgetPosition | null = null;\n\n\tprivate _isResizing: boolean = false;\n\n\tconstructor(\n\t\tprotected readonly _editor: ICodeEditor,\n\t\tminimumSize: dom.IDimension = new dom.Dimension(10, 10)\n\t) {\n\t\tsuper();\n\t\tthis._resizableNode.domNode.style.position = 'absolute';\n\t\tthis._resizableNode.minSize = dom.Dimension.lift(minimumSize);\n\t\tthis._resizableNode.layout(minimumSize.height, minimumSize.width);\n\t\tthis._resizableNode.enableSashes(true, true, true, true);\n\t\tthis._register(this._resizableNode.onDidResize(e => {\n\t\t\tthis._resize(new dom.Dimension(e.dimension.width, e.dimension.height));\n\t\t\tif (e.done) {\n\t\t\t\tthis._isResizing = false;\n\t\t\t}\n\t\t}));\n\t\tthis._register(this._resizableNode.onDidWillResize(() => {\n\t\t\tthis._isResizing = true;\n\t\t}));\n\t}\n\n\tget isResizing() {\n\t\treturn this._isResizing;\n\t}\n\n\tabstract getId(): string;\n\n\tgetDomNode(): HTMLElement {\n\t\treturn this._resizableNode.domNode;\n\t}\n\n\tgetPosition(): IContentWidgetPosition | null {\n\t\treturn this._contentPosition;\n\t}\n\n\tget position(): Position | undefined {\n\t\treturn this._contentPosition?.position ? Position.lift(this._contentPosition.position) : undefined;\n\t}\n\n\tprotected _availableVerticalSpaceAbove(position: IPosition): number | undefined {\n\t\tconst editorDomNode = this._editor.getDomNode();\n\t\tconst mouseBox = this._editor.getScrolledVisiblePosition(position);\n\t\tif (!editorDomNode || !mouseBox) {\n\t\t\treturn;\n\t\t}\n\t\tconst editorBox = dom.getDomNodePagePosition(editorDomNode);\n\t\treturn editorBox.top + mouseBox.top - TOP_HEIGHT;\n\t}\n\n\tprotected _availableVerticalSpaceBelow(position: IPosition): number | undefined {\n\t\tconst editorDomNode = this._editor.getDomNode();\n\t\tconst mouseBox = this._editor.getScrolledVisiblePosition(position);\n\t\tif (!editorDomNode || !mouseBox) {\n\t\t\treturn;\n\t\t}\n\t\tconst editorBox = dom.getDomNodePagePosition(editorDomNode);\n\t\tconst bodyBox = dom.getClientArea(editorDomNode.ownerDocument.body);\n\t\tconst mouseBottom = editorBox.top + mouseBox.top + mouseBox.height;\n\t\treturn bodyBox.height - mouseBottom - BOTTOM_HEIGHT;\n\t}\n\n\tprotected _findPositionPreference(widgetHeight: number, showAtPosition: IPosition): ContentWidgetPositionPreference | undefined {\n\t\tconst maxHeightBelow = Math.min(this._availableVerticalSpaceBelow(showAtPosition) ?? Infinity, widgetHeight);\n\t\tconst maxHeightAbove = Math.min(this._availableVerticalSpaceAbove(showAtPosition) ?? Infinity, widgetHeight);\n\t\tconst maxHeight = Math.min(Math.max(maxHeightAbove, maxHeightBelow), widgetHeight);\n\t\tconst height = Math.min(widgetHeight, maxHeight);\n\t\tlet renderingAbove: ContentWidgetPositionPreference;\n\t\tif (this._editor.getOption(EditorOption.hover).above) {\n\t\t\trenderingAbove = height <= maxHeightAbove ? ContentWidgetPositionPreference.ABOVE : ContentWidgetPositionPreference.BELOW;\n\t\t} else {\n\t\t\trenderingAbove = height <= maxHeightBelow ? ContentWidgetPositionPreference.BELOW : ContentWidgetPositionPreference.ABOVE;\n\t\t}\n\t\tif (renderingAbove === ContentWidgetPositionPreference.ABOVE) {\n\t\t\tthis._resizableNode.enableSashes(true, true, false, false);\n\t\t} else {\n\t\t\tthis._resizableNode.enableSashes(false, true, true, false);\n\t\t}\n\t\treturn renderingAbove;\n\t}\n\n\tprotected _resize(dimension: dom.Dimension): void {\n\t\tthis._resizableNode.layout(dimension.height, dimension.width);\n\t}\n}\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\nimport { CancellationToken } from 'vs/base/common/cancellation';\nimport { CancellationError, onUnexpectedExternalError } from 'vs/base/common/errors';\nimport { DisposableStore } from 'vs/base/common/lifecycle';\nimport { IPosition, Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\nimport { LanguageFeatureRegistry } from 'vs/editor/common/languageFeatureRegistry';\nimport { InlayHint, InlayHintList, InlayHintsProvider, Command } from 'vs/editor/common/languages';\nimport { ITextModel } from 'vs/editor/common/model';\nimport { Schemas } from 'vs/base/common/network';\nimport { URI } from 'vs/base/common/uri';\n\nexport class InlayHintAnchor {\n\tconstructor(readonly range: Range, readonly direction: 'before' | 'after') { }\n}\n\nexport class InlayHintItem {\n\n\tprivate _isResolved: boolean = false;\n\tprivate _currentResolve?: Promise;\n\n\tconstructor(readonly hint: InlayHint, readonly anchor: InlayHintAnchor, readonly provider: InlayHintsProvider) { }\n\n\twith(delta: { anchor: InlayHintAnchor }): InlayHintItem {\n\t\tconst result = new InlayHintItem(this.hint, delta.anchor, this.provider);\n\t\tresult._isResolved = this._isResolved;\n\t\tresult._currentResolve = this._currentResolve;\n\t\treturn result;\n\t}\n\n\tasync resolve(token: CancellationToken): Promise {\n\t\tif (typeof this.provider.resolveInlayHint !== 'function') {\n\t\t\treturn;\n\t\t}\n\t\tif (this._currentResolve) {\n\t\t\t// wait for an active resolve operation and try again\n\t\t\t// when that's done.\n\t\t\tawait this._currentResolve;\n\t\t\tif (token.isCancellationRequested) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\treturn this.resolve(token);\n\t\t}\n\t\tif (!this._isResolved) {\n\t\t\tthis._currentResolve = this._doResolve(token)\n\t\t\t\t.finally(() => this._currentResolve = undefined);\n\t\t}\n\t\tawait this._currentResolve;\n\t}\n\n\tprivate async _doResolve(token: CancellationToken) {\n\t\ttry {\n\t\t\tconst newHint = await Promise.resolve(this.provider.resolveInlayHint!(this.hint, token));\n\t\t\tthis.hint.tooltip = newHint?.tooltip ?? this.hint.tooltip;\n\t\t\tthis.hint.label = newHint?.label ?? this.hint.label;\n\t\t\tthis.hint.textEdits = newHint?.textEdits ?? this.hint.textEdits;\n\t\t\tthis._isResolved = true;\n\t\t} catch (err) {\n\t\t\tonUnexpectedExternalError(err);\n\t\t\tthis._isResolved = false;\n\t\t}\n\t}\n}\n\nexport class InlayHintsFragments {\n\n\tprivate static _emptyInlayHintList: InlayHintList = Object.freeze({ dispose() { }, hints: [] });\n\n\tstatic async create(registry: LanguageFeatureRegistry, model: ITextModel, ranges: Range[], token: CancellationToken): Promise {\n\n\t\tconst data: [InlayHintList, InlayHintsProvider][] = [];\n\n\t\tconst promises = registry.ordered(model).reverse().map(provider => ranges.map(async range => {\n\t\t\ttry {\n\t\t\t\tconst result = await provider.provideInlayHints(model, range, token);\n\t\t\t\tif (result?.hints.length || provider.onDidChangeInlayHints) {\n\t\t\t\t\tdata.push([result ?? InlayHintsFragments._emptyInlayHintList, provider]);\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\tonUnexpectedExternalError(err);\n\t\t\t}\n\t\t}));\n\n\t\tawait Promise.all(promises.flat());\n\n\t\tif (token.isCancellationRequested || model.isDisposed()) {\n\t\t\tthrow new CancellationError();\n\t\t}\n\n\t\treturn new InlayHintsFragments(ranges, data, model);\n\t}\n\n\tprivate readonly _disposables = new DisposableStore();\n\n\treadonly items: readonly InlayHintItem[];\n\treadonly ranges: readonly Range[];\n\treadonly provider: Set;\n\n\tprivate constructor(ranges: Range[], data: [InlayHintList, InlayHintsProvider][], model: ITextModel) {\n\t\tthis.ranges = ranges;\n\t\tthis.provider = new Set();\n\t\tconst items: InlayHintItem[] = [];\n\t\tfor (const [list, provider] of data) {\n\t\t\tthis._disposables.add(list);\n\t\t\tthis.provider.add(provider);\n\n\t\t\tfor (const hint of list.hints) {\n\t\t\t\t// compute the range to which the item should be attached to\n\t\t\t\tconst position = model.validatePosition(hint.position);\n\t\t\t\tlet direction: 'before' | 'after' = 'before';\n\n\t\t\t\tconst wordRange = InlayHintsFragments._getRangeAtPosition(model, position);\n\t\t\t\tlet range: Range;\n\n\t\t\t\tif (wordRange.getStartPosition().isBefore(position)) {\n\t\t\t\t\trange = Range.fromPositions(wordRange.getStartPosition(), position);\n\t\t\t\t\tdirection = 'after';\n\t\t\t\t} else {\n\t\t\t\t\trange = Range.fromPositions(position, wordRange.getEndPosition());\n\t\t\t\t\tdirection = 'before';\n\t\t\t\t}\n\n\t\t\t\titems.push(new InlayHintItem(hint, new InlayHintAnchor(range, direction), provider));\n\t\t\t}\n\t\t}\n\t\tthis.items = items.sort((a, b) => Position.compare(a.hint.position, b.hint.position));\n\t}\n\n\tdispose(): void {\n\t\tthis._disposables.dispose();\n\t}\n\n\tprivate static _getRangeAtPosition(model: ITextModel, position: IPosition): Range {\n\t\tconst line = position.lineNumber;\n\t\tconst word = model.getWordAtPosition(position);\n\t\tif (word) {\n\t\t\t// always prefer the word range\n\t\t\treturn new Range(line, word.startColumn, line, word.endColumn);\n\t\t}\n\n\t\tmodel.tokenization.tokenizeIfCheap(line);\n\t\tconst tokens = model.tokenization.getLineTokens(line);\n\t\tconst offset = position.column - 1;\n\t\tconst idx = tokens.findTokenIndexAtOffset(offset);\n\n\t\tlet start = tokens.getStartOffset(idx);\n\t\tlet end = tokens.getEndOffset(idx);\n\n\t\tif (end - start === 1) {\n\t\t\t// single character token, when at its end try leading/trailing token instead\n\t\t\tif (start === offset && idx > 1) {\n\t\t\t\t// leading token\n\t\t\t\tstart = tokens.getStartOffset(idx - 1);\n\t\t\t\tend = tokens.getEndOffset(idx - 1);\n\t\t\t} else if (end === offset && idx < tokens.getCount() - 1) {\n\t\t\t\t// trailing token\n\t\t\t\tstart = tokens.getStartOffset(idx + 1);\n\t\t\t\tend = tokens.getEndOffset(idx + 1);\n\t\t\t}\n\t\t}\n\n\t\treturn new Range(line, start + 1, line, end + 1);\n\t}\n}\n\nexport function asCommandLink(command: Command): string {\n\treturn URI.from({\n\t\tscheme: Schemas.command,\n\t\tpath: command.id,\n\t\tquery: command.arguments && encodeURIComponent(JSON.stringify(command.arguments))\n\t}).toString();\n}\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\nimport { assertNever } from 'vs/base/common/assert';\nimport { DeferredPromise } from 'vs/base/common/async';\nimport { CancellationToken } from 'vs/base/common/cancellation';\nimport { SetMap } from 'vs/base/common/map';\nimport { onUnexpectedExternalError } from 'vs/base/common/errors';\nimport { IDisposable } from 'vs/base/common/lifecycle';\nimport { ISingleEditOperation } from 'vs/editor/common/core/editOperation';\nimport { Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\nimport { LanguageFeatureRegistry } from 'vs/editor/common/languageFeatureRegistry';\nimport { Command, InlineCompletion, InlineCompletionContext, InlineCompletionProviderGroupId, InlineCompletions, InlineCompletionsProvider } from 'vs/editor/common/languages';\nimport { ILanguageConfigurationService } from 'vs/editor/common/languages/languageConfigurationRegistry';\nimport { ITextModel } from 'vs/editor/common/model';\nimport { fixBracketsInLine } from 'vs/editor/common/model/bracketPairsTextModelPart/fixBrackets';\nimport { getReadonlyEmptyArray } from 'vs/editor/contrib/inlineCompletions/browser/utils';\nimport { SnippetParser, Text } from 'vs/editor/contrib/snippet/browser/snippetParser';\n\nexport async function provideInlineCompletions(\n\tregistry: LanguageFeatureRegistry,\n\tposition: Position,\n\tmodel: ITextModel,\n\tcontext: InlineCompletionContext,\n\ttoken: CancellationToken = CancellationToken.None,\n\tlanguageConfigurationService?: ILanguageConfigurationService,\n): Promise {\n\t// Important: Don't use position after the await calls, as the model could have been changed in the meantime!\n\tconst defaultReplaceRange = getDefaultRange(position, model);\n\tconst providers = registry.all(model);\n\n\tconst multiMap = new SetMap>();\n\tfor (const provider of providers) {\n\t\tif (provider.groupId) {\n\t\t\tmultiMap.add(provider.groupId, provider);\n\t\t}\n\t}\n\n\tfunction getPreferredProviders(provider: InlineCompletionsProvider): InlineCompletionsProvider[] {\n\t\tif (!provider.yieldsToGroupIds) { return []; }\n\t\tconst result: InlineCompletionsProvider[] = [];\n\t\tfor (const groupId of provider.yieldsToGroupIds || []) {\n\t\t\tconst providers = multiMap.get(groupId);\n\t\t\tfor (const p of providers) {\n\t\t\t\tresult.push(p);\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\ttype Result = Promise | null | undefined>;\n\tconst states = new Map>, Result>();\n\n\tconst seen = new Set>>();\n\tfunction findPreferredProviderCircle(provider: InlineCompletionsProvider, stack: InlineCompletionsProvider[]): InlineCompletionsProvider[] | undefined {\n\t\tstack = [...stack, provider];\n\t\tif (seen.has(provider)) { return stack; }\n\n\t\tseen.add(provider);\n\t\ttry {\n\t\t\tconst preferred = getPreferredProviders(provider);\n\t\t\tfor (const p of preferred) {\n\t\t\t\tconst c = findPreferredProviderCircle(p, stack);\n\t\t\t\tif (c) { return c; }\n\t\t\t}\n\t\t} finally {\n\t\t\tseen.delete(provider);\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tfunction processProvider(provider: InlineCompletionsProvider): Result {\n\t\tconst state = states.get(provider);\n\t\tif (state) {\n\t\t\treturn state;\n\t\t}\n\n\t\tconst circle = findPreferredProviderCircle(provider, []);\n\t\tif (circle) {\n\t\t\tonUnexpectedExternalError(new Error(`Inline completions: cyclic yield-to dependency detected. Path: ${circle.map(s => s.toString ? s.toString() : ('' + s)).join(' -> ')}`));\n\t\t}\n\n\t\tconst deferredPromise = new DeferredPromise | null | undefined>();\n\t\tstates.set(provider, deferredPromise.p);\n\n\t\t(async () => {\n\t\t\tif (!circle) {\n\t\t\t\tconst preferred = getPreferredProviders(provider);\n\t\t\t\tfor (const p of preferred) {\n\t\t\t\t\tconst result = await processProvider(p);\n\t\t\t\t\tif (result && result.items.length > 0) {\n\t\t\t\t\t\t// Skip provider\n\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst completions = await provider.provideInlineCompletions(model, position, context, token);\n\t\t\t\treturn completions;\n\t\t\t} catch (e) {\n\t\t\t\tonUnexpectedExternalError(e);\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t})().then(c => deferredPromise.complete(c), e => deferredPromise.error(e));\n\n\t\treturn deferredPromise.p;\n\t}\n\n\tconst providerResults = await Promise.all(providers.map(async provider => ({ provider, completions: await processProvider(provider) })));\n\n\tconst itemsByHash = new Map();\n\tconst lists: InlineCompletionList[] = [];\n\tfor (const result of providerResults) {\n\t\tconst completions = result.completions;\n\t\tif (!completions) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst list = new InlineCompletionList(completions, result.provider);\n\t\tlists.push(list);\n\n\t\tfor (const item of completions.items) {\n\t\t\tconst inlineCompletionItem = InlineCompletionItem.from(\n\t\t\t\titem,\n\t\t\t\tlist,\n\t\t\t\tdefaultReplaceRange,\n\t\t\t\tmodel,\n\t\t\t\tlanguageConfigurationService\n\t\t\t);\n\t\t\titemsByHash.set(inlineCompletionItem.hash(), inlineCompletionItem);\n\t\t}\n\t}\n\n\treturn new InlineCompletionProviderResult(Array.from(itemsByHash.values()), new Set(itemsByHash.keys()), lists);\n}\n\nexport class InlineCompletionProviderResult implements IDisposable {\n\n\tconstructor(\n\t\t/**\n\t\t * Free of duplicates.\n\t\t */\n\t\tpublic readonly completions: readonly InlineCompletionItem[],\n\t\tprivate readonly hashs: Set,\n\t\tprivate readonly providerResults: readonly InlineCompletionList[],\n\t) { }\n\n\tpublic has(item: InlineCompletionItem): boolean {\n\t\treturn this.hashs.has(item.hash());\n\t}\n\n\tdispose(): void {\n\t\tfor (const result of this.providerResults) {\n\t\t\tresult.removeRef();\n\t\t}\n\t}\n}\n\n/**\n * A ref counted pointer to the computed `InlineCompletions` and the `InlineCompletionsProvider` that\n * computed them.\n */\nexport class InlineCompletionList {\n\tprivate refCount = 1;\n\tconstructor(\n\t\tpublic readonly inlineCompletions: InlineCompletions,\n\t\tpublic readonly provider: InlineCompletionsProvider,\n\t) { }\n\n\taddRef(): void {\n\t\tthis.refCount++;\n\t}\n\n\tremoveRef(): void {\n\t\tthis.refCount--;\n\t\tif (this.refCount === 0) {\n\t\t\tthis.provider.freeInlineCompletions(this.inlineCompletions);\n\t\t}\n\t}\n}\n\nexport class InlineCompletionItem {\n\tpublic static from(\n\t\tinlineCompletion: InlineCompletion,\n\t\tsource: InlineCompletionList,\n\t\tdefaultReplaceRange: Range,\n\t\ttextModel: ITextModel,\n\t\tlanguageConfigurationService: ILanguageConfigurationService | undefined,\n\t) {\n\t\tlet insertText: string;\n\t\tlet snippetInfo: SnippetInfo | undefined;\n\t\tlet range = inlineCompletion.range ? Range.lift(inlineCompletion.range) : defaultReplaceRange;\n\n\t\tif (typeof inlineCompletion.insertText === 'string') {\n\t\t\tinsertText = inlineCompletion.insertText;\n\n\t\t\tif (languageConfigurationService && inlineCompletion.completeBracketPairs) {\n\t\t\t\tinsertText = closeBrackets(\n\t\t\t\t\tinsertText,\n\t\t\t\t\trange.getStartPosition(),\n\t\t\t\t\ttextModel,\n\t\t\t\t\tlanguageConfigurationService\n\t\t\t\t);\n\n\t\t\t\t// Modify range depending on if brackets are added or removed\n\t\t\t\tconst diff = insertText.length - inlineCompletion.insertText.length;\n\t\t\t\tif (diff !== 0) {\n\t\t\t\t\trange = new Range(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn + diff);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tsnippetInfo = undefined;\n\t\t} else if ('snippet' in inlineCompletion.insertText) {\n\t\t\tconst preBracketCompletionLength = inlineCompletion.insertText.snippet.length;\n\n\t\t\tif (languageConfigurationService && inlineCompletion.completeBracketPairs) {\n\t\t\t\tinlineCompletion.insertText.snippet = closeBrackets(\n\t\t\t\t\tinlineCompletion.insertText.snippet,\n\t\t\t\t\trange.getStartPosition(),\n\t\t\t\t\ttextModel,\n\t\t\t\t\tlanguageConfigurationService\n\t\t\t\t);\n\n\t\t\t\t// Modify range depending on if brackets are added or removed\n\t\t\t\tconst diff = inlineCompletion.insertText.snippet.length - preBracketCompletionLength;\n\t\t\t\tif (diff !== 0) {\n\t\t\t\t\trange = new Range(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn + diff);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst snippet = new SnippetParser().parse(inlineCompletion.insertText.snippet);\n\n\t\t\tif (snippet.children.length === 1 && snippet.children[0] instanceof Text) {\n\t\t\t\tinsertText = snippet.children[0].value;\n\t\t\t\tsnippetInfo = undefined;\n\t\t\t} else {\n\t\t\t\tinsertText = snippet.toString();\n\t\t\t\tsnippetInfo = {\n\t\t\t\t\tsnippet: inlineCompletion.insertText.snippet,\n\t\t\t\t\trange: range\n\t\t\t\t};\n\t\t\t}\n\t\t} else {\n\t\t\tassertNever(inlineCompletion.insertText);\n\t\t}\n\n\t\treturn new InlineCompletionItem(\n\t\t\tinsertText,\n\t\t\tinlineCompletion.command,\n\t\t\trange,\n\t\t\tinsertText,\n\t\t\tsnippetInfo,\n\t\t\tinlineCompletion.additionalTextEdits || getReadonlyEmptyArray(),\n\t\t\tinlineCompletion,\n\t\t\tsource,\n\t\t);\n\t}\n\n\tconstructor(\n\t\treadonly filterText: string,\n\t\treadonly command: Command | undefined,\n\t\treadonly range: Range,\n\t\treadonly insertText: string,\n\t\treadonly snippetInfo: SnippetInfo | undefined,\n\n\t\treadonly additionalTextEdits: readonly ISingleEditOperation[],\n\n\n\t\t/**\n\t\t * A reference to the original inline completion this inline completion has been constructed from.\n\t\t * Used for event data to ensure referential equality.\n\t\t*/\n\t\treadonly sourceInlineCompletion: InlineCompletion,\n\n\t\t/**\n\t\t * A reference to the original inline completion list this inline completion has been constructed from.\n\t\t * Used for event data to ensure referential equality.\n\t\t*/\n\t\treadonly source: InlineCompletionList,\n\t) {\n\t\tfilterText = filterText.replace(/\\r\\n|\\r/g, '\\n');\n\t\tinsertText = filterText.replace(/\\r\\n|\\r/g, '\\n');\n\t}\n\n\tpublic withRange(updatedRange: Range): InlineCompletionItem {\n\t\treturn new InlineCompletionItem(\n\t\t\tthis.filterText,\n\t\t\tthis.command,\n\t\t\tupdatedRange,\n\t\t\tthis.insertText,\n\t\t\tthis.snippetInfo,\n\t\t\tthis.additionalTextEdits,\n\t\t\tthis.sourceInlineCompletion,\n\t\t\tthis.source,\n\t\t);\n\t}\n\n\tpublic hash(): string {\n\t\treturn JSON.stringify({ insertText: this.insertText, range: this.range.toString() });\n\t}\n}\n\nexport interface SnippetInfo {\n\tsnippet: string;\n\t/* Could be different than the main range */\n\trange: Range;\n}\n\nfunction getDefaultRange(position: Position, model: ITextModel): Range {\n\tconst word = model.getWordAtPosition(position);\n\tconst maxColumn = model.getLineMaxColumn(position.lineNumber);\n\t// By default, always replace up until the end of the current line.\n\t// This default might be subject to change!\n\treturn word\n\t\t? new Range(position.lineNumber, word.startColumn, position.lineNumber, maxColumn)\n\t\t: Range.fromPositions(position, position.with(undefined, maxColumn));\n}\n\nfunction closeBrackets(text: string, position: Position, model: ITextModel, languageConfigurationService: ILanguageConfigurationService): string {\n\tconst lineStart = model.getLineContent(position.lineNumber).substring(0, position.column - 1);\n\tconst newLine = lineStart + text;\n\n\tconst newTokens = model.tokenization.tokenizeLineWithEdit(position, newLine.length - (position.column - 1), text);\n\tconst slicedTokens = newTokens?.sliceAndInflate(position.column - 1, newLine.length, 0);\n\tif (!slicedTokens) {\n\t\treturn text;\n\t}\n\n\tconst newText = fixBracketsInLine(slicedTokens, languageConfigurationService);\n\n\treturn newText;\n}\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\nimport { IHoverWidget, IUpdatableHoverContent, IUpdatableHoverOptions } from 'vs/base/browser/ui/hover/hover';\nimport { IHoverDelegate, IHoverDelegateOptions, IHoverDelegateTarget } from 'vs/base/browser/ui/hover/hoverDelegate';\nimport { HoverPosition } from 'vs/base/browser/ui/hover/hoverWidget';\nimport { CancellationTokenSource } from 'vs/base/common/cancellation';\nimport { isMarkdownString, type IMarkdownString } from 'vs/base/common/htmlContent';\nimport { IDisposable } from 'vs/base/common/lifecycle';\nimport { isFunction, isString } from 'vs/base/common/types';\nimport { localize } from 'vs/nls';\n\ntype IUpdatableHoverResolvedContent = IMarkdownString | string | HTMLElement | undefined;\n\nexport class UpdatableHoverWidget implements IDisposable {\n\n\tprivate _hoverWidget: IHoverWidget | undefined;\n\tprivate _cancellationTokenSource: CancellationTokenSource | undefined;\n\n\tconstructor(private hoverDelegate: IHoverDelegate, private target: IHoverDelegateTarget | HTMLElement, private fadeInAnimation: boolean) {\n\t}\n\n\tasync update(content: IUpdatableHoverContent, focus?: boolean, options?: IUpdatableHoverOptions): Promise {\n\t\tif (this._cancellationTokenSource) {\n\t\t\t// there's an computation ongoing, cancel it\n\t\t\tthis._cancellationTokenSource.dispose(true);\n\t\t\tthis._cancellationTokenSource = undefined;\n\t\t}\n\t\tif (this.isDisposed) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet resolvedContent;\n\t\tif (content === undefined || isString(content) || content instanceof HTMLElement) {\n\t\t\tresolvedContent = content;\n\t\t} else if (!isFunction(content.markdown)) {\n\t\t\tresolvedContent = content.markdown ?? content.markdownNotSupportedFallback;\n\t\t} else {\n\t\t\t// compute the content, potentially long-running\n\n\t\t\t// show 'Loading' if no hover is up yet\n\t\t\tif (!this._hoverWidget) {\n\t\t\t\tthis.show(localize('iconLabel.loading', \"Loading...\"), focus, options);\n\t\t\t}\n\n\t\t\t// compute the content\n\t\t\tthis._cancellationTokenSource = new CancellationTokenSource();\n\t\t\tconst token = this._cancellationTokenSource.token;\n\t\t\tresolvedContent = await content.markdown(token);\n\t\t\tif (resolvedContent === undefined) {\n\t\t\t\tresolvedContent = content.markdownNotSupportedFallback;\n\t\t\t}\n\n\t\t\tif (this.isDisposed || token.isCancellationRequested) {\n\t\t\t\t// either the widget has been closed in the meantime\n\t\t\t\t// or there has been a new call to `update`\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tthis.show(resolvedContent, focus, options);\n\t}\n\n\tprivate show(content: IUpdatableHoverResolvedContent, focus?: boolean, options?: IUpdatableHoverOptions): void {\n\t\tconst oldHoverWidget = this._hoverWidget;\n\n\t\tif (this.hasContent(content)) {\n\t\t\tconst hoverOptions: IHoverDelegateOptions = {\n\t\t\t\tcontent,\n\t\t\t\ttarget: this.target,\n\t\t\t\tappearance: {\n\t\t\t\t\tshowPointer: this.hoverDelegate.placement === 'element',\n\t\t\t\t\tskipFadeInAnimation: !this.fadeInAnimation || !!oldHoverWidget, // do not fade in if the hover is already showing\n\t\t\t\t},\n\t\t\t\tposition: {\n\t\t\t\t\thoverPosition: HoverPosition.BELOW,\n\t\t\t\t},\n\t\t\t\t...options\n\t\t\t};\n\n\t\t\tthis._hoverWidget = this.hoverDelegate.showHover(hoverOptions, focus);\n\t\t}\n\t\toldHoverWidget?.dispose();\n\t}\n\n\tprivate hasContent(content: IUpdatableHoverResolvedContent): content is NonNullable {\n\t\tif (!content) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (isMarkdownString(content)) {\n\t\t\treturn !!content.value;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tget isDisposed() {\n\t\treturn this._hoverWidget?.isDisposed;\n\t}\n\n\tdispose(): void {\n\t\tthis._hoverWidget?.dispose();\n\t\tthis._cancellationTokenSource?.dispose(true);\n\t\tthis._cancellationTokenSource = undefined;\n\t}\n}\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\nimport { addStandardDisposableListener, getDomNodePagePosition } from 'vs/base/browser/dom';\nimport { Action } from 'vs/base/common/actions';\nimport { Codicon } from 'vs/base/common/codicons';\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport { isIOS } from 'vs/base/common/platform';\nimport { ThemeIcon } from 'vs/base/common/themables';\nimport { IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser';\nimport { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditor/codeEditorWidget';\nimport { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditor/diffEditorWidget';\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\nimport { DetailedLineRangeMapping } from 'vs/editor/common/diff/rangeMapping';\nimport { EndOfLineSequence, ITextModel } from 'vs/editor/common/model';\nimport { localize } from 'vs/nls';\nimport { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';\nimport { IContextMenuService } from 'vs/platform/contextview/browser/contextView';\n\nexport class InlineDiffDeletedCodeMargin extends Disposable {\n\tprivate readonly _diffActions: HTMLElement;\n\n\tprivate _visibility: boolean = false;\n\n\tget visibility(): boolean {\n\t\treturn this._visibility;\n\t}\n\n\tset visibility(_visibility: boolean) {\n\t\tif (this._visibility !== _visibility) {\n\t\t\tthis._visibility = _visibility;\n\t\t\tthis._diffActions.style.visibility = _visibility ? 'visible' : 'hidden';\n\t\t}\n\t}\n\n\tconstructor(\n\t\tprivate readonly _getViewZoneId: () => string,\n\t\tprivate readonly _marginDomNode: HTMLElement,\n\t\tprivate readonly _modifiedEditor: CodeEditorWidget,\n\t\tprivate readonly _diff: DetailedLineRangeMapping,\n\t\tprivate readonly _editor: DiffEditorWidget,\n\t\tprivate readonly _viewLineCounts: number[],\n\t\tprivate readonly _originalTextModel: ITextModel,\n\t\tprivate readonly _contextMenuService: IContextMenuService,\n\t\tprivate readonly _clipboardService: IClipboardService,\n\t) {\n\t\tsuper();\n\n\t\t// make sure the diff margin shows above overlay.\n\t\tthis._marginDomNode.style.zIndex = '10';\n\n\t\tthis._diffActions = document.createElement('div');\n\t\tthis._diffActions.className = ThemeIcon.asClassName(Codicon.lightBulb) + ' lightbulb-glyph';\n\t\tthis._diffActions.style.position = 'absolute';\n\t\tconst lineHeight = this._modifiedEditor.getOption(EditorOption.lineHeight);\n\t\tthis._diffActions.style.right = '0px';\n\t\tthis._diffActions.style.visibility = 'hidden';\n\t\tthis._diffActions.style.height = `${lineHeight}px`;\n\t\tthis._diffActions.style.lineHeight = `${lineHeight}px`;\n\t\tthis._marginDomNode.appendChild(this._diffActions);\n\n\t\tlet currentLineNumberOffset = 0;\n\n\t\tconst useShadowDOM = _modifiedEditor.getOption(EditorOption.useShadowDOM) && !isIOS; // Do not use shadow dom on IOS #122035\n\t\tconst showContextMenu = (x: number, y: number) => {\n\t\t\tthis._contextMenuService.showContextMenu({\n\t\t\t\tdomForShadowRoot: useShadowDOM ? _modifiedEditor.getDomNode() ?? undefined : undefined,\n\t\t\t\tgetAnchor: () => ({ x, y }),\n\t\t\t\tgetActions: () => {\n\t\t\t\t\tconst actions: Action[] = [];\n\t\t\t\t\tconst isDeletion = _diff.modified.isEmpty;\n\n\t\t\t\t\t// default action\n\t\t\t\t\tactions.push(new Action(\n\t\t\t\t\t\t'diff.clipboard.copyDeletedContent',\n\t\t\t\t\t\tisDeletion\n\t\t\t\t\t\t\t? (_diff.original.length > 1\n\t\t\t\t\t\t\t\t? localize('diff.clipboard.copyDeletedLinesContent.label', \"Copy deleted lines\")\n\t\t\t\t\t\t\t\t: localize('diff.clipboard.copyDeletedLinesContent.single.label', \"Copy deleted line\"))\n\t\t\t\t\t\t\t: (_diff.original.length > 1\n\t\t\t\t\t\t\t\t? localize('diff.clipboard.copyChangedLinesContent.label', \"Copy changed lines\")\n\t\t\t\t\t\t\t\t: localize('diff.clipboard.copyChangedLinesContent.single.label', \"Copy changed line\")),\n\t\t\t\t\t\tundefined,\n\t\t\t\t\t\ttrue,\n\t\t\t\t\t\tasync () => {\n\t\t\t\t\t\t\tconst originalText = this._originalTextModel.getValueInRange(_diff.original.toExclusiveRange());\n\t\t\t\t\t\t\tawait this._clipboardService.writeText(originalText);\n\t\t\t\t\t\t}\n\t\t\t\t\t));\n\n\t\t\t\t\tif (_diff.original.length > 1) {\n\t\t\t\t\t\tactions.push(new Action(\n\t\t\t\t\t\t\t'diff.clipboard.copyDeletedLineContent',\n\t\t\t\t\t\t\tisDeletion\n\t\t\t\t\t\t\t\t? localize('diff.clipboard.copyDeletedLineContent.label', \"Copy deleted line ({0})\",\n\t\t\t\t\t\t\t\t\t_diff.original.startLineNumber + currentLineNumberOffset)\n\t\t\t\t\t\t\t\t: localize('diff.clipboard.copyChangedLineContent.label', \"Copy changed line ({0})\",\n\t\t\t\t\t\t\t\t\t_diff.original.startLineNumber + currentLineNumberOffset),\n\t\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t\ttrue,\n\t\t\t\t\t\t\tasync () => {\n\t\t\t\t\t\t\t\tlet lineContent = this._originalTextModel.getLineContent(_diff.original.startLineNumber + currentLineNumberOffset);\n\t\t\t\t\t\t\t\tif (lineContent === '') {\n\t\t\t\t\t\t\t\t\t// empty line -> new line\n\t\t\t\t\t\t\t\t\tconst eof = this._originalTextModel.getEndOfLineSequence();\n\t\t\t\t\t\t\t\t\tlineContent = eof === EndOfLineSequence.LF ? '\\n' : '\\r\\n';\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tawait this._clipboardService.writeText(lineContent);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t));\n\t\t\t\t\t}\n\t\t\t\t\tconst readOnly = _modifiedEditor.getOption(EditorOption.readOnly);\n\t\t\t\t\tif (!readOnly) {\n\t\t\t\t\t\tactions.push(new Action(\n\t\t\t\t\t\t\t'diff.inline.revertChange',\n\t\t\t\t\t\t\tlocalize('diff.inline.revertChange.label', \"Revert this change\"),\n\t\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t\ttrue,\n\t\t\t\t\t\t\tasync () => {\n\t\t\t\t\t\t\t\tthis._editor.revert(this._diff);\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\treturn actions;\n\t\t\t\t},\n\t\t\t\tautoSelectFirstItem: true\n\t\t\t});\n\t\t};\n\n\t\tthis._register(addStandardDisposableListener(this._diffActions, 'mousedown', e => {\n\t\t\tif (!e.leftButton) { return; }\n\n\t\t\tconst { top, height } = getDomNodePagePosition(this._diffActions);\n\t\t\tconst pad = Math.floor(lineHeight / 3);\n\t\t\te.preventDefault();\n\t\t\tshowContextMenu(e.posx, top + height + pad);\n\t\t}));\n\n\t\tthis._register(_modifiedEditor.onMouseMove((e: IEditorMouseEvent) => {\n\t\t\tif ((e.target.type === MouseTargetType.CONTENT_VIEW_ZONE || e.target.type === MouseTargetType.GUTTER_VIEW_ZONE) && e.target.detail.viewZoneId === this._getViewZoneId()) {\n\t\t\t\tcurrentLineNumberOffset = this._updateLightBulbPosition(this._marginDomNode, e.event.browserEvent.y, lineHeight);\n\t\t\t\tthis.visibility = true;\n\t\t\t} else {\n\t\t\t\tthis.visibility = false;\n\t\t\t}\n\t\t}));\n\n\t\tthis._register(_modifiedEditor.onMouseDown((e: IEditorMouseEvent) => {\n\t\t\tif (!e.event.leftButton) { return; }\n\n\t\t\tif (e.target.type === MouseTargetType.CONTENT_VIEW_ZONE || e.target.type === MouseTargetType.GUTTER_VIEW_ZONE) {\n\t\t\t\tconst viewZoneId = e.target.detail.viewZoneId;\n\n\t\t\t\tif (viewZoneId === this._getViewZoneId()) {\n\t\t\t\t\te.event.preventDefault();\n\t\t\t\t\tcurrentLineNumberOffset = this._updateLightBulbPosition(this._marginDomNode, e.event.browserEvent.y, lineHeight);\n\t\t\t\t\tshowContextMenu(e.event.posx, e.event.posy + lineHeight);\n\t\t\t\t}\n\t\t\t}\n\t\t}));\n\t}\n\n\tprivate _updateLightBulbPosition(marginDomNode: HTMLElement, y: number, lineHeight: number): number {\n\t\tconst { top } = getDomNodePagePosition(marginDomNode);\n\t\tconst offset = y - top;\n\t\tconst lineNumberOffset = Math.floor(offset / lineHeight);\n\t\tconst newTop = lineNumberOffset * lineHeight;\n\t\tthis._diffActions.style.top = `${newTop}px`;\n\t\tif (this._viewLineCounts) {\n\t\t\tlet acc = 0;\n\t\t\tfor (let i = 0; i < this._viewLineCounts.length; i++) {\n\t\t\t\tacc += this._viewLineCounts[i];\n\t\t\t\tif (lineNumberOffset < acc) {\n\t\t\t\t\treturn i;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn lineNumberOffset;\n\t}\n}\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\nimport { h } from 'vs/base/browser/dom';\nimport { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';\nimport { Action } from 'vs/base/common/actions';\nimport { booleanComparator, compareBy, numberComparator, tieBreakComparators } from 'vs/base/common/arrays';\nimport { findMaxIdx } from 'vs/base/common/arraysFind';\nimport { Codicon } from 'vs/base/common/codicons';\nimport { Disposable, toDisposable } from 'vs/base/common/lifecycle';\nimport { IObservable, autorun, autorunHandleChanges, autorunWithStore, constObservable, derived, derivedWithStore, observableFromEvent, observableSignalFromEvent, observableValue, recomputeInitiallyAndOnChange } from 'vs/base/common/observable';\nimport { ThemeIcon } from 'vs/base/common/themables';\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\nimport { DiffEditorEditors } from 'vs/editor/browser/widget/diffEditor/components/diffEditorEditors';\nimport { DiffEditorViewModel } from 'vs/editor/browser/widget/diffEditor/diffEditorViewModel';\nimport { PlaceholderViewZone, ViewZoneOverlayWidget, applyStyle, applyViewZones } from 'vs/editor/browser/widget/diffEditor/utils';\nimport { EditorLayoutInfo } from 'vs/editor/common/config/editorOptions';\nimport { LineRange } from 'vs/editor/common/core/lineRange';\nimport { OffsetRange, OffsetRangeSet } from 'vs/editor/common/core/offsetRange';\nimport { MovedText } from 'vs/editor/common/diff/linesDiffComputer';\nimport { localize } from 'vs/nls';\n\nexport class MovedBlocksLinesFeature extends Disposable {\n\tpublic static readonly movedCodeBlockPadding = 4;\n\n\tprivate readonly _element: SVGElement;\n\tprivate readonly _originalScrollTop = observableFromEvent(this._editors.original.onDidScrollChange, () => this._editors.original.getScrollTop());\n\tprivate readonly _modifiedScrollTop = observableFromEvent(this._editors.modified.onDidScrollChange, () => this._editors.modified.getScrollTop());\n\tprivate readonly _viewZonesChanged = observableSignalFromEvent('onDidChangeViewZones', this._editors.modified.onDidChangeViewZones);\n\n\tpublic readonly width = observableValue(this, 0);\n\n\tconstructor(\n\t\tprivate readonly _rootElement: HTMLElement,\n\t\tprivate readonly _diffModel: IObservable,\n\t\tprivate readonly _originalEditorLayoutInfo: IObservable,\n\t\tprivate readonly _modifiedEditorLayoutInfo: IObservable,\n\t\tprivate readonly _editors: DiffEditorEditors,\n\t) {\n\t\tsuper();\n\n\t\tthis._element = document.createElementNS('http://www.w3.org/2000/svg', 'svg');\n\t\tthis._element.setAttribute('class', 'moved-blocks-lines');\n\t\tthis._rootElement.appendChild(this._element);\n\t\tthis._register(toDisposable(() => this._element.remove()));\n\n\t\tthis._register(autorun(reader => {\n\t\t\t/** @description update moved blocks lines positioning */\n\t\t\tconst info = this._originalEditorLayoutInfo.read(reader);\n\t\t\tconst info2 = this._modifiedEditorLayoutInfo.read(reader);\n\t\t\tif (!info || !info2) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis._element.style.left = `${info.width - info.verticalScrollbarWidth}px`;\n\t\t\tthis._element.style.height = `${info.height}px`;\n\t\t\tthis._element.style.width = `${info.verticalScrollbarWidth + info.contentLeft - MovedBlocksLinesFeature.movedCodeBlockPadding + this.width.read(reader)}px`;\n\t\t}));\n\n\t\tthis._register(recomputeInitiallyAndOnChange(this._state));\n\n\t\tconst movedBlockViewZones = derived(reader => {\n\t\t\tconst model = this._diffModel.read(reader);\n\t\t\tconst d = model?.diff.read(reader);\n\t\t\tif (!d) { return []; }\n\t\t\treturn d.movedTexts.map(move => ({\n\t\t\t\tmove,\n\t\t\t\toriginal: new PlaceholderViewZone(constObservable(move.lineRangeMapping.original.startLineNumber - 1), 18),\n\t\t\t\tmodified: new PlaceholderViewZone(constObservable(move.lineRangeMapping.modified.startLineNumber - 1), 18),\n\t\t\t}));\n\t\t});\n\n\t\tthis._register(applyViewZones(this._editors.original, movedBlockViewZones.map(zones => /** @description movedBlockViewZones.original */ zones.map(z => z.original))));\n\t\tthis._register(applyViewZones(this._editors.modified, movedBlockViewZones.map(zones => /** @description movedBlockViewZones.modified */ zones.map(z => z.modified))));\n\n\t\tthis._register(autorunWithStore((reader, store) => {\n\t\t\tconst blocks = movedBlockViewZones.read(reader);\n\t\t\tfor (const b of blocks) {\n\t\t\t\tstore.add(new MovedBlockOverlayWidget(this._editors.original, b.original, b.move, 'original', this._diffModel.get()!));\n\t\t\t\tstore.add(new MovedBlockOverlayWidget(this._editors.modified, b.modified, b.move, 'modified', this._diffModel.get()!));\n\t\t\t}\n\t\t}));\n\n\t\tconst originalHasFocus = observableSignalFromEvent(\n\t\t\t'original.onDidFocusEditorWidget',\n\t\t\te => this._editors.original.onDidFocusEditorWidget(() => setTimeout(() => e(undefined), 0))\n\t\t);\n\t\tconst modifiedHasFocus = observableSignalFromEvent(\n\t\t\t'modified.onDidFocusEditorWidget',\n\t\t\te => this._editors.modified.onDidFocusEditorWidget(() => setTimeout(() => e(undefined), 0))\n\t\t);\n\n\t\tlet lastChangedEditor: 'original' | 'modified' = 'modified';\n\n\t\tthis._register(autorunHandleChanges({\n\t\t\tcreateEmptyChangeSummary: () => undefined,\n\t\t\thandleChange: (ctx, summary) => {\n\t\t\t\tif (ctx.didChange(originalHasFocus)) { lastChangedEditor = 'original'; }\n\t\t\t\tif (ctx.didChange(modifiedHasFocus)) { lastChangedEditor = 'modified'; }\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}, reader => {\n\t\t\t/** @description MovedBlocksLines.setActiveMovedTextFromCursor */\n\t\t\toriginalHasFocus.read(reader);\n\t\t\tmodifiedHasFocus.read(reader);\n\n\t\t\tconst m = this._diffModel.read(reader);\n\t\t\tif (!m) { return; }\n\t\t\tconst diff = m.diff.read(reader);\n\n\t\t\tlet movedText: MovedText | undefined = undefined;\n\n\t\t\tif (diff && lastChangedEditor === 'original') {\n\t\t\t\tconst originalPos = this._editors.originalCursor.read(reader);\n\t\t\t\tif (originalPos) {\n\t\t\t\t\tmovedText = diff.movedTexts.find(m => m.lineRangeMapping.original.contains(originalPos.lineNumber));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (diff && lastChangedEditor === 'modified') {\n\t\t\t\tconst modifiedPos = this._editors.modifiedCursor.read(reader);\n\t\t\t\tif (modifiedPos) {\n\t\t\t\t\tmovedText = diff.movedTexts.find(m => m.lineRangeMapping.modified.contains(modifiedPos.lineNumber));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (movedText !== m.movedTextToCompare.get()) {\n\t\t\t\tm.movedTextToCompare.set(undefined, undefined);\n\t\t\t}\n\t\t\tm.setActiveMovedText(movedText);\n\t\t}));\n\t}\n\n\tprivate readonly _modifiedViewZonesChangedSignal = observableSignalFromEvent('modified.onDidChangeViewZones', this._editors.modified.onDidChangeViewZones);\n\tprivate readonly _originalViewZonesChangedSignal = observableSignalFromEvent('original.onDidChangeViewZones', this._editors.original.onDidChangeViewZones);\n\n\tprivate readonly _state = derivedWithStore(this, (reader, store) => {\n\t\t/** @description state */\n\n\t\tthis._element.replaceChildren();\n\t\tconst model = this._diffModel.read(reader);\n\t\tconst moves = model?.diff.read(reader)?.movedTexts;\n\t\tif (!moves || moves.length === 0) {\n\t\t\tthis.width.set(0, undefined);\n\t\t\treturn;\n\t\t}\n\n\t\tthis._viewZonesChanged.read(reader);\n\n\t\tconst infoOrig = this._originalEditorLayoutInfo.read(reader);\n\t\tconst infoMod = this._modifiedEditorLayoutInfo.read(reader);\n\t\tif (!infoOrig || !infoMod) {\n\t\t\tthis.width.set(0, undefined);\n\t\t\treturn;\n\t\t}\n\n\t\tthis._modifiedViewZonesChangedSignal.read(reader);\n\t\tthis._originalViewZonesChangedSignal.read(reader);\n\n\t\tconst lines = moves.map((move) => {\n\t\t\tfunction computeLineStart(range: LineRange, editor: ICodeEditor) {\n\t\t\t\tconst t1 = editor.getTopForLineNumber(range.startLineNumber, true);\n\t\t\t\tconst t2 = editor.getTopForLineNumber(range.endLineNumberExclusive, true);\n\t\t\t\treturn (t1 + t2) / 2;\n\t\t\t}\n\n\t\t\tconst start = computeLineStart(move.lineRangeMapping.original, this._editors.original);\n\t\t\tconst startOffset = this._originalScrollTop.read(reader);\n\t\t\tconst end = computeLineStart(move.lineRangeMapping.modified, this._editors.modified);\n\t\t\tconst endOffset = this._modifiedScrollTop.read(reader);\n\n\t\t\tconst from = start - startOffset;\n\t\t\tconst to = end - endOffset;\n\n\t\t\tconst top = Math.min(start, end);\n\t\t\tconst bottom = Math.max(start, end);\n\n\t\t\treturn { range: new OffsetRange(top, bottom), from, to, fromWithoutScroll: start, toWithoutScroll: end, move };\n\t\t});\n\n\t\tlines.sort(tieBreakComparators(\n\t\t\tcompareBy(l => l.fromWithoutScroll > l.toWithoutScroll, booleanComparator),\n\t\t\tcompareBy(l => l.fromWithoutScroll > l.toWithoutScroll ? l.fromWithoutScroll : -l.toWithoutScroll, numberComparator)\n\t\t));\n\n\t\tconst layout = LinesLayout.compute(lines.map(l => l.range));\n\n\t\tconst padding = 10;\n\t\tconst lineAreaLeft = infoOrig.verticalScrollbarWidth;\n\t\tconst lineAreaWidth = (layout.getTrackCount() - 1) * 10 + padding * 2;\n\t\tconst width = lineAreaLeft + lineAreaWidth + (infoMod.contentLeft - MovedBlocksLinesFeature.movedCodeBlockPadding);\n\n\t\tlet idx = 0;\n\t\tfor (const line of lines) {\n\t\t\tconst track = layout.getTrack(idx);\n\t\t\tconst verticalY = lineAreaLeft + padding + track * 10;\n\n\t\t\tconst arrowHeight = 15;\n\t\t\tconst arrowWidth = 15;\n\t\t\tconst right = width;\n\n\t\t\tconst rectWidth = infoMod.glyphMarginWidth + infoMod.lineNumbersWidth;\n\t\t\tconst rectHeight = 18;\n\t\t\tconst rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');\n\t\t\trect.classList.add('arrow-rectangle');\n\t\t\trect.setAttribute('x', `${right - rectWidth}`);\n\t\t\trect.setAttribute('y', `${line.to - rectHeight / 2}`);\n\t\t\trect.setAttribute('width', `${rectWidth}`);\n\t\t\trect.setAttribute('height', `${rectHeight}`);\n\t\t\tthis._element.appendChild(rect);\n\n\t\t\tconst g = document.createElementNS('http://www.w3.org/2000/svg', 'g');\n\n\t\t\tconst path = document.createElementNS('http://www.w3.org/2000/svg', 'path');\n\n\t\t\tpath.setAttribute('d', `M ${0} ${line.from} L ${verticalY} ${line.from} L ${verticalY} ${line.to} L ${right - arrowWidth} ${line.to}`);\n\t\t\tpath.setAttribute('fill', 'none');\n\t\t\tg.appendChild(path);\n\n\t\t\tconst arrowRight = document.createElementNS('http://www.w3.org/2000/svg', 'polygon');\n\t\t\tarrowRight.classList.add('arrow');\n\n\t\t\tstore.add(autorun(reader => {\n\t\t\t\tpath.classList.toggle('currentMove', line.move === model.activeMovedText.read(reader));\n\t\t\t\tarrowRight.classList.toggle('currentMove', line.move === model.activeMovedText.read(reader));\n\t\t\t}));\n\n\t\t\tarrowRight.setAttribute('points', `${right - arrowWidth},${line.to - arrowHeight / 2} ${right},${line.to} ${right - arrowWidth},${line.to + arrowHeight / 2}`);\n\t\t\tg.appendChild(arrowRight);\n\n\t\t\tthis._element.appendChild(g);\n\n\t\t\t/*\n\t\t\tTODO@hediet\n\t\t\tpath.addEventListener('mouseenter', () => {\n\t\t\t\tmodel.setHoveredMovedText(line.move);\n\t\t\t});\n\t\t\tpath.addEventListener('mouseleave', () => {\n\t\t\t\tmodel.setHoveredMovedText(undefined);\n\t\t\t});*/\n\n\t\t\tidx++;\n\t\t}\n\n\t\tthis.width.set(lineAreaWidth, undefined);\n\t});\n}\n\nclass LinesLayout {\n\tpublic static compute(lines: OffsetRange[]): LinesLayout {\n\t\tconst setsPerTrack: OffsetRangeSet[] = [];\n\t\tconst trackPerLineIdx: number[] = [];\n\n\t\tfor (const line of lines) {\n\t\t\tlet trackIdx = setsPerTrack.findIndex(set => !set.intersectsStrict(line));\n\t\t\tif (trackIdx === -1) {\n\t\t\t\tconst maxTrackCount = 6;\n\t\t\t\tif (setsPerTrack.length >= maxTrackCount) {\n\t\t\t\t\ttrackIdx = findMaxIdx(setsPerTrack, compareBy(set => set.intersectWithRangeLength(line), numberComparator));\n\t\t\t\t} else {\n\t\t\t\t\ttrackIdx = setsPerTrack.length;\n\t\t\t\t\tsetsPerTrack.push(new OffsetRangeSet());\n\t\t\t\t}\n\t\t\t}\n\t\t\tsetsPerTrack[trackIdx].addRange(line);\n\t\t\ttrackPerLineIdx.push(trackIdx);\n\t\t}\n\n\t\treturn new LinesLayout(setsPerTrack.length, trackPerLineIdx);\n\t}\n\n\tprivate constructor(\n\t\tprivate readonly _trackCount: number,\n\t\tprivate readonly trackPerLineIdx: number[]\n\t) { }\n\n\tgetTrack(lineIdx: number): number {\n\t\treturn this.trackPerLineIdx[lineIdx];\n\t}\n\n\tgetTrackCount(): number {\n\t\treturn this._trackCount;\n\t}\n}\n\nclass MovedBlockOverlayWidget extends ViewZoneOverlayWidget {\n\tprivate readonly _nodes = h('div.diff-moved-code-block', { style: { marginRight: '4px' } }, [\n\t\th('div.text-content@textContent'),\n\t\th('div.action-bar@actionBar'),\n\t]);\n\n\tconstructor(\n\t\tprivate readonly _editor: ICodeEditor,\n\t\t_viewZone: PlaceholderViewZone,\n\t\tprivate readonly _move: MovedText,\n\t\tprivate readonly _kind: 'original' | 'modified',\n\t\tprivate readonly _diffModel: DiffEditorViewModel,\n\t) {\n\t\tconst root = h('div.diff-hidden-lines-widget');\n\t\tsuper(_editor, _viewZone, root.root);\n\t\troot.root.appendChild(this._nodes.root);\n\n\t\tconst editorLayout = observableFromEvent(this._editor.onDidLayoutChange, () => this._editor.getLayoutInfo());\n\n\t\tthis._register(applyStyle(this._nodes.root, {\n\t\t\tpaddingRight: editorLayout.map(l => l.verticalScrollbarWidth)\n\t\t}));\n\n\t\tlet text: string;\n\n\t\tif (_move.changes.length > 0) {\n\t\t\ttext = this._kind === 'original' ? localize(\n\t\t\t\t'codeMovedToWithChanges',\n\t\t\t\t'Code moved with changes to line {0}-{1}',\n\t\t\t\tthis._move.lineRangeMapping.modified.startLineNumber,\n\t\t\t\tthis._move.lineRangeMapping.modified.endLineNumberExclusive - 1,\n\t\t\t) : localize(\n\t\t\t\t'codeMovedFromWithChanges',\n\t\t\t\t'Code moved with changes from line {0}-{1}',\n\t\t\t\tthis._move.lineRangeMapping.original.startLineNumber,\n\t\t\t\tthis._move.lineRangeMapping.original.endLineNumberExclusive - 1,\n\t\t\t);\n\t\t} else {\n\t\t\ttext = this._kind === 'original' ? localize(\n\t\t\t\t'codeMovedTo',\n\t\t\t\t'Code moved to line {0}-{1}',\n\t\t\t\tthis._move.lineRangeMapping.modified.startLineNumber,\n\t\t\t\tthis._move.lineRangeMapping.modified.endLineNumberExclusive - 1,\n\t\t\t) : localize(\n\t\t\t\t'codeMovedFrom',\n\t\t\t\t'Code moved from line {0}-{1}',\n\t\t\t\tthis._move.lineRangeMapping.original.startLineNumber,\n\t\t\t\tthis._move.lineRangeMapping.original.endLineNumberExclusive - 1,\n\t\t\t);\n\t\t}\n\n\t\tconst actionBar = this._register(new ActionBar(this._nodes.actionBar, {\n\t\t\thighlightToggledItems: true,\n\t\t}));\n\n\t\tconst caption = new Action(\n\t\t\t'',\n\t\t\ttext,\n\t\t\t'',\n\t\t\tfalse,\n\t\t);\n\t\tactionBar.push(caption, { icon: false, label: true });\n\n\t\tconst actionCompare = new Action(\n\t\t\t'',\n\t\t\t'Compare',\n\t\t\tThemeIcon.asClassName(Codicon.compareChanges),\n\t\t\ttrue,\n\t\t\t() => {\n\t\t\t\tthis._editor.focus();\n\t\t\t\tthis._diffModel.movedTextToCompare.set(this._diffModel.movedTextToCompare.get() === _move ? undefined : this._move, undefined);\n\t\t\t},\n\t\t);\n\t\tthis._register(autorun(reader => {\n\t\t\tconst isActive = this._diffModel.movedTextToCompare.read(reader) === _move;\n\t\t\tactionCompare.checked = isActive;\n\t\t}));\n\n\t\tactionBar.push(actionCompare, { icon: false, label: true });\n\t}\n}\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\nimport { addDisposableListener, h, EventType } from 'vs/base/browser/dom';\nimport { renderIcon } from 'vs/base/browser/ui/iconLabel/iconLabels';\nimport { Codicon } from 'vs/base/common/codicons';\nimport { Disposable, toDisposable } from 'vs/base/common/lifecycle';\nimport { IObservable, autorunWithStore, derived } from 'vs/base/common/observable';\nimport { IGlyphMarginWidget, IGlyphMarginWidgetPosition } from 'vs/editor/browser/editorBrowser';\nimport { DiffEditorEditors } from 'vs/editor/browser/widget/diffEditor/components/diffEditorEditors';\nimport { DiffEditorOptions } from 'vs/editor/browser/widget/diffEditor/diffEditorOptions';\nimport { DiffEditorViewModel } from 'vs/editor/browser/widget/diffEditor/diffEditorViewModel';\nimport { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditor/diffEditorWidget';\nimport { LineRange, LineRangeSet } from 'vs/editor/common/core/lineRange';\nimport { Range } from 'vs/editor/common/core/range';\nimport { LineRangeMapping, RangeMapping } from 'vs/editor/common/diff/rangeMapping';\nimport { GlyphMarginLane } from 'vs/editor/common/model';\nimport { localize } from 'vs/nls';\n\nconst emptyArr: never[] = [];\n\nexport class RevertButtonsFeature extends Disposable {\n\tconstructor(\n\t\tprivate readonly _editors: DiffEditorEditors,\n\t\tprivate readonly _diffModel: IObservable,\n\t\tprivate readonly _options: DiffEditorOptions,\n\t\tprivate readonly _widget: DiffEditorWidget\n\t) {\n\t\tsuper();\n\n\t\tthis._register(autorunWithStore((reader, store) => {\n\t\t\tif (!this._options.shouldRenderOldRevertArrows.read(reader)) { return; }\n\t\t\tconst model = this._diffModel.read(reader);\n\t\t\tconst diff = model?.diff.read(reader);\n\t\t\tif (!model || !diff) { return; }\n\t\t\tif (model.movedTextToCompare.read(reader)) { return; }\n\n\t\t\tconst glyphWidgetsModified: IGlyphMarginWidget[] = [];\n\n\t\t\tconst selectedDiffs = this._selectedDiffs.read(reader);\n\t\t\tconst selectedDiffsSet = new Set(selectedDiffs.map(d => d.mapping));\n\n\t\t\tif (selectedDiffs.length > 0) {\n\t\t\t\t// The button to revert the selection\n\t\t\t\tconst selections = this._editors.modifiedSelections.read(reader);\n\n\t\t\t\tconst btn = store.add(new RevertButton(\n\t\t\t\t\tselections[selections.length - 1].positionLineNumber,\n\t\t\t\t\tthis._widget,\n\t\t\t\t\tselectedDiffs.flatMap(d => d.rangeMappings),\n\t\t\t\t\ttrue\n\t\t\t\t));\n\t\t\t\tthis._editors.modified.addGlyphMarginWidget(btn);\n\t\t\t\tglyphWidgetsModified.push(btn);\n\t\t\t}\n\n\t\t\tfor (const m of diff.mappings) {\n\t\t\t\tif (selectedDiffsSet.has(m)) { continue; }\n\t\t\t\tif (!m.lineRangeMapping.modified.isEmpty && m.lineRangeMapping.innerChanges) {\n\t\t\t\t\tconst btn = store.add(new RevertButton(\n\t\t\t\t\t\tm.lineRangeMapping.modified.startLineNumber,\n\t\t\t\t\t\tthis._widget,\n\t\t\t\t\t\tm.lineRangeMapping,\n\t\t\t\t\t\tfalse\n\t\t\t\t\t));\n\t\t\t\t\tthis._editors.modified.addGlyphMarginWidget(btn);\n\t\t\t\t\tglyphWidgetsModified.push(btn);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tstore.add(toDisposable(() => {\n\t\t\t\tfor (const w of glyphWidgetsModified) {\n\t\t\t\t\tthis._editors.modified.removeGlyphMarginWidget(w);\n\t\t\t\t}\n\t\t\t}));\n\t\t}));\n\t}\n\n\tprivate readonly _selectedDiffs = derived(this, (reader) => {\n\t\t/** @description selectedDiffs */\n\t\tconst model = this._diffModel.read(reader);\n\t\tconst diff = model?.diff.read(reader);\n\t\t// Return `emptyArr` because it is a constant. [] is always a new array and would trigger a change.\n\t\tif (!diff) { return emptyArr; }\n\n\t\tconst selections = this._editors.modifiedSelections.read(reader);\n\t\tif (selections.every(s => s.isEmpty())) { return emptyArr; }\n\n\t\tconst selectedLineNumbers = new LineRangeSet(selections.map(s => LineRange.fromRangeInclusive(s)));\n\n\t\tconst selectedMappings = diff.mappings.filter(m =>\n\t\t\tm.lineRangeMapping.innerChanges && selectedLineNumbers.intersects(m.lineRangeMapping.modified)\n\t\t);\n\t\tconst result = selectedMappings.map(mapping => ({\n\t\t\tmapping,\n\t\t\trangeMappings: mapping.lineRangeMapping.innerChanges!.filter(\n\t\t\t\tc => selections.some(s => Range.areIntersecting(c.modifiedRange, s))\n\t\t\t)\n\t\t}));\n\t\tif (result.length === 0 || result.every(r => r.rangeMappings.length === 0)) { return emptyArr; }\n\t\treturn result;\n\t});\n}\n\nexport class RevertButton extends Disposable implements IGlyphMarginWidget {\n\tpublic static counter = 0;\n\n\tprivate readonly _id: string = `revertButton${RevertButton.counter++}`;\n\n\tgetId(): string { return this._id; }\n\n\tprivate readonly _domNode = h('div.revertButton', {\n\t\ttitle: this._revertSelection\n\t\t\t? localize('revertSelectedChanges', 'Revert Selected Changes')\n\t\t\t: localize('revertChange', 'Revert Change')\n\t},\n\t\t[renderIcon(Codicon.arrowRight)]\n\t).root;\n\n\tconstructor(\n\t\tprivate readonly _lineNumber: number,\n\t\tprivate readonly _widget: DiffEditorWidget,\n\t\tprivate readonly _diffs: RangeMapping[] | LineRangeMapping,\n\t\tprivate readonly _revertSelection: boolean,\n\t) {\n\t\tsuper();\n\n\n\t\tthis._register(addDisposableListener(this._domNode, EventType.MOUSE_DOWN, e => {\n\t\t\t// don't prevent context menu from showing up\n\t\t\tif (e.button !== 2) {\n\t\t\t\te.stopPropagation();\n\t\t\t\te.preventDefault();\n\t\t\t}\n\t\t}));\n\n\t\tthis._register(addDisposableListener(this._domNode, EventType.MOUSE_UP, e => {\n\t\t\te.stopPropagation();\n\t\t\te.preventDefault();\n\t\t}));\n\n\t\tthis._register(addDisposableListener(this._domNode, EventType.CLICK, (e) => {\n\t\t\tif (this._diffs instanceof LineRangeMapping) {\n\t\t\t\tthis._widget.revert(this._diffs);\n\t\t\t} else {\n\t\t\t\tthis._widget.revertRangeMappings(this._diffs);\n\t\t\t}\n\t\t\te.stopPropagation();\n\t\t\te.preventDefault();\n\t\t}));\n\t}\n\n\t/**\n\t * Get the dom node of the glyph widget.\n\t */\n\tgetDomNode(): HTMLElement {\n\t\treturn this._domNode;\n\t}\n\n\t/**\n\t * Get the placement of the glyph widget.\n\t */\n\tgetPosition(): IGlyphMarginWidgetPosition {\n\t\treturn {\n\t\t\tlane: GlyphMarginLane.Right,\n\t\t\trange: {\n\t\t\t\tstartColumn: 1,\n\t\t\t\tstartLineNumber: this._lineNumber,\n\t\t\t\tendColumn: 1,\n\t\t\t\tendLineNumber: this._lineNumber,\n\t\t\t},\n\t\t\tzIndex: 10001,\n\t\t};\n\t}\n}\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\nimport * as arrays from 'vs/base/common/arrays';\nimport { IMarkdownString } from 'vs/base/common/htmlContent';\nimport { IJSONSchema } from 'vs/base/common/jsonSchema';\nimport * as objects from 'vs/base/common/objects';\nimport * as platform from 'vs/base/common/platform';\nimport { ScrollbarVisibility } from 'vs/base/common/scrollable';\nimport { Constants } from 'vs/base/common/uint';\nimport { FontInfo } from 'vs/editor/common/config/fontInfo';\nimport { EDITOR_MODEL_DEFAULTS } from 'vs/editor/common/core/textModelDefaults';\nimport { USUAL_WORD_SEPARATORS } from 'vs/editor/common/core/wordHelper';\nimport * as nls from 'vs/nls';\nimport { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility';\nimport { IConfigurationPropertySchema } from 'vs/platform/configuration/common/configurationRegistry';\n\n//#region typed options\n\n/**\n * Configuration options for auto closing quotes and brackets\n */\nexport type EditorAutoClosingStrategy = 'always' | 'languageDefined' | 'beforeWhitespace' | 'never';\n\n/**\n * Configuration options for auto wrapping quotes and brackets\n */\nexport type EditorAutoSurroundStrategy = 'languageDefined' | 'quotes' | 'brackets' | 'never';\n\n/**\n * Configuration options for typing over closing quotes or brackets\n */\nexport type EditorAutoClosingEditStrategy = 'always' | 'auto' | 'never';\n\n/**\n * Configuration options for auto indentation in the editor\n */\nexport const enum EditorAutoIndentStrategy {\n\tNone = 0,\n\tKeep = 1,\n\tBrackets = 2,\n\tAdvanced = 3,\n\tFull = 4\n}\n\n/**\n * Configuration options for the editor.\n */\nexport interface IEditorOptions {\n\t/**\n\t * This editor is used inside a diff editor.\n\t */\n\tinDiffEditor?: boolean;\n\t/**\n\t * The aria label for the editor's textarea (when it is focused).\n\t */\n\tariaLabel?: string;\n\n\t/**\n\t * Whether the aria-required attribute should be set on the editors textarea.\n\t */\n\tariaRequired?: boolean;\n\t/**\n\t * Control whether a screen reader announces inline suggestion content immediately.\n\t */\n\tscreenReaderAnnounceInlineSuggestion?: boolean;\n\t/**\n\t * The `tabindex` property of the editor's textarea\n\t */\n\ttabIndex?: number;\n\t/**\n\t * Render vertical lines at the specified columns.\n\t * Defaults to empty array.\n\t */\n\trulers?: (number | IRulerOption)[];\n\t/**\n\t * Locales used for segmenting lines into words when doing word related navigations or operations.\n\t *\n\t * Specify the BCP 47 language tag of the word you wish to recognize (e.g., ja, zh-CN, zh-Hant-TW, etc.).\n\t * Defaults to empty array\n\t */\n\twordSegmenterLocales?: string | string[];\n\t/**\n\t * A string containing the word separators used when doing word navigation.\n\t * Defaults to `~!@#$%^&*()-=+[{]}\\\\|;:\\'\",.<>/?\n\t */\n\twordSeparators?: string;\n\t/**\n\t * Enable Linux primary clipboard.\n\t * Defaults to true.\n\t */\n\tselectionClipboard?: boolean;\n\t/**\n\t * Control the rendering of line numbers.\n\t * If it is a function, it will be invoked when rendering a line number and the return value will be rendered.\n\t * Otherwise, if it is a truthy, line numbers will be rendered normally (equivalent of using an identity function).\n\t * Otherwise, line numbers will not be rendered.\n\t * Defaults to `on`.\n\t */\n\tlineNumbers?: LineNumbersType;\n\t/**\n\t * Controls the minimal number of visible leading and trailing lines surrounding the cursor.\n\t * Defaults to 0.\n\t*/\n\tcursorSurroundingLines?: number;\n\t/**\n\t * Controls when `cursorSurroundingLines` should be enforced\n\t * Defaults to `default`, `cursorSurroundingLines` is not enforced when cursor position is changed\n\t * by mouse.\n\t*/\n\tcursorSurroundingLinesStyle?: 'default' | 'all';\n\t/**\n\t * Render last line number when the file ends with a newline.\n\t * Defaults to 'on' for Windows and macOS and 'dimmed' for Linux.\n\t*/\n\trenderFinalNewline?: 'on' | 'off' | 'dimmed';\n\t/**\n\t * Remove unusual line terminators like LINE SEPARATOR (LS), PARAGRAPH SEPARATOR (PS).\n\t * Defaults to 'prompt'.\n\t */\n\tunusualLineTerminators?: 'auto' | 'off' | 'prompt';\n\t/**\n\t * Should the corresponding line be selected when clicking on the line number?\n\t * Defaults to true.\n\t */\n\tselectOnLineNumbers?: boolean;\n\t/**\n\t * Control the width of line numbers, by reserving horizontal space for rendering at least an amount of digits.\n\t * Defaults to 5.\n\t */\n\tlineNumbersMinChars?: number;\n\t/**\n\t * Enable the rendering of the glyph margin.\n\t * Defaults to true in vscode and to false in monaco-editor.\n\t */\n\tglyphMargin?: boolean;\n\t/**\n\t * The width reserved for line decorations (in px).\n\t * Line decorations are placed between line numbers and the editor content.\n\t * You can pass in a string in the format floating point followed by \"ch\". e.g. 1.3ch.\n\t * Defaults to 10.\n\t */\n\tlineDecorationsWidth?: number | string;\n\t/**\n\t * When revealing the cursor, a virtual padding (px) is added to the cursor, turning it into a rectangle.\n\t * This virtual padding ensures that the cursor gets revealed before hitting the edge of the viewport.\n\t * Defaults to 30 (px).\n\t */\n\trevealHorizontalRightPadding?: number;\n\t/**\n\t * Render the editor selection with rounded borders.\n\t * Defaults to true.\n\t */\n\troundedSelection?: boolean;\n\t/**\n\t * Class name to be added to the editor.\n\t */\n\textraEditorClassName?: string;\n\t/**\n\t * Should the editor be read only. See also `domReadOnly`.\n\t * Defaults to false.\n\t */\n\treadOnly?: boolean;\n\t/**\n\t * The message to display when the editor is readonly.\n\t */\n\treadOnlyMessage?: IMarkdownString;\n\t/**\n\t * Should the textarea used for input use the DOM `readonly` attribute.\n\t * Defaults to false.\n\t */\n\tdomReadOnly?: boolean;\n\t/**\n\t * Enable linked editing.\n\t * Defaults to false.\n\t */\n\tlinkedEditing?: boolean;\n\t/**\n\t * deprecated, use linkedEditing instead\n\t */\n\trenameOnType?: boolean;\n\t/**\n\t * Should the editor render validation decorations.\n\t * Defaults to editable.\n\t */\n\trenderValidationDecorations?: 'editable' | 'on' | 'off';\n\t/**\n\t * Control the behavior and rendering of the scrollbars.\n\t */\n\tscrollbar?: IEditorScrollbarOptions;\n\t/**\n\t * Control the behavior of sticky scroll options\n\t */\n\tstickyScroll?: IEditorStickyScrollOptions;\n\t/**\n\t * Control the behavior and rendering of the minimap.\n\t */\n\tminimap?: IEditorMinimapOptions;\n\t/**\n\t * Control the behavior of the find widget.\n\t */\n\tfind?: IEditorFindOptions;\n\t/**\n\t * Display overflow widgets as `fixed`.\n\t * Defaults to `false`.\n\t */\n\tfixedOverflowWidgets?: boolean;\n\t/**\n\t * The number of vertical lanes the overview ruler should render.\n\t * Defaults to 3.\n\t */\n\toverviewRulerLanes?: number;\n\t/**\n\t * Controls if a border should be drawn around the overview ruler.\n\t * Defaults to `true`.\n\t */\n\toverviewRulerBorder?: boolean;\n\t/**\n\t * Control the cursor animation style, possible values are 'blink', 'smooth', 'phase', 'expand' and 'solid'.\n\t * Defaults to 'blink'.\n\t */\n\tcursorBlinking?: 'blink' | 'smooth' | 'phase' | 'expand' | 'solid';\n\t/**\n\t * Zoom the font in the editor when using the mouse wheel in combination with holding Ctrl.\n\t * Defaults to false.\n\t */\n\tmouseWheelZoom?: boolean;\n\t/**\n\t * Control the mouse pointer style, either 'text' or 'default' or 'copy'\n\t * Defaults to 'text'\n\t */\n\tmouseStyle?: 'text' | 'default' | 'copy';\n\t/**\n\t * Enable smooth caret animation.\n\t * Defaults to 'off'.\n\t */\n\tcursorSmoothCaretAnimation?: 'off' | 'explicit' | 'on';\n\t/**\n\t * Control the cursor style, either 'block' or 'line'.\n\t * Defaults to 'line'.\n\t */\n\tcursorStyle?: 'line' | 'block' | 'underline' | 'line-thin' | 'block-outline' | 'underline-thin';\n\t/**\n\t * Control the width of the cursor when cursorStyle is set to 'line'\n\t */\n\tcursorWidth?: number;\n\t/**\n\t * Enable font ligatures.\n\t * Defaults to false.\n\t */\n\tfontLigatures?: boolean | string;\n\t/**\n\t * Enable font variations.\n\t * Defaults to false.\n\t */\n\tfontVariations?: boolean | string;\n\t/**\n\t * Controls whether to use default color decorations or not using the default document color provider\n\t */\n\tdefaultColorDecorators?: boolean;\n\t/**\n\t * Disable the use of `transform: translate3d(0px, 0px, 0px)` for the editor margin and lines layers.\n\t * The usage of `transform: translate3d(0px, 0px, 0px)` acts as a hint for browsers to create an extra layer.\n\t * Defaults to false.\n\t */\n\tdisableLayerHinting?: boolean;\n\t/**\n\t * Disable the optimizations for monospace fonts.\n\t * Defaults to false.\n\t */\n\tdisableMonospaceOptimizations?: boolean;\n\t/**\n\t * Should the cursor be hidden in the overview ruler.\n\t * Defaults to false.\n\t */\n\thideCursorInOverviewRuler?: boolean;\n\t/**\n\t * Enable that scrolling can go one screen size after the last line.\n\t * Defaults to true.\n\t */\n\tscrollBeyondLastLine?: boolean;\n\t/**\n\t * Enable that scrolling can go beyond the last column by a number of columns.\n\t * Defaults to 5.\n\t */\n\tscrollBeyondLastColumn?: number;\n\t/**\n\t * Enable that the editor animates scrolling to a position.\n\t * Defaults to false.\n\t */\n\tsmoothScrolling?: boolean;\n\t/**\n\t * Enable that the editor will install a ResizeObserver to check if its container dom node size has changed.\n\t * Defaults to false.\n\t */\n\tautomaticLayout?: boolean;\n\t/**\n\t * Control the wrapping of the editor.\n\t * When `wordWrap` = \"off\", the lines will never wrap.\n\t * When `wordWrap` = \"on\", the lines will wrap at the viewport width.\n\t * When `wordWrap` = \"wordWrapColumn\", the lines will wrap at `wordWrapColumn`.\n\t * When `wordWrap` = \"bounded\", the lines will wrap at min(viewport width, wordWrapColumn).\n\t * Defaults to \"off\".\n\t */\n\twordWrap?: 'off' | 'on' | 'wordWrapColumn' | 'bounded';\n\t/**\n\t * Override the `wordWrap` setting.\n\t */\n\twordWrapOverride1?: 'off' | 'on' | 'inherit';\n\t/**\n\t * Override the `wordWrapOverride1` setting.\n\t */\n\twordWrapOverride2?: 'off' | 'on' | 'inherit';\n\t/**\n\t * Control the wrapping of the editor.\n\t * When `wordWrap` = \"off\", the lines will never wrap.\n\t * When `wordWrap` = \"on\", the lines will wrap at the viewport width.\n\t * When `wordWrap` = \"wordWrapColumn\", the lines will wrap at `wordWrapColumn`.\n\t * When `wordWrap` = \"bounded\", the lines will wrap at min(viewport width, wordWrapColumn).\n\t * Defaults to 80.\n\t */\n\twordWrapColumn?: number;\n\t/**\n\t * Control indentation of wrapped lines. Can be: 'none', 'same', 'indent' or 'deepIndent'.\n\t * Defaults to 'same' in vscode and to 'none' in monaco-editor.\n\t */\n\twrappingIndent?: 'none' | 'same' | 'indent' | 'deepIndent';\n\t/**\n\t * Controls the wrapping strategy to use.\n\t * Defaults to 'simple'.\n\t */\n\twrappingStrategy?: 'simple' | 'advanced';\n\t/**\n\t * Configure word wrapping characters. A break will be introduced before these characters.\n\t */\n\twordWrapBreakBeforeCharacters?: string;\n\t/**\n\t * Configure word wrapping characters. A break will be introduced after these characters.\n\t */\n\twordWrapBreakAfterCharacters?: string;\n\t/**\n\t * Sets whether line breaks appear wherever the text would otherwise overflow its content box.\n\t * When wordBreak = 'normal', Use the default line break rule.\n\t * When wordBreak = 'keepAll', Word breaks should not be used for Chinese/Japanese/Korean (CJK) text. Non-CJK text behavior is the same as for normal.\n\t */\n\twordBreak?: 'normal' | 'keepAll';\n\t/**\n\t * Performance guard: Stop rendering a line after x characters.\n\t * Defaults to 10000.\n\t * Use -1 to never stop rendering\n\t */\n\tstopRenderingLineAfter?: number;\n\t/**\n\t * Configure the editor's hover.\n\t */\n\thover?: IEditorHoverOptions;\n\t/**\n\t * Enable detecting links and making them clickable.\n\t * Defaults to true.\n\t */\n\tlinks?: boolean;\n\t/**\n\t * Enable inline color decorators and color picker rendering.\n\t */\n\tcolorDecorators?: boolean;\n\t/**\n\t * Controls what is the condition to spawn a color picker from a color dectorator\n\t */\n\tcolorDecoratorsActivatedOn?: 'clickAndHover' | 'click' | 'hover';\n\t/**\n\t * Controls the max number of color decorators that can be rendered in an editor at once.\n\t */\n\tcolorDecoratorsLimit?: number;\n\t/**\n\t * Control the behaviour of comments in the editor.\n\t */\n\tcomments?: IEditorCommentsOptions;\n\t/**\n\t * Enable custom contextmenu.\n\t * Defaults to true.\n\t */\n\tcontextmenu?: boolean;\n\t/**\n\t * A multiplier to be used on the `deltaX` and `deltaY` of mouse wheel scroll events.\n\t * Defaults to 1.\n\t */\n\tmouseWheelScrollSensitivity?: number;\n\t/**\n\t * FastScrolling mulitplier speed when pressing `Alt`\n\t * Defaults to 5.\n\t */\n\tfastScrollSensitivity?: number;\n\t/**\n\t * Enable that the editor scrolls only the predominant axis. Prevents horizontal drift when scrolling vertically on a trackpad.\n\t * Defaults to true.\n\t */\n\tscrollPredominantAxis?: boolean;\n\t/**\n\t * Enable that the selection with the mouse and keys is doing column selection.\n\t * Defaults to false.\n\t */\n\tcolumnSelection?: boolean;\n\t/**\n\t * The modifier to be used to add multiple cursors with the mouse.\n\t * Defaults to 'alt'\n\t */\n\tmultiCursorModifier?: 'ctrlCmd' | 'alt';\n\t/**\n\t * Merge overlapping selections.\n\t * Defaults to true\n\t */\n\tmultiCursorMergeOverlapping?: boolean;\n\t/**\n\t * Configure the behaviour when pasting a text with the line count equal to the cursor count.\n\t * Defaults to 'spread'.\n\t */\n\tmultiCursorPaste?: 'spread' | 'full';\n\t/**\n\t * Controls the max number of text cursors that can be in an active editor at once.\n\t */\n\tmultiCursorLimit?: number;\n\t/**\n\t * Configure the editor's accessibility support.\n\t * Defaults to 'auto'. It is best to leave this to 'auto'.\n\t */\n\taccessibilitySupport?: 'auto' | 'off' | 'on';\n\t/**\n\t * Controls the number of lines in the editor that can be read out by a screen reader\n\t */\n\taccessibilityPageSize?: number;\n\t/**\n\t * Suggest options.\n\t */\n\tsuggest?: ISuggestOptions;\n\tinlineSuggest?: IInlineSuggestOptions;\n\texperimentalInlineEdit?: IInlineEditOptions;\n\t/**\n\t * Smart select options.\n\t */\n\tsmartSelect?: ISmartSelectOptions;\n\t/**\n\t *\n\t */\n\tgotoLocation?: IGotoLocationOptions;\n\t/**\n\t * Enable quick suggestions (shadow suggestions)\n\t * Defaults to true.\n\t */\n\tquickSuggestions?: boolean | IQuickSuggestionsOptions;\n\t/**\n\t * Quick suggestions show delay (in ms)\n\t * Defaults to 10 (ms)\n\t */\n\tquickSuggestionsDelay?: number;\n\t/**\n\t * Controls the spacing around the editor.\n\t */\n\tpadding?: IEditorPaddingOptions;\n\t/**\n\t * Parameter hint options.\n\t */\n\tparameterHints?: IEditorParameterHintOptions;\n\t/**\n\t * Options for auto closing brackets.\n\t * Defaults to language defined behavior.\n\t */\n\tautoClosingBrackets?: EditorAutoClosingStrategy;\n\t/**\n\t * Options for auto closing comments.\n\t * Defaults to language defined behavior.\n\t */\n\tautoClosingComments?: EditorAutoClosingStrategy;\n\t/**\n\t * Options for auto closing quotes.\n\t * Defaults to language defined behavior.\n\t */\n\tautoClosingQuotes?: EditorAutoClosingStrategy;\n\t/**\n\t * Options for pressing backspace near quotes or bracket pairs.\n\t */\n\tautoClosingDelete?: EditorAutoClosingEditStrategy;\n\t/**\n\t * Options for typing over closing quotes or brackets.\n\t */\n\tautoClosingOvertype?: EditorAutoClosingEditStrategy;\n\t/**\n\t * Options for auto surrounding.\n\t * Defaults to always allowing auto surrounding.\n\t */\n\tautoSurround?: EditorAutoSurroundStrategy;\n\t/**\n\t * Controls whether the editor should automatically adjust the indentation when users type, paste, move or indent lines.\n\t * Defaults to advanced.\n\t */\n\tautoIndent?: 'none' | 'keep' | 'brackets' | 'advanced' | 'full';\n\t/**\n\t * Emulate selection behaviour of tab characters when using spaces for indentation.\n\t * This means selection will stick to tab stops.\n\t */\n\tstickyTabStops?: boolean;\n\t/**\n\t * Enable format on type.\n\t * Defaults to false.\n\t */\n\tformatOnType?: boolean;\n\t/**\n\t * Enable format on paste.\n\t * Defaults to false.\n\t */\n\tformatOnPaste?: boolean;\n\t/**\n\t * Controls if the editor should allow to move selections via drag and drop.\n\t * Defaults to false.\n\t */\n\tdragAndDrop?: boolean;\n\t/**\n\t * Enable the suggestion box to pop-up on trigger characters.\n\t * Defaults to true.\n\t */\n\tsuggestOnTriggerCharacters?: boolean;\n\t/**\n\t * Accept suggestions on ENTER.\n\t * Defaults to 'on'.\n\t */\n\tacceptSuggestionOnEnter?: 'on' | 'smart' | 'off';\n\t/**\n\t * Accept suggestions on provider defined characters.\n\t * Defaults to true.\n\t */\n\tacceptSuggestionOnCommitCharacter?: boolean;\n\t/**\n\t * Enable snippet suggestions. Default to 'true'.\n\t */\n\tsnippetSuggestions?: 'top' | 'bottom' | 'inline' | 'none';\n\t/**\n\t * Copying without a selection copies the current line.\n\t */\n\temptySelectionClipboard?: boolean;\n\t/**\n\t * Syntax highlighting is copied.\n\t */\n\tcopyWithSyntaxHighlighting?: boolean;\n\t/**\n\t * The history mode for suggestions.\n\t */\n\tsuggestSelection?: 'first' | 'recentlyUsed' | 'recentlyUsedByPrefix';\n\t/**\n\t * The font size for the suggest widget.\n\t * Defaults to the editor font size.\n\t */\n\tsuggestFontSize?: number;\n\t/**\n\t * The line height for the suggest widget.\n\t * Defaults to the editor line height.\n\t */\n\tsuggestLineHeight?: number;\n\t/**\n\t * Enable tab completion.\n\t */\n\ttabCompletion?: 'on' | 'off' | 'onlySnippets';\n\t/**\n\t * Enable selection highlight.\n\t * Defaults to true.\n\t */\n\tselectionHighlight?: boolean;\n\t/**\n\t * Enable semantic occurrences highlight.\n\t * Defaults to 'singleFile'.\n\t * 'off' disables occurrence highlighting\n\t * 'singleFile' triggers occurrence highlighting in the current document\n\t * 'multiFile' triggers occurrence highlighting across valid open documents\n\t */\n\toccurrencesHighlight?: 'off' | 'singleFile' | 'multiFile';\n\t/**\n\t * Show code lens\n\t * Defaults to true.\n\t */\n\tcodeLens?: boolean;\n\t/**\n\t * Code lens font family. Defaults to editor font family.\n\t */\n\tcodeLensFontFamily?: string;\n\t/**\n\t * Code lens font size. Default to 90% of the editor font size\n\t */\n\tcodeLensFontSize?: number;\n\t/**\n\t * Control the behavior and rendering of the code action lightbulb.\n\t */\n\tlightbulb?: IEditorLightbulbOptions;\n\t/**\n\t * Timeout for running code actions on save.\n\t */\n\tcodeActionsOnSaveTimeout?: number;\n\t/**\n\t * Enable code folding.\n\t * Defaults to true.\n\t */\n\tfolding?: boolean;\n\t/**\n\t * Selects the folding strategy. 'auto' uses the strategies contributed for the current document, 'indentation' uses the indentation based folding strategy.\n\t * Defaults to 'auto'.\n\t */\n\tfoldingStrategy?: 'auto' | 'indentation';\n\t/**\n\t * Enable highlight for folded regions.\n\t * Defaults to true.\n\t */\n\tfoldingHighlight?: boolean;\n\t/**\n\t * Auto fold imports folding regions.\n\t * Defaults to true.\n\t */\n\tfoldingImportsByDefault?: boolean;\n\t/**\n\t * Maximum number of foldable regions.\n\t * Defaults to 5000.\n\t */\n\tfoldingMaximumRegions?: number;\n\t/**\n\t * Controls whether the fold actions in the gutter stay always visible or hide unless the mouse is over the gutter.\n\t * Defaults to 'mouseover'.\n\t */\n\tshowFoldingControls?: 'always' | 'never' | 'mouseover';\n\t/**\n\t * Controls whether clicking on the empty content after a folded line will unfold the line.\n\t * Defaults to false.\n\t */\n\tunfoldOnClickAfterEndOfLine?: boolean;\n\t/**\n\t * Enable highlighting of matching brackets.\n\t * Defaults to 'always'.\n\t */\n\tmatchBrackets?: 'never' | 'near' | 'always';\n\t/**\n\t * Enable experimental whitespace rendering.\n\t * Defaults to 'svg'.\n\t */\n\texperimentalWhitespaceRendering?: 'svg' | 'font' | 'off';\n\t/**\n\t * Enable rendering of whitespace.\n\t * Defaults to 'selection'.\n\t */\n\trenderWhitespace?: 'none' | 'boundary' | 'selection' | 'trailing' | 'all';\n\t/**\n\t * Enable rendering of control characters.\n\t * Defaults to true.\n\t */\n\trenderControlCharacters?: boolean;\n\t/**\n\t * Enable rendering of current line highlight.\n\t * Defaults to all.\n\t */\n\trenderLineHighlight?: 'none' | 'gutter' | 'line' | 'all';\n\t/**\n\t * Control if the current line highlight should be rendered only the editor is focused.\n\t * Defaults to false.\n\t */\n\trenderLineHighlightOnlyWhenFocus?: boolean;\n\t/**\n\t * Inserting and deleting whitespace follows tab stops.\n\t */\n\tuseTabStops?: boolean;\n\t/**\n\t * The font family\n\t */\n\tfontFamily?: string;\n\t/**\n\t * The font weight\n\t */\n\tfontWeight?: string;\n\t/**\n\t * The font size\n\t */\n\tfontSize?: number;\n\t/**\n\t * The line height\n\t */\n\tlineHeight?: number;\n\t/**\n\t * The letter spacing\n\t */\n\tletterSpacing?: number;\n\t/**\n\t * Controls fading out of unused variables.\n\t */\n\tshowUnused?: boolean;\n\t/**\n\t * Controls whether to focus the inline editor in the peek widget by default.\n\t * Defaults to false.\n\t */\n\tpeekWidgetDefaultFocus?: 'tree' | 'editor';\n\t/**\n\t * Controls whether the definition link opens element in the peek widget.\n\t * Defaults to false.\n\t */\n\tdefinitionLinkOpensInPeek?: boolean;\n\t/**\n\t * Controls strikethrough deprecated variables.\n\t */\n\tshowDeprecated?: boolean;\n\t/**\n\t * Controls whether suggestions allow matches in the middle of the word instead of only at the beginning\n\t */\n\tmatchOnWordStartOnly?: boolean;\n\t/**\n\t * Control the behavior and rendering of the inline hints.\n\t */\n\tinlayHints?: IEditorInlayHintsOptions;\n\t/**\n\t * Control if the editor should use shadow DOM.\n\t */\n\tuseShadowDOM?: boolean;\n\t/**\n\t * Controls the behavior of editor guides.\n\t*/\n\tguides?: IGuidesOptions;\n\n\t/**\n\t * Controls the behavior of the unicode highlight feature\n\t * (by default, ambiguous and invisible characters are highlighted).\n\t */\n\tunicodeHighlight?: IUnicodeHighlightOptions;\n\n\t/**\n\t * Configures bracket pair colorization (disabled by default).\n\t*/\n\tbracketPairColorization?: IBracketPairColorizationOptions;\n\n\t/**\n\t * Controls dropping into the editor from an external source.\n\t *\n\t * When enabled, this shows a preview of the drop location and triggers an `onDropIntoEditor` event.\n\t */\n\tdropIntoEditor?: IDropIntoEditorOptions;\n\n\t/**\n\t * Controls support for changing how content is pasted into the editor.\n\t */\n\tpasteAs?: IPasteAsOptions;\n\n\t/**\n\t * Controls whether the editor / terminal receives tabs or defers them to the workbench for navigation.\n\t */\n\ttabFocusMode?: boolean;\n\n\t/**\n\t * Controls whether the accessibility hint should be provided to screen reader users when an inline completion is shown.\n\t */\n\tinlineCompletionsAccessibilityVerbose?: boolean;\n}\n\n/**\n * @internal\n * The width of the minimap gutter, in pixels.\n */\nexport const MINIMAP_GUTTER_WIDTH = 8;\n\nexport interface IDiffEditorBaseOptions {\n\t/**\n\t * Allow the user to resize the diff editor split view.\n\t * Defaults to true.\n\t */\n\tenableSplitViewResizing?: boolean;\n\t/**\n\t * The default ratio when rendering side-by-side editors.\n\t * Must be a number between 0 and 1, min sizes apply.\n\t * Defaults to 0.5\n\t */\n\tsplitViewDefaultRatio?: number;\n\t/**\n\t * Render the differences in two side-by-side editors.\n\t * Defaults to true.\n\t */\n\trenderSideBySide?: boolean;\n\t/**\n\t * When `renderSideBySide` is enabled, `useInlineViewWhenSpaceIsLimited` is set,\n\t * and the diff editor has a width less than `renderSideBySideInlineBreakpoint`, the inline view is used.\n\t */\n\trenderSideBySideInlineBreakpoint?: number | undefined;\n\t/**\n\t * When `renderSideBySide` is enabled, `useInlineViewWhenSpaceIsLimited` is set,\n\t * and the diff editor has a width less than `renderSideBySideInlineBreakpoint`, the inline view is used.\n\t */\n\tuseInlineViewWhenSpaceIsLimited?: boolean;\n\t/**\n\t * Timeout in milliseconds after which diff computation is cancelled.\n\t * Defaults to 5000.\n\t */\n\tmaxComputationTime?: number;\n\t/**\n\t * Maximum supported file size in MB.\n\t * Defaults to 50.\n\t */\n\tmaxFileSize?: number;\n\t/**\n\t * Compute the diff by ignoring leading/trailing whitespace\n\t * Defaults to true.\n\t */\n\tignoreTrimWhitespace?: boolean;\n\t/**\n\t * Render +/- indicators for added/deleted changes.\n\t * Defaults to true.\n\t */\n\trenderIndicators?: boolean;\n\t/**\n\t * Shows icons in the glyph margin to revert changes.\n\t * Default to true.\n\t */\n\trenderMarginRevertIcon?: boolean;\n\t/**\n\t * Indicates if the gutter menu should be rendered.\n\t*/\n\trenderGutterMenu?: boolean;\n\t/**\n\t * Original model should be editable?\n\t * Defaults to false.\n\t */\n\toriginalEditable?: boolean;\n\t/**\n\t * Should the diff editor enable code lens?\n\t * Defaults to false.\n\t */\n\tdiffCodeLens?: boolean;\n\t/**\n\t * Is the diff editor should render overview ruler\n\t * Defaults to true\n\t */\n\trenderOverviewRuler?: boolean;\n\t/**\n\t * Control the wrapping of the diff editor.\n\t */\n\tdiffWordWrap?: 'off' | 'on' | 'inherit';\n\t/**\n\t * Diff Algorithm\n\t*/\n\tdiffAlgorithm?: 'legacy' | 'advanced';\n\n\t/**\n\t * Whether the diff editor aria label should be verbose.\n\t */\n\taccessibilityVerbose?: boolean;\n\n\texperimental?: {\n\t\t/**\n\t\t * Defaults to false.\n\t\t */\n\t\tshowMoves?: boolean;\n\n\t\tshowEmptyDecorations?: boolean;\n\t};\n\n\t/**\n\t * Is the diff editor inside another editor\n\t * Defaults to false\n\t */\n\tisInEmbeddedEditor?: boolean;\n\n\t/**\n\t * If the diff editor should only show the difference review mode.\n\t */\n\tonlyShowAccessibleDiffViewer?: boolean;\n\n\thideUnchangedRegions?: {\n\t\tenabled?: boolean;\n\t\trevealLineCount?: number;\n\t\tminimumLineCount?: number;\n\t\tcontextLineCount?: number;\n\t};\n}\n\n/**\n * Configuration options for the diff editor.\n */\nexport interface IDiffEditorOptions extends IEditorOptions, IDiffEditorBaseOptions {\n}\n\n/**\n * @internal\n */\nexport type ValidDiffEditorBaseOptions = Readonly>;\n\n//#endregion\n\n/**\n * An event describing that the configuration of the editor has changed.\n */\nexport class ConfigurationChangedEvent {\n\tprivate readonly _values: boolean[];\n\t/**\n\t * @internal\n\t */\n\tconstructor(values: boolean[]) {\n\t\tthis._values = values;\n\t}\n\tpublic hasChanged(id: EditorOption): boolean {\n\t\treturn this._values[id];\n\t}\n}\n\n/**\n * All computed editor options.\n */\nexport interface IComputedEditorOptions {\n\tget(id: T): FindComputedEditorOptionValueById;\n}\n\n//#region IEditorOption\n\n/**\n * @internal\n */\nexport interface IEnvironmentalOptions {\n\treadonly memory: ComputeOptionsMemory | null;\n\treadonly outerWidth: number;\n\treadonly outerHeight: number;\n\treadonly fontInfo: FontInfo;\n\treadonly extraEditorClassName: string;\n\treadonly isDominatedByLongLines: boolean;\n\treadonly viewLineCount: number;\n\treadonly lineNumbersDigitCount: number;\n\treadonly emptySelectionClipboard: boolean;\n\treadonly pixelRatio: number;\n\treadonly tabFocusMode: boolean;\n\treadonly accessibilitySupport: AccessibilitySupport;\n\treadonly glyphMarginDecorationLaneCount: number;\n}\n\n/**\n * @internal\n */\nexport class ComputeOptionsMemory {\n\n\tpublic stableMinimapLayoutInput: IMinimapLayoutInput | null;\n\tpublic stableFitMaxMinimapScale: number;\n\tpublic stableFitRemainingWidth: number;\n\n\tconstructor() {\n\t\tthis.stableMinimapLayoutInput = null;\n\t\tthis.stableFitMaxMinimapScale = 0;\n\t\tthis.stableFitRemainingWidth = 0;\n\t}\n}\n\nexport interface IEditorOption {\n\treadonly id: K;\n\treadonly name: string;\n\tdefaultValue: V;\n\t/**\n\t * @internal\n\t */\n\treadonly schema: IConfigurationPropertySchema | { [path: string]: IConfigurationPropertySchema } | undefined;\n\t/**\n\t * @internal\n\t */\n\tvalidate(input: any): V;\n\t/**\n\t * @internal\n\t */\n\tcompute(env: IEnvironmentalOptions, options: IComputedEditorOptions, value: V): V;\n\n\t/**\n\t * Might modify `value`.\n\t*/\n\tapplyUpdate(value: V | undefined, update: V): ApplyUpdateResult;\n}\n\n/**\n * @internal\n */\ntype PossibleKeyName0 = { [K in keyof IEditorOptions]: IEditorOptions[K] extends V | undefined ? K : never }[keyof IEditorOptions];\n/**\n * @internal\n */\ntype PossibleKeyName = NonNullable>;\n\n/**\n * @internal\n */\nabstract class BaseEditorOption implements IEditorOption {\n\n\tpublic readonly id: K;\n\tpublic readonly name: string;\n\tpublic readonly defaultValue: V;\n\tpublic readonly schema: IConfigurationPropertySchema | { [path: string]: IConfigurationPropertySchema } | undefined;\n\n\tconstructor(id: K, name: PossibleKeyName, defaultValue: V, schema?: IConfigurationPropertySchema | { [path: string]: IConfigurationPropertySchema }) {\n\t\tthis.id = id;\n\t\tthis.name = name;\n\t\tthis.defaultValue = defaultValue;\n\t\tthis.schema = schema;\n\t}\n\n\tpublic applyUpdate(value: V | undefined, update: V): ApplyUpdateResult {\n\t\treturn applyUpdate(value, update);\n\t}\n\n\tpublic abstract validate(input: any): V;\n\n\tpublic compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, value: V): V {\n\t\treturn value;\n\t}\n}\n\nexport class ApplyUpdateResult {\n\tconstructor(\n\t\tpublic readonly newValue: T,\n\t\tpublic readonly didChange: boolean\n\t) { }\n}\n\nfunction applyUpdate(value: T | undefined, update: T): ApplyUpdateResult {\n\tif (typeof value !== 'object' || typeof update !== 'object' || !value || !update) {\n\t\treturn new ApplyUpdateResult(update, value !== update);\n\t}\n\tif (Array.isArray(value) || Array.isArray(update)) {\n\t\tconst arrayEquals = Array.isArray(value) && Array.isArray(update) && arrays.equals(value, update);\n\t\treturn new ApplyUpdateResult(update, !arrayEquals);\n\t}\n\tlet didChange = false;\n\tfor (const key in update) {\n\t\tif ((update as T & object).hasOwnProperty(key)) {\n\t\t\tconst result = applyUpdate(value[key], update[key]);\n\t\t\tif (result.didChange) {\n\t\t\t\tvalue[key] = result.newValue;\n\t\t\t\tdidChange = true;\n\t\t\t}\n\t\t}\n\t}\n\treturn new ApplyUpdateResult(value, didChange);\n}\n\n/**\n * @internal\n */\nabstract class ComputedEditorOption implements IEditorOption {\n\n\tpublic readonly id: K;\n\tpublic readonly name: '_never_';\n\tpublic readonly defaultValue: V;\n\tpublic readonly schema: IConfigurationPropertySchema | undefined = undefined;\n\n\tconstructor(id: K) {\n\t\tthis.id = id;\n\t\tthis.name = '_never_';\n\t\tthis.defaultValue = undefined;\n\t}\n\n\tpublic applyUpdate(value: V | undefined, update: V): ApplyUpdateResult {\n\t\treturn applyUpdate(value, update);\n\t}\n\n\tpublic validate(input: any): V {\n\t\treturn this.defaultValue;\n\t}\n\n\tpublic abstract compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, value: V): V;\n}\n\nclass SimpleEditorOption implements IEditorOption {\n\n\tpublic readonly id: K;\n\tpublic readonly name: PossibleKeyName;\n\tpublic readonly defaultValue: V;\n\tpublic readonly schema: IConfigurationPropertySchema | undefined;\n\n\tconstructor(id: K, name: PossibleKeyName, defaultValue: V, schema?: IConfigurationPropertySchema) {\n\t\tthis.id = id;\n\t\tthis.name = name;\n\t\tthis.defaultValue = defaultValue;\n\t\tthis.schema = schema;\n\t}\n\n\tpublic applyUpdate(value: V | undefined, update: V): ApplyUpdateResult {\n\t\treturn applyUpdate(value, update);\n\t}\n\n\tpublic validate(input: any): V {\n\t\tif (typeof input === 'undefined') {\n\t\t\treturn this.defaultValue;\n\t\t}\n\t\treturn input as any;\n\t}\n\n\tpublic compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, value: V): V {\n\t\treturn value;\n\t}\n}\n\n/**\n * @internal\n */\nexport function boolean(value: any, defaultValue: boolean): boolean {\n\tif (typeof value === 'undefined') {\n\t\treturn defaultValue;\n\t}\n\tif (value === 'false') {\n\t\t// treat the string 'false' as false\n\t\treturn false;\n\t}\n\treturn Boolean(value);\n}\n\nclass EditorBooleanOption extends SimpleEditorOption {\n\n\tconstructor(id: K, name: PossibleKeyName, defaultValue: boolean, schema: IConfigurationPropertySchema | undefined = undefined) {\n\t\tif (typeof schema !== 'undefined') {\n\t\t\tschema.type = 'boolean';\n\t\t\tschema.default = defaultValue;\n\t\t}\n\t\tsuper(id, name, defaultValue, schema);\n\t}\n\n\tpublic override validate(input: any): boolean {\n\t\treturn boolean(input, this.defaultValue);\n\t}\n}\n\n/**\n * @internal\n */\nexport function clampedInt(value: any, defaultValue: T, minimum: number, maximum: number): number | T {\n\tif (typeof value === 'undefined') {\n\t\treturn defaultValue;\n\t}\n\tlet r = parseInt(value, 10);\n\tif (isNaN(r)) {\n\t\treturn defaultValue;\n\t}\n\tr = Math.max(minimum, r);\n\tr = Math.min(maximum, r);\n\treturn r | 0;\n}\n\nclass EditorIntOption extends SimpleEditorOption {\n\n\tpublic static clampedInt(value: any, defaultValue: T, minimum: number, maximum: number): number | T {\n\t\treturn clampedInt(value, defaultValue, minimum, maximum);\n\t}\n\n\tpublic readonly minimum: number;\n\tpublic readonly maximum: number;\n\n\tconstructor(id: K, name: PossibleKeyName, defaultValue: number, minimum: number, maximum: number, schema: IConfigurationPropertySchema | undefined = undefined) {\n\t\tif (typeof schema !== 'undefined') {\n\t\t\tschema.type = 'integer';\n\t\t\tschema.default = defaultValue;\n\t\t\tschema.minimum = minimum;\n\t\t\tschema.maximum = maximum;\n\t\t}\n\t\tsuper(id, name, defaultValue, schema);\n\t\tthis.minimum = minimum;\n\t\tthis.maximum = maximum;\n\t}\n\n\tpublic override validate(input: any): number {\n\t\treturn EditorIntOption.clampedInt(input, this.defaultValue, this.minimum, this.maximum);\n\t}\n}\n/**\n * @internal\n */\nexport function clampedFloat(value: any, defaultValue: T, minimum: number, maximum: number): number | T {\n\tif (typeof value === 'undefined') {\n\t\treturn defaultValue;\n\t}\n\tconst r = EditorFloatOption.float(value, defaultValue);\n\treturn EditorFloatOption.clamp(r, minimum, maximum);\n}\n\nclass EditorFloatOption extends SimpleEditorOption {\n\n\tpublic static clamp(n: number, min: number, max: number): number {\n\t\tif (n < min) {\n\t\t\treturn min;\n\t\t}\n\t\tif (n > max) {\n\t\t\treturn max;\n\t\t}\n\t\treturn n;\n\t}\n\n\tpublic static float(value: any, defaultValue: number): number {\n\t\tif (typeof value === 'number') {\n\t\t\treturn value;\n\t\t}\n\t\tif (typeof value === 'undefined') {\n\t\t\treturn defaultValue;\n\t\t}\n\t\tconst r = parseFloat(value);\n\t\treturn (isNaN(r) ? defaultValue : r);\n\t}\n\n\tpublic readonly validationFn: (value: number) => number;\n\n\tconstructor(id: K, name: PossibleKeyName, defaultValue: number, validationFn: (value: number) => number, schema?: IConfigurationPropertySchema) {\n\t\tif (typeof schema !== 'undefined') {\n\t\t\tschema.type = 'number';\n\t\t\tschema.default = defaultValue;\n\t\t}\n\t\tsuper(id, name, defaultValue, schema);\n\t\tthis.validationFn = validationFn;\n\t}\n\n\tpublic override validate(input: any): number {\n\t\treturn this.validationFn(EditorFloatOption.float(input, this.defaultValue));\n\t}\n}\n\nclass EditorStringOption extends SimpleEditorOption {\n\n\tpublic static string(value: any, defaultValue: string): string {\n\t\tif (typeof value !== 'string') {\n\t\t\treturn defaultValue;\n\t\t}\n\t\treturn value;\n\t}\n\n\tconstructor(id: K, name: PossibleKeyName, defaultValue: string, schema: IConfigurationPropertySchema | undefined = undefined) {\n\t\tif (typeof schema !== 'undefined') {\n\t\t\tschema.type = 'string';\n\t\t\tschema.default = defaultValue;\n\t\t}\n\t\tsuper(id, name, defaultValue, schema);\n\t}\n\n\tpublic override validate(input: any): string {\n\t\treturn EditorStringOption.string(input, this.defaultValue);\n\t}\n}\n\n/**\n * @internal\n */\nexport function stringSet(value: T | undefined, defaultValue: T, allowedValues: ReadonlyArray, renamedValues?: Record): T {\n\tif (typeof value !== 'string') {\n\t\treturn defaultValue;\n\t}\n\tif (renamedValues && value in renamedValues) {\n\t\treturn renamedValues[value];\n\t}\n\tif (allowedValues.indexOf(value) === -1) {\n\t\treturn defaultValue;\n\t}\n\treturn value;\n}\n\nclass EditorStringEnumOption extends SimpleEditorOption {\n\n\tprivate readonly _allowedValues: ReadonlyArray;\n\n\tconstructor(id: K, name: PossibleKeyName, defaultValue: V, allowedValues: ReadonlyArray, schema: IConfigurationPropertySchema | undefined = undefined) {\n\t\tif (typeof schema !== 'undefined') {\n\t\t\tschema.type = 'string';\n\t\t\tschema.enum = allowedValues;\n\t\t\tschema.default = defaultValue;\n\t\t}\n\t\tsuper(id, name, defaultValue, schema);\n\t\tthis._allowedValues = allowedValues;\n\t}\n\n\tpublic override validate(input: any): V {\n\t\treturn stringSet(input, this.defaultValue, this._allowedValues);\n\t}\n}\n\nclass EditorEnumOption extends BaseEditorOption {\n\n\tprivate readonly _allowedValues: T[];\n\tprivate readonly _convert: (value: T) => V;\n\n\tconstructor(id: K, name: PossibleKeyName, defaultValue: V, defaultStringValue: string, allowedValues: T[], convert: (value: T) => V, schema: IConfigurationPropertySchema | undefined = undefined) {\n\t\tif (typeof schema !== 'undefined') {\n\t\t\tschema.type = 'string';\n\t\t\tschema.enum = allowedValues;\n\t\t\tschema.default = defaultStringValue;\n\t\t}\n\t\tsuper(id, name, defaultValue, schema);\n\t\tthis._allowedValues = allowedValues;\n\t\tthis._convert = convert;\n\t}\n\n\tpublic validate(input: any): V {\n\t\tif (typeof input !== 'string') {\n\t\t\treturn this.defaultValue;\n\t\t}\n\t\tif (this._allowedValues.indexOf(input) === -1) {\n\t\t\treturn this.defaultValue;\n\t\t}\n\t\treturn this._convert(input);\n\t}\n}\n\n//#endregion\n\n//#region autoIndent\n\nfunction _autoIndentFromString(autoIndent: 'none' | 'keep' | 'brackets' | 'advanced' | 'full'): EditorAutoIndentStrategy {\n\tswitch (autoIndent) {\n\t\tcase 'none': return EditorAutoIndentStrategy.None;\n\t\tcase 'keep': return EditorAutoIndentStrategy.Keep;\n\t\tcase 'brackets': return EditorAutoIndentStrategy.Brackets;\n\t\tcase 'advanced': return EditorAutoIndentStrategy.Advanced;\n\t\tcase 'full': return EditorAutoIndentStrategy.Full;\n\t}\n}\n\n//#endregion\n\n//#region accessibilitySupport\n\nclass EditorAccessibilitySupport extends BaseEditorOption {\n\n\tconstructor() {\n\t\tsuper(\n\t\t\tEditorOption.accessibilitySupport, 'accessibilitySupport', AccessibilitySupport.Unknown,\n\t\t\t{\n\t\t\t\ttype: 'string',\n\t\t\t\tenum: ['auto', 'on', 'off'],\n\t\t\t\tenumDescriptions: [\n\t\t\t\t\tnls.localize('accessibilitySupport.auto', \"Use platform APIs to detect when a Screen Reader is attached.\"),\n\t\t\t\t\tnls.localize('accessibilitySupport.on', \"Optimize for usage with a Screen Reader.\"),\n\t\t\t\t\tnls.localize('accessibilitySupport.off', \"Assume a screen reader is not attached.\"),\n\t\t\t\t],\n\t\t\t\tdefault: 'auto',\n\t\t\t\ttags: ['accessibility'],\n\t\t\t\tdescription: nls.localize('accessibilitySupport', \"Controls if the UI should run in a mode where it is optimized for screen readers.\")\n\t\t\t}\n\t\t);\n\t}\n\n\tpublic validate(input: any): AccessibilitySupport {\n\t\tswitch (input) {\n\t\t\tcase 'auto': return AccessibilitySupport.Unknown;\n\t\t\tcase 'off': return AccessibilitySupport.Disabled;\n\t\t\tcase 'on': return AccessibilitySupport.Enabled;\n\t\t}\n\t\treturn this.defaultValue;\n\t}\n\n\tpublic override compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, value: AccessibilitySupport): AccessibilitySupport {\n\t\tif (value === AccessibilitySupport.Unknown) {\n\t\t\t// The editor reads the `accessibilitySupport` from the environment\n\t\t\treturn env.accessibilitySupport;\n\t\t}\n\t\treturn value;\n\t}\n}\n\n//#endregion\n\n//#region comments\n\n/**\n * Configuration options for editor comments\n */\nexport interface IEditorCommentsOptions {\n\t/**\n\t * Insert a space after the line comment token and inside the block comments tokens.\n\t * Defaults to true.\n\t */\n\tinsertSpace?: boolean;\n\t/**\n\t * Ignore empty lines when inserting line comments.\n\t * Defaults to true.\n\t */\n\tignoreEmptyLines?: boolean;\n}\n\n/**\n * @internal\n */\nexport type EditorCommentsOptions = Readonly>;\n\nclass EditorComments extends BaseEditorOption {\n\n\tconstructor() {\n\t\tconst defaults: EditorCommentsOptions = {\n\t\t\tinsertSpace: true,\n\t\t\tignoreEmptyLines: true,\n\t\t};\n\t\tsuper(\n\t\t\tEditorOption.comments, 'comments', defaults,\n\t\t\t{\n\t\t\t\t'editor.comments.insertSpace': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: defaults.insertSpace,\n\t\t\t\t\tdescription: nls.localize('comments.insertSpace', \"Controls whether a space character is inserted when commenting.\")\n\t\t\t\t},\n\t\t\t\t'editor.comments.ignoreEmptyLines': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: defaults.ignoreEmptyLines,\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.')\n\t\t\t\t},\n\t\t\t}\n\t\t);\n\t}\n\n\tpublic validate(_input: any): EditorCommentsOptions {\n\t\tif (!_input || typeof _input !== 'object') {\n\t\t\treturn this.defaultValue;\n\t\t}\n\t\tconst input = _input as IEditorCommentsOptions;\n\t\treturn {\n\t\t\tinsertSpace: boolean(input.insertSpace, this.defaultValue.insertSpace),\n\t\t\tignoreEmptyLines: boolean(input.ignoreEmptyLines, this.defaultValue.ignoreEmptyLines),\n\t\t};\n\t}\n}\n\n//#endregion\n\n//#region cursorBlinking\n\n/**\n * The kind of animation in which the editor's cursor should be rendered.\n */\nexport const 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\nfunction _cursorBlinkingStyleFromString(cursorBlinkingStyle: 'blink' | 'smooth' | 'phase' | 'expand' | 'solid'): TextEditorCursorBlinkingStyle {\n\tswitch (cursorBlinkingStyle) {\n\t\tcase 'blink': return TextEditorCursorBlinkingStyle.Blink;\n\t\tcase 'smooth': return TextEditorCursorBlinkingStyle.Smooth;\n\t\tcase 'phase': return TextEditorCursorBlinkingStyle.Phase;\n\t\tcase 'expand': return TextEditorCursorBlinkingStyle.Expand;\n\t\tcase 'solid': return TextEditorCursorBlinkingStyle.Solid;\n\t}\n}\n\n//#endregion\n\n//#region cursorStyle\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\nfunction _cursorStyleFromString(cursorStyle: 'line' | 'block' | 'underline' | 'line-thin' | 'block-outline' | 'underline-thin'): TextEditorCursorStyle {\n\tswitch (cursorStyle) {\n\t\tcase 'line': return TextEditorCursorStyle.Line;\n\t\tcase 'block': return TextEditorCursorStyle.Block;\n\t\tcase 'underline': return TextEditorCursorStyle.Underline;\n\t\tcase 'line-thin': return TextEditorCursorStyle.LineThin;\n\t\tcase 'block-outline': return TextEditorCursorStyle.BlockOutline;\n\t\tcase 'underline-thin': return TextEditorCursorStyle.UnderlineThin;\n\t}\n}\n\n//#endregion\n\n//#region editorClassName\n\nclass EditorClassName extends ComputedEditorOption {\n\n\tconstructor() {\n\t\tsuper(EditorOption.editorClassName);\n\t}\n\n\tpublic compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, _: string): string {\n\t\tconst classNames = ['monaco-editor'];\n\t\tif (options.get(EditorOption.extraEditorClassName)) {\n\t\t\tclassNames.push(options.get(EditorOption.extraEditorClassName));\n\t\t}\n\t\tif (env.extraEditorClassName) {\n\t\t\tclassNames.push(env.extraEditorClassName);\n\t\t}\n\t\tif (options.get(EditorOption.mouseStyle) === 'default') {\n\t\t\tclassNames.push('mouse-default');\n\t\t} else if (options.get(EditorOption.mouseStyle) === 'copy') {\n\t\t\tclassNames.push('mouse-copy');\n\t\t}\n\n\t\tif (options.get(EditorOption.showUnused)) {\n\t\t\tclassNames.push('showUnused');\n\t\t}\n\n\t\tif (options.get(EditorOption.showDeprecated)) {\n\t\t\tclassNames.push('showDeprecated');\n\t\t}\n\n\t\treturn classNames.join(' ');\n\t}\n}\n\n//#endregion\n\n//#region emptySelectionClipboard\n\nclass EditorEmptySelectionClipboard extends EditorBooleanOption {\n\n\tconstructor() {\n\t\tsuper(\n\t\t\tEditorOption.emptySelectionClipboard, 'emptySelectionClipboard', true,\n\t\t\t{ description: nls.localize('emptySelectionClipboard', \"Controls whether copying without a selection copies the current line.\") }\n\t\t);\n\t}\n\n\tpublic override compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, value: boolean): boolean {\n\t\treturn value && env.emptySelectionClipboard;\n\t}\n}\n\n//#endregion\n\n//#region find\n\n/**\n * Configuration options for editor find widget\n */\nexport interface IEditorFindOptions {\n\t/**\n\t* Controls whether the cursor should move to find matches while typing.\n\t*/\n\tcursorMoveOnType?: boolean;\n\t/**\n\t * Controls if we seed search string in the Find Widget with editor selection.\n\t */\n\tseedSearchStringFromSelection?: 'never' | 'always' | 'selection';\n\t/**\n\t * Controls if Find in Selection flag is turned on in the editor.\n\t */\n\tautoFindInSelection?: 'never' | 'always' | 'multiline';\n\t/*\n\t * Controls whether the Find Widget should add extra lines on top of the editor.\n\t */\n\taddExtraSpaceOnTop?: boolean;\n\t/**\n\t * @internal\n\t * Controls if the Find Widget should read or modify the shared find clipboard on macOS\n\t */\n\tglobalFindClipboard?: boolean;\n\t/**\n\t * Controls whether the search result and diff result automatically restarts from the beginning (or the end) when no further matches can be found\n\t */\n\tloop?: boolean;\n}\n\n/**\n * @internal\n */\nexport type EditorFindOptions = Readonly>;\n\nclass EditorFind extends BaseEditorOption {\n\n\tconstructor() {\n\t\tconst defaults: EditorFindOptions = {\n\t\t\tcursorMoveOnType: true,\n\t\t\tseedSearchStringFromSelection: 'always',\n\t\t\tautoFindInSelection: 'never',\n\t\t\tglobalFindClipboard: false,\n\t\t\taddExtraSpaceOnTop: true,\n\t\t\tloop: true\n\t\t};\n\t\tsuper(\n\t\t\tEditorOption.find, 'find', defaults,\n\t\t\t{\n\t\t\t\t'editor.find.cursorMoveOnType': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: defaults.cursorMoveOnType,\n\t\t\t\t\tdescription: nls.localize('find.cursorMoveOnType', \"Controls whether the cursor should jump to find matches while typing.\")\n\t\t\t\t},\n\t\t\t\t'editor.find.seedSearchStringFromSelection': {\n\t\t\t\t\ttype: 'string',\n\t\t\t\t\tenum: ['never', 'always', 'selection'],\n\t\t\t\t\tdefault: defaults.seedSearchStringFromSelection,\n\t\t\t\t\tenumDescriptions: [\n\t\t\t\t\t\tnls.localize('editor.find.seedSearchStringFromSelection.never', 'Never seed search string from the editor selection.'),\n\t\t\t\t\t\tnls.localize('editor.find.seedSearchStringFromSelection.always', 'Always seed search string from the editor selection, including word at cursor position.'),\n\t\t\t\t\t\tnls.localize('editor.find.seedSearchStringFromSelection.selection', 'Only seed search string from the editor selection.')\n\t\t\t\t\t],\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.\")\n\t\t\t\t},\n\t\t\t\t'editor.find.autoFindInSelection': {\n\t\t\t\t\ttype: 'string',\n\t\t\t\t\tenum: ['never', 'always', 'multiline'],\n\t\t\t\t\tdefault: defaults.autoFindInSelection,\n\t\t\t\t\tenumDescriptions: [\n\t\t\t\t\t\tnls.localize('editor.find.autoFindInSelection.never', 'Never turn on Find in Selection automatically (default).'),\n\t\t\t\t\t\tnls.localize('editor.find.autoFindInSelection.always', 'Always turn on Find in Selection automatically.'),\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.')\n\t\t\t\t\t],\n\t\t\t\t\tdescription: nls.localize('find.autoFindInSelection', \"Controls the condition for turning on Find in Selection automatically.\")\n\t\t\t\t},\n\t\t\t\t'editor.find.globalFindClipboard': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: defaults.globalFindClipboard,\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.\"),\n\t\t\t\t\tincluded: platform.isMacintosh\n\t\t\t\t},\n\t\t\t\t'editor.find.addExtraSpaceOnTop': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: defaults.addExtraSpaceOnTop,\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.\")\n\t\t\t\t},\n\t\t\t\t'editor.find.loop': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: defaults.loop,\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.\")\n\t\t\t\t},\n\n\t\t\t}\n\t\t);\n\t}\n\n\tpublic validate(_input: any): EditorFindOptions {\n\t\tif (!_input || typeof _input !== 'object') {\n\t\t\treturn this.defaultValue;\n\t\t}\n\t\tconst input = _input as IEditorFindOptions;\n\t\treturn {\n\t\t\tcursorMoveOnType: boolean(input.cursorMoveOnType, this.defaultValue.cursorMoveOnType),\n\t\t\tseedSearchStringFromSelection: typeof _input.seedSearchStringFromSelection === 'boolean'\n\t\t\t\t? (_input.seedSearchStringFromSelection ? 'always' : 'never')\n\t\t\t\t: stringSet<'never' | 'always' | 'selection'>(input.seedSearchStringFromSelection, this.defaultValue.seedSearchStringFromSelection, ['never', 'always', 'selection']),\n\t\t\tautoFindInSelection: typeof _input.autoFindInSelection === 'boolean'\n\t\t\t\t? (_input.autoFindInSelection ? 'always' : 'never')\n\t\t\t\t: stringSet<'never' | 'always' | 'multiline'>(input.autoFindInSelection, this.defaultValue.autoFindInSelection, ['never', 'always', 'multiline']),\n\t\t\tglobalFindClipboard: boolean(input.globalFindClipboard, this.defaultValue.globalFindClipboard),\n\t\t\taddExtraSpaceOnTop: boolean(input.addExtraSpaceOnTop, this.defaultValue.addExtraSpaceOnTop),\n\t\t\tloop: boolean(input.loop, this.defaultValue.loop),\n\t\t};\n\t}\n}\n\n//#endregion\n\n//#region fontLigatures\n\n/**\n * @internal\n */\nexport class EditorFontLigatures extends BaseEditorOption {\n\n\tpublic static OFF = '\"liga\" off, \"calt\" off';\n\tpublic static ON = '\"liga\" on, \"calt\" on';\n\n\tconstructor() {\n\t\tsuper(\n\t\t\tEditorOption.fontLigatures, 'fontLigatures', EditorFontLigatures.OFF,\n\t\t\t{\n\t\t\t\tanyOf: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: 'boolean',\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.\"),\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: 'string',\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.\")\n\t\t\t\t\t}\n\t\t\t\t],\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.\"),\n\t\t\t\tdefault: false\n\t\t\t}\n\t\t);\n\t}\n\n\tpublic validate(input: any): string {\n\t\tif (typeof input === 'undefined') {\n\t\t\treturn this.defaultValue;\n\t\t}\n\t\tif (typeof input === 'string') {\n\t\t\tif (input === 'false' || input.length === 0) {\n\t\t\t\treturn EditorFontLigatures.OFF;\n\t\t\t}\n\t\t\tif (input === 'true') {\n\t\t\t\treturn EditorFontLigatures.ON;\n\t\t\t}\n\t\t\treturn input;\n\t\t}\n\t\tif (Boolean(input)) {\n\t\t\treturn EditorFontLigatures.ON;\n\t\t}\n\t\treturn EditorFontLigatures.OFF;\n\t}\n}\n\n//#endregion\n\n//#region fontVariations\n\n/**\n * @internal\n */\nexport class EditorFontVariations extends BaseEditorOption {\n\t// Text is laid out using default settings.\n\tpublic static OFF = 'normal';\n\n\t// Translate `fontWeight` config to the `font-variation-settings` CSS property.\n\tpublic static TRANSLATE = 'translate';\n\n\tconstructor() {\n\t\tsuper(\n\t\t\tEditorOption.fontVariations, 'fontVariations', EditorFontVariations.OFF,\n\t\t\t{\n\t\t\t\tanyOf: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\t\tdescription: nls.localize('fontVariations', \"Enables/Disables the translation from font-weight to font-variation-settings. Change this to a string for fine-grained control of the 'font-variation-settings' CSS property.\"),\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: 'string',\n\t\t\t\t\t\tdescription: nls.localize('fontVariationSettings', \"Explicit 'font-variation-settings' CSS property. A boolean can be passed instead if one only needs to translate font-weight to font-variation-settings.\")\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\tdescription: nls.localize('fontVariationsGeneral', \"Configures font variations. Can be either a boolean to enable/disable the translation from font-weight to font-variation-settings or a string for the value of the CSS 'font-variation-settings' property.\"),\n\t\t\t\tdefault: false\n\t\t\t}\n\t\t);\n\t}\n\n\tpublic validate(input: any): string {\n\t\tif (typeof input === 'undefined') {\n\t\t\treturn this.defaultValue;\n\t\t}\n\t\tif (typeof input === 'string') {\n\t\t\tif (input === 'false') {\n\t\t\t\treturn EditorFontVariations.OFF;\n\t\t\t}\n\t\t\tif (input === 'true') {\n\t\t\t\treturn EditorFontVariations.TRANSLATE;\n\t\t\t}\n\t\t\treturn input;\n\t\t}\n\t\tif (Boolean(input)) {\n\t\t\treturn EditorFontVariations.TRANSLATE;\n\t\t}\n\t\treturn EditorFontVariations.OFF;\n\t}\n\n\tpublic override compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, value: string): string {\n\t\t// The value is computed from the fontWeight if it is true.\n\t\t// So take the result from env.fontInfo\n\t\treturn env.fontInfo.fontVariationSettings;\n\t}\n}\n\n//#endregion\n\n//#region fontInfo\n\nclass EditorFontInfo extends ComputedEditorOption {\n\n\tconstructor() {\n\t\tsuper(EditorOption.fontInfo);\n\t}\n\n\tpublic compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, _: FontInfo): FontInfo {\n\t\treturn env.fontInfo;\n\t}\n}\n\n//#endregion\n\n//#region fontSize\n\nclass EditorFontSize extends SimpleEditorOption {\n\n\tconstructor() {\n\t\tsuper(\n\t\t\tEditorOption.fontSize, 'fontSize', EDITOR_FONT_DEFAULTS.fontSize,\n\t\t\t{\n\t\t\t\ttype: 'number',\n\t\t\t\tminimum: 6,\n\t\t\t\tmaximum: 100,\n\t\t\t\tdefault: EDITOR_FONT_DEFAULTS.fontSize,\n\t\t\t\tdescription: nls.localize('fontSize', \"Controls the font size in pixels.\")\n\t\t\t}\n\t\t);\n\t}\n\n\tpublic override validate(input: any): number {\n\t\tconst r = EditorFloatOption.float(input, this.defaultValue);\n\t\tif (r === 0) {\n\t\t\treturn EDITOR_FONT_DEFAULTS.fontSize;\n\t\t}\n\t\treturn EditorFloatOption.clamp(r, 6, 100);\n\t}\n\tpublic override compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, value: number): number {\n\t\t// The final fontSize respects the editor zoom level.\n\t\t// So take the result from env.fontInfo\n\t\treturn env.fontInfo.fontSize;\n\t}\n}\n\n//#endregion\n\n//#region fontWeight\n\nclass EditorFontWeight extends BaseEditorOption {\n\tprivate static SUGGESTION_VALUES = ['normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900'];\n\tprivate static MINIMUM_VALUE = 1;\n\tprivate static MAXIMUM_VALUE = 1000;\n\n\tconstructor() {\n\t\tsuper(\n\t\t\tEditorOption.fontWeight, 'fontWeight', EDITOR_FONT_DEFAULTS.fontWeight,\n\t\t\t{\n\t\t\t\tanyOf: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: 'number',\n\t\t\t\t\t\tminimum: EditorFontWeight.MINIMUM_VALUE,\n\t\t\t\t\t\tmaximum: EditorFontWeight.MAXIMUM_VALUE,\n\t\t\t\t\t\terrorMessage: nls.localize('fontWeightErrorMessage', \"Only \\\"normal\\\" and \\\"bold\\\" keywords or numbers between 1 and 1000 are allowed.\")\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: 'string',\n\t\t\t\t\t\tpattern: '^(normal|bold|1000|[1-9][0-9]{0,2})$'\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tenum: EditorFontWeight.SUGGESTION_VALUES\n\t\t\t\t\t}\n\t\t\t\t],\n\t\t\t\tdefault: EDITOR_FONT_DEFAULTS.fontWeight,\n\t\t\t\tdescription: nls.localize('fontWeight', \"Controls the font weight. Accepts \\\"normal\\\" and \\\"bold\\\" keywords or numbers between 1 and 1000.\")\n\t\t\t}\n\t\t);\n\t}\n\n\tpublic validate(input: any): string {\n\t\tif (input === 'normal' || input === 'bold') {\n\t\t\treturn input;\n\t\t}\n\t\treturn String(EditorIntOption.clampedInt(input, EDITOR_FONT_DEFAULTS.fontWeight, EditorFontWeight.MINIMUM_VALUE, EditorFontWeight.MAXIMUM_VALUE));\n\t}\n}\n\n//#endregion\n\n//#region gotoLocation\n\nexport type GoToLocationValues = 'peek' | 'gotoAndPeek' | 'goto';\n\n/**\n * Configuration options for go to location\n */\nexport interface IGotoLocationOptions {\n\n\tmultiple?: GoToLocationValues;\n\n\tmultipleDefinitions?: GoToLocationValues;\n\tmultipleTypeDefinitions?: GoToLocationValues;\n\tmultipleDeclarations?: GoToLocationValues;\n\tmultipleImplementations?: GoToLocationValues;\n\tmultipleReferences?: GoToLocationValues;\n\n\talternativeDefinitionCommand?: string;\n\talternativeTypeDefinitionCommand?: string;\n\talternativeDeclarationCommand?: string;\n\talternativeImplementationCommand?: string;\n\talternativeReferenceCommand?: string;\n}\n\n/**\n * @internal\n */\nexport type GoToLocationOptions = Readonly>;\n\nclass EditorGoToLocation extends BaseEditorOption {\n\n\tconstructor() {\n\t\tconst defaults: GoToLocationOptions = {\n\t\t\tmultiple: 'peek',\n\t\t\tmultipleDefinitions: 'peek',\n\t\t\tmultipleTypeDefinitions: 'peek',\n\t\t\tmultipleDeclarations: 'peek',\n\t\t\tmultipleImplementations: 'peek',\n\t\t\tmultipleReferences: 'peek',\n\t\t\talternativeDefinitionCommand: 'editor.action.goToReferences',\n\t\t\talternativeTypeDefinitionCommand: 'editor.action.goToReferences',\n\t\t\talternativeDeclarationCommand: 'editor.action.goToReferences',\n\t\t\talternativeImplementationCommand: '',\n\t\t\talternativeReferenceCommand: '',\n\t\t};\n\t\tconst jsonSubset: IJSONSchema = {\n\t\t\ttype: 'string',\n\t\t\tenum: ['peek', 'gotoAndPeek', 'goto'],\n\t\t\tdefault: defaults.multiple,\n\t\t\tenumDescriptions: [\n\t\t\t\tnls.localize('editor.gotoLocation.multiple.peek', 'Show Peek view of the results (default)'),\n\t\t\t\tnls.localize('editor.gotoLocation.multiple.gotoAndPeek', 'Go to the primary result and show a Peek view'),\n\t\t\t\tnls.localize('editor.gotoLocation.multiple.goto', 'Go to the primary result and enable Peek-less navigation to others')\n\t\t\t]\n\t\t};\n\t\tconst alternativeCommandOptions = ['', 'editor.action.referenceSearch.trigger', 'editor.action.goToReferences', 'editor.action.peekImplementation', 'editor.action.goToImplementation', 'editor.action.peekTypeDefinition', 'editor.action.goToTypeDefinition', 'editor.action.peekDeclaration', 'editor.action.revealDeclaration', 'editor.action.peekDefinition', 'editor.action.revealDefinitionAside', 'editor.action.revealDefinition'];\n\t\tsuper(\n\t\t\tEditorOption.gotoLocation, 'gotoLocation', defaults,\n\t\t\t{\n\t\t\t\t'editor.gotoLocation.multiple': {\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.\"),\n\t\t\t\t},\n\t\t\t\t'editor.gotoLocation.multipleDefinitions': {\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.\"),\n\t\t\t\t\t...jsonSubset,\n\t\t\t\t},\n\t\t\t\t'editor.gotoLocation.multipleTypeDefinitions': {\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.\"),\n\t\t\t\t\t...jsonSubset,\n\t\t\t\t},\n\t\t\t\t'editor.gotoLocation.multipleDeclarations': {\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.\"),\n\t\t\t\t\t...jsonSubset,\n\t\t\t\t},\n\t\t\t\t'editor.gotoLocation.multipleImplementations': {\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.\"),\n\t\t\t\t\t...jsonSubset,\n\t\t\t\t},\n\t\t\t\t'editor.gotoLocation.multipleReferences': {\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.\"),\n\t\t\t\t\t...jsonSubset,\n\t\t\t\t},\n\t\t\t\t'editor.gotoLocation.alternativeDefinitionCommand': {\n\t\t\t\t\ttype: 'string',\n\t\t\t\t\tdefault: defaults.alternativeDefinitionCommand,\n\t\t\t\t\tenum: alternativeCommandOptions,\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.\")\n\t\t\t\t},\n\t\t\t\t'editor.gotoLocation.alternativeTypeDefinitionCommand': {\n\t\t\t\t\ttype: 'string',\n\t\t\t\t\tdefault: defaults.alternativeTypeDefinitionCommand,\n\t\t\t\t\tenum: alternativeCommandOptions,\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.\")\n\t\t\t\t},\n\t\t\t\t'editor.gotoLocation.alternativeDeclarationCommand': {\n\t\t\t\t\ttype: 'string',\n\t\t\t\t\tdefault: defaults.alternativeDeclarationCommand,\n\t\t\t\t\tenum: alternativeCommandOptions,\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.\")\n\t\t\t\t},\n\t\t\t\t'editor.gotoLocation.alternativeImplementationCommand': {\n\t\t\t\t\ttype: 'string',\n\t\t\t\t\tdefault: defaults.alternativeImplementationCommand,\n\t\t\t\t\tenum: alternativeCommandOptions,\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.\")\n\t\t\t\t},\n\t\t\t\t'editor.gotoLocation.alternativeReferenceCommand': {\n\t\t\t\t\ttype: 'string',\n\t\t\t\t\tdefault: defaults.alternativeReferenceCommand,\n\t\t\t\t\tenum: alternativeCommandOptions,\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.\")\n\t\t\t\t},\n\t\t\t}\n\t\t);\n\t}\n\n\tpublic validate(_input: any): GoToLocationOptions {\n\t\tif (!_input || typeof _input !== 'object') {\n\t\t\treturn this.defaultValue;\n\t\t}\n\t\tconst input = _input as IGotoLocationOptions;\n\t\treturn {\n\t\t\tmultiple: stringSet(input.multiple, this.defaultValue.multiple, ['peek', 'gotoAndPeek', 'goto']),\n\t\t\tmultipleDefinitions: input.multipleDefinitions ?? stringSet(input.multipleDefinitions, 'peek', ['peek', 'gotoAndPeek', 'goto']),\n\t\t\tmultipleTypeDefinitions: input.multipleTypeDefinitions ?? stringSet(input.multipleTypeDefinitions, 'peek', ['peek', 'gotoAndPeek', 'goto']),\n\t\t\tmultipleDeclarations: input.multipleDeclarations ?? stringSet(input.multipleDeclarations, 'peek', ['peek', 'gotoAndPeek', 'goto']),\n\t\t\tmultipleImplementations: input.multipleImplementations ?? stringSet(input.multipleImplementations, 'peek', ['peek', 'gotoAndPeek', 'goto']),\n\t\t\tmultipleReferences: input.multipleReferences ?? stringSet(input.multipleReferences, 'peek', ['peek', 'gotoAndPeek', 'goto']),\n\t\t\talternativeDefinitionCommand: EditorStringOption.string(input.alternativeDefinitionCommand, this.defaultValue.alternativeDefinitionCommand),\n\t\t\talternativeTypeDefinitionCommand: EditorStringOption.string(input.alternativeTypeDefinitionCommand, this.defaultValue.alternativeTypeDefinitionCommand),\n\t\t\talternativeDeclarationCommand: EditorStringOption.string(input.alternativeDeclarationCommand, this.defaultValue.alternativeDeclarationCommand),\n\t\t\talternativeImplementationCommand: EditorStringOption.string(input.alternativeImplementationCommand, this.defaultValue.alternativeImplementationCommand),\n\t\t\talternativeReferenceCommand: EditorStringOption.string(input.alternativeReferenceCommand, this.defaultValue.alternativeReferenceCommand),\n\t\t};\n\t}\n}\n\n//#endregion\n\n//#region hover\n\n/**\n * Configuration options for editor hover\n */\nexport interface IEditorHoverOptions {\n\t/**\n\t * Enable the hover.\n\t * Defaults to true.\n\t */\n\tenabled?: boolean;\n\t/**\n\t * Delay for showing the hover.\n\t * Defaults to 300.\n\t */\n\tdelay?: number;\n\t/**\n\t * Is the hover sticky such that it can be clicked and its contents selected?\n\t * Defaults to true.\n\t */\n\tsticky?: boolean;\n\t/**\n\t * Controls how long the hover is visible after you hovered out of it.\n\t * Require sticky setting to be true.\n\t */\n\thidingDelay?: number;\n\t/**\n\t * Should the hover be shown above the line if possible?\n\t * Defaults to false.\n\t */\n\tabove?: boolean;\n}\n\n/**\n * @internal\n */\nexport type EditorHoverOptions = Readonly>;\n\nclass EditorHover extends BaseEditorOption {\n\n\tconstructor() {\n\t\tconst defaults: EditorHoverOptions = {\n\t\t\tenabled: true,\n\t\t\tdelay: 300,\n\t\t\thidingDelay: 300,\n\t\t\tsticky: true,\n\t\t\tabove: true,\n\t\t};\n\t\tsuper(\n\t\t\tEditorOption.hover, 'hover', defaults,\n\t\t\t{\n\t\t\t\t'editor.hover.enabled': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: defaults.enabled,\n\t\t\t\t\tdescription: nls.localize('hover.enabled', \"Controls whether the hover is shown.\")\n\t\t\t\t},\n\t\t\t\t'editor.hover.delay': {\n\t\t\t\t\ttype: 'number',\n\t\t\t\t\tdefault: defaults.delay,\n\t\t\t\t\tminimum: 0,\n\t\t\t\t\tmaximum: 10000,\n\t\t\t\t\tdescription: nls.localize('hover.delay', \"Controls the delay in milliseconds after which the hover is shown.\")\n\t\t\t\t},\n\t\t\t\t'editor.hover.sticky': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: defaults.sticky,\n\t\t\t\t\tdescription: nls.localize('hover.sticky', \"Controls whether the hover should remain visible when mouse is moved over it.\")\n\t\t\t\t},\n\t\t\t\t'editor.hover.hidingDelay': {\n\t\t\t\t\ttype: 'integer',\n\t\t\t\t\tminimum: 0,\n\t\t\t\t\tdefault: defaults.hidingDelay,\n\t\t\t\t\tdescription: nls.localize('hover.hidingDelay', \"Controls the delay in milliseconds after which the hover is hidden. Requires `editor.hover.sticky` to be enabled.\")\n\t\t\t\t},\n\t\t\t\t'editor.hover.above': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: defaults.above,\n\t\t\t\t\tdescription: nls.localize('hover.above', \"Prefer showing hovers above the line, if there's space.\")\n\t\t\t\t},\n\t\t\t}\n\t\t);\n\t}\n\n\tpublic validate(_input: any): EditorHoverOptions {\n\t\tif (!_input || typeof _input !== 'object') {\n\t\t\treturn this.defaultValue;\n\t\t}\n\t\tconst input = _input as IEditorHoverOptions;\n\t\treturn {\n\t\t\tenabled: boolean(input.enabled, this.defaultValue.enabled),\n\t\t\tdelay: EditorIntOption.clampedInt(input.delay, this.defaultValue.delay, 0, 10000),\n\t\t\tsticky: boolean(input.sticky, this.defaultValue.sticky),\n\t\t\thidingDelay: EditorIntOption.clampedInt(input.hidingDelay, this.defaultValue.hidingDelay, 0, 600000),\n\t\t\tabove: boolean(input.above, this.defaultValue.above),\n\t\t};\n\t}\n}\n\n//#endregion\n\n//#region layoutInfo\n\n/**\n * A description for the overview ruler position.\n */\nexport interface OverviewRulerPosition {\n\t/**\n\t * Width of the overview ruler\n\t */\n\treadonly width: number;\n\t/**\n\t * Height of the overview ruler\n\t */\n\treadonly height: number;\n\t/**\n\t * Top position for the overview ruler\n\t */\n\treadonly top: number;\n\t/**\n\t * Right position for the overview ruler\n\t */\n\treadonly right: number;\n}\n\nexport const enum RenderMinimap {\n\tNone = 0,\n\tText = 1,\n\tBlocks = 2,\n}\n\n/**\n * The internal layout details of the editor.\n */\nexport interface EditorLayoutInfo {\n\n\t/**\n\t * Full editor width.\n\t */\n\treadonly width: number;\n\t/**\n\t * Full editor height.\n\t */\n\treadonly height: number;\n\n\t/**\n\t * Left position for the glyph margin.\n\t */\n\treadonly glyphMarginLeft: number;\n\t/**\n\t * The width of the glyph margin.\n\t */\n\treadonly glyphMarginWidth: number;\n\n\t/**\n\t * The number of decoration lanes to render in the glyph margin.\n\t */\n\treadonly glyphMarginDecorationLaneCount: number;\n\n\t/**\n\t * Left position for the line numbers.\n\t */\n\treadonly lineNumbersLeft: number;\n\t/**\n\t * The width of the line numbers.\n\t */\n\treadonly lineNumbersWidth: number;\n\n\t/**\n\t * Left position for the line decorations.\n\t */\n\treadonly decorationsLeft: number;\n\t/**\n\t * The width of the line decorations.\n\t */\n\treadonly decorationsWidth: number;\n\n\t/**\n\t * Left position for the content (actual text)\n\t */\n\treadonly contentLeft: number;\n\t/**\n\t * The width of the content (actual text)\n\t */\n\treadonly contentWidth: number;\n\n\t/**\n\t * Layout information for the minimap\n\t */\n\treadonly minimap: EditorMinimapLayoutInfo;\n\n\t/**\n\t * The number of columns (of typical characters) fitting on a viewport line.\n\t */\n\treadonly viewportColumn: number;\n\n\treadonly isWordWrapMinified: boolean;\n\treadonly isViewportWrapping: boolean;\n\treadonly wrappingColumn: number;\n\n\t/**\n\t * The width of the vertical scrollbar.\n\t */\n\treadonly verticalScrollbarWidth: number;\n\t/**\n\t * The height of the horizontal scrollbar.\n\t */\n\treadonly horizontalScrollbarHeight: number;\n\n\t/**\n\t * The position of the overview ruler.\n\t */\n\treadonly overviewRuler: OverviewRulerPosition;\n}\n\n/**\n * The internal layout details of the editor.\n */\nexport interface EditorMinimapLayoutInfo {\n\treadonly renderMinimap: RenderMinimap;\n\treadonly minimapLeft: number;\n\treadonly minimapWidth: number;\n\treadonly minimapHeightIsEditorHeight: boolean;\n\treadonly minimapIsSampling: boolean;\n\treadonly minimapScale: number;\n\treadonly minimapLineHeight: number;\n\treadonly minimapCanvasInnerWidth: number;\n\treadonly minimapCanvasInnerHeight: number;\n\treadonly minimapCanvasOuterWidth: number;\n\treadonly minimapCanvasOuterHeight: number;\n}\n\n/**\n * @internal\n */\nexport interface EditorLayoutInfoComputerEnv {\n\treadonly memory: ComputeOptionsMemory | null;\n\treadonly outerWidth: number;\n\treadonly outerHeight: number;\n\treadonly isDominatedByLongLines: boolean;\n\treadonly lineHeight: number;\n\treadonly viewLineCount: number;\n\treadonly lineNumbersDigitCount: number;\n\treadonly typicalHalfwidthCharacterWidth: number;\n\treadonly maxDigitWidth: number;\n\treadonly pixelRatio: number;\n\treadonly glyphMarginDecorationLaneCount: number;\n}\n\n/**\n * @internal\n */\nexport interface IMinimapLayoutInput {\n\treadonly outerWidth: number;\n\treadonly outerHeight: number;\n\treadonly lineHeight: number;\n\treadonly typicalHalfwidthCharacterWidth: number;\n\treadonly pixelRatio: number;\n\treadonly scrollBeyondLastLine: boolean;\n\treadonly paddingTop: number;\n\treadonly paddingBottom: number;\n\treadonly minimap: Readonly>;\n\treadonly verticalScrollbarWidth: number;\n\treadonly viewLineCount: number;\n\treadonly remainingWidth: number;\n\treadonly isViewportWrapping: boolean;\n}\n\n/**\n * @internal\n */\nexport class EditorLayoutInfoComputer extends ComputedEditorOption {\n\n\tconstructor() {\n\t\tsuper(EditorOption.layoutInfo);\n\t}\n\n\tpublic compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, _: EditorLayoutInfo): EditorLayoutInfo {\n\t\treturn EditorLayoutInfoComputer.computeLayout(options, {\n\t\t\tmemory: env.memory,\n\t\t\touterWidth: env.outerWidth,\n\t\t\touterHeight: env.outerHeight,\n\t\t\tisDominatedByLongLines: env.isDominatedByLongLines,\n\t\t\tlineHeight: env.fontInfo.lineHeight,\n\t\t\tviewLineCount: env.viewLineCount,\n\t\t\tlineNumbersDigitCount: env.lineNumbersDigitCount,\n\t\t\ttypicalHalfwidthCharacterWidth: env.fontInfo.typicalHalfwidthCharacterWidth,\n\t\t\tmaxDigitWidth: env.fontInfo.maxDigitWidth,\n\t\t\tpixelRatio: env.pixelRatio,\n\t\t\tglyphMarginDecorationLaneCount: env.glyphMarginDecorationLaneCount\n\t\t});\n\t}\n\n\tpublic static computeContainedMinimapLineCount(input: {\n\t\tviewLineCount: number;\n\t\tscrollBeyondLastLine: boolean;\n\t\tpaddingTop: number;\n\t\tpaddingBottom: number;\n\t\theight: number;\n\t\tlineHeight: number;\n\t\tpixelRatio: number;\n\t}): { typicalViewportLineCount: number; extraLinesBeforeFirstLine: number; extraLinesBeyondLastLine: number; desiredRatio: number; minimapLineCount: number } {\n\t\tconst typicalViewportLineCount = input.height / input.lineHeight;\n\t\tconst extraLinesBeforeFirstLine = Math.floor(input.paddingTop / input.lineHeight);\n\t\tlet extraLinesBeyondLastLine = Math.floor(input.paddingBottom / input.lineHeight);\n\t\tif (input.scrollBeyondLastLine) {\n\t\t\textraLinesBeyondLastLine = Math.max(extraLinesBeyondLastLine, typicalViewportLineCount - 1);\n\t\t}\n\t\tconst desiredRatio = (extraLinesBeforeFirstLine + input.viewLineCount + extraLinesBeyondLastLine) / (input.pixelRatio * input.height);\n\t\tconst minimapLineCount = Math.floor(input.viewLineCount / desiredRatio);\n\t\treturn { typicalViewportLineCount, extraLinesBeforeFirstLine, extraLinesBeyondLastLine, desiredRatio, minimapLineCount };\n\t}\n\n\tprivate static _computeMinimapLayout(input: IMinimapLayoutInput, memory: ComputeOptionsMemory): EditorMinimapLayoutInfo {\n\t\tconst outerWidth = input.outerWidth;\n\t\tconst outerHeight = input.outerHeight;\n\t\tconst pixelRatio = input.pixelRatio;\n\n\t\tif (!input.minimap.enabled) {\n\t\t\treturn {\n\t\t\t\trenderMinimap: RenderMinimap.None,\n\t\t\t\tminimapLeft: 0,\n\t\t\t\tminimapWidth: 0,\n\t\t\t\tminimapHeightIsEditorHeight: false,\n\t\t\t\tminimapIsSampling: false,\n\t\t\t\tminimapScale: 1,\n\t\t\t\tminimapLineHeight: 1,\n\t\t\t\tminimapCanvasInnerWidth: 0,\n\t\t\t\tminimapCanvasInnerHeight: Math.floor(pixelRatio * outerHeight),\n\t\t\t\tminimapCanvasOuterWidth: 0,\n\t\t\t\tminimapCanvasOuterHeight: outerHeight,\n\t\t\t};\n\t\t}\n\n\t\t// Can use memory if only the `viewLineCount` and `remainingWidth` have changed\n\t\tconst stableMinimapLayoutInput = memory.stableMinimapLayoutInput;\n\t\tconst couldUseMemory = (\n\t\t\tstableMinimapLayoutInput\n\t\t\t// && input.outerWidth === lastMinimapLayoutInput.outerWidth !!! INTENTIONAL OMITTED\n\t\t\t&& input.outerHeight === stableMinimapLayoutInput.outerHeight\n\t\t\t&& input.lineHeight === stableMinimapLayoutInput.lineHeight\n\t\t\t&& input.typicalHalfwidthCharacterWidth === stableMinimapLayoutInput.typicalHalfwidthCharacterWidth\n\t\t\t&& input.pixelRatio === stableMinimapLayoutInput.pixelRatio\n\t\t\t&& input.scrollBeyondLastLine === stableMinimapLayoutInput.scrollBeyondLastLine\n\t\t\t&& input.paddingTop === stableMinimapLayoutInput.paddingTop\n\t\t\t&& input.paddingBottom === stableMinimapLayoutInput.paddingBottom\n\t\t\t&& input.minimap.enabled === stableMinimapLayoutInput.minimap.enabled\n\t\t\t&& input.minimap.side === stableMinimapLayoutInput.minimap.side\n\t\t\t&& input.minimap.size === stableMinimapLayoutInput.minimap.size\n\t\t\t&& input.minimap.showSlider === stableMinimapLayoutInput.minimap.showSlider\n\t\t\t&& input.minimap.renderCharacters === stableMinimapLayoutInput.minimap.renderCharacters\n\t\t\t&& input.minimap.maxColumn === stableMinimapLayoutInput.minimap.maxColumn\n\t\t\t&& input.minimap.scale === stableMinimapLayoutInput.minimap.scale\n\t\t\t&& input.verticalScrollbarWidth === stableMinimapLayoutInput.verticalScrollbarWidth\n\t\t\t// && input.viewLineCount === lastMinimapLayoutInput.viewLineCount !!! INTENTIONAL OMITTED\n\t\t\t// && input.remainingWidth === lastMinimapLayoutInput.remainingWidth !!! INTENTIONAL OMITTED\n\t\t\t&& input.isViewportWrapping === stableMinimapLayoutInput.isViewportWrapping\n\t\t);\n\n\t\tconst lineHeight = input.lineHeight;\n\t\tconst typicalHalfwidthCharacterWidth = input.typicalHalfwidthCharacterWidth;\n\t\tconst scrollBeyondLastLine = input.scrollBeyondLastLine;\n\t\tconst minimapRenderCharacters = input.minimap.renderCharacters;\n\t\tlet minimapScale = (pixelRatio >= 2 ? Math.round(input.minimap.scale * 2) : input.minimap.scale);\n\t\tconst minimapMaxColumn = input.minimap.maxColumn;\n\t\tconst minimapSize = input.minimap.size;\n\t\tconst minimapSide = input.minimap.side;\n\t\tconst verticalScrollbarWidth = input.verticalScrollbarWidth;\n\t\tconst viewLineCount = input.viewLineCount;\n\t\tconst remainingWidth = input.remainingWidth;\n\t\tconst isViewportWrapping = input.isViewportWrapping;\n\n\t\tconst baseCharHeight = minimapRenderCharacters ? 2 : 3;\n\t\tlet minimapCanvasInnerHeight = Math.floor(pixelRatio * outerHeight);\n\t\tconst minimapCanvasOuterHeight = minimapCanvasInnerHeight / pixelRatio;\n\t\tlet minimapHeightIsEditorHeight = false;\n\t\tlet minimapIsSampling = false;\n\t\tlet minimapLineHeight = baseCharHeight * minimapScale;\n\t\tlet minimapCharWidth = minimapScale / pixelRatio;\n\t\tlet minimapWidthMultiplier: number = 1;\n\n\t\tif (minimapSize === 'fill' || minimapSize === 'fit') {\n\t\t\tconst { typicalViewportLineCount, extraLinesBeforeFirstLine, extraLinesBeyondLastLine, desiredRatio, minimapLineCount } = EditorLayoutInfoComputer.computeContainedMinimapLineCount({\n\t\t\t\tviewLineCount: viewLineCount,\n\t\t\t\tscrollBeyondLastLine: scrollBeyondLastLine,\n\t\t\t\tpaddingTop: input.paddingTop,\n\t\t\t\tpaddingBottom: input.paddingBottom,\n\t\t\t\theight: outerHeight,\n\t\t\t\tlineHeight: lineHeight,\n\t\t\t\tpixelRatio: pixelRatio\n\t\t\t});\n\t\t\t// ratio is intentionally not part of the layout to avoid the layout changing all the time\n\t\t\t// when doing sampling\n\t\t\tconst ratio = viewLineCount / minimapLineCount;\n\n\t\t\tif (ratio > 1) {\n\t\t\t\tminimapHeightIsEditorHeight = true;\n\t\t\t\tminimapIsSampling = true;\n\t\t\t\tminimapScale = 1;\n\t\t\t\tminimapLineHeight = 1;\n\t\t\t\tminimapCharWidth = minimapScale / pixelRatio;\n\t\t\t} else {\n\t\t\t\tlet fitBecomesFill = false;\n\t\t\t\tlet maxMinimapScale = minimapScale + 1;\n\n\t\t\t\tif (minimapSize === 'fit') {\n\t\t\t\t\tconst effectiveMinimapHeight = Math.ceil((extraLinesBeforeFirstLine + viewLineCount + extraLinesBeyondLastLine) * minimapLineHeight);\n\t\t\t\t\tif (isViewportWrapping && couldUseMemory && remainingWidth <= memory.stableFitRemainingWidth) {\n\t\t\t\t\t\t// There is a loop when using `fit` and viewport wrapping:\n\t\t\t\t\t\t// - view line count impacts minimap layout\n\t\t\t\t\t\t// - minimap layout impacts viewport width\n\t\t\t\t\t\t// - viewport width impacts view line count\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.\n\t\t\t\t\t\tfitBecomesFill = true;\n\t\t\t\t\t\tmaxMinimapScale = memory.stableFitMaxMinimapScale;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tfitBecomesFill = (effectiveMinimapHeight > minimapCanvasInnerHeight);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (minimapSize === 'fill' || fitBecomesFill) {\n\t\t\t\t\tminimapHeightIsEditorHeight = true;\n\t\t\t\t\tconst configuredMinimapScale = minimapScale;\n\t\t\t\t\tminimapLineHeight = Math.min(lineHeight * pixelRatio, Math.max(1, Math.floor(1 / desiredRatio)));\n\t\t\t\t\tif (isViewportWrapping && couldUseMemory && remainingWidth <= memory.stableFitRemainingWidth) {\n\t\t\t\t\t\t// There is a loop when using `fill` and viewport wrapping:\n\t\t\t\t\t\t// - view line count impacts minimap layout\n\t\t\t\t\t\t// - minimap layout impacts viewport width\n\t\t\t\t\t\t// - viewport width impacts view line count\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.\n\t\t\t\t\t\tmaxMinimapScale = memory.stableFitMaxMinimapScale;\n\t\t\t\t\t}\n\t\t\t\t\tminimapScale = Math.min(maxMinimapScale, Math.max(1, Math.floor(minimapLineHeight / baseCharHeight)));\n\t\t\t\t\tif (minimapScale > configuredMinimapScale) {\n\t\t\t\t\t\tminimapWidthMultiplier = Math.min(2, minimapScale / configuredMinimapScale);\n\t\t\t\t\t}\n\t\t\t\t\tminimapCharWidth = minimapScale / pixelRatio / minimapWidthMultiplier;\n\t\t\t\t\tminimapCanvasInnerHeight = Math.ceil((Math.max(typicalViewportLineCount, extraLinesBeforeFirstLine + viewLineCount + extraLinesBeyondLastLine)) * minimapLineHeight);\n\t\t\t\t\tif (isViewportWrapping) {\n\t\t\t\t\t\t// remember for next time\n\t\t\t\t\t\tmemory.stableMinimapLayoutInput = input;\n\t\t\t\t\t\tmemory.stableFitRemainingWidth = remainingWidth;\n\t\t\t\t\t\tmemory.stableFitMaxMinimapScale = minimapScale;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tmemory.stableMinimapLayoutInput = null;\n\t\t\t\t\t\tmemory.stableFitRemainingWidth = 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Given:\n\t\t// (leaving 2px for the cursor to have space after the last character)\n\t\t// viewportColumn = (contentWidth - verticalScrollbarWidth - 2) / typicalHalfwidthCharacterWidth\n\t\t// minimapWidth = viewportColumn * minimapCharWidth\n\t\t// contentWidth = remainingWidth - minimapWidth\n\t\t// What are good values for contentWidth and minimapWidth ?\n\n\t\t// minimapWidth = ((contentWidth - verticalScrollbarWidth - 2) / typicalHalfwidthCharacterWidth) * minimapCharWidth\n\t\t// typicalHalfwidthCharacterWidth * minimapWidth = (contentWidth - verticalScrollbarWidth - 2) * minimapCharWidth\n\t\t// typicalHalfwidthCharacterWidth * minimapWidth = (remainingWidth - minimapWidth - verticalScrollbarWidth - 2) * minimapCharWidth\n\t\t// (typicalHalfwidthCharacterWidth + minimapCharWidth) * minimapWidth = (remainingWidth - verticalScrollbarWidth - 2) * minimapCharWidth\n\t\t// minimapWidth = ((remainingWidth - verticalScrollbarWidth - 2) * minimapCharWidth) / (typicalHalfwidthCharacterWidth + minimapCharWidth)\n\n\t\tconst minimapMaxWidth = Math.floor(minimapMaxColumn * minimapCharWidth);\n\t\tconst minimapWidth = Math.min(minimapMaxWidth, Math.max(0, Math.floor(((remainingWidth - verticalScrollbarWidth - 2) * minimapCharWidth) / (typicalHalfwidthCharacterWidth + minimapCharWidth))) + MINIMAP_GUTTER_WIDTH);\n\n\t\tlet minimapCanvasInnerWidth = Math.floor(pixelRatio * minimapWidth);\n\t\tconst minimapCanvasOuterWidth = minimapCanvasInnerWidth / pixelRatio;\n\t\tminimapCanvasInnerWidth = Math.floor(minimapCanvasInnerWidth * minimapWidthMultiplier);\n\n\t\tconst renderMinimap = (minimapRenderCharacters ? RenderMinimap.Text : RenderMinimap.Blocks);\n\t\tconst minimapLeft = (minimapSide === 'left' ? 0 : (outerWidth - minimapWidth - verticalScrollbarWidth));\n\n\t\treturn {\n\t\t\trenderMinimap,\n\t\t\tminimapLeft,\n\t\t\tminimapWidth,\n\t\t\tminimapHeightIsEditorHeight,\n\t\t\tminimapIsSampling,\n\t\t\tminimapScale,\n\t\t\tminimapLineHeight,\n\t\t\tminimapCanvasInnerWidth,\n\t\t\tminimapCanvasInnerHeight,\n\t\t\tminimapCanvasOuterWidth,\n\t\t\tminimapCanvasOuterHeight,\n\t\t};\n\t}\n\n\tpublic static computeLayout(options: IComputedEditorOptions, env: EditorLayoutInfoComputerEnv): EditorLayoutInfo {\n\t\tconst outerWidth = env.outerWidth | 0;\n\t\tconst outerHeight = env.outerHeight | 0;\n\t\tconst lineHeight = env.lineHeight | 0;\n\t\tconst lineNumbersDigitCount = env.lineNumbersDigitCount | 0;\n\t\tconst typicalHalfwidthCharacterWidth = env.typicalHalfwidthCharacterWidth;\n\t\tconst maxDigitWidth = env.maxDigitWidth;\n\t\tconst pixelRatio = env.pixelRatio;\n\t\tconst viewLineCount = env.viewLineCount;\n\n\t\tconst wordWrapOverride2 = options.get(EditorOption.wordWrapOverride2);\n\t\tconst wordWrapOverride1 = (wordWrapOverride2 === 'inherit' ? options.get(EditorOption.wordWrapOverride1) : wordWrapOverride2);\n\t\tconst wordWrap = (wordWrapOverride1 === 'inherit' ? options.get(EditorOption.wordWrap) : wordWrapOverride1);\n\n\t\tconst wordWrapColumn = options.get(EditorOption.wordWrapColumn);\n\t\tconst isDominatedByLongLines = env.isDominatedByLongLines;\n\n\t\tconst showGlyphMargin = options.get(EditorOption.glyphMargin);\n\t\tconst showLineNumbers = (options.get(EditorOption.lineNumbers).renderType !== RenderLineNumbersType.Off);\n\t\tconst lineNumbersMinChars = options.get(EditorOption.lineNumbersMinChars);\n\t\tconst scrollBeyondLastLine = options.get(EditorOption.scrollBeyondLastLine);\n\t\tconst padding = options.get(EditorOption.padding);\n\t\tconst minimap = options.get(EditorOption.minimap);\n\n\t\tconst scrollbar = options.get(EditorOption.scrollbar);\n\t\tconst verticalScrollbarWidth = scrollbar.verticalScrollbarSize;\n\t\tconst verticalScrollbarHasArrows = scrollbar.verticalHasArrows;\n\t\tconst scrollbarArrowSize = scrollbar.arrowSize;\n\t\tconst horizontalScrollbarHeight = scrollbar.horizontalScrollbarSize;\n\n\t\tconst folding = options.get(EditorOption.folding);\n\t\tconst showFoldingDecoration = options.get(EditorOption.showFoldingControls) !== 'never';\n\n\t\tlet lineDecorationsWidth = options.get(EditorOption.lineDecorationsWidth);\n\t\tif (folding && showFoldingDecoration) {\n\t\t\tlineDecorationsWidth += 16;\n\t\t}\n\n\t\tlet lineNumbersWidth = 0;\n\t\tif (showLineNumbers) {\n\t\t\tconst digitCount = Math.max(lineNumbersDigitCount, lineNumbersMinChars);\n\t\t\tlineNumbersWidth = Math.round(digitCount * maxDigitWidth);\n\t\t}\n\n\t\tlet glyphMarginWidth = 0;\n\t\tif (showGlyphMargin) {\n\t\t\tglyphMarginWidth = lineHeight * env.glyphMarginDecorationLaneCount;\n\t\t}\n\n\t\tlet glyphMarginLeft = 0;\n\t\tlet lineNumbersLeft = glyphMarginLeft + glyphMarginWidth;\n\t\tlet decorationsLeft = lineNumbersLeft + lineNumbersWidth;\n\t\tlet contentLeft = decorationsLeft + lineDecorationsWidth;\n\n\t\tconst remainingWidth = outerWidth - glyphMarginWidth - lineNumbersWidth - lineDecorationsWidth;\n\n\t\tlet isWordWrapMinified = false;\n\t\tlet isViewportWrapping = false;\n\t\tlet wrappingColumn = -1;\n\n\t\tif (wordWrapOverride1 === 'inherit' && isDominatedByLongLines) {\n\t\t\t// Force viewport width wrapping if model is dominated by long lines\n\t\t\tisWordWrapMinified = true;\n\t\t\tisViewportWrapping = true;\n\t\t} else if (wordWrap === 'on' || wordWrap === 'bounded') {\n\t\t\tisViewportWrapping = true;\n\t\t} else if (wordWrap === 'wordWrapColumn') {\n\t\t\twrappingColumn = wordWrapColumn;\n\t\t}\n\n\t\tconst minimapLayout = EditorLayoutInfoComputer._computeMinimapLayout({\n\t\t\touterWidth: outerWidth,\n\t\t\touterHeight: outerHeight,\n\t\t\tlineHeight: lineHeight,\n\t\t\ttypicalHalfwidthCharacterWidth: typicalHalfwidthCharacterWidth,\n\t\t\tpixelRatio: pixelRatio,\n\t\t\tscrollBeyondLastLine: scrollBeyondLastLine,\n\t\t\tpaddingTop: padding.top,\n\t\t\tpaddingBottom: padding.bottom,\n\t\t\tminimap: minimap,\n\t\t\tverticalScrollbarWidth: verticalScrollbarWidth,\n\t\t\tviewLineCount: viewLineCount,\n\t\t\tremainingWidth: remainingWidth,\n\t\t\tisViewportWrapping: isViewportWrapping,\n\t\t}, env.memory || new ComputeOptionsMemory());\n\n\t\tif (minimapLayout.renderMinimap !== RenderMinimap.None && minimapLayout.minimapLeft === 0) {\n\t\t\t// the minimap is rendered to the left, so move everything to the right\n\t\t\tglyphMarginLeft += minimapLayout.minimapWidth;\n\t\t\tlineNumbersLeft += minimapLayout.minimapWidth;\n\t\t\tdecorationsLeft += minimapLayout.minimapWidth;\n\t\t\tcontentLeft += minimapLayout.minimapWidth;\n\t\t}\n\t\tconst contentWidth = remainingWidth - minimapLayout.minimapWidth;\n\n\t\t// (leaving 2px for the cursor to have space after the last character)\n\t\tconst viewportColumn = Math.max(1, Math.floor((contentWidth - verticalScrollbarWidth - 2) / typicalHalfwidthCharacterWidth));\n\n\t\tconst verticalArrowSize = (verticalScrollbarHasArrows ? scrollbarArrowSize : 0);\n\n\t\tif (isViewportWrapping) {\n\t\t\t// compute the actual wrappingColumn\n\t\t\twrappingColumn = Math.max(1, viewportColumn);\n\t\t\tif (wordWrap === 'bounded') {\n\t\t\t\twrappingColumn = Math.min(wrappingColumn, wordWrapColumn);\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\twidth: outerWidth,\n\t\t\theight: outerHeight,\n\n\t\t\tglyphMarginLeft: glyphMarginLeft,\n\t\t\tglyphMarginWidth: glyphMarginWidth,\n\t\t\tglyphMarginDecorationLaneCount: env.glyphMarginDecorationLaneCount,\n\n\t\t\tlineNumbersLeft: lineNumbersLeft,\n\t\t\tlineNumbersWidth: lineNumbersWidth,\n\n\t\t\tdecorationsLeft: decorationsLeft,\n\t\t\tdecorationsWidth: lineDecorationsWidth,\n\n\t\t\tcontentLeft: contentLeft,\n\t\t\tcontentWidth: contentWidth,\n\n\t\t\tminimap: minimapLayout,\n\n\t\t\tviewportColumn: viewportColumn,\n\n\t\t\tisWordWrapMinified: isWordWrapMinified,\n\t\t\tisViewportWrapping: isViewportWrapping,\n\t\t\twrappingColumn: wrappingColumn,\n\n\t\t\tverticalScrollbarWidth: verticalScrollbarWidth,\n\t\t\thorizontalScrollbarHeight: horizontalScrollbarHeight,\n\n\t\t\toverviewRuler: {\n\t\t\t\ttop: verticalArrowSize,\n\t\t\t\twidth: verticalScrollbarWidth,\n\t\t\t\theight: (outerHeight - 2 * verticalArrowSize),\n\t\t\t\tright: 0\n\t\t\t}\n\t\t};\n\t}\n}\n\n//#endregion\n\n//#region WrappingStrategy\nclass WrappingStrategy extends BaseEditorOption {\n\n\tconstructor() {\n\t\tsuper(EditorOption.wrappingStrategy, 'wrappingStrategy', 'simple',\n\t\t\t{\n\t\t\t\t'editor.wrappingStrategy': {\n\t\t\t\t\tenumDescriptions: [\n\t\t\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.\"),\n\t\t\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.\")\n\t\t\t\t\t],\n\t\t\t\t\ttype: 'string',\n\t\t\t\t\tenum: ['simple', 'advanced'],\n\t\t\t\t\tdefault: 'simple',\n\t\t\t\t\tdescription: nls.localize('wrappingStrategy', \"Controls the algorithm that computes wrapping points. Note that when in accessibility mode, advanced will be used for the best experience.\")\n\t\t\t\t}\n\t\t\t}\n\t\t);\n\t}\n\n\tpublic validate(input: any): 'simple' | 'advanced' {\n\t\treturn stringSet<'simple' | 'advanced'>(input, 'simple', ['simple', 'advanced']);\n\t}\n\n\tpublic override compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, value: 'simple' | 'advanced'): 'simple' | 'advanced' {\n\t\tconst accessibilitySupport = options.get(EditorOption.accessibilitySupport);\n\t\tif (accessibilitySupport === AccessibilitySupport.Enabled) {\n\t\t\t// if we know for a fact that a screen reader is attached, we switch our strategy to advanced to\n\t\t\t// help that the editor's wrapping points match the textarea's wrapping points\n\t\t\treturn 'advanced';\n\t\t}\n\t\treturn value;\n\t}\n}\n//#endregion\n\n//#region lightbulb\n\nexport enum ShowLightbulbIconMode {\n\tOff = 'off',\n\tOnCode = 'onCode',\n\tOn = 'on'\n}\n\n/**\n * Configuration options for editor lightbulb\n */\nexport interface IEditorLightbulbOptions {\n\t/**\n\t * Enable the lightbulb code action.\n\t * The three possible values are `off`, `on` and `onCode` and the default is `onCode`.\n\t * `off` disables the code action menu.\n\t * `on` shows the code action menu on code and on empty lines.\n\t * `onCode` shows the code action menu on code only.\n\t */\n\tenabled?: ShowLightbulbIconMode;\n}\n\n/**\n * @internal\n */\nexport type EditorLightbulbOptions = Readonly>;\n\nclass EditorLightbulb extends BaseEditorOption {\n\n\tconstructor() {\n\t\tconst defaults: EditorLightbulbOptions = { enabled: ShowLightbulbIconMode.On };\n\t\tsuper(\n\t\t\tEditorOption.lightbulb, 'lightbulb', defaults,\n\t\t\t{\n\t\t\t\t'editor.lightbulb.enabled': {\n\t\t\t\t\ttype: 'string',\n\t\t\t\t\ttags: ['experimental'],\n\t\t\t\t\tenum: [ShowLightbulbIconMode.Off, ShowLightbulbIconMode.OnCode, ShowLightbulbIconMode.On],\n\t\t\t\t\tdefault: defaults.enabled,\n\t\t\t\t\tenumDescriptions: [\n\t\t\t\t\t\tnls.localize('editor.lightbulb.enabled.off', 'Disable the code action menu.'),\n\t\t\t\t\t\tnls.localize('editor.lightbulb.enabled.onCode', 'Show the code action menu when the cursor is on lines with code.'),\n\t\t\t\t\t\tnls.localize('editor.lightbulb.enabled.on', 'Show the code action menu when the cursor is on lines with code or on empty lines.'),\n\t\t\t\t\t],\n\t\t\t\t\tdescription: nls.localize('enabled', \"Enables the Code Action lightbulb in the editor.\")\n\t\t\t\t}\n\t\t\t}\n\t\t);\n\t}\n\n\tpublic validate(_input: any): EditorLightbulbOptions {\n\t\tif (!_input || typeof _input !== 'object') {\n\t\t\treturn this.defaultValue;\n\t\t}\n\t\tconst input = _input as IEditorLightbulbOptions;\n\t\treturn {\n\t\t\tenabled: stringSet(input.enabled, this.defaultValue.enabled, [ShowLightbulbIconMode.Off, ShowLightbulbIconMode.OnCode, ShowLightbulbIconMode.On])\n\t\t};\n\t}\n}\n\n//#endregion\n\n//#region stickyScroll\n\nexport interface IEditorStickyScrollOptions {\n\t/**\n\t * Enable the sticky scroll\n\t */\n\tenabled?: boolean;\n\t/**\n\t * Maximum number of sticky lines to show\n\t */\n\tmaxLineCount?: number;\n\t/**\n\t * Model to choose for sticky scroll by default\n\t */\n\tdefaultModel?: 'outlineModel' | 'foldingProviderModel' | 'indentationModel';\n\t/**\n\t * Define whether to scroll sticky scroll with editor horizontal scrollbae\n\t */\n\tscrollWithEditor?: boolean;\n}\n\n/**\n * @internal\n */\nexport type EditorStickyScrollOptions = Readonly>;\n\nclass EditorStickyScroll extends BaseEditorOption {\n\n\tconstructor() {\n\t\tconst defaults: EditorStickyScrollOptions = { enabled: true, maxLineCount: 5, defaultModel: 'outlineModel', scrollWithEditor: true };\n\t\tsuper(\n\t\t\tEditorOption.stickyScroll, 'stickyScroll', defaults,\n\t\t\t{\n\t\t\t\t'editor.stickyScroll.enabled': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: defaults.enabled,\n\t\t\t\t\tdescription: nls.localize('editor.stickyScroll.enabled', \"Shows the nested current scopes during the scroll at the top of the editor.\"),\n\t\t\t\t\ttags: ['experimental']\n\t\t\t\t},\n\t\t\t\t'editor.stickyScroll.maxLineCount': {\n\t\t\t\t\ttype: 'number',\n\t\t\t\t\tdefault: defaults.maxLineCount,\n\t\t\t\t\tminimum: 1,\n\t\t\t\t\tmaximum: 20,\n\t\t\t\t\tdescription: nls.localize('editor.stickyScroll.maxLineCount', \"Defines the maximum number of sticky lines to show.\")\n\t\t\t\t},\n\t\t\t\t'editor.stickyScroll.defaultModel': {\n\t\t\t\t\ttype: 'string',\n\t\t\t\t\tenum: ['outlineModel', 'foldingProviderModel', 'indentationModel'],\n\t\t\t\t\tdefault: defaults.defaultModel,\n\t\t\t\t\tdescription: nls.localize('editor.stickyScroll.defaultModel', \"Defines the model to use for determining which lines to stick. If the outline model does not exist, it will fall back on the folding provider model which falls back on the indentation model. This order is respected in all three cases.\")\n\t\t\t\t},\n\t\t\t\t'editor.stickyScroll.scrollWithEditor': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: defaults.scrollWithEditor,\n\t\t\t\t\tdescription: nls.localize('editor.stickyScroll.scrollWithEditor', \"Enable scrolling of Sticky Scroll with the editor's horizontal scrollbar.\")\n\t\t\t\t},\n\t\t\t}\n\t\t);\n\t}\n\n\tpublic validate(_input: any): EditorStickyScrollOptions {\n\t\tif (!_input || typeof _input !== 'object') {\n\t\t\treturn this.defaultValue;\n\t\t}\n\t\tconst input = _input as IEditorStickyScrollOptions;\n\t\treturn {\n\t\t\tenabled: boolean(input.enabled, this.defaultValue.enabled),\n\t\t\tmaxLineCount: EditorIntOption.clampedInt(input.maxLineCount, this.defaultValue.maxLineCount, 1, 20),\n\t\t\tdefaultModel: stringSet<'outlineModel' | 'foldingProviderModel' | 'indentationModel'>(input.defaultModel, this.defaultValue.defaultModel, ['outlineModel', 'foldingProviderModel', 'indentationModel']),\n\t\t\tscrollWithEditor: boolean(input.scrollWithEditor, this.defaultValue.scrollWithEditor)\n\t\t};\n\t}\n}\n\n//#endregion\n\n//#region inlayHints\n\n/**\n * Configuration options for editor inlayHints\n */\nexport interface IEditorInlayHintsOptions {\n\t/**\n\t * Enable the inline hints.\n\t * Defaults to true.\n\t */\n\tenabled?: 'on' | 'off' | 'offUnlessPressed' | 'onUnlessPressed';\n\n\t/**\n\t * Font size of inline hints.\n\t * Default to 90% of the editor font size.\n\t */\n\tfontSize?: number;\n\n\t/**\n\t * Font family of inline hints.\n\t * Defaults to editor font family.\n\t */\n\tfontFamily?: string;\n\n\t/**\n\t * Enables the padding around the inlay hint.\n\t * Defaults to false.\n\t */\n\tpadding?: boolean;\n}\n\n/**\n * @internal\n */\nexport type EditorInlayHintsOptions = Readonly>;\n\nclass EditorInlayHints extends BaseEditorOption {\n\n\tconstructor() {\n\t\tconst defaults: EditorInlayHintsOptions = { enabled: 'on', fontSize: 0, fontFamily: '', padding: false };\n\t\tsuper(\n\t\t\tEditorOption.inlayHints, 'inlayHints', defaults,\n\t\t\t{\n\t\t\t\t'editor.inlayHints.enabled': {\n\t\t\t\t\ttype: 'string',\n\t\t\t\t\tdefault: defaults.enabled,\n\t\t\t\t\tdescription: nls.localize('inlayHints.enable', \"Enables the inlay hints in the editor.\"),\n\t\t\t\t\tenum: ['on', 'onUnlessPressed', 'offUnlessPressed', 'off'],\n\t\t\t\t\tmarkdownEnumDescriptions: [\n\t\t\t\t\t\tnls.localize('editor.inlayHints.on', \"Inlay hints are enabled\"),\n\t\t\t\t\t\tnls.localize('editor.inlayHints.onUnlessPressed', \"Inlay hints are showing by default and hide when holding {0}\", platform.isMacintosh ? `Ctrl+Option` : `Ctrl+Alt`),\n\t\t\t\t\t\tnls.localize('editor.inlayHints.offUnlessPressed', \"Inlay hints are hidden by default and show when holding {0}\", platform.isMacintosh ? `Ctrl+Option` : `Ctrl+Alt`),\n\t\t\t\t\t\tnls.localize('editor.inlayHints.off', \"Inlay hints are disabled\"),\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t\t'editor.inlayHints.fontSize': {\n\t\t\t\t\ttype: 'number',\n\t\t\t\t\tdefault: defaults.fontSize,\n\t\t\t\t\tmarkdownDescription: nls.localize('inlayHints.fontSize', \"Controls font size of inlay hints in the editor. As default the {0} is used when the configured value is less than {1} or greater than the editor font size.\", '`#editor.fontSize#`', '`5`')\n\t\t\t\t},\n\t\t\t\t'editor.inlayHints.fontFamily': {\n\t\t\t\t\ttype: 'string',\n\t\t\t\t\tdefault: defaults.fontFamily,\n\t\t\t\t\tmarkdownDescription: nls.localize('inlayHints.fontFamily', \"Controls font family of inlay hints in the editor. When set to empty, the {0} is used.\", '`#editor.fontFamily#`')\n\t\t\t\t},\n\t\t\t\t'editor.inlayHints.padding': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: defaults.padding,\n\t\t\t\t\tdescription: nls.localize('inlayHints.padding', \"Enables the padding around the inlay hints in the editor.\")\n\t\t\t\t}\n\t\t\t}\n\t\t);\n\t}\n\n\tpublic validate(_input: any): EditorInlayHintsOptions {\n\t\tif (!_input || typeof _input !== 'object') {\n\t\t\treturn this.defaultValue;\n\t\t}\n\t\tconst input = _input as IEditorInlayHintsOptions;\n\t\tif (typeof input.enabled === 'boolean') {\n\t\t\tinput.enabled = input.enabled ? 'on' : 'off';\n\t\t}\n\t\treturn {\n\t\t\tenabled: stringSet<'on' | 'off' | 'offUnlessPressed' | 'onUnlessPressed'>(input.enabled, this.defaultValue.enabled, ['on', 'off', 'offUnlessPressed', 'onUnlessPressed']),\n\t\t\tfontSize: EditorIntOption.clampedInt(input.fontSize, this.defaultValue.fontSize, 0, 100),\n\t\t\tfontFamily: EditorStringOption.string(input.fontFamily, this.defaultValue.fontFamily),\n\t\t\tpadding: boolean(input.padding, this.defaultValue.padding)\n\t\t};\n\t}\n}\n\n//#endregion\n\n//#region lineDecorationsWidth\n\nclass EditorLineDecorationsWidth extends BaseEditorOption {\n\n\tconstructor() {\n\t\tsuper(EditorOption.lineDecorationsWidth, 'lineDecorationsWidth', 10);\n\t}\n\n\tpublic validate(input: any): number {\n\t\tif (typeof input === 'string' && /^\\d+(\\.\\d+)?ch$/.test(input)) {\n\t\t\tconst multiple = parseFloat(input.substring(0, input.length - 2));\n\t\t\treturn -multiple; // negative numbers signal a multiple\n\t\t} else {\n\t\t\treturn EditorIntOption.clampedInt(input, this.defaultValue, 0, 1000);\n\t\t}\n\t}\n\n\tpublic override compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, value: number): number {\n\t\tif (value < 0) {\n\t\t\t// negative numbers signal a multiple\n\t\t\treturn EditorIntOption.clampedInt(-value * env.fontInfo.typicalHalfwidthCharacterWidth, this.defaultValue, 0, 1000);\n\t\t} else {\n\t\t\treturn value;\n\t\t}\n\t}\n}\n\n//#endregion\n\n//#region lineHeight\n\nclass EditorLineHeight extends EditorFloatOption {\n\n\tconstructor() {\n\t\tsuper(\n\t\t\tEditorOption.lineHeight, 'lineHeight',\n\t\t\tEDITOR_FONT_DEFAULTS.lineHeight,\n\t\t\tx => EditorFloatOption.clamp(x, 0, 150),\n\t\t\t{ markdownDescription: nls.localize('lineHeight', \"Controls the line height. \\n - Use 0 to automatically compute the line height from the font size.\\n - Values between 0 and 8 will be used as a multiplier with the font size.\\n - Values greater than or equal to 8 will be used as effective values.\") }\n\t\t);\n\t}\n\n\tpublic override compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, value: number): number {\n\t\t// The lineHeight is computed from the fontSize if it is 0.\n\t\t// Moreover, the final lineHeight respects the editor zoom level.\n\t\t// So take the result from env.fontInfo\n\t\treturn env.fontInfo.lineHeight;\n\t}\n}\n\n//#endregion\n\n//#region minimap\n\n/**\n * Configuration options for editor minimap\n */\nexport interface IEditorMinimapOptions {\n\t/**\n\t * Enable the rendering of the minimap.\n\t * Defaults to true.\n\t */\n\tenabled?: boolean;\n\t/**\n\t * Control the rendering of minimap.\n\t */\n\tautohide?: boolean;\n\t/**\n\t * Control the side of the minimap in editor.\n\t * Defaults to 'right'.\n\t */\n\tside?: 'right' | 'left';\n\t/**\n\t * Control the minimap rendering mode.\n\t * Defaults to 'actual'.\n\t */\n\tsize?: 'proportional' | 'fill' | 'fit';\n\t/**\n\t * Control the rendering of the minimap slider.\n\t * Defaults to 'mouseover'.\n\t */\n\tshowSlider?: 'always' | 'mouseover';\n\t/**\n\t * Render the actual text on a line (as opposed to color blocks).\n\t * Defaults to true.\n\t */\n\trenderCharacters?: boolean;\n\t/**\n\t * Limit the width of the minimap to render at most a certain number of columns.\n\t * Defaults to 120.\n\t */\n\tmaxColumn?: number;\n\t/**\n\t * Relative size of the font in the minimap. Defaults to 1.\n\t */\n\tscale?: number;\n\t/**\n\t * Whether to show named regions as section headers. Defaults to true.\n\t */\n\tshowRegionSectionHeaders?: boolean;\n\t/**\n\t * Whether to show MARK: comments as section headers. Defaults to true.\n\t */\n\tshowMarkSectionHeaders?: boolean;\n\t/**\n\t * Font size of section headers. Defaults to 9.\n\t */\n\tsectionHeaderFontSize?: number;\n}\n\n/**\n * @internal\n */\nexport type EditorMinimapOptions = Readonly>;\n\nclass EditorMinimap extends BaseEditorOption {\n\n\tconstructor() {\n\t\tconst defaults: EditorMinimapOptions = {\n\t\t\tenabled: true,\n\t\t\tsize: 'proportional',\n\t\t\tside: 'right',\n\t\t\tshowSlider: 'mouseover',\n\t\t\tautohide: false,\n\t\t\trenderCharacters: true,\n\t\t\tmaxColumn: 120,\n\t\t\tscale: 1,\n\t\t\tshowRegionSectionHeaders: true,\n\t\t\tshowMarkSectionHeaders: true,\n\t\t\tsectionHeaderFontSize: 9,\n\t\t};\n\t\tsuper(\n\t\t\tEditorOption.minimap, 'minimap', defaults,\n\t\t\t{\n\t\t\t\t'editor.minimap.enabled': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: defaults.enabled,\n\t\t\t\t\tdescription: nls.localize('minimap.enabled', \"Controls whether the minimap is shown.\")\n\t\t\t\t},\n\t\t\t\t'editor.minimap.autohide': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: defaults.autohide,\n\t\t\t\t\tdescription: nls.localize('minimap.autohide', \"Controls whether the minimap is hidden automatically.\")\n\t\t\t\t},\n\t\t\t\t'editor.minimap.size': {\n\t\t\t\t\ttype: 'string',\n\t\t\t\t\tenum: ['proportional', 'fill', 'fit'],\n\t\t\t\t\tenumDescriptions: [\n\t\t\t\t\t\tnls.localize('minimap.size.proportional', \"The minimap has the same size as the editor contents (and might scroll).\"),\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).\"),\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).\"),\n\t\t\t\t\t],\n\t\t\t\t\tdefault: defaults.size,\n\t\t\t\t\tdescription: nls.localize('minimap.size', \"Controls the size of the minimap.\")\n\t\t\t\t},\n\t\t\t\t'editor.minimap.side': {\n\t\t\t\t\ttype: 'string',\n\t\t\t\t\tenum: ['left', 'right'],\n\t\t\t\t\tdefault: defaults.side,\n\t\t\t\t\tdescription: nls.localize('minimap.side', \"Controls the side where to render the minimap.\")\n\t\t\t\t},\n\t\t\t\t'editor.minimap.showSlider': {\n\t\t\t\t\ttype: 'string',\n\t\t\t\t\tenum: ['always', 'mouseover'],\n\t\t\t\t\tdefault: defaults.showSlider,\n\t\t\t\t\tdescription: nls.localize('minimap.showSlider', \"Controls when the minimap slider is shown.\")\n\t\t\t\t},\n\t\t\t\t'editor.minimap.scale': {\n\t\t\t\t\ttype: 'number',\n\t\t\t\t\tdefault: defaults.scale,\n\t\t\t\t\tminimum: 1,\n\t\t\t\t\tmaximum: 3,\n\t\t\t\t\tenum: [1, 2, 3],\n\t\t\t\t\tdescription: nls.localize('minimap.scale', \"Scale of content drawn in the minimap: 1, 2 or 3.\")\n\t\t\t\t},\n\t\t\t\t'editor.minimap.renderCharacters': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: defaults.renderCharacters,\n\t\t\t\t\tdescription: nls.localize('minimap.renderCharacters', \"Render the actual characters on a line as opposed to color blocks.\")\n\t\t\t\t},\n\t\t\t\t'editor.minimap.maxColumn': {\n\t\t\t\t\ttype: 'number',\n\t\t\t\t\tdefault: defaults.maxColumn,\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.\")\n\t\t\t\t},\n\t\t\t\t'editor.minimap.showRegionSectionHeaders': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: defaults.showRegionSectionHeaders,\n\t\t\t\t\tdescription: nls.localize('minimap.showRegionSectionHeaders', \"Controls whether named regions are shown as section headers in the minimap.\")\n\t\t\t\t},\n\t\t\t\t'editor.minimap.showMarkSectionHeaders': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: defaults.showMarkSectionHeaders,\n\t\t\t\t\tdescription: nls.localize('minimap.showMarkSectionHeaders', \"Controls whether MARK: comments are shown as section headers in the minimap.\")\n\t\t\t\t},\n\t\t\t\t'editor.minimap.sectionHeaderFontSize': {\n\t\t\t\t\ttype: 'number',\n\t\t\t\t\tdefault: defaults.sectionHeaderFontSize,\n\t\t\t\t\tdescription: nls.localize('minimap.sectionHeaderFontSize', \"Controls the font size of section headers in the minimap.\")\n\t\t\t\t}\n\t\t\t}\n\t\t);\n\t}\n\n\tpublic validate(_input: any): EditorMinimapOptions {\n\t\tif (!_input || typeof _input !== 'object') {\n\t\t\treturn this.defaultValue;\n\t\t}\n\t\tconst input = _input as IEditorMinimapOptions;\n\t\treturn {\n\t\t\tenabled: boolean(input.enabled, this.defaultValue.enabled),\n\t\t\tautohide: boolean(input.autohide, this.defaultValue.autohide),\n\t\t\tsize: stringSet<'proportional' | 'fill' | 'fit'>(input.size, this.defaultValue.size, ['proportional', 'fill', 'fit']),\n\t\t\tside: stringSet<'right' | 'left'>(input.side, this.defaultValue.side, ['right', 'left']),\n\t\t\tshowSlider: stringSet<'always' | 'mouseover'>(input.showSlider, this.defaultValue.showSlider, ['always', 'mouseover']),\n\t\t\trenderCharacters: boolean(input.renderCharacters, this.defaultValue.renderCharacters),\n\t\t\tscale: EditorIntOption.clampedInt(input.scale, 1, 1, 3),\n\t\t\tmaxColumn: EditorIntOption.clampedInt(input.maxColumn, this.defaultValue.maxColumn, 1, 10000),\n\t\t\tshowRegionSectionHeaders: boolean(input.showRegionSectionHeaders, this.defaultValue.showRegionSectionHeaders),\n\t\t\tshowMarkSectionHeaders: boolean(input.showMarkSectionHeaders, this.defaultValue.showMarkSectionHeaders),\n\t\t\tsectionHeaderFontSize: EditorFloatOption.clamp(input.sectionHeaderFontSize ?? this.defaultValue.sectionHeaderFontSize, 4, 32),\n\t\t};\n\t}\n}\n\n//#endregion\n\n//#region multiCursorModifier\n\nfunction _multiCursorModifierFromString(multiCursorModifier: 'ctrlCmd' | 'alt'): 'altKey' | 'metaKey' | 'ctrlKey' {\n\tif (multiCursorModifier === 'ctrlCmd') {\n\t\treturn (platform.isMacintosh ? 'metaKey' : 'ctrlKey');\n\t}\n\treturn 'altKey';\n}\n\n//#endregion\n\n//#region padding\n\n/**\n * Configuration options for editor padding\n */\nexport interface IEditorPaddingOptions {\n\t/**\n\t * Spacing between top edge of editor and first line.\n\t */\n\ttop?: number;\n\t/**\n\t * Spacing between bottom edge of editor and last line.\n\t */\n\tbottom?: number;\n}\n\n/**\n * @internal\n */\nexport type InternalEditorPaddingOptions = Readonly>;\n\nclass EditorPadding extends BaseEditorOption {\n\n\tconstructor() {\n\t\tsuper(\n\t\t\tEditorOption.padding, 'padding', { top: 0, bottom: 0 },\n\t\t\t{\n\t\t\t\t'editor.padding.top': {\n\t\t\t\t\ttype: 'number',\n\t\t\t\t\tdefault: 0,\n\t\t\t\t\tminimum: 0,\n\t\t\t\t\tmaximum: 1000,\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.\")\n\t\t\t\t},\n\t\t\t\t'editor.padding.bottom': {\n\t\t\t\t\ttype: 'number',\n\t\t\t\t\tdefault: 0,\n\t\t\t\t\tminimum: 0,\n\t\t\t\t\tmaximum: 1000,\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.\")\n\t\t\t\t}\n\t\t\t}\n\t\t);\n\t}\n\n\tpublic validate(_input: any): InternalEditorPaddingOptions {\n\t\tif (!_input || typeof _input !== 'object') {\n\t\t\treturn this.defaultValue;\n\t\t}\n\t\tconst input = _input as IEditorPaddingOptions;\n\n\t\treturn {\n\t\t\ttop: EditorIntOption.clampedInt(input.top, 0, 0, 1000),\n\t\t\tbottom: EditorIntOption.clampedInt(input.bottom, 0, 0, 1000)\n\t\t};\n\t}\n}\n//#endregion\n\n//#region parameterHints\n\n/**\n * Configuration options for parameter hints\n */\nexport interface IEditorParameterHintOptions {\n\t/**\n\t * Enable parameter hints.\n\t * Defaults to true.\n\t */\n\tenabled?: boolean;\n\t/**\n\t * Enable cycling of parameter hints.\n\t * Defaults to false.\n\t */\n\tcycle?: boolean;\n}\n\n/**\n * @internal\n */\nexport type InternalParameterHintOptions = Readonly>;\n\nclass EditorParameterHints extends BaseEditorOption {\n\n\tconstructor() {\n\t\tconst defaults: InternalParameterHintOptions = {\n\t\t\tenabled: true,\n\t\t\tcycle: true\n\t\t};\n\t\tsuper(\n\t\t\tEditorOption.parameterHints, 'parameterHints', defaults,\n\t\t\t{\n\t\t\t\t'editor.parameterHints.enabled': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: defaults.enabled,\n\t\t\t\t\tdescription: nls.localize('parameterHints.enabled', \"Enables a pop-up that shows parameter documentation and type information as you type.\")\n\t\t\t\t},\n\t\t\t\t'editor.parameterHints.cycle': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: defaults.cycle,\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.\")\n\t\t\t\t},\n\t\t\t}\n\t\t);\n\t}\n\n\tpublic validate(_input: any): InternalParameterHintOptions {\n\t\tif (!_input || typeof _input !== 'object') {\n\t\t\treturn this.defaultValue;\n\t\t}\n\t\tconst input = _input as IEditorParameterHintOptions;\n\t\treturn {\n\t\t\tenabled: boolean(input.enabled, this.defaultValue.enabled),\n\t\t\tcycle: boolean(input.cycle, this.defaultValue.cycle)\n\t\t};\n\t}\n}\n\n//#endregion\n\n//#region pixelRatio\n\nclass EditorPixelRatio extends ComputedEditorOption {\n\n\tconstructor() {\n\t\tsuper(EditorOption.pixelRatio);\n\t}\n\n\tpublic compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, _: number): number {\n\t\treturn env.pixelRatio;\n\t}\n}\n\n//#endregion\n\n//#region quickSuggestions\n\nexport type QuickSuggestionsValue = 'on' | 'inline' | 'off';\n\n/**\n * Configuration options for quick suggestions\n */\nexport interface IQuickSuggestionsOptions {\n\tother?: boolean | QuickSuggestionsValue;\n\tcomments?: boolean | QuickSuggestionsValue;\n\tstrings?: boolean | QuickSuggestionsValue;\n}\n\nexport interface InternalQuickSuggestionsOptions {\n\treadonly other: QuickSuggestionsValue;\n\treadonly comments: QuickSuggestionsValue;\n\treadonly strings: QuickSuggestionsValue;\n}\n\nclass EditorQuickSuggestions extends BaseEditorOption {\n\n\tpublic override readonly defaultValue: InternalQuickSuggestionsOptions;\n\n\tconstructor() {\n\t\tconst defaults: InternalQuickSuggestionsOptions = {\n\t\t\tother: 'on',\n\t\t\tcomments: 'off',\n\t\t\tstrings: 'off'\n\t\t};\n\t\tconst types: IJSONSchema[] = [\n\t\t\t{ type: 'boolean' },\n\t\t\t{\n\t\t\t\ttype: 'string',\n\t\t\t\tenum: ['on', 'inline', 'off'],\n\t\t\t\tenumDescriptions: [nls.localize('on', \"Quick suggestions show inside the suggest widget\"), nls.localize('inline', \"Quick suggestions show as ghost text\"), nls.localize('off', \"Quick suggestions are disabled\")]\n\t\t\t}\n\t\t];\n\t\tsuper(EditorOption.quickSuggestions, 'quickSuggestions', defaults, {\n\t\t\ttype: 'object',\n\t\t\tadditionalProperties: false,\n\t\t\tproperties: {\n\t\t\t\tstrings: {\n\t\t\t\t\tanyOf: types,\n\t\t\t\t\tdefault: defaults.strings,\n\t\t\t\t\tdescription: nls.localize('quickSuggestions.strings', \"Enable quick suggestions inside strings.\")\n\t\t\t\t},\n\t\t\t\tcomments: {\n\t\t\t\t\tanyOf: types,\n\t\t\t\t\tdefault: defaults.comments,\n\t\t\t\t\tdescription: nls.localize('quickSuggestions.comments', \"Enable quick suggestions inside comments.\")\n\t\t\t\t},\n\t\t\t\tother: {\n\t\t\t\t\tanyOf: types,\n\t\t\t\t\tdefault: defaults.other,\n\t\t\t\t\tdescription: nls.localize('quickSuggestions.other', \"Enable quick suggestions outside of strings and comments.\")\n\t\t\t\t},\n\t\t\t},\n\t\t\tdefault: defaults,\n\t\t\tmarkdownDescription: nls.localize('quickSuggestions', \"Controls whether suggestions should automatically show up while typing. This can be controlled for typing in comments, strings, and other code. Quick suggestion can be configured to show as ghost text or with the suggest widget. Also be aware of the '{0}'-setting which controls if suggestions are triggered by special characters.\", `#editor.suggestOnTriggerCharacters#`)\n\t\t});\n\t\tthis.defaultValue = defaults;\n\t}\n\n\tpublic validate(input: any): InternalQuickSuggestionsOptions {\n\t\tif (typeof input === 'boolean') {\n\t\t\t// boolean -> all on/off\n\t\t\tconst value = input ? 'on' : 'off';\n\t\t\treturn { comments: value, strings: value, other: value };\n\t\t}\n\t\tif (!input || typeof input !== 'object') {\n\t\t\t// invalid object\n\t\t\treturn this.defaultValue;\n\t\t}\n\n\t\tconst { other, comments, strings } = (input);\n\t\tconst allowedValues: QuickSuggestionsValue[] = ['on', 'inline', 'off'];\n\t\tlet validatedOther: QuickSuggestionsValue;\n\t\tlet validatedComments: QuickSuggestionsValue;\n\t\tlet validatedStrings: QuickSuggestionsValue;\n\n\t\tif (typeof other === 'boolean') {\n\t\t\tvalidatedOther = other ? 'on' : 'off';\n\t\t} else {\n\t\t\tvalidatedOther = stringSet(other, this.defaultValue.other, allowedValues);\n\t\t}\n\t\tif (typeof comments === 'boolean') {\n\t\t\tvalidatedComments = comments ? 'on' : 'off';\n\t\t} else {\n\t\t\tvalidatedComments = stringSet(comments, this.defaultValue.comments, allowedValues);\n\t\t}\n\t\tif (typeof strings === 'boolean') {\n\t\t\tvalidatedStrings = strings ? 'on' : 'off';\n\t\t} else {\n\t\t\tvalidatedStrings = stringSet(strings, this.defaultValue.strings, allowedValues);\n\t\t}\n\t\treturn {\n\t\t\tother: validatedOther,\n\t\t\tcomments: validatedComments,\n\t\t\tstrings: validatedStrings\n\t\t};\n\t}\n}\n\n//#endregion\n\n//#region renderLineNumbers\n\nexport type LineNumbersType = 'on' | 'off' | 'relative' | 'interval' | ((lineNumber: number) => string);\n\nexport const enum RenderLineNumbersType {\n\tOff = 0,\n\tOn = 1,\n\tRelative = 2,\n\tInterval = 3,\n\tCustom = 4\n}\n\nexport interface InternalEditorRenderLineNumbersOptions {\n\treadonly renderType: RenderLineNumbersType;\n\treadonly renderFn: ((lineNumber: number) => string) | null;\n}\n\nclass EditorRenderLineNumbersOption extends BaseEditorOption {\n\n\tconstructor() {\n\t\tsuper(\n\t\t\tEditorOption.lineNumbers, 'lineNumbers', { renderType: RenderLineNumbersType.On, renderFn: null },\n\t\t\t{\n\t\t\t\ttype: 'string',\n\t\t\t\tenum: ['off', 'on', 'relative', 'interval'],\n\t\t\t\tenumDescriptions: [\n\t\t\t\t\tnls.localize('lineNumbers.off', \"Line numbers are not rendered.\"),\n\t\t\t\t\tnls.localize('lineNumbers.on', \"Line numbers are rendered as absolute number.\"),\n\t\t\t\t\tnls.localize('lineNumbers.relative', \"Line numbers are rendered as distance in lines to cursor position.\"),\n\t\t\t\t\tnls.localize('lineNumbers.interval', \"Line numbers are rendered every 10 lines.\")\n\t\t\t\t],\n\t\t\t\tdefault: 'on',\n\t\t\t\tdescription: nls.localize('lineNumbers', \"Controls the display of line numbers.\")\n\t\t\t}\n\t\t);\n\t}\n\n\tpublic validate(lineNumbers: any): InternalEditorRenderLineNumbersOptions {\n\t\tlet renderType: RenderLineNumbersType = this.defaultValue.renderType;\n\t\tlet renderFn: ((lineNumber: number) => string) | null = this.defaultValue.renderFn;\n\n\t\tif (typeof lineNumbers !== 'undefined') {\n\t\t\tif (typeof lineNumbers === 'function') {\n\t\t\t\trenderType = RenderLineNumbersType.Custom;\n\t\t\t\trenderFn = lineNumbers;\n\t\t\t} else if (lineNumbers === 'interval') {\n\t\t\t\trenderType = RenderLineNumbersType.Interval;\n\t\t\t} else if (lineNumbers === 'relative') {\n\t\t\t\trenderType = RenderLineNumbersType.Relative;\n\t\t\t} else if (lineNumbers === 'on') {\n\t\t\t\trenderType = RenderLineNumbersType.On;\n\t\t\t} else {\n\t\t\t\trenderType = RenderLineNumbersType.Off;\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\trenderType,\n\t\t\trenderFn\n\t\t};\n\t}\n}\n\n//#endregion\n\n//#region renderValidationDecorations\n\n/**\n * @internal\n */\nexport function filterValidationDecorations(options: IComputedEditorOptions): boolean {\n\tconst renderValidationDecorations = options.get(EditorOption.renderValidationDecorations);\n\tif (renderValidationDecorations === 'editable') {\n\t\treturn options.get(EditorOption.readOnly);\n\t}\n\treturn renderValidationDecorations === 'on' ? false : true;\n}\n\n//#endregion\n\n//#region rulers\n\nexport interface IRulerOption {\n\treadonly column: number;\n\treadonly color: string | null;\n}\n\nclass EditorRulers extends BaseEditorOption {\n\n\tconstructor() {\n\t\tconst defaults: IRulerOption[] = [];\n\t\tconst columnSchema: IJSONSchema = { type: 'number', description: nls.localize('rulers.size', \"Number of monospace characters at which this editor ruler will render.\") };\n\t\tsuper(\n\t\t\tEditorOption.rulers, 'rulers', defaults,\n\t\t\t{\n\t\t\t\ttype: 'array',\n\t\t\t\titems: {\n\t\t\t\t\tanyOf: [\n\t\t\t\t\t\tcolumnSchema,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: [\n\t\t\t\t\t\t\t\t'object'\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\tcolumn: columnSchema,\n\t\t\t\t\t\t\t\tcolor: {\n\t\t\t\t\t\t\t\t\ttype: 'string',\n\t\t\t\t\t\t\t\t\tdescription: nls.localize('rulers.color', \"Color of this editor ruler.\"),\n\t\t\t\t\t\t\t\t\tformat: 'color-hex'\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\tdefault: defaults,\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.\")\n\t\t\t}\n\t\t);\n\t}\n\n\tpublic validate(input: any): IRulerOption[] {\n\t\tif (Array.isArray(input)) {\n\t\t\tconst rulers: IRulerOption[] = [];\n\t\t\tfor (const _element of input) {\n\t\t\t\tif (typeof _element === 'number') {\n\t\t\t\t\trulers.push({\n\t\t\t\t\t\tcolumn: EditorIntOption.clampedInt(_element, 0, 0, 10000),\n\t\t\t\t\t\tcolor: null\n\t\t\t\t\t});\n\t\t\t\t} else if (_element && typeof _element === 'object') {\n\t\t\t\t\tconst element = _element as IRulerOption;\n\t\t\t\t\trulers.push({\n\t\t\t\t\t\tcolumn: EditorIntOption.clampedInt(element.column, 0, 0, 10000),\n\t\t\t\t\t\tcolor: element.color\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\trulers.sort((a, b) => a.column - b.column);\n\t\t\treturn rulers;\n\t\t}\n\t\treturn this.defaultValue;\n\t}\n}\n\n//#endregion\n\n//#region readonly\n\n/**\n * Configuration options for readonly message\n */\nclass ReadonlyMessage extends BaseEditorOption {\n\tconstructor() {\n\t\tconst defaults = undefined;\n\n\t\tsuper(\n\t\t\tEditorOption.readOnlyMessage, 'readOnlyMessage', defaults\n\t\t);\n\t}\n\n\tpublic validate(_input: any): IMarkdownString | undefined {\n\t\tif (!_input || typeof _input !== 'object') {\n\t\t\treturn this.defaultValue;\n\t\t}\n\t\treturn _input as IMarkdownString;\n\t}\n}\n\n//#endregion\n\n//#region scrollbar\n\n/**\n * Configuration options for editor scrollbars\n */\nexport interface IEditorScrollbarOptions {\n\t/**\n\t * The size of arrows (if displayed).\n\t * Defaults to 11.\n\t * **NOTE**: This option cannot be updated using `updateOptions()`\n\t */\n\tarrowSize?: number;\n\t/**\n\t * Render vertical scrollbar.\n\t * Defaults to 'auto'.\n\t */\n\tvertical?: 'auto' | 'visible' | 'hidden';\n\t/**\n\t * Render horizontal scrollbar.\n\t * Defaults to 'auto'.\n\t */\n\thorizontal?: 'auto' | 'visible' | 'hidden';\n\t/**\n\t * Cast horizontal and vertical shadows when the content is scrolled.\n\t * Defaults to true.\n\t * **NOTE**: This option cannot be updated using `updateOptions()`\n\t */\n\tuseShadows?: boolean;\n\t/**\n\t * Render arrows at the top and bottom of the vertical scrollbar.\n\t * Defaults to false.\n\t * **NOTE**: This option cannot be updated using `updateOptions()`\n\t */\n\tverticalHasArrows?: boolean;\n\t/**\n\t * Render arrows at the left and right of the horizontal scrollbar.\n\t * Defaults to false.\n\t * **NOTE**: This option cannot be updated using `updateOptions()`\n\t */\n\thorizontalHasArrows?: boolean;\n\t/**\n\t * Listen to mouse wheel events and react to them by scrolling.\n\t * Defaults to true.\n\t */\n\thandleMouseWheel?: boolean;\n\t/**\n\t * Always consume mouse wheel events (always call preventDefault() and stopPropagation() on the browser events).\n\t * Defaults to true.\n\t * **NOTE**: This option cannot be updated using `updateOptions()`\n\t */\n\talwaysConsumeMouseWheel?: boolean;\n\t/**\n\t * Height in pixels for the horizontal scrollbar.\n\t * Defaults to 10 (px).\n\t */\n\thorizontalScrollbarSize?: number;\n\t/**\n\t * Width in pixels for the vertical scrollbar.\n\t * Defaults to 10 (px).\n\t */\n\tverticalScrollbarSize?: number;\n\t/**\n\t * Width in pixels for the vertical slider.\n\t * Defaults to `verticalScrollbarSize`.\n\t * **NOTE**: This option cannot be updated using `updateOptions()`\n\t */\n\tverticalSliderSize?: number;\n\t/**\n\t * Height in pixels for the horizontal slider.\n\t * Defaults to `horizontalScrollbarSize`.\n\t * **NOTE**: This option cannot be updated using `updateOptions()`\n\t */\n\thorizontalSliderSize?: number;\n\t/**\n\t * Scroll gutter clicks move by page vs jump to position.\n\t * Defaults to false.\n\t */\n\tscrollByPage?: boolean;\n\n\t/**\n\t * When set, the horizontal scrollbar will not increase content height.\n\t * Defaults to false.\n\t */\n\tignoreHorizontalScrollbarInContentHeight?: boolean;\n}\n\nexport interface InternalEditorScrollbarOptions {\n\treadonly arrowSize: number;\n\treadonly vertical: ScrollbarVisibility;\n\treadonly horizontal: ScrollbarVisibility;\n\treadonly useShadows: boolean;\n\treadonly verticalHasArrows: boolean;\n\treadonly horizontalHasArrows: boolean;\n\treadonly handleMouseWheel: boolean;\n\treadonly alwaysConsumeMouseWheel: boolean;\n\treadonly horizontalScrollbarSize: number;\n\treadonly horizontalSliderSize: number;\n\treadonly verticalScrollbarSize: number;\n\treadonly verticalSliderSize: number;\n\treadonly scrollByPage: boolean;\n\treadonly ignoreHorizontalScrollbarInContentHeight: boolean;\n}\n\nfunction _scrollbarVisibilityFromString(visibility: string | undefined, defaultValue: ScrollbarVisibility): ScrollbarVisibility {\n\tif (typeof visibility !== 'string') {\n\t\treturn defaultValue;\n\t}\n\tswitch (visibility) {\n\t\tcase 'hidden': return ScrollbarVisibility.Hidden;\n\t\tcase 'visible': return ScrollbarVisibility.Visible;\n\t\tdefault: return ScrollbarVisibility.Auto;\n\t}\n}\n\nclass EditorScrollbar extends BaseEditorOption {\n\n\tconstructor() {\n\t\tconst defaults: InternalEditorScrollbarOptions = {\n\t\t\tvertical: ScrollbarVisibility.Auto,\n\t\t\thorizontal: ScrollbarVisibility.Auto,\n\t\t\tarrowSize: 11,\n\t\t\tuseShadows: true,\n\t\t\tverticalHasArrows: false,\n\t\t\thorizontalHasArrows: false,\n\t\t\thorizontalScrollbarSize: 12,\n\t\t\thorizontalSliderSize: 12,\n\t\t\tverticalScrollbarSize: 14,\n\t\t\tverticalSliderSize: 14,\n\t\t\thandleMouseWheel: true,\n\t\t\talwaysConsumeMouseWheel: true,\n\t\t\tscrollByPage: false,\n\t\t\tignoreHorizontalScrollbarInContentHeight: false,\n\t\t};\n\t\tsuper(\n\t\t\tEditorOption.scrollbar, 'scrollbar', defaults,\n\t\t\t{\n\t\t\t\t'editor.scrollbar.vertical': {\n\t\t\t\t\ttype: 'string',\n\t\t\t\t\tenum: ['auto', 'visible', 'hidden'],\n\t\t\t\t\tenumDescriptions: [\n\t\t\t\t\t\tnls.localize('scrollbar.vertical.auto', \"The vertical scrollbar will be visible only when necessary.\"),\n\t\t\t\t\t\tnls.localize('scrollbar.vertical.visible', \"The vertical scrollbar will always be visible.\"),\n\t\t\t\t\t\tnls.localize('scrollbar.vertical.fit', \"The vertical scrollbar will always be hidden.\"),\n\t\t\t\t\t],\n\t\t\t\t\tdefault: 'auto',\n\t\t\t\t\tdescription: nls.localize('scrollbar.vertical', \"Controls the visibility of the vertical scrollbar.\")\n\t\t\t\t},\n\t\t\t\t'editor.scrollbar.horizontal': {\n\t\t\t\t\ttype: 'string',\n\t\t\t\t\tenum: ['auto', 'visible', 'hidden'],\n\t\t\t\t\tenumDescriptions: [\n\t\t\t\t\t\tnls.localize('scrollbar.horizontal.auto', \"The horizontal scrollbar will be visible only when necessary.\"),\n\t\t\t\t\t\tnls.localize('scrollbar.horizontal.visible', \"The horizontal scrollbar will always be visible.\"),\n\t\t\t\t\t\tnls.localize('scrollbar.horizontal.fit', \"The horizontal scrollbar will always be hidden.\"),\n\t\t\t\t\t],\n\t\t\t\t\tdefault: 'auto',\n\t\t\t\t\tdescription: nls.localize('scrollbar.horizontal', \"Controls the visibility of the horizontal scrollbar.\")\n\t\t\t\t},\n\t\t\t\t'editor.scrollbar.verticalScrollbarSize': {\n\t\t\t\t\ttype: 'number',\n\t\t\t\t\tdefault: defaults.verticalScrollbarSize,\n\t\t\t\t\tdescription: nls.localize('scrollbar.verticalScrollbarSize', \"The width of the vertical scrollbar.\")\n\t\t\t\t},\n\t\t\t\t'editor.scrollbar.horizontalScrollbarSize': {\n\t\t\t\t\ttype: 'number',\n\t\t\t\t\tdefault: defaults.horizontalScrollbarSize,\n\t\t\t\t\tdescription: nls.localize('scrollbar.horizontalScrollbarSize', \"The height of the horizontal scrollbar.\")\n\t\t\t\t},\n\t\t\t\t'editor.scrollbar.scrollByPage': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: defaults.scrollByPage,\n\t\t\t\t\tdescription: nls.localize('scrollbar.scrollByPage', \"Controls whether clicks scroll by page or jump to click position.\")\n\t\t\t\t},\n\t\t\t\t'editor.scrollbar.ignoreHorizontalScrollbarInContentHeight': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: defaults.ignoreHorizontalScrollbarInContentHeight,\n\t\t\t\t\tdescription: nls.localize('scrollbar.ignoreHorizontalScrollbarInContentHeight', \"When set, the horizontal scrollbar will not increase the size of the editor's content.\")\n\t\t\t\t}\n\t\t\t}\n\t\t);\n\t}\n\n\tpublic validate(_input: any): InternalEditorScrollbarOptions {\n\t\tif (!_input || typeof _input !== 'object') {\n\t\t\treturn this.defaultValue;\n\t\t}\n\t\tconst input = _input as IEditorScrollbarOptions;\n\t\tconst horizontalScrollbarSize = EditorIntOption.clampedInt(input.horizontalScrollbarSize, this.defaultValue.horizontalScrollbarSize, 0, 1000);\n\t\tconst verticalScrollbarSize = EditorIntOption.clampedInt(input.verticalScrollbarSize, this.defaultValue.verticalScrollbarSize, 0, 1000);\n\t\treturn {\n\t\t\tarrowSize: EditorIntOption.clampedInt(input.arrowSize, this.defaultValue.arrowSize, 0, 1000),\n\t\t\tvertical: _scrollbarVisibilityFromString(input.vertical, this.defaultValue.vertical),\n\t\t\thorizontal: _scrollbarVisibilityFromString(input.horizontal, this.defaultValue.horizontal),\n\t\t\tuseShadows: boolean(input.useShadows, this.defaultValue.useShadows),\n\t\t\tverticalHasArrows: boolean(input.verticalHasArrows, this.defaultValue.verticalHasArrows),\n\t\t\thorizontalHasArrows: boolean(input.horizontalHasArrows, this.defaultValue.horizontalHasArrows),\n\t\t\thandleMouseWheel: boolean(input.handleMouseWheel, this.defaultValue.handleMouseWheel),\n\t\t\talwaysConsumeMouseWheel: boolean(input.alwaysConsumeMouseWheel, this.defaultValue.alwaysConsumeMouseWheel),\n\t\t\thorizontalScrollbarSize: horizontalScrollbarSize,\n\t\t\thorizontalSliderSize: EditorIntOption.clampedInt(input.horizontalSliderSize, horizontalScrollbarSize, 0, 1000),\n\t\t\tverticalScrollbarSize: verticalScrollbarSize,\n\t\t\tverticalSliderSize: EditorIntOption.clampedInt(input.verticalSliderSize, verticalScrollbarSize, 0, 1000),\n\t\t\tscrollByPage: boolean(input.scrollByPage, this.defaultValue.scrollByPage),\n\t\t\tignoreHorizontalScrollbarInContentHeight: boolean(input.ignoreHorizontalScrollbarInContentHeight, this.defaultValue.ignoreHorizontalScrollbarInContentHeight),\n\t\t};\n\t}\n}\n\n//#endregion\n\n//#region UnicodeHighlight\n\nexport type InUntrustedWorkspace = 'inUntrustedWorkspace';\n\n/**\n * @internal\n*/\nexport const inUntrustedWorkspace: InUntrustedWorkspace = 'inUntrustedWorkspace';\n\n/**\n * Configuration options for unicode highlighting.\n */\nexport interface IUnicodeHighlightOptions {\n\n\t/**\n\t * Controls whether all non-basic ASCII characters are highlighted. Only characters between U+0020 and U+007E, tab, line-feed and carriage-return are considered basic ASCII.\n\t */\n\tnonBasicASCII?: boolean | InUntrustedWorkspace;\n\n\t/**\n\t * Controls whether characters that just reserve space or have no width at all are highlighted.\n\t */\n\tinvisibleCharacters?: boolean;\n\n\t/**\n\t * Controls whether characters are highlighted that can be confused with basic ASCII characters, except those that are common in the current user locale.\n\t */\n\tambiguousCharacters?: boolean;\n\n\t/**\n\t * Controls whether characters in comments should also be subject to unicode highlighting.\n\t */\n\tincludeComments?: boolean | InUntrustedWorkspace;\n\n\t/**\n\t * Controls whether characters in strings should also be subject to unicode highlighting.\n\t */\n\tincludeStrings?: boolean | InUntrustedWorkspace;\n\n\t/**\n\t * Defines allowed characters that are not being highlighted.\n\t */\n\tallowedCharacters?: Record;\n\n\t/**\n\t * Unicode characters that are common in allowed locales are not being highlighted.\n\t */\n\tallowedLocales?: Record;\n}\n\n/**\n * @internal\n */\nexport type InternalUnicodeHighlightOptions = Required>;\n\n/**\n * @internal\n */\nexport const unicodeHighlightConfigKeys = {\n\tallowedCharacters: 'editor.unicodeHighlight.allowedCharacters',\n\tinvisibleCharacters: 'editor.unicodeHighlight.invisibleCharacters',\n\tnonBasicASCII: 'editor.unicodeHighlight.nonBasicASCII',\n\tambiguousCharacters: 'editor.unicodeHighlight.ambiguousCharacters',\n\tincludeComments: 'editor.unicodeHighlight.includeComments',\n\tincludeStrings: 'editor.unicodeHighlight.includeStrings',\n\tallowedLocales: 'editor.unicodeHighlight.allowedLocales',\n};\n\nclass UnicodeHighlight extends BaseEditorOption {\n\tconstructor() {\n\t\tconst defaults: InternalUnicodeHighlightOptions = {\n\t\t\tnonBasicASCII: inUntrustedWorkspace,\n\t\t\tinvisibleCharacters: true,\n\t\t\tambiguousCharacters: true,\n\t\t\tincludeComments: inUntrustedWorkspace,\n\t\t\tincludeStrings: true,\n\t\t\tallowedCharacters: {},\n\t\t\tallowedLocales: { _os: true, _vscode: true },\n\t\t};\n\n\t\tsuper(\n\t\t\tEditorOption.unicodeHighlighting, 'unicodeHighlight', defaults,\n\t\t\t{\n\t\t\t\t[unicodeHighlightConfigKeys.nonBasicASCII]: {\n\t\t\t\t\trestricted: true,\n\t\t\t\t\ttype: ['boolean', 'string'],\n\t\t\t\t\tenum: [true, false, inUntrustedWorkspace],\n\t\t\t\t\tdefault: defaults.nonBasicASCII,\n\t\t\t\t\tdescription: nls.localize('unicodeHighlight.nonBasicASCII', \"Controls whether all non-basic ASCII characters are highlighted. Only characters between U+0020 and U+007E, tab, line-feed and carriage-return are considered basic ASCII.\")\n\t\t\t\t},\n\t\t\t\t[unicodeHighlightConfigKeys.invisibleCharacters]: {\n\t\t\t\t\trestricted: true,\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: defaults.invisibleCharacters,\n\t\t\t\t\tdescription: nls.localize('unicodeHighlight.invisibleCharacters', \"Controls whether characters that just reserve space or have no width at all are highlighted.\")\n\t\t\t\t},\n\t\t\t\t[unicodeHighlightConfigKeys.ambiguousCharacters]: {\n\t\t\t\t\trestricted: true,\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: defaults.ambiguousCharacters,\n\t\t\t\t\tdescription: nls.localize('unicodeHighlight.ambiguousCharacters', \"Controls whether characters are highlighted that can be confused with basic ASCII characters, except those that are common in the current user locale.\")\n\t\t\t\t},\n\t\t\t\t[unicodeHighlightConfigKeys.includeComments]: {\n\t\t\t\t\trestricted: true,\n\t\t\t\t\ttype: ['boolean', 'string'],\n\t\t\t\t\tenum: [true, false, inUntrustedWorkspace],\n\t\t\t\t\tdefault: defaults.includeComments,\n\t\t\t\t\tdescription: nls.localize('unicodeHighlight.includeComments', \"Controls whether characters in comments should also be subject to Unicode highlighting.\")\n\t\t\t\t},\n\t\t\t\t[unicodeHighlightConfigKeys.includeStrings]: {\n\t\t\t\t\trestricted: true,\n\t\t\t\t\ttype: ['boolean', 'string'],\n\t\t\t\t\tenum: [true, false, inUntrustedWorkspace],\n\t\t\t\t\tdefault: defaults.includeStrings,\n\t\t\t\t\tdescription: nls.localize('unicodeHighlight.includeStrings', \"Controls whether characters in strings should also be subject to Unicode highlighting.\")\n\t\t\t\t},\n\t\t\t\t[unicodeHighlightConfigKeys.allowedCharacters]: {\n\t\t\t\t\trestricted: true,\n\t\t\t\t\ttype: 'object',\n\t\t\t\t\tdefault: defaults.allowedCharacters,\n\t\t\t\t\tdescription: nls.localize('unicodeHighlight.allowedCharacters', \"Defines allowed characters that are not being highlighted.\"),\n\t\t\t\t\tadditionalProperties: {\n\t\t\t\t\t\ttype: 'boolean'\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t[unicodeHighlightConfigKeys.allowedLocales]: {\n\t\t\t\t\trestricted: true,\n\t\t\t\t\ttype: 'object',\n\t\t\t\t\tadditionalProperties: {\n\t\t\t\t\t\ttype: 'boolean'\n\t\t\t\t\t},\n\t\t\t\t\tdefault: defaults.allowedLocales,\n\t\t\t\t\tdescription: nls.localize('unicodeHighlight.allowedLocales', \"Unicode characters that are common in allowed locales are not being highlighted.\")\n\t\t\t\t},\n\t\t\t}\n\t\t);\n\t}\n\n\tpublic override applyUpdate(value: Required> | undefined, update: Required>): ApplyUpdateResult>> {\n\t\tlet didChange = false;\n\t\tif (update.allowedCharacters && value) {\n\t\t\t// Treat allowedCharacters atomically\n\t\t\tif (!objects.equals(value.allowedCharacters, update.allowedCharacters)) {\n\t\t\t\tvalue = { ...value, allowedCharacters: update.allowedCharacters };\n\t\t\t\tdidChange = true;\n\t\t\t}\n\t\t}\n\t\tif (update.allowedLocales && value) {\n\t\t\t// Treat allowedLocales atomically\n\t\t\tif (!objects.equals(value.allowedLocales, update.allowedLocales)) {\n\t\t\t\tvalue = { ...value, allowedLocales: update.allowedLocales };\n\t\t\t\tdidChange = true;\n\t\t\t}\n\t\t}\n\n\t\tconst result = super.applyUpdate(value, update);\n\t\tif (didChange) {\n\t\t\treturn new ApplyUpdateResult(result.newValue, true);\n\t\t}\n\t\treturn result;\n\t}\n\n\tpublic validate(_input: any): InternalUnicodeHighlightOptions {\n\t\tif (!_input || typeof _input !== 'object') {\n\t\t\treturn this.defaultValue;\n\t\t}\n\t\tconst input = _input as IUnicodeHighlightOptions;\n\t\treturn {\n\t\t\tnonBasicASCII: primitiveSet(input.nonBasicASCII, inUntrustedWorkspace, [true, false, inUntrustedWorkspace]),\n\t\t\tinvisibleCharacters: boolean(input.invisibleCharacters, this.defaultValue.invisibleCharacters),\n\t\t\tambiguousCharacters: boolean(input.ambiguousCharacters, this.defaultValue.ambiguousCharacters),\n\t\t\tincludeComments: primitiveSet(input.includeComments, inUntrustedWorkspace, [true, false, inUntrustedWorkspace]),\n\t\t\tincludeStrings: primitiveSet(input.includeStrings, inUntrustedWorkspace, [true, false, inUntrustedWorkspace]),\n\t\t\tallowedCharacters: this.validateBooleanMap(_input.allowedCharacters, this.defaultValue.allowedCharacters),\n\t\t\tallowedLocales: this.validateBooleanMap(_input.allowedLocales, this.defaultValue.allowedLocales),\n\t\t};\n\t}\n\n\tprivate validateBooleanMap(map: unknown, defaultValue: Record): Record {\n\t\tif ((typeof map !== 'object') || !map) {\n\t\t\treturn defaultValue;\n\t\t}\n\t\tconst result: Record = {};\n\t\tfor (const [key, value] of Object.entries(map)) {\n\t\t\tif (value === true) {\n\t\t\t\tresult[key] = true;\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n}\n\n//#endregion\n\n//#region inlineSuggest\n\nexport interface IInlineSuggestOptions {\n\t/**\n\t * Enable or disable the rendering of automatic inline completions.\n\t*/\n\tenabled?: boolean;\n\n\t/**\n\t * Configures the mode.\n\t * Use `prefix` to only show ghost text if the text to replace is a prefix of the suggestion text.\n\t * Use `subword` to only show ghost text if the replace text is a subword of the suggestion text.\n\t * Use `subwordSmart` to only show ghost text if the replace text is a subword of the suggestion text, but the subword must start after the cursor position.\n\t * Defaults to `prefix`.\n\t*/\n\tmode?: 'prefix' | 'subword' | 'subwordSmart';\n\n\tshowToolbar?: 'always' | 'onHover' | 'never';\n\n\tsuppressSuggestions?: boolean;\n\n\t/**\n\t * Does not clear active inline suggestions when the editor loses focus.\n\t */\n\tkeepOnBlur?: boolean;\n\n\t/**\n\t * Font family for inline suggestions.\n\t */\n\tfontFamily?: string | 'default';\n}\n\n/**\n * @internal\n */\nexport type InternalInlineSuggestOptions = Readonly>;\n\n/**\n * Configuration options for inline suggestions\n */\nclass InlineEditorSuggest extends BaseEditorOption {\n\tconstructor() {\n\t\tconst defaults: InternalInlineSuggestOptions = {\n\t\t\tenabled: true,\n\t\t\tmode: 'subwordSmart',\n\t\t\tshowToolbar: 'onHover',\n\t\t\tsuppressSuggestions: false,\n\t\t\tkeepOnBlur: false,\n\t\t\tfontFamily: 'default'\n\t\t};\n\n\t\tsuper(\n\t\t\tEditorOption.inlineSuggest, 'inlineSuggest', defaults,\n\t\t\t{\n\t\t\t\t'editor.inlineSuggest.enabled': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: defaults.enabled,\n\t\t\t\t\tdescription: nls.localize('inlineSuggest.enabled', \"Controls whether to automatically show inline suggestions in the editor.\")\n\t\t\t\t},\n\t\t\t\t'editor.inlineSuggest.showToolbar': {\n\t\t\t\t\ttype: 'string',\n\t\t\t\t\tdefault: defaults.showToolbar,\n\t\t\t\t\tenum: ['always', 'onHover', 'never'],\n\t\t\t\t\tenumDescriptions: [\n\t\t\t\t\t\tnls.localize('inlineSuggest.showToolbar.always', \"Show the inline suggestion toolbar whenever an inline suggestion is shown.\"),\n\t\t\t\t\t\tnls.localize('inlineSuggest.showToolbar.onHover', \"Show the inline suggestion toolbar when hovering over an inline suggestion.\"),\n\t\t\t\t\t\tnls.localize('inlineSuggest.showToolbar.never', \"Never show the inline suggestion toolbar.\"),\n\t\t\t\t\t],\n\t\t\t\t\tdescription: nls.localize('inlineSuggest.showToolbar', \"Controls when to show the inline suggestion toolbar.\"),\n\t\t\t\t},\n\t\t\t\t'editor.inlineSuggest.suppressSuggestions': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: defaults.suppressSuggestions,\n\t\t\t\t\tdescription: nls.localize('inlineSuggest.suppressSuggestions', \"Controls how inline suggestions interact with the suggest widget. If enabled, the suggest widget is not shown automatically when inline suggestions are available.\")\n\t\t\t\t},\n\t\t\t\t'editor.inlineSuggest.fontFamily': {\n\t\t\t\t\ttype: 'string',\n\t\t\t\t\tdefault: defaults.fontFamily,\n\t\t\t\t\tdescription: nls.localize('inlineSuggest.fontFamily', \"Controls the font family of the inline suggestions.\")\n\t\t\t\t},\n\t\t\t}\n\t\t);\n\t}\n\n\tpublic validate(_input: any): InternalInlineSuggestOptions {\n\t\tif (!_input || typeof _input !== 'object') {\n\t\t\treturn this.defaultValue;\n\t\t}\n\t\tconst input = _input as IInlineSuggestOptions;\n\t\treturn {\n\t\t\tenabled: boolean(input.enabled, this.defaultValue.enabled),\n\t\t\tmode: stringSet(input.mode, this.defaultValue.mode, ['prefix', 'subword', 'subwordSmart']),\n\t\t\tshowToolbar: stringSet(input.showToolbar, this.defaultValue.showToolbar, ['always', 'onHover', 'never']),\n\t\t\tsuppressSuggestions: boolean(input.suppressSuggestions, this.defaultValue.suppressSuggestions),\n\t\t\tkeepOnBlur: boolean(input.keepOnBlur, this.defaultValue.keepOnBlur),\n\t\t\tfontFamily: EditorStringOption.string(input.fontFamily, this.defaultValue.fontFamily)\n\t\t};\n\t}\n}\n\n//#endregion\n\n//#region inlineEdit\n\nexport interface IInlineEditOptions {\n\t/**\n\t * Enable or disable the rendering of automatic inline edit.\n\t*/\n\tenabled?: boolean;\n\tshowToolbar?: 'always' | 'onHover' | 'never';\n\t/**\n\t * Font family for inline suggestions.\n\t */\n\tfontFamily?: string | 'default';\n\n\t/**\n\t * Does not clear active inline suggestions when the editor loses focus.\n\t */\n\tkeepOnBlur?: boolean;\n\n\tbackgroundColoring?: boolean;\n}\n\n/**\n * @internal\n */\nexport type InternalInlineEditOptions = Readonly>;\n\nclass InlineEditorEdit extends BaseEditorOption {\n\tconstructor() {\n\t\tconst defaults: InternalInlineEditOptions = {\n\t\t\tenabled: false,\n\t\t\tshowToolbar: 'onHover',\n\t\t\tfontFamily: 'default',\n\t\t\tkeepOnBlur: false,\n\t\t\tbackgroundColoring: false,\n\t\t};\n\n\t\tsuper(\n\t\t\tEditorOption.inlineEdit, 'experimentalInlineEdit', defaults,\n\t\t\t{\n\t\t\t\t'editor.experimentalInlineEdit.enabled': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: defaults.enabled,\n\t\t\t\t\tdescription: nls.localize('inlineEdit.enabled', \"Controls whether to show inline edits in the editor.\")\n\t\t\t\t},\n\t\t\t\t'editor.experimentalInlineEdit.showToolbar': {\n\t\t\t\t\ttype: 'string',\n\t\t\t\t\tdefault: defaults.showToolbar,\n\t\t\t\t\tenum: ['always', 'onHover', 'never'],\n\t\t\t\t\tenumDescriptions: [\n\t\t\t\t\t\tnls.localize('inlineEdit.showToolbar.always', \"Show the inline edit toolbar whenever an inline suggestion is shown.\"),\n\t\t\t\t\t\tnls.localize('inlineEdit.showToolbar.onHover', \"Show the inline edit toolbar when hovering over an inline suggestion.\"),\n\t\t\t\t\t\tnls.localize('inlineEdit.showToolbar.never', \"Never show the inline edit toolbar.\"),\n\t\t\t\t\t],\n\t\t\t\t\tdescription: nls.localize('inlineEdit.showToolbar', \"Controls when to show the inline edit toolbar.\"),\n\t\t\t\t},\n\t\t\t\t'editor.experimentalInlineEdit.fontFamily': {\n\t\t\t\t\ttype: 'string',\n\t\t\t\t\tdefault: defaults.fontFamily,\n\t\t\t\t\tdescription: nls.localize('inlineEdit.fontFamily', \"Controls the font family of the inline edit.\")\n\t\t\t\t},\n\t\t\t\t'editor.experimentalInlineEdit.backgroundColoring': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: defaults.backgroundColoring,\n\t\t\t\t\tdescription: nls.localize('inlineEdit.backgroundColoring', \"Controls whether to color the background of inline edits.\")\n\t\t\t\t},\n\t\t\t}\n\t\t);\n\t}\n\n\tpublic validate(_input: any): InternalInlineEditOptions {\n\t\tif (!_input || typeof _input !== 'object') {\n\t\t\treturn this.defaultValue;\n\t\t}\n\t\tconst input = _input as IInlineEditOptions;\n\t\treturn {\n\t\t\tenabled: boolean(input.enabled, this.defaultValue.enabled),\n\t\t\tshowToolbar: stringSet(input.showToolbar, this.defaultValue.showToolbar, ['always', 'onHover', 'never']),\n\t\t\tfontFamily: EditorStringOption.string(input.fontFamily, this.defaultValue.fontFamily),\n\t\t\tkeepOnBlur: boolean(input.keepOnBlur, this.defaultValue.keepOnBlur),\n\t\t\tbackgroundColoring: boolean(input.backgroundColoring, this.defaultValue.backgroundColoring)\n\t\t};\n\t}\n}\n\n//#region bracketPairColorization\n\nexport interface IBracketPairColorizationOptions {\n\t/**\n\t * Enable or disable bracket pair colorization.\n\t*/\n\tenabled?: boolean;\n\n\t/**\n\t * Use independent color pool per bracket type.\n\t*/\n\tindependentColorPoolPerBracketType?: boolean;\n}\n\n/**\n * @internal\n */\nexport type InternalBracketPairColorizationOptions = Readonly>;\n\n/**\n * Configuration options for inline suggestions\n */\nclass BracketPairColorization extends BaseEditorOption {\n\tconstructor() {\n\t\tconst defaults: InternalBracketPairColorizationOptions = {\n\t\t\tenabled: EDITOR_MODEL_DEFAULTS.bracketPairColorizationOptions.enabled,\n\t\t\tindependentColorPoolPerBracketType: EDITOR_MODEL_DEFAULTS.bracketPairColorizationOptions.independentColorPoolPerBracketType,\n\t\t};\n\n\t\tsuper(\n\t\t\tEditorOption.bracketPairColorization, 'bracketPairColorization', defaults,\n\t\t\t{\n\t\t\t\t'editor.bracketPairColorization.enabled': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: defaults.enabled,\n\t\t\t\t\tmarkdownDescription: nls.localize('bracketPairColorization.enabled', \"Controls whether bracket pair colorization is enabled or not. Use {0} to override the bracket highlight colors.\", '`#workbench.colorCustomizations#`')\n\t\t\t\t},\n\t\t\t\t'editor.bracketPairColorization.independentColorPoolPerBracketType': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: defaults.independentColorPoolPerBracketType,\n\t\t\t\t\tdescription: nls.localize('bracketPairColorization.independentColorPoolPerBracketType', \"Controls whether each bracket type has its own independent color pool.\")\n\t\t\t\t},\n\t\t\t}\n\t\t);\n\t}\n\n\tpublic validate(_input: any): InternalBracketPairColorizationOptions {\n\t\tif (!_input || typeof _input !== 'object') {\n\t\t\treturn this.defaultValue;\n\t\t}\n\t\tconst input = _input as IBracketPairColorizationOptions;\n\t\treturn {\n\t\t\tenabled: boolean(input.enabled, this.defaultValue.enabled),\n\t\t\tindependentColorPoolPerBracketType: boolean(input.independentColorPoolPerBracketType, this.defaultValue.independentColorPoolPerBracketType),\n\t\t};\n\t}\n}\n\n//#endregion\n\n//#region guides\n\nexport interface IGuidesOptions {\n\t/**\n\t * Enable rendering of bracket pair guides.\n\t * Defaults to false.\n\t*/\n\tbracketPairs?: boolean | 'active';\n\n\t/**\n\t * Enable rendering of vertical bracket pair guides.\n\t * Defaults to 'active'.\n\t */\n\tbracketPairsHorizontal?: boolean | 'active';\n\n\t/**\n\t * Enable highlighting of the active bracket pair.\n\t * Defaults to true.\n\t*/\n\thighlightActiveBracketPair?: boolean;\n\n\t/**\n\t * Enable rendering of indent guides.\n\t * Defaults to true.\n\t */\n\tindentation?: boolean;\n\n\t/**\n\t * Enable highlighting of the active indent guide.\n\t * Defaults to true.\n\t */\n\thighlightActiveIndentation?: boolean | 'always';\n}\n\n/**\n * @internal\n */\nexport type InternalGuidesOptions = Readonly>;\n\n/**\n * Configuration options for inline suggestions\n */\nclass GuideOptions extends BaseEditorOption {\n\tconstructor() {\n\t\tconst defaults: InternalGuidesOptions = {\n\t\t\tbracketPairs: false,\n\t\t\tbracketPairsHorizontal: 'active',\n\t\t\thighlightActiveBracketPair: true,\n\n\t\t\tindentation: true,\n\t\t\thighlightActiveIndentation: true\n\t\t};\n\n\t\tsuper(\n\t\t\tEditorOption.guides, 'guides', defaults,\n\t\t\t{\n\t\t\t\t'editor.guides.bracketPairs': {\n\t\t\t\t\ttype: ['boolean', 'string'],\n\t\t\t\t\tenum: [true, 'active', false],\n\t\t\t\t\tenumDescriptions: [\n\t\t\t\t\t\tnls.localize('editor.guides.bracketPairs.true', \"Enables bracket pair guides.\"),\n\t\t\t\t\t\tnls.localize('editor.guides.bracketPairs.active', \"Enables bracket pair guides only for the active bracket pair.\"),\n\t\t\t\t\t\tnls.localize('editor.guides.bracketPairs.false', \"Disables bracket pair guides.\"),\n\t\t\t\t\t],\n\t\t\t\t\tdefault: defaults.bracketPairs,\n\t\t\t\t\tdescription: nls.localize('editor.guides.bracketPairs', \"Controls whether bracket pair guides are enabled or not.\")\n\t\t\t\t},\n\t\t\t\t'editor.guides.bracketPairsHorizontal': {\n\t\t\t\t\ttype: ['boolean', 'string'],\n\t\t\t\t\tenum: [true, 'active', false],\n\t\t\t\t\tenumDescriptions: [\n\t\t\t\t\t\tnls.localize('editor.guides.bracketPairsHorizontal.true', \"Enables horizontal guides as addition to vertical bracket pair guides.\"),\n\t\t\t\t\t\tnls.localize('editor.guides.bracketPairsHorizontal.active', \"Enables horizontal guides only for the active bracket pair.\"),\n\t\t\t\t\t\tnls.localize('editor.guides.bracketPairsHorizontal.false', \"Disables horizontal bracket pair guides.\"),\n\t\t\t\t\t],\n\t\t\t\t\tdefault: defaults.bracketPairsHorizontal,\n\t\t\t\t\tdescription: nls.localize('editor.guides.bracketPairsHorizontal', \"Controls whether horizontal bracket pair guides are enabled or not.\")\n\t\t\t\t},\n\t\t\t\t'editor.guides.highlightActiveBracketPair': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: defaults.highlightActiveBracketPair,\n\t\t\t\t\tdescription: nls.localize('editor.guides.highlightActiveBracketPair', \"Controls whether the editor should highlight the active bracket pair.\")\n\t\t\t\t},\n\t\t\t\t'editor.guides.indentation': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: defaults.indentation,\n\t\t\t\t\tdescription: nls.localize('editor.guides.indentation', \"Controls whether the editor should render indent guides.\")\n\t\t\t\t},\n\t\t\t\t'editor.guides.highlightActiveIndentation': {\n\t\t\t\t\ttype: ['boolean', 'string'],\n\t\t\t\t\tenum: [true, 'always', false],\n\t\t\t\t\tenumDescriptions: [\n\t\t\t\t\t\tnls.localize('editor.guides.highlightActiveIndentation.true', \"Highlights the active indent guide.\"),\n\t\t\t\t\t\tnls.localize('editor.guides.highlightActiveIndentation.always', \"Highlights the active indent guide even if bracket guides are highlighted.\"),\n\t\t\t\t\t\tnls.localize('editor.guides.highlightActiveIndentation.false', \"Do not highlight the active indent guide.\"),\n\t\t\t\t\t],\n\t\t\t\t\tdefault: defaults.highlightActiveIndentation,\n\n\t\t\t\t\tdescription: nls.localize('editor.guides.highlightActiveIndentation', \"Controls whether the editor should highlight the active indent guide.\")\n\t\t\t\t}\n\t\t\t}\n\t\t);\n\t}\n\n\tpublic validate(_input: any): InternalGuidesOptions {\n\t\tif (!_input || typeof _input !== 'object') {\n\t\t\treturn this.defaultValue;\n\t\t}\n\t\tconst input = _input as IGuidesOptions;\n\t\treturn {\n\t\t\tbracketPairs: primitiveSet(input.bracketPairs, this.defaultValue.bracketPairs, [true, false, 'active']),\n\t\t\tbracketPairsHorizontal: primitiveSet(input.bracketPairsHorizontal, this.defaultValue.bracketPairsHorizontal, [true, false, 'active']),\n\t\t\thighlightActiveBracketPair: boolean(input.highlightActiveBracketPair, this.defaultValue.highlightActiveBracketPair),\n\n\t\t\tindentation: boolean(input.indentation, this.defaultValue.indentation),\n\t\t\thighlightActiveIndentation: primitiveSet(input.highlightActiveIndentation, this.defaultValue.highlightActiveIndentation, [true, false, 'always']),\n\t\t};\n\t}\n}\n\nfunction primitiveSet(value: unknown, defaultValue: T, allowedValues: T[]): T {\n\tconst idx = allowedValues.indexOf(value as any);\n\tif (idx === -1) {\n\t\treturn defaultValue;\n\t}\n\treturn allowedValues[idx];\n}\n\n//#endregion\n\n//#region suggest\n\n/**\n * Configuration options for editor suggest widget\n */\nexport interface ISuggestOptions {\n\t/**\n\t * Overwrite word ends on accept. Default to false.\n\t */\n\tinsertMode?: 'insert' | 'replace';\n\t/**\n\t * Enable graceful matching. Defaults to true.\n\t */\n\tfilterGraceful?: boolean;\n\t/**\n\t * Prevent quick suggestions when a snippet is active. Defaults to true.\n\t */\n\tsnippetsPreventQuickSuggestions?: boolean;\n\t/**\n\t * Favors words that appear close to the cursor.\n\t */\n\tlocalityBonus?: boolean;\n\t/**\n\t * Enable using global storage for remembering suggestions.\n\t */\n\tshareSuggestSelections?: boolean;\n\t/**\n\t * Select suggestions when triggered via quick suggest or trigger characters\n\t */\n\tselectionMode?: 'always' | 'never' | 'whenTriggerCharacter' | 'whenQuickSuggestion';\n\t/**\n\t * Enable or disable icons in suggestions. Defaults to true.\n\t */\n\tshowIcons?: boolean;\n\t/**\n\t * Enable or disable the suggest status bar.\n\t */\n\tshowStatusBar?: boolean;\n\t/**\n\t * Enable or disable the rendering of the suggestion preview.\n\t */\n\tpreview?: boolean;\n\t/**\n\t * Configures the mode of the preview.\n\t*/\n\tpreviewMode?: 'prefix' | 'subword' | 'subwordSmart';\n\t/**\n\t * Show details inline with the label. Defaults to true.\n\t */\n\tshowInlineDetails?: boolean;\n\t/**\n\t * Show method-suggestions.\n\t */\n\tshowMethods?: boolean;\n\t/**\n\t * Show function-suggestions.\n\t */\n\tshowFunctions?: boolean;\n\t/**\n\t * Show constructor-suggestions.\n\t */\n\tshowConstructors?: boolean;\n\t/**\n\t * Show deprecated-suggestions.\n\t */\n\tshowDeprecated?: boolean;\n\t/**\n\t * Controls whether suggestions allow matches in the middle of the word instead of only at the beginning\n\t */\n\tmatchOnWordStartOnly?: boolean;\n\t/**\n\t * Show field-suggestions.\n\t */\n\tshowFields?: boolean;\n\t/**\n\t * Show variable-suggestions.\n\t */\n\tshowVariables?: boolean;\n\t/**\n\t * Show class-suggestions.\n\t */\n\tshowClasses?: boolean;\n\t/**\n\t * Show struct-suggestions.\n\t */\n\tshowStructs?: boolean;\n\t/**\n\t * Show interface-suggestions.\n\t */\n\tshowInterfaces?: boolean;\n\t/**\n\t * Show module-suggestions.\n\t */\n\tshowModules?: boolean;\n\t/**\n\t * Show property-suggestions.\n\t */\n\tshowProperties?: boolean;\n\t/**\n\t * Show event-suggestions.\n\t */\n\tshowEvents?: boolean;\n\t/**\n\t * Show operator-suggestions.\n\t */\n\tshowOperators?: boolean;\n\t/**\n\t * Show unit-suggestions.\n\t */\n\tshowUnits?: boolean;\n\t/**\n\t * Show value-suggestions.\n\t */\n\tshowValues?: boolean;\n\t/**\n\t * Show constant-suggestions.\n\t */\n\tshowConstants?: boolean;\n\t/**\n\t * Show enum-suggestions.\n\t */\n\tshowEnums?: boolean;\n\t/**\n\t * Show enumMember-suggestions.\n\t */\n\tshowEnumMembers?: boolean;\n\t/**\n\t * Show keyword-suggestions.\n\t */\n\tshowKeywords?: boolean;\n\t/**\n\t * Show text-suggestions.\n\t */\n\tshowWords?: boolean;\n\t/**\n\t * Show color-suggestions.\n\t */\n\tshowColors?: boolean;\n\t/**\n\t * Show file-suggestions.\n\t */\n\tshowFiles?: boolean;\n\t/**\n\t * Show reference-suggestions.\n\t */\n\tshowReferences?: boolean;\n\t/**\n\t * Show folder-suggestions.\n\t */\n\tshowFolders?: boolean;\n\t/**\n\t * Show typeParameter-suggestions.\n\t */\n\tshowTypeParameters?: boolean;\n\t/**\n\t * Show issue-suggestions.\n\t */\n\tshowIssues?: boolean;\n\t/**\n\t * Show user-suggestions.\n\t */\n\tshowUsers?: boolean;\n\t/**\n\t * Show snippet-suggestions.\n\t */\n\tshowSnippets?: boolean;\n}\n\n/**\n * @internal\n */\nexport type InternalSuggestOptions = Readonly>;\n\nclass EditorSuggest extends BaseEditorOption {\n\n\tconstructor() {\n\t\tconst defaults: InternalSuggestOptions = {\n\t\t\tinsertMode: 'insert',\n\t\t\tfilterGraceful: true,\n\t\t\tsnippetsPreventQuickSuggestions: false,\n\t\t\tlocalityBonus: false,\n\t\t\tshareSuggestSelections: false,\n\t\t\tselectionMode: 'always',\n\t\t\tshowIcons: true,\n\t\t\tshowStatusBar: false,\n\t\t\tpreview: false,\n\t\t\tpreviewMode: 'subwordSmart',\n\t\t\tshowInlineDetails: true,\n\t\t\tshowMethods: true,\n\t\t\tshowFunctions: true,\n\t\t\tshowConstructors: true,\n\t\t\tshowDeprecated: true,\n\t\t\tmatchOnWordStartOnly: true,\n\t\t\tshowFields: true,\n\t\t\tshowVariables: true,\n\t\t\tshowClasses: true,\n\t\t\tshowStructs: true,\n\t\t\tshowInterfaces: true,\n\t\t\tshowModules: true,\n\t\t\tshowProperties: true,\n\t\t\tshowEvents: true,\n\t\t\tshowOperators: true,\n\t\t\tshowUnits: true,\n\t\t\tshowValues: true,\n\t\t\tshowConstants: true,\n\t\t\tshowEnums: true,\n\t\t\tshowEnumMembers: true,\n\t\t\tshowKeywords: true,\n\t\t\tshowWords: true,\n\t\t\tshowColors: true,\n\t\t\tshowFiles: true,\n\t\t\tshowReferences: true,\n\t\t\tshowFolders: true,\n\t\t\tshowTypeParameters: true,\n\t\t\tshowSnippets: true,\n\t\t\tshowUsers: true,\n\t\t\tshowIssues: true,\n\t\t};\n\t\tsuper(\n\t\t\tEditorOption.suggest, 'suggest', defaults,\n\t\t\t{\n\t\t\t\t'editor.suggest.insertMode': {\n\t\t\t\t\ttype: 'string',\n\t\t\t\t\tenum: ['insert', 'replace'],\n\t\t\t\t\tenumDescriptions: [\n\t\t\t\t\t\tnls.localize('suggest.insertMode.insert', \"Insert suggestion without overwriting text right of the cursor.\"),\n\t\t\t\t\t\tnls.localize('suggest.insertMode.replace', \"Insert suggestion and overwrite text right of the cursor.\"),\n\t\t\t\t\t],\n\t\t\t\t\tdefault: defaults.insertMode,\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.\")\n\t\t\t\t},\n\t\t\t\t'editor.suggest.filterGraceful': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: defaults.filterGraceful,\n\t\t\t\t\tdescription: nls.localize('suggest.filterGraceful', \"Controls whether filtering and sorting suggestions accounts for small typos.\")\n\t\t\t\t},\n\t\t\t\t'editor.suggest.localityBonus': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: defaults.localityBonus,\n\t\t\t\t\tdescription: nls.localize('suggest.localityBonus', \"Controls whether sorting favors words that appear close to the cursor.\")\n\t\t\t\t},\n\t\t\t\t'editor.suggest.shareSuggestSelections': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: defaults.shareSuggestSelections,\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#`).\")\n\t\t\t\t},\n\t\t\t\t'editor.suggest.selectionMode': {\n\t\t\t\t\ttype: 'string',\n\t\t\t\t\tenum: ['always', 'never', 'whenTriggerCharacter', 'whenQuickSuggestion'],\n\t\t\t\t\tenumDescriptions: [\n\t\t\t\t\t\tnls.localize('suggest.insertMode.always', \"Always select a suggestion when automatically triggering IntelliSense.\"),\n\t\t\t\t\t\tnls.localize('suggest.insertMode.never', \"Never select a suggestion when automatically triggering IntelliSense.\"),\n\t\t\t\t\t\tnls.localize('suggest.insertMode.whenTriggerCharacter', \"Select a suggestion only when triggering IntelliSense from a trigger character.\"),\n\t\t\t\t\t\tnls.localize('suggest.insertMode.whenQuickSuggestion', \"Select a suggestion only when triggering IntelliSense as you type.\"),\n\t\t\t\t\t],\n\t\t\t\t\tdefault: defaults.selectionMode,\n\t\t\t\t\tmarkdownDescription: nls.localize('suggest.selectionMode', \"Controls whether a suggestion is selected when the widget shows. Note that this only applies to automatically triggered suggestions (`#editor.quickSuggestions#` and `#editor.suggestOnTriggerCharacters#`) and that a suggestion is always selected when explicitly invoked, e.g via `Ctrl+Space`.\")\n\t\t\t\t},\n\t\t\t\t'editor.suggest.snippetsPreventQuickSuggestions': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: defaults.snippetsPreventQuickSuggestions,\n\t\t\t\t\tdescription: nls.localize('suggest.snippetsPreventQuickSuggestions', \"Controls whether an active snippet prevents quick suggestions.\")\n\t\t\t\t},\n\t\t\t\t'editor.suggest.showIcons': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: defaults.showIcons,\n\t\t\t\t\tdescription: nls.localize('suggest.showIcons', \"Controls whether to show or hide icons in suggestions.\")\n\t\t\t\t},\n\t\t\t\t'editor.suggest.showStatusBar': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: defaults.showStatusBar,\n\t\t\t\t\tdescription: nls.localize('suggest.showStatusBar', \"Controls the visibility of the status bar at the bottom of the suggest widget.\")\n\t\t\t\t},\n\t\t\t\t'editor.suggest.preview': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: defaults.preview,\n\t\t\t\t\tdescription: nls.localize('suggest.preview', \"Controls whether to preview the suggestion outcome in the editor.\")\n\t\t\t\t},\n\t\t\t\t'editor.suggest.showInlineDetails': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: defaults.showInlineDetails,\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.\")\n\t\t\t\t},\n\t\t\t\t'editor.suggest.maxVisibleSuggestions': {\n\t\t\t\t\ttype: 'number',\n\t\t\t\t\tdeprecationMessage: nls.localize('suggest.maxVisibleSuggestions.dep', \"This setting is deprecated. The suggest widget can now be resized.\"),\n\t\t\t\t},\n\t\t\t\t'editor.suggest.filteredTypes': {\n\t\t\t\t\ttype: 'object',\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.\")\n\t\t\t\t},\n\t\t\t\t'editor.suggest.showMethods': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: true,\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showMethods', \"When enabled IntelliSense shows `method`-suggestions.\")\n\t\t\t\t},\n\t\t\t\t'editor.suggest.showFunctions': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: true,\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showFunctions', \"When enabled IntelliSense shows `function`-suggestions.\")\n\t\t\t\t},\n\t\t\t\t'editor.suggest.showConstructors': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: true,\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showConstructors', \"When enabled IntelliSense shows `constructor`-suggestions.\")\n\t\t\t\t},\n\t\t\t\t'editor.suggest.showDeprecated': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: true,\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showDeprecated', \"When enabled IntelliSense shows `deprecated`-suggestions.\")\n\t\t\t\t},\n\t\t\t\t'editor.suggest.matchOnWordStartOnly': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: true,\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.matchOnWordStartOnly', \"When enabled IntelliSense filtering requires that the first character matches on a word start. For example, `c` on `Console` or `WebContext` but _not_ on `description`. When disabled IntelliSense will show more results but still sorts them by match quality.\")\n\t\t\t\t},\n\t\t\t\t'editor.suggest.showFields': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: true,\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showFields', \"When enabled IntelliSense shows `field`-suggestions.\")\n\t\t\t\t},\n\t\t\t\t'editor.suggest.showVariables': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: true,\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showVariables', \"When enabled IntelliSense shows `variable`-suggestions.\")\n\t\t\t\t},\n\t\t\t\t'editor.suggest.showClasses': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: true,\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showClasss', \"When enabled IntelliSense shows `class`-suggestions.\")\n\t\t\t\t},\n\t\t\t\t'editor.suggest.showStructs': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: true,\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showStructs', \"When enabled IntelliSense shows `struct`-suggestions.\")\n\t\t\t\t},\n\t\t\t\t'editor.suggest.showInterfaces': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: true,\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showInterfaces', \"When enabled IntelliSense shows `interface`-suggestions.\")\n\t\t\t\t},\n\t\t\t\t'editor.suggest.showModules': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: true,\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showModules', \"When enabled IntelliSense shows `module`-suggestions.\")\n\t\t\t\t},\n\t\t\t\t'editor.suggest.showProperties': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: true,\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showPropertys', \"When enabled IntelliSense shows `property`-suggestions.\")\n\t\t\t\t},\n\t\t\t\t'editor.suggest.showEvents': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: true,\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showEvents', \"When enabled IntelliSense shows `event`-suggestions.\")\n\t\t\t\t},\n\t\t\t\t'editor.suggest.showOperators': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: true,\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showOperators', \"When enabled IntelliSense shows `operator`-suggestions.\")\n\t\t\t\t},\n\t\t\t\t'editor.suggest.showUnits': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: true,\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showUnits', \"When enabled IntelliSense shows `unit`-suggestions.\")\n\t\t\t\t},\n\t\t\t\t'editor.suggest.showValues': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: true,\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showValues', \"When enabled IntelliSense shows `value`-suggestions.\")\n\t\t\t\t},\n\t\t\t\t'editor.suggest.showConstants': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: true,\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showConstants', \"When enabled IntelliSense shows `constant`-suggestions.\")\n\t\t\t\t},\n\t\t\t\t'editor.suggest.showEnums': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: true,\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showEnums', \"When enabled IntelliSense shows `enum`-suggestions.\")\n\t\t\t\t},\n\t\t\t\t'editor.suggest.showEnumMembers': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: true,\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showEnumMembers', \"When enabled IntelliSense shows `enumMember`-suggestions.\")\n\t\t\t\t},\n\t\t\t\t'editor.suggest.showKeywords': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: true,\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showKeywords', \"When enabled IntelliSense shows `keyword`-suggestions.\")\n\t\t\t\t},\n\t\t\t\t'editor.suggest.showWords': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: true,\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showTexts', \"When enabled IntelliSense shows `text`-suggestions.\")\n\t\t\t\t},\n\t\t\t\t'editor.suggest.showColors': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: true,\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showColors', \"When enabled IntelliSense shows `color`-suggestions.\")\n\t\t\t\t},\n\t\t\t\t'editor.suggest.showFiles': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: true,\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showFiles', \"When enabled IntelliSense shows `file`-suggestions.\")\n\t\t\t\t},\n\t\t\t\t'editor.suggest.showReferences': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: true,\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showReferences', \"When enabled IntelliSense shows `reference`-suggestions.\")\n\t\t\t\t},\n\t\t\t\t'editor.suggest.showCustomcolors': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: true,\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showCustomcolors', \"When enabled IntelliSense shows `customcolor`-suggestions.\")\n\t\t\t\t},\n\t\t\t\t'editor.suggest.showFolders': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: true,\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showFolders', \"When enabled IntelliSense shows `folder`-suggestions.\")\n\t\t\t\t},\n\t\t\t\t'editor.suggest.showTypeParameters': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: true,\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showTypeParameters', \"When enabled IntelliSense shows `typeParameter`-suggestions.\")\n\t\t\t\t},\n\t\t\t\t'editor.suggest.showSnippets': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: true,\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showSnippets', \"When enabled IntelliSense shows `snippet`-suggestions.\")\n\t\t\t\t},\n\t\t\t\t'editor.suggest.showUsers': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: true,\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showUsers', \"When enabled IntelliSense shows `user`-suggestions.\")\n\t\t\t\t},\n\t\t\t\t'editor.suggest.showIssues': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: true,\n\t\t\t\t\tmarkdownDescription: nls.localize('editor.suggest.showIssues', \"When enabled IntelliSense shows `issues`-suggestions.\")\n\t\t\t\t}\n\t\t\t}\n\t\t);\n\t}\n\n\tpublic validate(_input: any): InternalSuggestOptions {\n\t\tif (!_input || typeof _input !== 'object') {\n\t\t\treturn this.defaultValue;\n\t\t}\n\t\tconst input = _input as ISuggestOptions;\n\t\treturn {\n\t\t\tinsertMode: stringSet(input.insertMode, this.defaultValue.insertMode, ['insert', 'replace']),\n\t\t\tfilterGraceful: boolean(input.filterGraceful, this.defaultValue.filterGraceful),\n\t\t\tsnippetsPreventQuickSuggestions: boolean(input.snippetsPreventQuickSuggestions, this.defaultValue.filterGraceful),\n\t\t\tlocalityBonus: boolean(input.localityBonus, this.defaultValue.localityBonus),\n\t\t\tshareSuggestSelections: boolean(input.shareSuggestSelections, this.defaultValue.shareSuggestSelections),\n\t\t\tselectionMode: stringSet(input.selectionMode, this.defaultValue.selectionMode, ['always', 'never', 'whenQuickSuggestion', 'whenTriggerCharacter']),\n\t\t\tshowIcons: boolean(input.showIcons, this.defaultValue.showIcons),\n\t\t\tshowStatusBar: boolean(input.showStatusBar, this.defaultValue.showStatusBar),\n\t\t\tpreview: boolean(input.preview, this.defaultValue.preview),\n\t\t\tpreviewMode: stringSet(input.previewMode, this.defaultValue.previewMode, ['prefix', 'subword', 'subwordSmart']),\n\t\t\tshowInlineDetails: boolean(input.showInlineDetails, this.defaultValue.showInlineDetails),\n\t\t\tshowMethods: boolean(input.showMethods, this.defaultValue.showMethods),\n\t\t\tshowFunctions: boolean(input.showFunctions, this.defaultValue.showFunctions),\n\t\t\tshowConstructors: boolean(input.showConstructors, this.defaultValue.showConstructors),\n\t\t\tshowDeprecated: boolean(input.showDeprecated, this.defaultValue.showDeprecated),\n\t\t\tmatchOnWordStartOnly: boolean(input.matchOnWordStartOnly, this.defaultValue.matchOnWordStartOnly),\n\t\t\tshowFields: boolean(input.showFields, this.defaultValue.showFields),\n\t\t\tshowVariables: boolean(input.showVariables, this.defaultValue.showVariables),\n\t\t\tshowClasses: boolean(input.showClasses, this.defaultValue.showClasses),\n\t\t\tshowStructs: boolean(input.showStructs, this.defaultValue.showStructs),\n\t\t\tshowInterfaces: boolean(input.showInterfaces, this.defaultValue.showInterfaces),\n\t\t\tshowModules: boolean(input.showModules, this.defaultValue.showModules),\n\t\t\tshowProperties: boolean(input.showProperties, this.defaultValue.showProperties),\n\t\t\tshowEvents: boolean(input.showEvents, this.defaultValue.showEvents),\n\t\t\tshowOperators: boolean(input.showOperators, this.defaultValue.showOperators),\n\t\t\tshowUnits: boolean(input.showUnits, this.defaultValue.showUnits),\n\t\t\tshowValues: boolean(input.showValues, this.defaultValue.showValues),\n\t\t\tshowConstants: boolean(input.showConstants, this.defaultValue.showConstants),\n\t\t\tshowEnums: boolean(input.showEnums, this.defaultValue.showEnums),\n\t\t\tshowEnumMembers: boolean(input.showEnumMembers, this.defaultValue.showEnumMembers),\n\t\t\tshowKeywords: boolean(input.showKeywords, this.defaultValue.showKeywords),\n\t\t\tshowWords: boolean(input.showWords, this.defaultValue.showWords),\n\t\t\tshowColors: boolean(input.showColors, this.defaultValue.showColors),\n\t\t\tshowFiles: boolean(input.showFiles, this.defaultValue.showFiles),\n\t\t\tshowReferences: boolean(input.showReferences, this.defaultValue.showReferences),\n\t\t\tshowFolders: boolean(input.showFolders, this.defaultValue.showFolders),\n\t\t\tshowTypeParameters: boolean(input.showTypeParameters, this.defaultValue.showTypeParameters),\n\t\t\tshowSnippets: boolean(input.showSnippets, this.defaultValue.showSnippets),\n\t\t\tshowUsers: boolean(input.showUsers, this.defaultValue.showUsers),\n\t\t\tshowIssues: boolean(input.showIssues, this.defaultValue.showIssues),\n\t\t};\n\t}\n}\n\n//#endregion\n\n//#region smart select\n\nexport interface ISmartSelectOptions {\n\tselectLeadingAndTrailingWhitespace?: boolean;\n\tselectSubwords?: boolean;\n}\n\n/**\n * @internal\n */\nexport type SmartSelectOptions = Readonly>;\n\nclass SmartSelect extends BaseEditorOption {\n\n\tconstructor() {\n\t\tsuper(\n\t\t\tEditorOption.smartSelect, 'smartSelect',\n\t\t\t{\n\t\t\t\tselectLeadingAndTrailingWhitespace: true,\n\t\t\t\tselectSubwords: true,\n\t\t\t},\n\t\t\t{\n\t\t\t\t'editor.smartSelect.selectLeadingAndTrailingWhitespace': {\n\t\t\t\t\tdescription: nls.localize('selectLeadingAndTrailingWhitespace', \"Whether leading and trailing whitespace should always be selected.\"),\n\t\t\t\t\tdefault: true,\n\t\t\t\t\ttype: 'boolean'\n\t\t\t\t},\n\t\t\t\t'editor.smartSelect.selectSubwords': {\n\t\t\t\t\tdescription: nls.localize('selectSubwords', \"Whether subwords (like 'foo' in 'fooBar' or 'foo_bar') should be selected.\"),\n\t\t\t\t\tdefault: true,\n\t\t\t\t\ttype: 'boolean'\n\t\t\t\t}\n\t\t\t}\n\t\t);\n\t}\n\n\tpublic validate(input: any): Readonly> {\n\t\tif (!input || typeof input !== 'object') {\n\t\t\treturn this.defaultValue;\n\t\t}\n\t\treturn {\n\t\t\tselectLeadingAndTrailingWhitespace: boolean((input as ISmartSelectOptions).selectLeadingAndTrailingWhitespace, this.defaultValue.selectLeadingAndTrailingWhitespace),\n\t\t\tselectSubwords: boolean((input as ISmartSelectOptions).selectSubwords, this.defaultValue.selectSubwords),\n\t\t};\n\t}\n}\n\n//#endregion\n\n//#region wordSegmenterLocales\n\n/**\n * Locales used for segmenting lines into words when doing word related navigations or operations.\n *\n * Specify the BCP 47 language tag of the word you wish to recognize (e.g., ja, zh-CN, zh-Hant-TW, etc.).\n */\nclass WordSegmenterLocales extends BaseEditorOption {\n\tconstructor() {\n\t\tconst defaults: string[] = [];\n\n\t\tsuper(\n\t\t\tEditorOption.wordSegmenterLocales, 'wordSegmenterLocales', defaults,\n\t\t\t{\n\t\t\t\tanyOf: [\n\t\t\t\t\t{\n\t\t\t\t\t\tdescription: nls.localize('wordSegmenterLocales', \"Locales to be used for word segmentation when doing word related navigations or operations. Specify the BCP 47 language tag of the word you wish to recognize (e.g., ja, zh-CN, zh-Hant-TW, etc.).\"),\n\t\t\t\t\t\ttype: 'string',\n\t\t\t\t\t}, {\n\t\t\t\t\t\tdescription: nls.localize('wordSegmenterLocales', \"Locales to be used for word segmentation when doing word related navigations or operations. Specify the BCP 47 language tag of the word you wish to recognize (e.g., ja, zh-CN, zh-Hant-TW, etc.).\"),\n\t\t\t\t\t\ttype: 'array',\n\t\t\t\t\t\titems: {\n\t\t\t\t\t\t\ttype: 'string'\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);\n\t}\n\n\tpublic validate(input: any): string[] {\n\t\tif (typeof input === 'string') {\n\t\t\tinput = [input];\n\t\t}\n\t\tif (Array.isArray(input)) {\n\t\t\tconst validLocales: string[] = [];\n\t\t\tfor (const locale of input) {\n\t\t\t\tif (typeof locale === 'string') {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tif (Intl.Segmenter.supportedLocalesOf(locale).length > 0) {\n\t\t\t\t\t\t\tvalidLocales.push(locale);\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// ignore invalid locales\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn validLocales;\n\t\t}\n\n\t\treturn this.defaultValue;\n\t}\n}\n\n\n//#endregion\n\n//#region wrappingIndent\n\n/**\n * Describes how to indent wrapped lines.\n */\nexport const 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}\n\nclass WrappingIndentOption extends BaseEditorOption {\n\n\tconstructor() {\n\t\tsuper(EditorOption.wrappingIndent, 'wrappingIndent', WrappingIndent.Same,\n\t\t\t{\n\t\t\t\t'editor.wrappingIndent': {\n\t\t\t\t\ttype: 'string',\n\t\t\t\t\tenum: ['none', 'same', 'indent', 'deepIndent'],\n\t\t\t\t\tenumDescriptions: [\n\t\t\t\t\t\tnls.localize('wrappingIndent.none', \"No indentation. Wrapped lines begin at column 1.\"),\n\t\t\t\t\t\tnls.localize('wrappingIndent.same', \"Wrapped lines get the same indentation as the parent.\"),\n\t\t\t\t\t\tnls.localize('wrappingIndent.indent', \"Wrapped lines get +1 indentation toward the parent.\"),\n\t\t\t\t\t\tnls.localize('wrappingIndent.deepIndent', \"Wrapped lines get +2 indentation toward the parent.\"),\n\t\t\t\t\t],\n\t\t\t\t\tdescription: nls.localize('wrappingIndent', \"Controls the indentation of wrapped lines.\"),\n\t\t\t\t\tdefault: 'same'\n\t\t\t\t}\n\t\t\t}\n\t\t);\n\t}\n\n\tpublic validate(input: any): WrappingIndent {\n\t\tswitch (input) {\n\t\t\tcase 'none': return WrappingIndent.None;\n\t\t\tcase 'same': return WrappingIndent.Same;\n\t\t\tcase 'indent': return WrappingIndent.Indent;\n\t\t\tcase 'deepIndent': return WrappingIndent.DeepIndent;\n\t\t}\n\t\treturn WrappingIndent.Same;\n\t}\n\n\tpublic override compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, value: WrappingIndent): WrappingIndent {\n\t\tconst accessibilitySupport = options.get(EditorOption.accessibilitySupport);\n\t\tif (accessibilitySupport === AccessibilitySupport.Enabled) {\n\t\t\t// if we know for a fact that a screen reader is attached, we use no indent wrapping to\n\t\t\t// help that the editor's wrapping points match the textarea's wrapping points\n\t\t\treturn WrappingIndent.None;\n\t\t}\n\t\treturn value;\n\t}\n}\n\n//#endregion\n\n//#region wrappingInfo\n\nexport interface EditorWrappingInfo {\n\treadonly isDominatedByLongLines: boolean;\n\treadonly isWordWrapMinified: boolean;\n\treadonly isViewportWrapping: boolean;\n\treadonly wrappingColumn: number;\n}\n\nclass EditorWrappingInfoComputer extends ComputedEditorOption {\n\n\tconstructor() {\n\t\tsuper(EditorOption.wrappingInfo);\n\t}\n\n\tpublic compute(env: IEnvironmentalOptions, options: IComputedEditorOptions, _: EditorWrappingInfo): EditorWrappingInfo {\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\n\n\t\treturn {\n\t\t\tisDominatedByLongLines: env.isDominatedByLongLines,\n\t\t\tisWordWrapMinified: layoutInfo.isWordWrapMinified,\n\t\t\tisViewportWrapping: layoutInfo.isViewportWrapping,\n\t\t\twrappingColumn: layoutInfo.wrappingColumn,\n\t\t};\n\t}\n}\n\n//#endregion\n\n//#region dropIntoEditor\n\n/**\n * Configuration options for editor drop into behavior\n */\nexport interface IDropIntoEditorOptions {\n\t/**\n\t * Enable dropping into editor.\n\t * Defaults to true.\n\t */\n\tenabled?: boolean;\n\n\t/**\n\t * Controls if a widget is shown after a drop.\n\t * Defaults to 'afterDrop'.\n\t */\n\tshowDropSelector?: 'afterDrop' | 'never';\n}\n\n/**\n * @internal\n */\nexport type EditorDropIntoEditorOptions = Readonly>;\n\nclass EditorDropIntoEditor extends BaseEditorOption {\n\n\tconstructor() {\n\t\tconst defaults: EditorDropIntoEditorOptions = { enabled: true, showDropSelector: 'afterDrop' };\n\t\tsuper(\n\t\t\tEditorOption.dropIntoEditor, 'dropIntoEditor', defaults,\n\t\t\t{\n\t\t\t\t'editor.dropIntoEditor.enabled': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: defaults.enabled,\n\t\t\t\t\tmarkdownDescription: nls.localize('dropIntoEditor.enabled', \"Controls whether you can drag and drop a file into a text editor by holding down the `Shift` key (instead of opening the file in an editor).\"),\n\t\t\t\t},\n\t\t\t\t'editor.dropIntoEditor.showDropSelector': {\n\t\t\t\t\ttype: 'string',\n\t\t\t\t\tmarkdownDescription: nls.localize('dropIntoEditor.showDropSelector', \"Controls if a widget is shown when dropping files into the editor. This widget lets you control how the file is dropped.\"),\n\t\t\t\t\tenum: [\n\t\t\t\t\t\t'afterDrop',\n\t\t\t\t\t\t'never'\n\t\t\t\t\t],\n\t\t\t\t\tenumDescriptions: [\n\t\t\t\t\t\tnls.localize('dropIntoEditor.showDropSelector.afterDrop', \"Show the drop selector widget after a file is dropped into the editor.\"),\n\t\t\t\t\t\tnls.localize('dropIntoEditor.showDropSelector.never', \"Never show the drop selector widget. Instead the default drop provider is always used.\"),\n\t\t\t\t\t],\n\t\t\t\t\tdefault: 'afterDrop',\n\t\t\t\t},\n\t\t\t}\n\t\t);\n\t}\n\n\tpublic validate(_input: any): EditorDropIntoEditorOptions {\n\t\tif (!_input || typeof _input !== 'object') {\n\t\t\treturn this.defaultValue;\n\t\t}\n\t\tconst input = _input as IDropIntoEditorOptions;\n\t\treturn {\n\t\t\tenabled: boolean(input.enabled, this.defaultValue.enabled),\n\t\t\tshowDropSelector: stringSet(input.showDropSelector, this.defaultValue.showDropSelector, ['afterDrop', 'never']),\n\t\t};\n\t}\n}\n\n//#endregion\n\n//#region pasteAs\n\n/**\n * Configuration options for editor pasting as into behavior\n */\nexport interface IPasteAsOptions {\n\t/**\n\t * Enable paste as functionality in editors.\n\t * Defaults to true.\n\t */\n\tenabled?: boolean;\n\n\t/**\n\t * Controls if a widget is shown after a drop.\n\t * Defaults to 'afterPaste'.\n\t */\n\tshowPasteSelector?: 'afterPaste' | 'never';\n}\n\n/**\n * @internal\n */\nexport type EditorPasteAsOptions = Readonly>;\n\nclass EditorPasteAs extends BaseEditorOption {\n\n\tconstructor() {\n\t\tconst defaults: EditorPasteAsOptions = { enabled: true, showPasteSelector: 'afterPaste' };\n\t\tsuper(\n\t\t\tEditorOption.pasteAs, 'pasteAs', defaults,\n\t\t\t{\n\t\t\t\t'editor.pasteAs.enabled': {\n\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\tdefault: defaults.enabled,\n\t\t\t\t\tmarkdownDescription: nls.localize('pasteAs.enabled', \"Controls whether you can paste content in different ways.\"),\n\t\t\t\t},\n\t\t\t\t'editor.pasteAs.showPasteSelector': {\n\t\t\t\t\ttype: 'string',\n\t\t\t\t\tmarkdownDescription: nls.localize('pasteAs.showPasteSelector', \"Controls if a widget is shown when pasting content in to the editor. This widget lets you control how the file is pasted.\"),\n\t\t\t\t\tenum: [\n\t\t\t\t\t\t'afterPaste',\n\t\t\t\t\t\t'never'\n\t\t\t\t\t],\n\t\t\t\t\tenumDescriptions: [\n\t\t\t\t\t\tnls.localize('pasteAs.showPasteSelector.afterPaste', \"Show the paste selector widget after content is pasted into the editor.\"),\n\t\t\t\t\t\tnls.localize('pasteAs.showPasteSelector.never', \"Never show the paste selector widget. Instead the default pasting behavior is always used.\"),\n\t\t\t\t\t],\n\t\t\t\t\tdefault: 'afterPaste',\n\t\t\t\t},\n\t\t\t}\n\t\t);\n\t}\n\n\tpublic validate(_input: any): EditorPasteAsOptions {\n\t\tif (!_input || typeof _input !== 'object') {\n\t\t\treturn this.defaultValue;\n\t\t}\n\t\tconst input = _input as IPasteAsOptions;\n\t\treturn {\n\t\t\tenabled: boolean(input.enabled, this.defaultValue.enabled),\n\t\t\tshowPasteSelector: stringSet(input.showPasteSelector, this.defaultValue.showPasteSelector, ['afterPaste', 'never']),\n\t\t};\n\t}\n}\n\n//#endregion\n\nconst DEFAULT_WINDOWS_FONT_FAMILY = 'Consolas, \\'Courier New\\', monospace';\nconst DEFAULT_MAC_FONT_FAMILY = 'Menlo, Monaco, \\'Courier New\\', monospace';\nconst DEFAULT_LINUX_FONT_FAMILY = '\\'Droid Sans Mono\\', \\'monospace\\', monospace';\n\n/**\n * @internal\n */\nexport const EDITOR_FONT_DEFAULTS = {\n\tfontFamily: (\n\t\tplatform.isMacintosh ? DEFAULT_MAC_FONT_FAMILY : (platform.isLinux ? DEFAULT_LINUX_FONT_FAMILY : DEFAULT_WINDOWS_FONT_FAMILY)\n\t),\n\tfontWeight: 'normal',\n\tfontSize: (\n\t\tplatform.isMacintosh ? 12 : 14\n\t),\n\tlineHeight: 0,\n\tletterSpacing: 0,\n};\n\n/**\n * @internal\n */\nexport const editorOptionsRegistry: IEditorOption[] = [];\n\nfunction register(option: IEditorOption): IEditorOption {\n\teditorOptionsRegistry[option.id] = option;\n\treturn option;\n}\n\nexport const enum EditorOption {\n\tacceptSuggestionOnCommitCharacter,\n\tacceptSuggestionOnEnter,\n\taccessibilitySupport,\n\taccessibilityPageSize,\n\tariaLabel,\n\tariaRequired,\n\tautoClosingBrackets,\n\tautoClosingComments,\n\tscreenReaderAnnounceInlineSuggestion,\n\tautoClosingDelete,\n\tautoClosingOvertype,\n\tautoClosingQuotes,\n\tautoIndent,\n\tautomaticLayout,\n\tautoSurround,\n\tbracketPairColorization,\n\tguides,\n\tcodeLens,\n\tcodeLensFontFamily,\n\tcodeLensFontSize,\n\tcolorDecorators,\n\tcolorDecoratorsLimit,\n\tcolumnSelection,\n\tcomments,\n\tcontextmenu,\n\tcopyWithSyntaxHighlighting,\n\tcursorBlinking,\n\tcursorSmoothCaretAnimation,\n\tcursorStyle,\n\tcursorSurroundingLines,\n\tcursorSurroundingLinesStyle,\n\tcursorWidth,\n\tdisableLayerHinting,\n\tdisableMonospaceOptimizations,\n\tdomReadOnly,\n\tdragAndDrop,\n\tdropIntoEditor,\n\temptySelectionClipboard,\n\texperimentalWhitespaceRendering,\n\textraEditorClassName,\n\tfastScrollSensitivity,\n\tfind,\n\tfixedOverflowWidgets,\n\tfolding,\n\tfoldingStrategy,\n\tfoldingHighlight,\n\tfoldingImportsByDefault,\n\tfoldingMaximumRegions,\n\tunfoldOnClickAfterEndOfLine,\n\tfontFamily,\n\tfontInfo,\n\tfontLigatures,\n\tfontSize,\n\tfontWeight,\n\tfontVariations,\n\tformatOnPaste,\n\tformatOnType,\n\tglyphMargin,\n\tgotoLocation,\n\thideCursorInOverviewRuler,\n\thover,\n\tinDiffEditor,\n\tinlineSuggest,\n\tinlineEdit,\n\tletterSpacing,\n\tlightbulb,\n\tlineDecorationsWidth,\n\tlineHeight,\n\tlineNumbers,\n\tlineNumbersMinChars,\n\tlinkedEditing,\n\tlinks,\n\tmatchBrackets,\n\tminimap,\n\tmouseStyle,\n\tmouseWheelScrollSensitivity,\n\tmouseWheelZoom,\n\tmultiCursorMergeOverlapping,\n\tmultiCursorModifier,\n\tmultiCursorPaste,\n\tmultiCursorLimit,\n\toccurrencesHighlight,\n\toverviewRulerBorder,\n\toverviewRulerLanes,\n\tpadding,\n\tpasteAs,\n\tparameterHints,\n\tpeekWidgetDefaultFocus,\n\tdefinitionLinkOpensInPeek,\n\tquickSuggestions,\n\tquickSuggestionsDelay,\n\treadOnly,\n\treadOnlyMessage,\n\trenameOnType,\n\trenderControlCharacters,\n\trenderFinalNewline,\n\trenderLineHighlight,\n\trenderLineHighlightOnlyWhenFocus,\n\trenderValidationDecorations,\n\trenderWhitespace,\n\trevealHorizontalRightPadding,\n\troundedSelection,\n\trulers,\n\tscrollbar,\n\tscrollBeyondLastColumn,\n\tscrollBeyondLastLine,\n\tscrollPredominantAxis,\n\tselectionClipboard,\n\tselectionHighlight,\n\tselectOnLineNumbers,\n\tshowFoldingControls,\n\tshowUnused,\n\tsnippetSuggestions,\n\tsmartSelect,\n\tsmoothScrolling,\n\tstickyScroll,\n\tstickyTabStops,\n\tstopRenderingLineAfter,\n\tsuggest,\n\tsuggestFontSize,\n\tsuggestLineHeight,\n\tsuggestOnTriggerCharacters,\n\tsuggestSelection,\n\ttabCompletion,\n\ttabIndex,\n\tunicodeHighlighting,\n\tunusualLineTerminators,\n\tuseShadowDOM,\n\tuseTabStops,\n\twordBreak,\n\twordSegmenterLocales,\n\twordSeparators,\n\twordWrap,\n\twordWrapBreakAfterCharacters,\n\twordWrapBreakBeforeCharacters,\n\twordWrapColumn,\n\twordWrapOverride1,\n\twordWrapOverride2,\n\twrappingIndent,\n\twrappingStrategy,\n\tshowDeprecated,\n\tinlayHints,\n\t// Leave these at the end (because they have dependencies!)\n\teditorClassName,\n\tpixelRatio,\n\ttabFocusMode,\n\tlayoutInfo,\n\twrappingInfo,\n\tdefaultColorDecorators,\n\tcolorDecoratorsActivatedOn,\n\tinlineCompletionsAccessibilityVerbose\n}\n\nexport const EditorOptions = {\n\tacceptSuggestionOnCommitCharacter: register(new EditorBooleanOption(\n\t\tEditorOption.acceptSuggestionOnCommitCharacter, 'acceptSuggestionOnCommitCharacter', true,\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.\") }\n\t)),\n\tacceptSuggestionOnEnter: register(new EditorStringEnumOption(\n\t\tEditorOption.acceptSuggestionOnEnter, 'acceptSuggestionOnEnter',\n\t\t'on' as 'on' | 'smart' | 'off',\n\t\t['on', 'smart', 'off'] as const,\n\t\t{\n\t\t\tmarkdownEnumDescriptions: [\n\t\t\t\t'',\n\t\t\t\tnls.localize('acceptSuggestionOnEnterSmart', \"Only accept a suggestion with `Enter` when it makes a textual change.\"),\n\t\t\t\t''\n\t\t\t],\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.\")\n\t\t}\n\t)),\n\taccessibilitySupport: register(new EditorAccessibilitySupport()),\n\taccessibilityPageSize: register(new EditorIntOption(EditorOption.accessibilityPageSize, 'accessibilityPageSize', 10, 1, Constants.MAX_SAFE_SMALL_INTEGER,\n\t\t{\n\t\t\tdescription: nls.localize('accessibilityPageSize', \"Controls the number of lines in the editor that can be read out by a screen reader at once. When we detect a screen reader we automatically set the default to be 500. Warning: this has a performance implication for numbers larger than the default.\"),\n\t\t\ttags: ['accessibility']\n\t\t})),\n\tariaLabel: register(new EditorStringOption(\n\t\tEditorOption.ariaLabel, 'ariaLabel', nls.localize('editorViewAccessibleLabel', \"Editor content\")\n\t)),\n\tariaRequired: register(new EditorBooleanOption(\n\t\tEditorOption.ariaRequired, 'ariaRequired', false, undefined\n\t)),\n\tscreenReaderAnnounceInlineSuggestion: register(new EditorBooleanOption(\n\t\tEditorOption.screenReaderAnnounceInlineSuggestion, 'screenReaderAnnounceInlineSuggestion', true,\n\t\t{\n\t\t\tdescription: nls.localize('screenReaderAnnounceInlineSuggestion', \"Control whether inline suggestions are announced by a screen reader.\"),\n\t\t\ttags: ['accessibility']\n\t\t}\n\t)),\n\tautoClosingBrackets: register(new EditorStringEnumOption(\n\t\tEditorOption.autoClosingBrackets, 'autoClosingBrackets',\n\t\t'languageDefined' as 'always' | 'languageDefined' | 'beforeWhitespace' | 'never',\n\t\t['always', 'languageDefined', 'beforeWhitespace', 'never'] as const,\n\t\t{\n\t\t\tenumDescriptions: [\n\t\t\t\t'',\n\t\t\t\tnls.localize('editor.autoClosingBrackets.languageDefined', \"Use language configurations to determine when to autoclose brackets.\"),\n\t\t\t\tnls.localize('editor.autoClosingBrackets.beforeWhitespace', \"Autoclose brackets only when the cursor is to the left of whitespace.\"),\n\t\t\t\t'',\n\t\t\t],\n\t\t\tdescription: nls.localize('autoClosingBrackets', \"Controls whether the editor should automatically close brackets after the user adds an opening bracket.\")\n\t\t}\n\t)),\n\tautoClosingComments: register(new EditorStringEnumOption(\n\t\tEditorOption.autoClosingComments, 'autoClosingComments',\n\t\t'languageDefined' as 'always' | 'languageDefined' | 'beforeWhitespace' | 'never',\n\t\t['always', 'languageDefined', 'beforeWhitespace', 'never'] as const,\n\t\t{\n\t\t\tenumDescriptions: [\n\t\t\t\t'',\n\t\t\t\tnls.localize('editor.autoClosingComments.languageDefined', \"Use language configurations to determine when to autoclose comments.\"),\n\t\t\t\tnls.localize('editor.autoClosingComments.beforeWhitespace', \"Autoclose comments only when the cursor is to the left of whitespace.\"),\n\t\t\t\t'',\n\t\t\t],\n\t\t\tdescription: nls.localize('autoClosingComments', \"Controls whether the editor should automatically close comments after the user adds an opening comment.\")\n\t\t}\n\t)),\n\tautoClosingDelete: register(new EditorStringEnumOption(\n\t\tEditorOption.autoClosingDelete, 'autoClosingDelete',\n\t\t'auto' as 'always' | 'auto' | 'never',\n\t\t['always', 'auto', 'never'] as const,\n\t\t{\n\t\t\tenumDescriptions: [\n\t\t\t\t'',\n\t\t\t\tnls.localize('editor.autoClosingDelete.auto', \"Remove adjacent closing quotes or brackets only if they were automatically inserted.\"),\n\t\t\t\t'',\n\t\t\t],\n\t\t\tdescription: nls.localize('autoClosingDelete', \"Controls whether the editor should remove adjacent closing quotes or brackets when deleting.\")\n\t\t}\n\t)),\n\tautoClosingOvertype: register(new EditorStringEnumOption(\n\t\tEditorOption.autoClosingOvertype, 'autoClosingOvertype',\n\t\t'auto' as 'always' | 'auto' | 'never',\n\t\t['always', 'auto', 'never'] as const,\n\t\t{\n\t\t\tenumDescriptions: [\n\t\t\t\t'',\n\t\t\t\tnls.localize('editor.autoClosingOvertype.auto', \"Type over closing quotes or brackets only if they were automatically inserted.\"),\n\t\t\t\t'',\n\t\t\t],\n\t\t\tdescription: nls.localize('autoClosingOvertype', \"Controls whether the editor should type over closing quotes or brackets.\")\n\t\t}\n\t)),\n\tautoClosingQuotes: register(new EditorStringEnumOption(\n\t\tEditorOption.autoClosingQuotes, 'autoClosingQuotes',\n\t\t'languageDefined' as 'always' | 'languageDefined' | 'beforeWhitespace' | 'never',\n\t\t['always', 'languageDefined', 'beforeWhitespace', 'never'] as const,\n\t\t{\n\t\t\tenumDescriptions: [\n\t\t\t\t'',\n\t\t\t\tnls.localize('editor.autoClosingQuotes.languageDefined', \"Use language configurations to determine when to autoclose quotes.\"),\n\t\t\t\tnls.localize('editor.autoClosingQuotes.beforeWhitespace', \"Autoclose quotes only when the cursor is to the left of whitespace.\"),\n\t\t\t\t'',\n\t\t\t],\n\t\t\tdescription: nls.localize('autoClosingQuotes', \"Controls whether the editor should automatically close quotes after the user adds an opening quote.\")\n\t\t}\n\t)),\n\tautoIndent: register(new EditorEnumOption(\n\t\tEditorOption.autoIndent, 'autoIndent',\n\t\tEditorAutoIndentStrategy.Full, 'full',\n\t\t['none', 'keep', 'brackets', 'advanced', 'full'],\n\t\t_autoIndentFromString,\n\t\t{\n\t\t\tenumDescriptions: [\n\t\t\t\tnls.localize('editor.autoIndent.none', \"The editor will not insert indentation automatically.\"),\n\t\t\t\tnls.localize('editor.autoIndent.keep', \"The editor will keep the current line's indentation.\"),\n\t\t\t\tnls.localize('editor.autoIndent.brackets', \"The editor will keep the current line's indentation and honor language defined brackets.\"),\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.\"),\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.\"),\n\t\t\t],\n\t\t\tdescription: nls.localize('autoIndent', \"Controls whether the editor should automatically adjust the indentation when users type, paste, move or indent lines.\")\n\t\t}\n\t)),\n\tautomaticLayout: register(new EditorBooleanOption(\n\t\tEditorOption.automaticLayout, 'automaticLayout', false,\n\t)),\n\tautoSurround: register(new EditorStringEnumOption(\n\t\tEditorOption.autoSurround, 'autoSurround',\n\t\t'languageDefined' as 'languageDefined' | 'quotes' | 'brackets' | 'never',\n\t\t['languageDefined', 'quotes', 'brackets', 'never'] as const,\n\t\t{\n\t\t\tenumDescriptions: [\n\t\t\t\tnls.localize('editor.autoSurround.languageDefined', \"Use language configurations to determine when to automatically surround selections.\"),\n\t\t\t\tnls.localize('editor.autoSurround.quotes', \"Surround with quotes but not brackets.\"),\n\t\t\t\tnls.localize('editor.autoSurround.brackets', \"Surround with brackets but not quotes.\"),\n\t\t\t\t''\n\t\t\t],\n\t\t\tdescription: nls.localize('autoSurround', \"Controls whether the editor should automatically surround selections when typing quotes or brackets.\")\n\t\t}\n\t)),\n\tbracketPairColorization: register(new BracketPairColorization()),\n\tbracketPairGuides: register(new GuideOptions()),\n\tstickyTabStops: register(new EditorBooleanOption(\n\t\tEditorOption.stickyTabStops, 'stickyTabStops', false,\n\t\t{ description: nls.localize('stickyTabStops', \"Emulate selection behavior of tab characters when using spaces for indentation. Selection will stick to tab stops.\") }\n\t)),\n\tcodeLens: register(new EditorBooleanOption(\n\t\tEditorOption.codeLens, 'codeLens', true,\n\t\t{ description: nls.localize('codeLens', \"Controls whether the editor shows CodeLens.\") }\n\t)),\n\tcodeLensFontFamily: register(new EditorStringOption(\n\t\tEditorOption.codeLensFontFamily, 'codeLensFontFamily', '',\n\t\t{ description: nls.localize('codeLensFontFamily', \"Controls the font family for CodeLens.\") }\n\t)),\n\tcodeLensFontSize: register(new EditorIntOption(EditorOption.codeLensFontSize, 'codeLensFontSize', 0, 0, 100, {\n\t\ttype: 'number',\n\t\tdefault: 0,\n\t\tminimum: 0,\n\t\tmaximum: 100,\n\t\tmarkdownDescription: nls.localize('codeLensFontSize', \"Controls the font size in pixels for CodeLens. When set to 0, 90% of `#editor.fontSize#` is used.\")\n\t})),\n\tcolorDecorators: register(new EditorBooleanOption(\n\t\tEditorOption.colorDecorators, 'colorDecorators', true,\n\t\t{ description: nls.localize('colorDecorators', \"Controls whether the editor should render the inline color decorators and color picker.\") }\n\t)),\n\tcolorDecoratorActivatedOn: register(new EditorStringEnumOption(EditorOption.colorDecoratorsActivatedOn, 'colorDecoratorsActivatedOn', 'clickAndHover' as 'clickAndHover' | 'hover' | 'click', ['clickAndHover', 'hover', 'click'] as const, {\n\t\tenumDescriptions: [\n\t\t\tnls.localize('editor.colorDecoratorActivatedOn.clickAndHover', \"Make the color picker appear both on click and hover of the color decorator\"),\n\t\t\tnls.localize('editor.colorDecoratorActivatedOn.hover', \"Make the color picker appear on hover of the color decorator\"),\n\t\t\tnls.localize('editor.colorDecoratorActivatedOn.click', \"Make the color picker appear on click of the color decorator\")\n\t\t],\n\t\tdescription: nls.localize('colorDecoratorActivatedOn', \"Controls the condition to make a color picker appear from a color decorator\")\n\t})),\n\tcolorDecoratorsLimit: register(new EditorIntOption(\n\t\tEditorOption.colorDecoratorsLimit, 'colorDecoratorsLimit', 500, 1, 1000000,\n\t\t{\n\t\t\tmarkdownDescription: nls.localize('colorDecoratorsLimit', \"Controls the max number of color decorators that can be rendered in an editor at once.\")\n\t\t}\n\t)),\n\tcolumnSelection: register(new EditorBooleanOption(\n\t\tEditorOption.columnSelection, 'columnSelection', false,\n\t\t{ description: nls.localize('columnSelection', \"Enable that the selection with the mouse and keys is doing column selection.\") }\n\t)),\n\tcomments: register(new EditorComments()),\n\tcontextmenu: register(new EditorBooleanOption(\n\t\tEditorOption.contextmenu, 'contextmenu', true,\n\t)),\n\tcopyWithSyntaxHighlighting: register(new EditorBooleanOption(\n\t\tEditorOption.copyWithSyntaxHighlighting, 'copyWithSyntaxHighlighting', true,\n\t\t{ description: nls.localize('copyWithSyntaxHighlighting', \"Controls whether syntax highlighting should be copied into the clipboard.\") }\n\t)),\n\tcursorBlinking: register(new EditorEnumOption(\n\t\tEditorOption.cursorBlinking, 'cursorBlinking',\n\t\tTextEditorCursorBlinkingStyle.Blink, 'blink',\n\t\t['blink', 'smooth', 'phase', 'expand', 'solid'],\n\t\t_cursorBlinkingStyleFromString,\n\t\t{ description: nls.localize('cursorBlinking', \"Control the cursor animation style.\") }\n\t)),\n\tcursorSmoothCaretAnimation: register(new EditorStringEnumOption(\n\t\tEditorOption.cursorSmoothCaretAnimation, 'cursorSmoothCaretAnimation',\n\t\t'off' as 'off' | 'explicit' | 'on',\n\t\t['off', 'explicit', 'on'] as const,\n\t\t{\n\t\t\tenumDescriptions: [\n\t\t\t\tnls.localize('cursorSmoothCaretAnimation.off', \"Smooth caret animation is disabled.\"),\n\t\t\t\tnls.localize('cursorSmoothCaretAnimation.explicit', \"Smooth caret animation is enabled only when the user moves the cursor with an explicit gesture.\"),\n\t\t\t\tnls.localize('cursorSmoothCaretAnimation.on', \"Smooth caret animation is always enabled.\")\n\t\t\t],\n\t\t\tdescription: nls.localize('cursorSmoothCaretAnimation', \"Controls whether the smooth caret animation should be enabled.\")\n\t\t}\n\t)),\n\tcursorStyle: register(new EditorEnumOption(\n\t\tEditorOption.cursorStyle, 'cursorStyle',\n\t\tTextEditorCursorStyle.Line, 'line',\n\t\t['line', 'block', 'underline', 'line-thin', 'block-outline', 'underline-thin'],\n\t\t_cursorStyleFromString,\n\t\t{ description: nls.localize('cursorStyle', \"Controls the cursor style.\") }\n\t)),\n\tcursorSurroundingLines: register(new EditorIntOption(\n\t\tEditorOption.cursorSurroundingLines, 'cursorSurroundingLines',\n\t\t0, 0, Constants.MAX_SAFE_SMALL_INTEGER,\n\t\t{ description: nls.localize('cursorSurroundingLines', \"Controls the minimal number of visible leading lines (minimum 0) and trailing lines (minimum 1) surrounding the cursor. Known as 'scrollOff' or 'scrollOffset' in some other editors.\") }\n\t)),\n\tcursorSurroundingLinesStyle: register(new EditorStringEnumOption(\n\t\tEditorOption.cursorSurroundingLinesStyle, 'cursorSurroundingLinesStyle',\n\t\t'default' as 'default' | 'all',\n\t\t['default', 'all'] as const,\n\t\t{\n\t\t\tenumDescriptions: [\n\t\t\t\tnls.localize('cursorSurroundingLinesStyle.default', \"`cursorSurroundingLines` is enforced only when triggered via the keyboard or API.\"),\n\t\t\t\tnls.localize('cursorSurroundingLinesStyle.all', \"`cursorSurroundingLines` is enforced always.\")\n\t\t\t],\n\t\t\tmarkdownDescription: nls.localize('cursorSurroundingLinesStyle', \"Controls when `#editor.cursorSurroundingLines#` should be enforced.\")\n\t\t}\n\t)),\n\tcursorWidth: register(new EditorIntOption(\n\t\tEditorOption.cursorWidth, 'cursorWidth',\n\t\t0, 0, Constants.MAX_SAFE_SMALL_INTEGER,\n\t\t{ markdownDescription: nls.localize('cursorWidth', \"Controls the width of the cursor when `#editor.cursorStyle#` is set to `line`.\") }\n\t)),\n\tdisableLayerHinting: register(new EditorBooleanOption(\n\t\tEditorOption.disableLayerHinting, 'disableLayerHinting', false,\n\t)),\n\tdisableMonospaceOptimizations: register(new EditorBooleanOption(\n\t\tEditorOption.disableMonospaceOptimizations, 'disableMonospaceOptimizations', false\n\t)),\n\tdomReadOnly: register(new EditorBooleanOption(\n\t\tEditorOption.domReadOnly, 'domReadOnly', false,\n\t)),\n\tdragAndDrop: register(new EditorBooleanOption(\n\t\tEditorOption.dragAndDrop, 'dragAndDrop', true,\n\t\t{ description: nls.localize('dragAndDrop', \"Controls whether the editor should allow moving selections via drag and drop.\") }\n\t)),\n\temptySelectionClipboard: register(new EditorEmptySelectionClipboard()),\n\tdropIntoEditor: register(new EditorDropIntoEditor()),\n\tstickyScroll: register(new EditorStickyScroll()),\n\texperimentalWhitespaceRendering: register(new EditorStringEnumOption(\n\t\tEditorOption.experimentalWhitespaceRendering, 'experimentalWhitespaceRendering',\n\t\t'svg' as 'svg' | 'font' | 'off',\n\t\t['svg', 'font', 'off'] as const,\n\t\t{\n\t\t\tenumDescriptions: [\n\t\t\t\tnls.localize('experimentalWhitespaceRendering.svg', \"Use a new rendering method with svgs.\"),\n\t\t\t\tnls.localize('experimentalWhitespaceRendering.font', \"Use a new rendering method with font characters.\"),\n\t\t\t\tnls.localize('experimentalWhitespaceRendering.off', \"Use the stable rendering method.\"),\n\t\t\t],\n\t\t\tdescription: nls.localize('experimentalWhitespaceRendering', \"Controls whether whitespace is rendered with a new, experimental method.\")\n\t\t}\n\t)),\n\textraEditorClassName: register(new EditorStringOption(\n\t\tEditorOption.extraEditorClassName, 'extraEditorClassName', '',\n\t)),\n\tfastScrollSensitivity: register(new EditorFloatOption(\n\t\tEditorOption.fastScrollSensitivity, 'fastScrollSensitivity',\n\t\t5, x => (x <= 0 ? 5 : x),\n\t\t{ markdownDescription: nls.localize('fastScrollSensitivity', \"Scrolling speed multiplier when pressing `Alt`.\") }\n\t)),\n\tfind: register(new EditorFind()),\n\tfixedOverflowWidgets: register(new EditorBooleanOption(\n\t\tEditorOption.fixedOverflowWidgets, 'fixedOverflowWidgets', false,\n\t)),\n\tfolding: register(new EditorBooleanOption(\n\t\tEditorOption.folding, 'folding', true,\n\t\t{ description: nls.localize('folding', \"Controls whether the editor has code folding enabled.\") }\n\t)),\n\tfoldingStrategy: register(new EditorStringEnumOption(\n\t\tEditorOption.foldingStrategy, 'foldingStrategy',\n\t\t'auto' as 'auto' | 'indentation',\n\t\t['auto', 'indentation'] as const,\n\t\t{\n\t\t\tenumDescriptions: [\n\t\t\t\tnls.localize('foldingStrategy.auto', \"Use a language-specific folding strategy if available, else the indentation-based one.\"),\n\t\t\t\tnls.localize('foldingStrategy.indentation', \"Use the indentation-based folding strategy.\"),\n\t\t\t],\n\t\t\tdescription: nls.localize('foldingStrategy', \"Controls the strategy for computing folding ranges.\")\n\t\t}\n\t)),\n\tfoldingHighlight: register(new EditorBooleanOption(\n\t\tEditorOption.foldingHighlight, 'foldingHighlight', true,\n\t\t{ description: nls.localize('foldingHighlight', \"Controls whether the editor should highlight folded ranges.\") }\n\t)),\n\tfoldingImportsByDefault: register(new EditorBooleanOption(\n\t\tEditorOption.foldingImportsByDefault, 'foldingImportsByDefault', false,\n\t\t{ description: nls.localize('foldingImportsByDefault', \"Controls whether the editor automatically collapses import ranges.\") }\n\t)),\n\tfoldingMaximumRegions: register(new EditorIntOption(\n\t\tEditorOption.foldingMaximumRegions, 'foldingMaximumRegions',\n\t\t5000, 10, 65000, // limit must be less than foldingRanges MAX_FOLDING_REGIONS\n\t\t{ description: nls.localize('foldingMaximumRegions', \"The maximum number of foldable regions. Increasing this value may result in the editor becoming less responsive when the current source has a large number of foldable regions.\") }\n\t)),\n\tunfoldOnClickAfterEndOfLine: register(new EditorBooleanOption(\n\t\tEditorOption.unfoldOnClickAfterEndOfLine, 'unfoldOnClickAfterEndOfLine', false,\n\t\t{ description: nls.localize('unfoldOnClickAfterEndOfLine', \"Controls whether clicking on the empty content after a folded line will unfold the line.\") }\n\t)),\n\tfontFamily: register(new EditorStringOption(\n\t\tEditorOption.fontFamily, 'fontFamily', EDITOR_FONT_DEFAULTS.fontFamily,\n\t\t{ description: nls.localize('fontFamily', \"Controls the font family.\") }\n\t)),\n\tfontInfo: register(new EditorFontInfo()),\n\tfontLigatures2: register(new EditorFontLigatures()),\n\tfontSize: register(new EditorFontSize()),\n\tfontWeight: register(new EditorFontWeight()),\n\tfontVariations: register(new EditorFontVariations()),\n\tformatOnPaste: register(new EditorBooleanOption(\n\t\tEditorOption.formatOnPaste, 'formatOnPaste', false,\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.\") }\n\t)),\n\tformatOnType: register(new EditorBooleanOption(\n\t\tEditorOption.formatOnType, 'formatOnType', false,\n\t\t{ description: nls.localize('formatOnType', \"Controls whether the editor should automatically format the line after typing.\") }\n\t)),\n\tglyphMargin: register(new EditorBooleanOption(\n\t\tEditorOption.glyphMargin, 'glyphMargin', true,\n\t\t{ description: nls.localize('glyphMargin', \"Controls whether the editor should render the vertical glyph margin. Glyph margin is mostly used for debugging.\") }\n\t)),\n\tgotoLocation: register(new EditorGoToLocation()),\n\thideCursorInOverviewRuler: register(new EditorBooleanOption(\n\t\tEditorOption.hideCursorInOverviewRuler, 'hideCursorInOverviewRuler', false,\n\t\t{ description: nls.localize('hideCursorInOverviewRuler', \"Controls whether the cursor should be hidden in the overview ruler.\") }\n\t)),\n\thover: register(new EditorHover()),\n\tinDiffEditor: register(new EditorBooleanOption(\n\t\tEditorOption.inDiffEditor, 'inDiffEditor', false\n\t)),\n\tletterSpacing: register(new EditorFloatOption(\n\t\tEditorOption.letterSpacing, 'letterSpacing',\n\t\tEDITOR_FONT_DEFAULTS.letterSpacing, x => EditorFloatOption.clamp(x, -5, 20),\n\t\t{ description: nls.localize('letterSpacing', \"Controls the letter spacing in pixels.\") }\n\t)),\n\tlightbulb: register(new EditorLightbulb()),\n\tlineDecorationsWidth: register(new EditorLineDecorationsWidth()),\n\tlineHeight: register(new EditorLineHeight()),\n\tlineNumbers: register(new EditorRenderLineNumbersOption()),\n\tlineNumbersMinChars: register(new EditorIntOption(\n\t\tEditorOption.lineNumbersMinChars, 'lineNumbersMinChars',\n\t\t5, 1, 300\n\t)),\n\tlinkedEditing: register(new EditorBooleanOption(\n\t\tEditorOption.linkedEditing, 'linkedEditing', false,\n\t\t{ description: nls.localize('linkedEditing', \"Controls whether the editor has linked editing enabled. Depending on the language, related symbols such as HTML tags, are updated while editing.\") }\n\t)),\n\tlinks: register(new EditorBooleanOption(\n\t\tEditorOption.links, 'links', true,\n\t\t{ description: nls.localize('links', \"Controls whether the editor should detect links and make them clickable.\") }\n\t)),\n\tmatchBrackets: register(new EditorStringEnumOption(\n\t\tEditorOption.matchBrackets, 'matchBrackets',\n\t\t'always' as 'never' | 'near' | 'always',\n\t\t['always', 'near', 'never'] as const,\n\t\t{ description: nls.localize('matchBrackets', \"Highlight matching brackets.\") }\n\t)),\n\tminimap: register(new EditorMinimap()),\n\tmouseStyle: register(new EditorStringEnumOption(\n\t\tEditorOption.mouseStyle, 'mouseStyle',\n\t\t'text' as 'text' | 'default' | 'copy',\n\t\t['text', 'default', 'copy'] as const,\n\t)),\n\tmouseWheelScrollSensitivity: register(new EditorFloatOption(\n\t\tEditorOption.mouseWheelScrollSensitivity, 'mouseWheelScrollSensitivity',\n\t\t1, x => (x === 0 ? 1 : x),\n\t\t{ markdownDescription: nls.localize('mouseWheelScrollSensitivity', \"A multiplier to be used on the `deltaX` and `deltaY` of mouse wheel scroll events.\") }\n\t)),\n\tmouseWheelZoom: register(new EditorBooleanOption(\n\t\tEditorOption.mouseWheelZoom, 'mouseWheelZoom', false,\n\t\t{\n\t\t\tmarkdownDescription: platform.isMacintosh\n\t\t\t\t? nls.localize('mouseWheelZoom.mac', \"Zoom the font of the editor when using mouse wheel and holding `Cmd`.\")\n\t\t\t\t: nls.localize('mouseWheelZoom', \"Zoom the font of the editor when using mouse wheel and holding `Ctrl`.\")\n\t\t}\n\t)),\n\tmultiCursorMergeOverlapping: register(new EditorBooleanOption(\n\t\tEditorOption.multiCursorMergeOverlapping, 'multiCursorMergeOverlapping', true,\n\t\t{ description: nls.localize('multiCursorMergeOverlapping', \"Merge multiple cursors when they are overlapping.\") }\n\t)),\n\tmultiCursorModifier: register(new EditorEnumOption(\n\t\tEditorOption.multiCursorModifier, 'multiCursorModifier',\n\t\t'altKey', 'alt',\n\t\t['ctrlCmd', 'alt'],\n\t\t_multiCursorModifierFromString,\n\t\t{\n\t\t\tmarkdownEnumDescriptions: [\n\t\t\t\tnls.localize('multiCursorModifier.ctrlCmd', \"Maps to `Control` on Windows and Linux and to `Command` on macOS.\"),\n\t\t\t\tnls.localize('multiCursorModifier.alt', \"Maps to `Alt` on Windows and Linux and to `Option` on macOS.\")\n\t\t\t],\n\t\t\tmarkdownDescription: nls.localize({\n\t\t\t\tkey: 'multiCursorModifier',\n\t\t\t\tcomment: [\n\t\t\t\t\t'- `ctrlCmd` refers to a value the setting can take and should not be localized.',\n\t\t\t\t\t'- `Control` and `Command` refer to the modifier keys Ctrl or Cmd on the keyboard and can be localized.'\n\t\t\t\t]\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](https://code.visualstudio.com/docs/editor/codebasics#_multicursor-modifier).\")\n\t\t}\n\t)),\n\tmultiCursorPaste: register(new EditorStringEnumOption(\n\t\tEditorOption.multiCursorPaste, 'multiCursorPaste',\n\t\t'spread' as 'spread' | 'full',\n\t\t['spread', 'full'] as const,\n\t\t{\n\t\t\tmarkdownEnumDescriptions: [\n\t\t\t\tnls.localize('multiCursorPaste.spread', \"Each cursor pastes a single line of the text.\"),\n\t\t\t\tnls.localize('multiCursorPaste.full', \"Each cursor pastes the full text.\")\n\t\t\t],\n\t\t\tmarkdownDescription: nls.localize('multiCursorPaste', \"Controls pasting when the line count of the pasted text matches the cursor count.\")\n\t\t}\n\t)),\n\tmultiCursorLimit: register(new EditorIntOption(\n\t\tEditorOption.multiCursorLimit, 'multiCursorLimit', 10000, 1, 100000,\n\t\t{\n\t\t\tmarkdownDescription: nls.localize('multiCursorLimit', \"Controls the max number of cursors that can be in an active editor at once.\")\n\t\t}\n\t)),\n\toccurrencesHighlight: register(new EditorStringEnumOption(\n\t\tEditorOption.occurrencesHighlight, 'occurrencesHighlight',\n\t\t'singleFile' as 'off' | 'singleFile' | 'multiFile',\n\t\t['off', 'singleFile', 'multiFile'] as const,\n\t\t{\n\t\t\tmarkdownEnumDescriptions: [\n\t\t\t\tnls.localize('occurrencesHighlight.off', \"Does not highlight occurrences.\"),\n\t\t\t\tnls.localize('occurrencesHighlight.singleFile', \"Highlights occurrences only in the current file.\"),\n\t\t\t\tnls.localize('occurrencesHighlight.multiFile', \"Experimental: Highlights occurrences across all valid open files.\")\n\t\t\t],\n\t\t\tmarkdownDescription: nls.localize('occurrencesHighlight', \"Controls whether occurrences should be highlighted across open files.\")\n\t\t}\n\t)),\n\toverviewRulerBorder: register(new EditorBooleanOption(\n\t\tEditorOption.overviewRulerBorder, 'overviewRulerBorder', true,\n\t\t{ description: nls.localize('overviewRulerBorder', \"Controls whether a border should be drawn around the overview ruler.\") }\n\t)),\n\toverviewRulerLanes: register(new EditorIntOption(\n\t\tEditorOption.overviewRulerLanes, 'overviewRulerLanes',\n\t\t3, 0, 3\n\t)),\n\tpadding: register(new EditorPadding()),\n\tpasteAs: register(new EditorPasteAs()),\n\tparameterHints: register(new EditorParameterHints()),\n\tpeekWidgetDefaultFocus: register(new EditorStringEnumOption(\n\t\tEditorOption.peekWidgetDefaultFocus, 'peekWidgetDefaultFocus',\n\t\t'tree' as 'tree' | 'editor',\n\t\t['tree', 'editor'] as const,\n\t\t{\n\t\t\tenumDescriptions: [\n\t\t\t\tnls.localize('peekWidgetDefaultFocus.tree', \"Focus the tree when opening peek\"),\n\t\t\t\tnls.localize('peekWidgetDefaultFocus.editor', \"Focus the editor when opening peek\")\n\t\t\t],\n\t\t\tdescription: nls.localize('peekWidgetDefaultFocus', \"Controls whether to focus the inline editor or the tree in the peek widget.\")\n\t\t}\n\t)),\n\tdefinitionLinkOpensInPeek: register(new EditorBooleanOption(\n\t\tEditorOption.definitionLinkOpensInPeek, 'definitionLinkOpensInPeek', false,\n\t\t{ description: nls.localize('definitionLinkOpensInPeek', \"Controls whether the Go to Definition mouse gesture always opens the peek widget.\") }\n\t)),\n\tquickSuggestions: register(new EditorQuickSuggestions()),\n\tquickSuggestionsDelay: register(new EditorIntOption(\n\t\tEditorOption.quickSuggestionsDelay, 'quickSuggestionsDelay',\n\t\t10, 0, Constants.MAX_SAFE_SMALL_INTEGER,\n\t\t{ description: nls.localize('quickSuggestionsDelay', \"Controls the delay in milliseconds after which quick suggestions will show up.\") }\n\t)),\n\treadOnly: register(new EditorBooleanOption(\n\t\tEditorOption.readOnly, 'readOnly', false,\n\t)),\n\treadOnlyMessage: register(new ReadonlyMessage()),\n\trenameOnType: register(new EditorBooleanOption(\n\t\tEditorOption.renameOnType, 'renameOnType', false,\n\t\t{ description: nls.localize('renameOnType', \"Controls whether the editor auto renames on type.\"), markdownDeprecationMessage: nls.localize('renameOnTypeDeprecate', \"Deprecated, use `editor.linkedEditing` instead.\") }\n\t)),\n\trenderControlCharacters: register(new EditorBooleanOption(\n\t\tEditorOption.renderControlCharacters, 'renderControlCharacters', true,\n\t\t{ description: nls.localize('renderControlCharacters', \"Controls whether the editor should render control characters.\"), restricted: true }\n\t)),\n\trenderFinalNewline: register(new EditorStringEnumOption(\n\t\tEditorOption.renderFinalNewline, 'renderFinalNewline',\n\t\t(platform.isLinux ? 'dimmed' : 'on') as 'off' | 'on' | 'dimmed',\n\t\t['off', 'on', 'dimmed'] as const,\n\t\t{ description: nls.localize('renderFinalNewline', \"Render last line number when the file ends with a newline.\") }\n\t)),\n\trenderLineHighlight: register(new EditorStringEnumOption(\n\t\tEditorOption.renderLineHighlight, 'renderLineHighlight',\n\t\t'line' as 'none' | 'gutter' | 'line' | 'all',\n\t\t['none', 'gutter', 'line', 'all'] as const,\n\t\t{\n\t\t\tenumDescriptions: [\n\t\t\t\t'',\n\t\t\t\t'',\n\t\t\t\t'',\n\t\t\t\tnls.localize('renderLineHighlight.all', \"Highlights both the gutter and the current line.\"),\n\t\t\t],\n\t\t\tdescription: nls.localize('renderLineHighlight', \"Controls how the editor should render the current line highlight.\")\n\t\t}\n\t)),\n\trenderLineHighlightOnlyWhenFocus: register(new EditorBooleanOption(\n\t\tEditorOption.renderLineHighlightOnlyWhenFocus, 'renderLineHighlightOnlyWhenFocus', false,\n\t\t{ description: nls.localize('renderLineHighlightOnlyWhenFocus', \"Controls if the editor should render the current line highlight only when the editor is focused.\") }\n\t)),\n\trenderValidationDecorations: register(new EditorStringEnumOption(\n\t\tEditorOption.renderValidationDecorations, 'renderValidationDecorations',\n\t\t'editable' as 'editable' | 'on' | 'off',\n\t\t['editable', 'on', 'off'] as const\n\t)),\n\trenderWhitespace: register(new EditorStringEnumOption(\n\t\tEditorOption.renderWhitespace, 'renderWhitespace',\n\t\t'selection' as 'selection' | 'none' | 'boundary' | 'trailing' | 'all',\n\t\t['none', 'boundary', 'selection', 'trailing', 'all'] as const,\n\t\t{\n\t\t\tenumDescriptions: [\n\t\t\t\t'',\n\t\t\t\tnls.localize('renderWhitespace.boundary', \"Render whitespace characters except for single spaces between words.\"),\n\t\t\t\tnls.localize('renderWhitespace.selection', \"Render whitespace characters only on selected text.\"),\n\t\t\t\tnls.localize('renderWhitespace.trailing', \"Render only trailing whitespace characters.\"),\n\t\t\t\t''\n\t\t\t],\n\t\t\tdescription: nls.localize('renderWhitespace', \"Controls how the editor should render whitespace characters.\")\n\t\t}\n\t)),\n\trevealHorizontalRightPadding: register(new EditorIntOption(\n\t\tEditorOption.revealHorizontalRightPadding, 'revealHorizontalRightPadding',\n\t\t15, 0, 1000,\n\t)),\n\troundedSelection: register(new EditorBooleanOption(\n\t\tEditorOption.roundedSelection, 'roundedSelection', true,\n\t\t{ description: nls.localize('roundedSelection', \"Controls whether selections should have rounded corners.\") }\n\t)),\n\trulers: register(new EditorRulers()),\n\tscrollbar: register(new EditorScrollbar()),\n\tscrollBeyondLastColumn: register(new EditorIntOption(\n\t\tEditorOption.scrollBeyondLastColumn, 'scrollBeyondLastColumn',\n\t\t4, 0, Constants.MAX_SAFE_SMALL_INTEGER,\n\t\t{ description: nls.localize('scrollBeyondLastColumn', \"Controls the number of extra characters beyond which the editor will scroll horizontally.\") }\n\t)),\n\tscrollBeyondLastLine: register(new EditorBooleanOption(\n\t\tEditorOption.scrollBeyondLastLine, 'scrollBeyondLastLine', true,\n\t\t{ description: nls.localize('scrollBeyondLastLine', \"Controls whether the editor will scroll beyond the last line.\") }\n\t)),\n\tscrollPredominantAxis: register(new EditorBooleanOption(\n\t\tEditorOption.scrollPredominantAxis, 'scrollPredominantAxis', true,\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.\") }\n\t)),\n\tselectionClipboard: register(new EditorBooleanOption(\n\t\tEditorOption.selectionClipboard, 'selectionClipboard', true,\n\t\t{\n\t\t\tdescription: nls.localize('selectionClipboard', \"Controls whether the Linux primary clipboard should be supported.\"),\n\t\t\tincluded: platform.isLinux\n\t\t}\n\t)),\n\tselectionHighlight: register(new EditorBooleanOption(\n\t\tEditorOption.selectionHighlight, 'selectionHighlight', true,\n\t\t{ description: nls.localize('selectionHighlight', \"Controls whether the editor should highlight matches similar to the selection.\") }\n\t)),\n\tselectOnLineNumbers: register(new EditorBooleanOption(\n\t\tEditorOption.selectOnLineNumbers, 'selectOnLineNumbers', true,\n\t)),\n\tshowFoldingControls: register(new EditorStringEnumOption(\n\t\tEditorOption.showFoldingControls, 'showFoldingControls',\n\t\t'mouseover' as 'always' | 'never' | 'mouseover',\n\t\t['always', 'never', 'mouseover'] as const,\n\t\t{\n\t\t\tenumDescriptions: [\n\t\t\t\tnls.localize('showFoldingControls.always', \"Always show the folding controls.\"),\n\t\t\t\tnls.localize('showFoldingControls.never', \"Never show the folding controls and reduce the gutter size.\"),\n\t\t\t\tnls.localize('showFoldingControls.mouseover', \"Only show the folding controls when the mouse is over the gutter.\"),\n\t\t\t],\n\t\t\tdescription: nls.localize('showFoldingControls', \"Controls when the folding controls on the gutter are shown.\")\n\t\t}\n\t)),\n\tshowUnused: register(new EditorBooleanOption(\n\t\tEditorOption.showUnused, 'showUnused', true,\n\t\t{ description: nls.localize('showUnused', \"Controls fading out of unused code.\") }\n\t)),\n\tshowDeprecated: register(new EditorBooleanOption(\n\t\tEditorOption.showDeprecated, 'showDeprecated', true,\n\t\t{ description: nls.localize('showDeprecated', \"Controls strikethrough deprecated variables.\") }\n\t)),\n\tinlayHints: register(new EditorInlayHints()),\n\tsnippetSuggestions: register(new EditorStringEnumOption(\n\t\tEditorOption.snippetSuggestions, 'snippetSuggestions',\n\t\t'inline' as 'top' | 'bottom' | 'inline' | 'none',\n\t\t['top', 'bottom', 'inline', 'none'] as const,\n\t\t{\n\t\t\tenumDescriptions: [\n\t\t\t\tnls.localize('snippetSuggestions.top', \"Show snippet suggestions on top of other suggestions.\"),\n\t\t\t\tnls.localize('snippetSuggestions.bottom', \"Show snippet suggestions below other suggestions.\"),\n\t\t\t\tnls.localize('snippetSuggestions.inline', \"Show snippets suggestions with other suggestions.\"),\n\t\t\t\tnls.localize('snippetSuggestions.none', \"Do not show snippet suggestions.\"),\n\t\t\t],\n\t\t\tdescription: nls.localize('snippetSuggestions', \"Controls whether snippets are shown with other suggestions and how they are sorted.\")\n\t\t}\n\t)),\n\tsmartSelect: register(new SmartSelect()),\n\tsmoothScrolling: register(new EditorBooleanOption(\n\t\tEditorOption.smoothScrolling, 'smoothScrolling', false,\n\t\t{ description: nls.localize('smoothScrolling', \"Controls whether the editor will scroll using an animation.\") }\n\t)),\n\tstopRenderingLineAfter: register(new EditorIntOption(\n\t\tEditorOption.stopRenderingLineAfter, 'stopRenderingLineAfter',\n\t\t10000, -1, Constants.MAX_SAFE_SMALL_INTEGER,\n\t)),\n\tsuggest: register(new EditorSuggest()),\n\tinlineSuggest: register(new InlineEditorSuggest()),\n\tinlineEdit: register(new InlineEditorEdit()),\n\tinlineCompletionsAccessibilityVerbose: register(new EditorBooleanOption(EditorOption.inlineCompletionsAccessibilityVerbose, 'inlineCompletionsAccessibilityVerbose', false,\n\t\t{ description: nls.localize('inlineCompletionsAccessibilityVerbose', \"Controls whether the accessibility hint should be provided to screen reader users when an inline completion is shown.\") })),\n\tsuggestFontSize: register(new EditorIntOption(\n\t\tEditorOption.suggestFontSize, 'suggestFontSize',\n\t\t0, 0, 1000,\n\t\t{ markdownDescription: nls.localize('suggestFontSize', \"Font size for the suggest widget. When set to {0}, the value of {1} is used.\", '`0`', '`#editor.fontSize#`') }\n\t)),\n\tsuggestLineHeight: register(new EditorIntOption(\n\t\tEditorOption.suggestLineHeight, 'suggestLineHeight',\n\t\t0, 0, 1000,\n\t\t{ markdownDescription: nls.localize('suggestLineHeight', \"Line height for the suggest widget. When set to {0}, the value of {1} is used. The minimum value is 8.\", '`0`', '`#editor.lineHeight#`') }\n\t)),\n\tsuggestOnTriggerCharacters: register(new EditorBooleanOption(\n\t\tEditorOption.suggestOnTriggerCharacters, 'suggestOnTriggerCharacters', true,\n\t\t{ description: nls.localize('suggestOnTriggerCharacters', \"Controls whether suggestions should automatically show up when typing trigger characters.\") }\n\t)),\n\tsuggestSelection: register(new EditorStringEnumOption(\n\t\tEditorOption.suggestSelection, 'suggestSelection',\n\t\t'first' as 'first' | 'recentlyUsed' | 'recentlyUsedByPrefix',\n\t\t['first', 'recentlyUsed', 'recentlyUsedByPrefix'] as const,\n\t\t{\n\t\t\tmarkdownEnumDescriptions: [\n\t\t\t\tnls.localize('suggestSelection.first', \"Always select the first suggestion.\"),\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.\"),\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`.\"),\n\t\t\t],\n\t\t\tdescription: nls.localize('suggestSelection', \"Controls how suggestions are pre-selected when showing the suggest list.\")\n\t\t}\n\t)),\n\ttabCompletion: register(new EditorStringEnumOption(\n\t\tEditorOption.tabCompletion, 'tabCompletion',\n\t\t'off' as 'on' | 'off' | 'onlySnippets',\n\t\t['on', 'off', 'onlySnippets'] as const,\n\t\t{\n\t\t\tenumDescriptions: [\n\t\t\t\tnls.localize('tabCompletion.on', \"Tab complete will insert the best matching suggestion when pressing tab.\"),\n\t\t\t\tnls.localize('tabCompletion.off', \"Disable tab completions.\"),\n\t\t\t\tnls.localize('tabCompletion.onlySnippets', \"Tab complete snippets when their prefix match. Works best when 'quickSuggestions' aren't enabled.\"),\n\t\t\t],\n\t\t\tdescription: nls.localize('tabCompletion', \"Enables tab completions.\")\n\t\t}\n\t)),\n\ttabIndex: register(new EditorIntOption(\n\t\tEditorOption.tabIndex, 'tabIndex',\n\t\t0, -1, Constants.MAX_SAFE_SMALL_INTEGER\n\t)),\n\tunicodeHighlight: register(new UnicodeHighlight()),\n\tunusualLineTerminators: register(new EditorStringEnumOption(\n\t\tEditorOption.unusualLineTerminators, 'unusualLineTerminators',\n\t\t'prompt' as 'auto' | 'off' | 'prompt',\n\t\t['auto', 'off', 'prompt'] as const,\n\t\t{\n\t\t\tenumDescriptions: [\n\t\t\t\tnls.localize('unusualLineTerminators.auto', \"Unusual line terminators are automatically removed.\"),\n\t\t\t\tnls.localize('unusualLineTerminators.off', \"Unusual line terminators are ignored.\"),\n\t\t\t\tnls.localize('unusualLineTerminators.prompt', \"Unusual line terminators prompt to be removed.\"),\n\t\t\t],\n\t\t\tdescription: nls.localize('unusualLineTerminators', \"Remove unusual line terminators that might cause problems.\")\n\t\t}\n\t)),\n\tuseShadowDOM: register(new EditorBooleanOption(\n\t\tEditorOption.useShadowDOM, 'useShadowDOM', true\n\t)),\n\tuseTabStops: register(new EditorBooleanOption(\n\t\tEditorOption.useTabStops, 'useTabStops', true,\n\t\t{ description: nls.localize('useTabStops', \"Spaces and tabs are inserted and deleted in alignment with tab stops.\") }\n\t)),\n\twordBreak: register(new EditorStringEnumOption(\n\t\tEditorOption.wordBreak, 'wordBreak',\n\t\t'normal' as 'normal' | 'keepAll',\n\t\t['normal', 'keepAll'] as const,\n\t\t{\n\t\t\tmarkdownEnumDescriptions: [\n\t\t\t\tnls.localize('wordBreak.normal', \"Use the default line break rule.\"),\n\t\t\t\tnls.localize('wordBreak.keepAll', \"Word breaks should not be used for Chinese/Japanese/Korean (CJK) text. Non-CJK text behavior is the same as for normal.\"),\n\t\t\t],\n\t\t\tdescription: nls.localize('wordBreak', \"Controls the word break rules used for Chinese/Japanese/Korean (CJK) text.\")\n\t\t}\n\t)),\n\twordSegmenterLocales: register(new WordSegmenterLocales()),\n\twordSeparators: register(new EditorStringOption(\n\t\tEditorOption.wordSeparators, 'wordSeparators', USUAL_WORD_SEPARATORS,\n\t\t{ description: nls.localize('wordSeparators', \"Characters that will be used as word separators when doing word related navigations or operations.\") }\n\t)),\n\twordWrap: register(new EditorStringEnumOption(\n\t\tEditorOption.wordWrap, 'wordWrap',\n\t\t'off' as 'off' | 'on' | 'wordWrapColumn' | 'bounded',\n\t\t['off', 'on', 'wordWrapColumn', 'bounded'] as const,\n\t\t{\n\t\t\tmarkdownEnumDescriptions: [\n\t\t\t\tnls.localize('wordWrap.off', \"Lines will never wrap.\"),\n\t\t\t\tnls.localize('wordWrap.on', \"Lines will wrap at the viewport width.\"),\n\t\t\t\tnls.localize({\n\t\t\t\t\tkey: 'wordWrap.wordWrapColumn',\n\t\t\t\t\tcomment: [\n\t\t\t\t\t\t'- `editor.wordWrapColumn` refers to a different setting and should not be localized.'\n\t\t\t\t\t]\n\t\t\t\t}, \"Lines will wrap at `#editor.wordWrapColumn#`.\"),\n\t\t\t\tnls.localize({\n\t\t\t\t\tkey: 'wordWrap.bounded',\n\t\t\t\t\tcomment: [\n\t\t\t\t\t\t'- viewport means the edge of the visible window size.',\n\t\t\t\t\t\t'- `editor.wordWrapColumn` refers to a different setting and should not be localized.'\n\t\t\t\t\t]\n\t\t\t\t}, \"Lines will wrap at the minimum of viewport and `#editor.wordWrapColumn#`.\"),\n\t\t\t],\n\t\t\tdescription: nls.localize({\n\t\t\t\tkey: 'wordWrap',\n\t\t\t\tcomment: [\n\t\t\t\t\t'- \\'off\\', \\'on\\', \\'wordWrapColumn\\' and \\'bounded\\' refer to values the setting can take and should not be localized.',\n\t\t\t\t\t'- `editor.wordWrapColumn` refers to a different setting and should not be localized.'\n\t\t\t\t]\n\t\t\t}, \"Controls how lines should wrap.\")\n\t\t}\n\t)),\n\twordWrapBreakAfterCharacters: register(new EditorStringOption(\n\t\tEditorOption.wordWrapBreakAfterCharacters, 'wordWrapBreakAfterCharacters',\n\t\t// allow-any-unicode-next-line\n\t\t' \\t})]?|/&.,;¢°′″‰℃、。。、¢,.:;?!%・・ゝゞヽヾーァィゥェォッャュョヮヵヶぁぃぅぇぉっゃゅょゎゕゖㇰㇱㇲㇳㇴㇵㇶㇷㇸㇹㇺㇻㇼㇽㇾㇿ々〻ァィゥェォャュョッー”〉》」』】〕)]}」',\n\t)),\n\twordWrapBreakBeforeCharacters: register(new EditorStringOption(\n\t\tEditorOption.wordWrapBreakBeforeCharacters, 'wordWrapBreakBeforeCharacters',\n\t\t// allow-any-unicode-next-line\n\t\t'([{‘“〈《「『【〔([{「£¥$£¥++'\n\t)),\n\twordWrapColumn: register(new EditorIntOption(\n\t\tEditorOption.wordWrapColumn, 'wordWrapColumn',\n\t\t80, 1, Constants.MAX_SAFE_SMALL_INTEGER,\n\t\t{\n\t\t\tmarkdownDescription: nls.localize({\n\t\t\t\tkey: 'wordWrapColumn',\n\t\t\t\tcomment: [\n\t\t\t\t\t'- `editor.wordWrap` refers to a different setting and should not be localized.',\n\t\t\t\t\t'- \\'wordWrapColumn\\' and \\'bounded\\' refer to values the different setting can take and should not be localized.'\n\t\t\t\t]\n\t\t\t}, \"Controls the wrapping column of the editor when `#editor.wordWrap#` is `wordWrapColumn` or `bounded`.\")\n\t\t}\n\t)),\n\twordWrapOverride1: register(new EditorStringEnumOption(\n\t\tEditorOption.wordWrapOverride1, 'wordWrapOverride1',\n\t\t'inherit' as 'off' | 'on' | 'inherit',\n\t\t['off', 'on', 'inherit'] as const\n\t)),\n\twordWrapOverride2: register(new EditorStringEnumOption(\n\t\tEditorOption.wordWrapOverride2, 'wordWrapOverride2',\n\t\t'inherit' as 'off' | 'on' | 'inherit',\n\t\t['off', 'on', 'inherit'] as const\n\t)),\n\n\t// Leave these at the end (because they have dependencies!)\n\teditorClassName: register(new EditorClassName()),\n\tdefaultColorDecorators: register(new EditorBooleanOption(\n\t\tEditorOption.defaultColorDecorators, 'defaultColorDecorators', false,\n\t\t{ markdownDescription: nls.localize('defaultColorDecorators', \"Controls whether inline color decorations should be shown using the default document color provider\") }\n\t)),\n\tpixelRatio: register(new EditorPixelRatio()),\n\ttabFocusMode: register(new EditorBooleanOption(EditorOption.tabFocusMode, 'tabFocusMode', false,\n\t\t{ markdownDescription: nls.localize('tabFocusMode', \"Controls whether the editor receives tabs or defers them to the workbench for navigation.\") }\n\t)),\n\tlayoutInfo: register(new EditorLayoutInfoComputer()),\n\twrappingInfo: register(new EditorWrappingInfoComputer()),\n\twrappingIndent: register(new WrappingIndentOption()),\n\twrappingStrategy: register(new WrappingStrategy())\n};\n\ntype EditorOptionsType = typeof EditorOptions;\ntype FindEditorOptionsKeyById = { [K in keyof EditorOptionsType]: EditorOptionsType[K]['id'] extends T ? K : never }[keyof EditorOptionsType];\ntype ComputedEditorOptionValue> = T extends IEditorOption ? R : never;\nexport type FindComputedEditorOptionValueById = NonNullable]>>;\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\nimport * as dom from 'vs/base/browser/dom';\nimport { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';\nimport * as strings from 'vs/base/common/strings';\nimport { applyFontInfo } from 'vs/editor/browser/config/domFontInfo';\nimport { TextEditorCursorStyle, EditorOption } from 'vs/editor/common/config/editorOptions';\nimport { Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\nimport { RenderingContext, RestrictedRenderingContext } from 'vs/editor/browser/view/renderingContext';\nimport { ViewContext } from 'vs/editor/common/viewModel/viewContext';\nimport * as viewEvents from 'vs/editor/common/viewEvents';\nimport { MOUSE_CURSOR_TEXT_CSS_CLASS_NAME } from 'vs/base/browser/ui/mouseCursor/mouseCursor';\n\nexport interface IViewCursorRenderData {\n\tdomNode: HTMLElement;\n\tposition: Position;\n\tcontentLeft: number;\n\twidth: number;\n\theight: number;\n}\n\nclass ViewCursorRenderData {\n\tconstructor(\n\t\tpublic readonly top: number,\n\t\tpublic readonly left: number,\n\t\tpublic readonly paddingLeft: number,\n\t\tpublic readonly width: number,\n\t\tpublic readonly height: number,\n\t\tpublic readonly textContent: string,\n\t\tpublic readonly textContentClassName: string\n\t) { }\n}\n\nexport enum CursorPlurality {\n\tSingle,\n\tMultiPrimary,\n\tMultiSecondary,\n}\n\nexport class ViewCursor {\n\tprivate readonly _context: ViewContext;\n\tprivate readonly _domNode: FastDomNode;\n\n\tprivate _cursorStyle: TextEditorCursorStyle;\n\tprivate _lineCursorWidth: number;\n\tprivate _lineHeight: number;\n\tprivate _typicalHalfwidthCharacterWidth: number;\n\n\tprivate _isVisible: boolean;\n\n\tprivate _position: Position;\n\tprivate _pluralityClass: string;\n\n\tprivate _lastRenderedContent: string;\n\tprivate _renderData: ViewCursorRenderData | null;\n\n\tconstructor(context: ViewContext, plurality: CursorPlurality) {\n\t\tthis._context = context;\n\t\tconst options = this._context.configuration.options;\n\t\tconst fontInfo = options.get(EditorOption.fontInfo);\n\n\t\tthis._cursorStyle = options.get(EditorOption.cursorStyle);\n\t\tthis._lineHeight = options.get(EditorOption.lineHeight);\n\t\tthis._typicalHalfwidthCharacterWidth = fontInfo.typicalHalfwidthCharacterWidth;\n\t\tthis._lineCursorWidth = Math.min(options.get(EditorOption.cursorWidth), this._typicalHalfwidthCharacterWidth);\n\n\t\tthis._isVisible = true;\n\n\t\t// Create the dom node\n\t\tthis._domNode = createFastDomNode(document.createElement('div'));\n\t\tthis._domNode.setClassName(`cursor ${MOUSE_CURSOR_TEXT_CSS_CLASS_NAME}`);\n\t\tthis._domNode.setHeight(this._lineHeight);\n\t\tthis._domNode.setTop(0);\n\t\tthis._domNode.setLeft(0);\n\t\tapplyFontInfo(this._domNode, fontInfo);\n\t\tthis._domNode.setDisplay('none');\n\n\t\tthis._position = new Position(1, 1);\n\t\tthis._pluralityClass = '';\n\t\tthis.setPlurality(plurality);\n\n\t\tthis._lastRenderedContent = '';\n\t\tthis._renderData = null;\n\t}\n\n\tpublic getDomNode(): FastDomNode {\n\t\treturn this._domNode;\n\t}\n\n\tpublic getPosition(): Position {\n\t\treturn this._position;\n\t}\n\n\tpublic setPlurality(plurality: CursorPlurality) {\n\t\tswitch (plurality) {\n\t\t\tdefault:\n\t\t\tcase CursorPlurality.Single:\n\t\t\t\tthis._pluralityClass = '';\n\t\t\t\tbreak;\n\n\t\t\tcase CursorPlurality.MultiPrimary:\n\t\t\t\tthis._pluralityClass = 'cursor-primary';\n\t\t\t\tbreak;\n\n\t\t\tcase CursorPlurality.MultiSecondary:\n\t\t\t\tthis._pluralityClass = 'cursor-secondary';\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tpublic show(): void {\n\t\tif (!this._isVisible) {\n\t\t\tthis._domNode.setVisibility('inherit');\n\t\t\tthis._isVisible = true;\n\t\t}\n\t}\n\n\tpublic hide(): void {\n\t\tif (this._isVisible) {\n\t\t\tthis._domNode.setVisibility('hidden');\n\t\t\tthis._isVisible = false;\n\t\t}\n\t}\n\n\tpublic onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {\n\t\tconst options = this._context.configuration.options;\n\t\tconst fontInfo = options.get(EditorOption.fontInfo);\n\n\t\tthis._cursorStyle = options.get(EditorOption.cursorStyle);\n\t\tthis._lineHeight = options.get(EditorOption.lineHeight);\n\t\tthis._typicalHalfwidthCharacterWidth = fontInfo.typicalHalfwidthCharacterWidth;\n\t\tthis._lineCursorWidth = Math.min(options.get(EditorOption.cursorWidth), this._typicalHalfwidthCharacterWidth);\n\t\tapplyFontInfo(this._domNode, fontInfo);\n\n\t\treturn true;\n\t}\n\n\tpublic onCursorPositionChanged(position: Position, pauseAnimation: boolean): boolean {\n\t\tif (pauseAnimation) {\n\t\t\tthis._domNode.domNode.style.transitionProperty = 'none';\n\t\t} else {\n\t\t\tthis._domNode.domNode.style.transitionProperty = '';\n\t\t}\n\t\tthis._position = position;\n\t\treturn true;\n\t}\n\n\t/**\n\t * If `this._position` is inside a grapheme, returns the position where the grapheme starts.\n\t * Also returns the next grapheme.\n\t */\n\tprivate _getGraphemeAwarePosition(): [Position, string] {\n\t\tconst { lineNumber, column } = this._position;\n\t\tconst lineContent = this._context.viewModel.getLineContent(lineNumber);\n\t\tconst [startOffset, endOffset] = strings.getCharContainingOffset(lineContent, column - 1);\n\t\treturn [new Position(lineNumber, startOffset + 1), lineContent.substring(startOffset, endOffset)];\n\t}\n\n\tprivate _prepareRender(ctx: RenderingContext): ViewCursorRenderData | null {\n\t\tlet textContent = '';\n\t\tlet textContentClassName = '';\n\t\tconst [position, nextGrapheme] = this._getGraphemeAwarePosition();\n\n\t\tif (this._cursorStyle === TextEditorCursorStyle.Line || this._cursorStyle === TextEditorCursorStyle.LineThin) {\n\t\t\tconst visibleRange = ctx.visibleRangeForPosition(position);\n\t\t\tif (!visibleRange || visibleRange.outsideRenderedLine) {\n\t\t\t\t// Outside viewport\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst window = dom.getWindow(this._domNode.domNode);\n\t\t\tlet width: number;\n\t\t\tif (this._cursorStyle === TextEditorCursorStyle.Line) {\n\t\t\t\twidth = dom.computeScreenAwareSize(window, this._lineCursorWidth > 0 ? this._lineCursorWidth : 2);\n\t\t\t\tif (width > 2) {\n\t\t\t\t\ttextContent = nextGrapheme;\n\t\t\t\t\ttextContentClassName = this._getTokenClassName(position);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\twidth = dom.computeScreenAwareSize(window, 1);\n\t\t\t}\n\n\t\t\tlet left = visibleRange.left;\n\t\t\tlet paddingLeft = 0;\n\t\t\tif (width >= 2 && left >= 1) {\n\t\t\t\t// shift the cursor a bit between the characters\n\t\t\t\tpaddingLeft = 1;\n\t\t\t\tleft -= paddingLeft;\n\t\t\t}\n\n\t\t\tconst top = ctx.getVerticalOffsetForLineNumber(position.lineNumber) - ctx.bigNumbersDelta;\n\t\t\treturn new ViewCursorRenderData(top, left, paddingLeft, width, this._lineHeight, textContent, textContentClassName);\n\t\t}\n\n\t\tconst visibleRangeForCharacter = ctx.linesVisibleRangesForRange(new Range(position.lineNumber, position.column, position.lineNumber, position.column + nextGrapheme.length), false);\n\t\tif (!visibleRangeForCharacter || visibleRangeForCharacter.length === 0) {\n\t\t\t// Outside viewport\n\t\t\treturn null;\n\t\t}\n\n\t\tconst firstVisibleRangeForCharacter = visibleRangeForCharacter[0];\n\t\tif (firstVisibleRangeForCharacter.outsideRenderedLine || firstVisibleRangeForCharacter.ranges.length === 0) {\n\t\t\t// Outside viewport\n\t\t\treturn null;\n\t\t}\n\n\t\tconst range = firstVisibleRangeForCharacter.ranges[0];\n\t\tconst width = (\n\t\t\tnextGrapheme === '\\t'\n\t\t\t\t? this._typicalHalfwidthCharacterWidth\n\t\t\t\t: (range.width < 1\n\t\t\t\t\t? this._typicalHalfwidthCharacterWidth\n\t\t\t\t\t: range.width)\n\t\t);\n\n\t\tif (this._cursorStyle === TextEditorCursorStyle.Block) {\n\t\t\ttextContent = nextGrapheme;\n\t\t\ttextContentClassName = this._getTokenClassName(position);\n\t\t}\n\n\t\tlet top = ctx.getVerticalOffsetForLineNumber(position.lineNumber) - ctx.bigNumbersDelta;\n\t\tlet height = this._lineHeight;\n\n\t\t// Underline might interfere with clicking\n\t\tif (this._cursorStyle === TextEditorCursorStyle.Underline || this._cursorStyle === TextEditorCursorStyle.UnderlineThin) {\n\t\t\ttop += this._lineHeight - 2;\n\t\t\theight = 2;\n\t\t}\n\n\t\treturn new ViewCursorRenderData(top, range.left, 0, width, height, textContent, textContentClassName);\n\t}\n\n\tprivate _getTokenClassName(position: Position): string {\n\t\tconst lineData = this._context.viewModel.getViewLineData(position.lineNumber);\n\t\tconst tokenIndex = lineData.tokens.findTokenIndexAtOffset(position.column - 1);\n\t\treturn lineData.tokens.getClassName(tokenIndex);\n\t}\n\n\tpublic prepareRender(ctx: RenderingContext): void {\n\t\tthis._renderData = this._prepareRender(ctx);\n\t}\n\n\tpublic render(ctx: RestrictedRenderingContext): IViewCursorRenderData | null {\n\t\tif (!this._renderData) {\n\t\t\tthis._domNode.setDisplay('none');\n\t\t\treturn null;\n\t\t}\n\n\t\tif (this._lastRenderedContent !== this._renderData.textContent) {\n\t\t\tthis._lastRenderedContent = this._renderData.textContent;\n\t\t\tthis._domNode.domNode.textContent = this._lastRenderedContent;\n\t\t}\n\n\t\tthis._domNode.setClassName(`cursor ${this._pluralityClass} ${MOUSE_CURSOR_TEXT_CSS_CLASS_NAME} ${this._renderData.textContentClassName}`);\n\n\t\tthis._domNode.setDisplay('block');\n\t\tthis._domNode.setTop(this._renderData.top);\n\t\tthis._domNode.setLeft(this._renderData.left);\n\t\tthis._domNode.setPaddingLeft(this._renderData.paddingLeft);\n\t\tthis._domNode.setWidth(this._renderData.width);\n\t\tthis._domNode.setLineHeight(this._renderData.height);\n\t\tthis._domNode.setHeight(this._renderData.height);\n\n\t\treturn {\n\t\t\tdomNode: this._domNode.domNode,\n\t\t\tposition: this._position,\n\t\t\tcontentLeft: this._renderData.left,\n\t\t\theight: this._renderData.height,\n\t\t\twidth: 2\n\t\t};\n\t}\n}\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\nimport * as platform from 'vs/base/common/platform';\nimport { EditorFontVariations, EditorOption, FindComputedEditorOptionValueById, EDITOR_FONT_DEFAULTS } from 'vs/editor/common/config/editorOptions';\nimport { EditorZoom } from 'vs/editor/common/config/editorZoom';\n\n/**\n * Determined from empirical observations.\n * @internal\n */\nconst GOLDEN_LINE_HEIGHT_RATIO = platform.isMacintosh ? 1.5 : 1.35;\n\n/**\n * @internal\n */\nconst MINIMUM_LINE_HEIGHT = 8;\n\n/**\n * @internal\n */\nexport interface IValidatedEditorOptions {\n\tget(id: T): FindComputedEditorOptionValueById;\n}\n\nexport class BareFontInfo {\n\treadonly _bareFontInfoBrand: void = undefined;\n\n\t/**\n\t * @internal\n\t */\n\tpublic static createFromValidatedSettings(options: IValidatedEditorOptions, pixelRatio: number, ignoreEditorZoom: boolean): BareFontInfo {\n\t\tconst fontFamily = options.get(EditorOption.fontFamily);\n\t\tconst fontWeight = options.get(EditorOption.fontWeight);\n\t\tconst fontSize = options.get(EditorOption.fontSize);\n\t\tconst fontFeatureSettings = options.get(EditorOption.fontLigatures);\n\t\tconst fontVariationSettings = options.get(EditorOption.fontVariations);\n\t\tconst lineHeight = options.get(EditorOption.lineHeight);\n\t\tconst letterSpacing = options.get(EditorOption.letterSpacing);\n\t\treturn BareFontInfo._create(fontFamily, fontWeight, fontSize, fontFeatureSettings, fontVariationSettings, lineHeight, letterSpacing, pixelRatio, ignoreEditorZoom);\n\t}\n\n\t/**\n\t * @internal\n\t */\n\tprivate static _create(fontFamily: string, fontWeight: string, fontSize: number, fontFeatureSettings: string, fontVariationSettings: string, lineHeight: number, letterSpacing: number, pixelRatio: number, ignoreEditorZoom: boolean): BareFontInfo {\n\t\tif (lineHeight === 0) {\n\t\t\tlineHeight = GOLDEN_LINE_HEIGHT_RATIO * fontSize;\n\t\t} else if (lineHeight < MINIMUM_LINE_HEIGHT) {\n\t\t\t// Values too small to be line heights in pixels are in ems.\n\t\t\tlineHeight = lineHeight * fontSize;\n\t\t}\n\n\t\t// Enforce integer, minimum constraints\n\t\tlineHeight = Math.round(lineHeight);\n\t\tif (lineHeight < MINIMUM_LINE_HEIGHT) {\n\t\t\tlineHeight = MINIMUM_LINE_HEIGHT;\n\t\t}\n\n\t\tconst editorZoomLevelMultiplier = 1 + (ignoreEditorZoom ? 0 : EditorZoom.getZoomLevel() * 0.1);\n\t\tfontSize *= editorZoomLevelMultiplier;\n\t\tlineHeight *= editorZoomLevelMultiplier;\n\n\t\tif (fontVariationSettings === EditorFontVariations.TRANSLATE) {\n\t\t\tif (fontWeight === 'normal' || fontWeight === 'bold') {\n\t\t\t\tfontVariationSettings = EditorFontVariations.OFF;\n\t\t\t} else {\n\t\t\t\tconst fontWeightAsNumber = parseInt(fontWeight, 10);\n\t\t\t\tfontVariationSettings = `'wght' ${fontWeightAsNumber}`;\n\t\t\t\tfontWeight = 'normal';\n\t\t\t}\n\t\t}\n\n\t\treturn new BareFontInfo({\n\t\t\tpixelRatio: pixelRatio,\n\t\t\tfontFamily: fontFamily,\n\t\t\tfontWeight: fontWeight,\n\t\t\tfontSize: fontSize,\n\t\t\tfontFeatureSettings: fontFeatureSettings,\n\t\t\tfontVariationSettings,\n\t\t\tlineHeight: lineHeight,\n\t\t\tletterSpacing: letterSpacing\n\t\t});\n\t}\n\n\treadonly pixelRatio: number;\n\treadonly fontFamily: string;\n\treadonly fontWeight: string;\n\treadonly fontSize: number;\n\treadonly fontFeatureSettings: string;\n\treadonly fontVariationSettings: string;\n\treadonly lineHeight: number;\n\treadonly letterSpacing: number;\n\n\t/**\n\t * @internal\n\t */\n\tprotected constructor(opts: {\n\t\tpixelRatio: number;\n\t\tfontFamily: string;\n\t\tfontWeight: string;\n\t\tfontSize: number;\n\t\tfontFeatureSettings: string;\n\t\tfontVariationSettings: string;\n\t\tlineHeight: number;\n\t\tletterSpacing: number;\n\t}) {\n\t\tthis.pixelRatio = opts.pixelRatio;\n\t\tthis.fontFamily = String(opts.fontFamily);\n\t\tthis.fontWeight = String(opts.fontWeight);\n\t\tthis.fontSize = opts.fontSize;\n\t\tthis.fontFeatureSettings = opts.fontFeatureSettings;\n\t\tthis.fontVariationSettings = opts.fontVariationSettings;\n\t\tthis.lineHeight = opts.lineHeight | 0;\n\t\tthis.letterSpacing = opts.letterSpacing;\n\t}\n\n\t/**\n\t * @internal\n\t */\n\tpublic getId(): string {\n\t\treturn `${this.pixelRatio}-${this.fontFamily}-${this.fontWeight}-${this.fontSize}-${this.fontFeatureSettings}-${this.fontVariationSettings}-${this.lineHeight}-${this.letterSpacing}`;\n\t}\n\n\t/**\n\t * @internal\n\t */\n\tpublic getMassagedFontFamily(): string {\n\t\tconst fallbackFontFamily = EDITOR_FONT_DEFAULTS.fontFamily;\n\t\tconst fontFamily = BareFontInfo._wrapInQuotes(this.fontFamily);\n\t\tif (fallbackFontFamily && this.fontFamily !== fallbackFontFamily) {\n\t\t\treturn `${fontFamily}, ${fallbackFontFamily}`;\n\t\t}\n\t\treturn fontFamily;\n\t}\n\n\tprivate static _wrapInQuotes(fontFamily: string): string {\n\t\tif (/[,\"']/.test(fontFamily)) {\n\t\t\t// Looks like the font family might be already escaped\n\t\t\treturn fontFamily;\n\t\t}\n\t\tif (/[+ ]/.test(fontFamily)) {\n\t\t\t// Wrap a font family using + or with quotes\n\t\t\treturn `\"${fontFamily}\"`;\n\t\t}\n\t\treturn fontFamily;\n\t}\n}\n\n// change this whenever `FontInfo` members are changed\nexport const SERIALIZED_FONT_INFO_VERSION = 2;\n\nexport class FontInfo extends BareFontInfo {\n\treadonly _editorStylingBrand: void = undefined;\n\n\treadonly version: number = SERIALIZED_FONT_INFO_VERSION;\n\treadonly isTrusted: boolean;\n\treadonly isMonospace: boolean;\n\treadonly typicalHalfwidthCharacterWidth: number;\n\treadonly typicalFullwidthCharacterWidth: number;\n\treadonly canUseHalfwidthRightwardsArrow: boolean;\n\treadonly spaceWidth: number;\n\treadonly middotWidth: number;\n\treadonly wsmiddotWidth: number;\n\treadonly maxDigitWidth: number;\n\n\t/**\n\t * @internal\n\t */\n\tconstructor(opts: {\n\t\tpixelRatio: number;\n\t\tfontFamily: string;\n\t\tfontWeight: string;\n\t\tfontSize: number;\n\t\tfontFeatureSettings: string;\n\t\tfontVariationSettings: string;\n\t\tlineHeight: number;\n\t\tletterSpacing: number;\n\t\tisMonospace: boolean;\n\t\ttypicalHalfwidthCharacterWidth: number;\n\t\ttypicalFullwidthCharacterWidth: number;\n\t\tcanUseHalfwidthRightwardsArrow: boolean;\n\t\tspaceWidth: number;\n\t\tmiddotWidth: number;\n\t\twsmiddotWidth: number;\n\t\tmaxDigitWidth: number;\n\t}, isTrusted: boolean) {\n\t\tsuper(opts);\n\t\tthis.isTrusted = isTrusted;\n\t\tthis.isMonospace = opts.isMonospace;\n\t\tthis.typicalHalfwidthCharacterWidth = opts.typicalHalfwidthCharacterWidth;\n\t\tthis.typicalFullwidthCharacterWidth = opts.typicalFullwidthCharacterWidth;\n\t\tthis.canUseHalfwidthRightwardsArrow = opts.canUseHalfwidthRightwardsArrow;\n\t\tthis.spaceWidth = opts.spaceWidth;\n\t\tthis.middotWidth = opts.middotWidth;\n\t\tthis.wsmiddotWidth = opts.wsmiddotWidth;\n\t\tthis.maxDigitWidth = opts.maxDigitWidth;\n\t}\n\n\t/**\n\t * @internal\n\t */\n\tpublic equals(other: FontInfo): boolean {\n\t\treturn (\n\t\t\tthis.fontFamily === other.fontFamily\n\t\t\t&& this.fontWeight === other.fontWeight\n\t\t\t&& this.fontSize === other.fontSize\n\t\t\t&& this.fontFeatureSettings === other.fontFeatureSettings\n\t\t\t&& this.fontVariationSettings === other.fontVariationSettings\n\t\t\t&& this.lineHeight === other.lineHeight\n\t\t\t&& this.letterSpacing === other.letterSpacing\n\t\t\t&& this.typicalHalfwidthCharacterWidth === other.typicalHalfwidthCharacterWidth\n\t\t\t&& this.typicalFullwidthCharacterWidth === other.typicalFullwidthCharacterWidth\n\t\t\t&& this.canUseHalfwidthRightwardsArrow === other.canUseHalfwidthRightwardsArrow\n\t\t\t&& this.spaceWidth === other.spaceWidth\n\t\t\t&& this.middotWidth === other.middotWidth\n\t\t\t&& this.wsmiddotWidth === other.wsmiddotWidth\n\t\t\t&& this.maxDigitWidth === other.maxDigitWidth\n\t\t);\n\t}\n}\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\nimport { getWindowId } from 'vs/base/browser/dom';\nimport { PixelRatio } from 'vs/base/browser/pixelRatio';\nimport { Emitter } from 'vs/base/common/event';\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport { CharWidthRequest, CharWidthRequestType, readCharWidths } from 'vs/editor/browser/config/charWidthReader';\nimport { EditorFontLigatures } from 'vs/editor/common/config/editorOptions';\nimport { BareFontInfo, FontInfo } from 'vs/editor/common/config/fontInfo';\n\nexport class FontMeasurementsImpl extends Disposable {\n\n\tprivate readonly _cache = new Map();\n\n\tprivate _evictUntrustedReadingsTimeout = -1;\n\n\tprivate readonly _onDidChange = this._register(new Emitter());\n\tpublic readonly onDidChange = this._onDidChange.event;\n\n\tpublic override dispose(): void {\n\t\tif (this._evictUntrustedReadingsTimeout !== -1) {\n\t\t\tclearTimeout(this._evictUntrustedReadingsTimeout);\n\t\t\tthis._evictUntrustedReadingsTimeout = -1;\n\t\t}\n\t\tsuper.dispose();\n\t}\n\n\t/**\n\t * Clear all cached font information and trigger a change event.\n\t */\n\tpublic clearAllFontInfos(): void {\n\t\tthis._cache.clear();\n\t\tthis._onDidChange.fire();\n\t}\n\n\tprivate _ensureCache(targetWindow: Window): FontMeasurementsCache {\n\t\tconst windowId = getWindowId(targetWindow);\n\t\tlet cache = this._cache.get(windowId);\n\t\tif (!cache) {\n\t\t\tcache = new FontMeasurementsCache();\n\t\t\tthis._cache.set(windowId, cache);\n\t\t}\n\t\treturn cache;\n\t}\n\n\tprivate _writeToCache(targetWindow: Window, item: BareFontInfo, value: FontInfo): void {\n\t\tconst cache = this._ensureCache(targetWindow);\n\t\tcache.put(item, value);\n\n\t\tif (!value.isTrusted && this._evictUntrustedReadingsTimeout === -1) {\n\t\t\t// Try reading again after some time\n\t\t\tthis._evictUntrustedReadingsTimeout = targetWindow.setTimeout(() => {\n\t\t\t\tthis._evictUntrustedReadingsTimeout = -1;\n\t\t\t\tthis._evictUntrustedReadings(targetWindow);\n\t\t\t}, 5000);\n\t\t}\n\t}\n\n\tprivate _evictUntrustedReadings(targetWindow: Window): void {\n\t\tconst cache = this._ensureCache(targetWindow);\n\t\tconst values = cache.getValues();\n\t\tlet somethingRemoved = false;\n\t\tfor (const item of values) {\n\t\t\tif (!item.isTrusted) {\n\t\t\t\tsomethingRemoved = true;\n\t\t\t\tcache.remove(item);\n\t\t\t}\n\t\t}\n\t\tif (somethingRemoved) {\n\t\t\tthis._onDidChange.fire();\n\t\t}\n\t}\n\n\t/**\n\t * Read font information.\n\t */\n\tpublic readFontInfo(targetWindow: Window, bareFontInfo: BareFontInfo): FontInfo {\n\t\tconst cache = this._ensureCache(targetWindow);\n\t\tif (!cache.has(bareFontInfo)) {\n\t\t\tlet readConfig = this._actualReadFontInfo(targetWindow, bareFontInfo);\n\n\t\t\tif (readConfig.typicalHalfwidthCharacterWidth <= 2 || readConfig.typicalFullwidthCharacterWidth <= 2 || readConfig.spaceWidth <= 2 || readConfig.maxDigitWidth <= 2) {\n\t\t\t\t// Hey, it's Bug 14341 ... we couldn't read\n\t\t\t\treadConfig = new FontInfo({\n\t\t\t\t\tpixelRatio: PixelRatio.getInstance(targetWindow).value,\n\t\t\t\t\tfontFamily: readConfig.fontFamily,\n\t\t\t\t\tfontWeight: readConfig.fontWeight,\n\t\t\t\t\tfontSize: readConfig.fontSize,\n\t\t\t\t\tfontFeatureSettings: readConfig.fontFeatureSettings,\n\t\t\t\t\tfontVariationSettings: readConfig.fontVariationSettings,\n\t\t\t\t\tlineHeight: readConfig.lineHeight,\n\t\t\t\t\tletterSpacing: readConfig.letterSpacing,\n\t\t\t\t\tisMonospace: readConfig.isMonospace,\n\t\t\t\t\ttypicalHalfwidthCharacterWidth: Math.max(readConfig.typicalHalfwidthCharacterWidth, 5),\n\t\t\t\t\ttypicalFullwidthCharacterWidth: Math.max(readConfig.typicalFullwidthCharacterWidth, 5),\n\t\t\t\t\tcanUseHalfwidthRightwardsArrow: readConfig.canUseHalfwidthRightwardsArrow,\n\t\t\t\t\tspaceWidth: Math.max(readConfig.spaceWidth, 5),\n\t\t\t\t\tmiddotWidth: Math.max(readConfig.middotWidth, 5),\n\t\t\t\t\twsmiddotWidth: Math.max(readConfig.wsmiddotWidth, 5),\n\t\t\t\t\tmaxDigitWidth: Math.max(readConfig.maxDigitWidth, 5),\n\t\t\t\t}, false);\n\t\t\t}\n\n\t\t\tthis._writeToCache(targetWindow, bareFontInfo, readConfig);\n\t\t}\n\t\treturn cache.get(bareFontInfo);\n\t}\n\n\tprivate _createRequest(chr: string, type: CharWidthRequestType, all: CharWidthRequest[], monospace: CharWidthRequest[] | null): CharWidthRequest {\n\t\tconst result = new CharWidthRequest(chr, type);\n\t\tall.push(result);\n\t\tmonospace?.push(result);\n\t\treturn result;\n\t}\n\n\tprivate _actualReadFontInfo(targetWindow: Window, bareFontInfo: BareFontInfo): FontInfo {\n\t\tconst all: CharWidthRequest[] = [];\n\t\tconst monospace: CharWidthRequest[] = [];\n\n\t\tconst typicalHalfwidthCharacter = this._createRequest('n', CharWidthRequestType.Regular, all, monospace);\n\t\tconst typicalFullwidthCharacter = this._createRequest('\\uff4d', CharWidthRequestType.Regular, all, null);\n\t\tconst space = this._createRequest(' ', CharWidthRequestType.Regular, all, monospace);\n\t\tconst digit0 = this._createRequest('0', CharWidthRequestType.Regular, all, monospace);\n\t\tconst digit1 = this._createRequest('1', CharWidthRequestType.Regular, all, monospace);\n\t\tconst digit2 = this._createRequest('2', CharWidthRequestType.Regular, all, monospace);\n\t\tconst digit3 = this._createRequest('3', CharWidthRequestType.Regular, all, monospace);\n\t\tconst digit4 = this._createRequest('4', CharWidthRequestType.Regular, all, monospace);\n\t\tconst digit5 = this._createRequest('5', CharWidthRequestType.Regular, all, monospace);\n\t\tconst digit6 = this._createRequest('6', CharWidthRequestType.Regular, all, monospace);\n\t\tconst digit7 = this._createRequest('7', CharWidthRequestType.Regular, all, monospace);\n\t\tconst digit8 = this._createRequest('8', CharWidthRequestType.Regular, all, monospace);\n\t\tconst digit9 = this._createRequest('9', CharWidthRequestType.Regular, all, monospace);\n\n\t\t// monospace test: used for whitespace rendering\n\t\tconst rightwardsArrow = this._createRequest('→', CharWidthRequestType.Regular, all, monospace);\n\t\tconst halfwidthRightwardsArrow = this._createRequest('→', CharWidthRequestType.Regular, all, null);\n\n\t\t// U+00B7 - MIDDLE DOT\n\t\tconst middot = this._createRequest('·', CharWidthRequestType.Regular, all, monospace);\n\n\t\t// U+2E31 - WORD SEPARATOR MIDDLE DOT\n\t\tconst wsmiddotWidth = this._createRequest(String.fromCharCode(0x2E31), CharWidthRequestType.Regular, all, null);\n\n\t\t// monospace test: some characters\n\t\tconst monospaceTestChars = '|/-_ilm%';\n\t\tfor (let i = 0, len = monospaceTestChars.length; i < len; i++) {\n\t\t\tthis._createRequest(monospaceTestChars.charAt(i), CharWidthRequestType.Regular, all, monospace);\n\t\t\tthis._createRequest(monospaceTestChars.charAt(i), CharWidthRequestType.Italic, all, monospace);\n\t\t\tthis._createRequest(monospaceTestChars.charAt(i), CharWidthRequestType.Bold, all, monospace);\n\t\t}\n\n\t\treadCharWidths(targetWindow, bareFontInfo, all);\n\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);\n\n\t\tlet isMonospace = (bareFontInfo.fontFeatureSettings === EditorFontLigatures.OFF);\n\t\tconst referenceWidth = monospace[0].width;\n\t\tfor (let i = 1, len = monospace.length; isMonospace && i < len; i++) {\n\t\t\tconst diff = referenceWidth - monospace[i].width;\n\t\t\tif (diff < -0.001 || diff > 0.001) {\n\t\t\t\tisMonospace = false;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tlet canUseHalfwidthRightwardsArrow = true;\n\t\tif (isMonospace && halfwidthRightwardsArrow.width !== referenceWidth) {\n\t\t\t// using a halfwidth rightwards arrow would break monospace...\n\t\t\tcanUseHalfwidthRightwardsArrow = false;\n\t\t}\n\t\tif (halfwidthRightwardsArrow.width > rightwardsArrow.width) {\n\t\t\t// using a halfwidth rightwards arrow would paint a larger arrow than a regular rightwards arrow\n\t\t\tcanUseHalfwidthRightwardsArrow = false;\n\t\t}\n\n\t\treturn new FontInfo({\n\t\t\tpixelRatio: PixelRatio.getInstance(targetWindow).value,\n\t\t\tfontFamily: bareFontInfo.fontFamily,\n\t\t\tfontWeight: bareFontInfo.fontWeight,\n\t\t\tfontSize: bareFontInfo.fontSize,\n\t\t\tfontFeatureSettings: bareFontInfo.fontFeatureSettings,\n\t\t\tfontVariationSettings: bareFontInfo.fontVariationSettings,\n\t\t\tlineHeight: bareFontInfo.lineHeight,\n\t\t\tletterSpacing: bareFontInfo.letterSpacing,\n\t\t\tisMonospace: isMonospace,\n\t\t\ttypicalHalfwidthCharacterWidth: typicalHalfwidthCharacter.width,\n\t\t\ttypicalFullwidthCharacterWidth: typicalFullwidthCharacter.width,\n\t\t\tcanUseHalfwidthRightwardsArrow: canUseHalfwidthRightwardsArrow,\n\t\t\tspaceWidth: space.width,\n\t\t\tmiddotWidth: middot.width,\n\t\t\twsmiddotWidth: wsmiddotWidth.width,\n\t\t\tmaxDigitWidth: maxDigitWidth\n\t\t}, true);\n\t}\n}\n\nclass FontMeasurementsCache {\n\n\tprivate readonly _keys: { [key: string]: BareFontInfo };\n\tprivate readonly _values: { [key: string]: FontInfo };\n\n\tconstructor() {\n\t\tthis._keys = Object.create(null);\n\t\tthis._values = Object.create(null);\n\t}\n\n\tpublic has(item: BareFontInfo): boolean {\n\t\tconst itemId = item.getId();\n\t\treturn !!this._values[itemId];\n\t}\n\n\tpublic get(item: BareFontInfo): FontInfo {\n\t\tconst itemId = item.getId();\n\t\treturn this._values[itemId];\n\t}\n\n\tpublic put(item: BareFontInfo, value: FontInfo): void {\n\t\tconst itemId = item.getId();\n\t\tthis._keys[itemId] = item;\n\t\tthis._values[itemId] = value;\n\t}\n\n\tpublic remove(item: BareFontInfo): void {\n\t\tconst itemId = item.getId();\n\t\tdelete this._keys[itemId];\n\t\tdelete this._values[itemId];\n\t}\n\n\tpublic getValues(): FontInfo[] {\n\t\treturn Object.keys(this._keys).map(id => this._values[id]);\n\t}\n}\n\nexport const FontMeasurements = new FontMeasurementsImpl();\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\nimport { IDisposable } from 'vs/base/common/lifecycle';\nimport { Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\nimport { IEditorConfiguration } from 'vs/editor/common/config/editorConfiguration';\nimport { IModelDecoration, ITextModel, PositionAffinity } from 'vs/editor/common/model';\nimport { IViewModelLines } from 'vs/editor/common/viewModel/viewModelLines';\nimport { ICoordinatesConverter, InlineDecoration, InlineDecorationType, ViewModelDecoration } from 'vs/editor/common/viewModel';\nimport { filterValidationDecorations } from 'vs/editor/common/config/editorOptions';\nimport { StandardTokenType } from 'vs/editor/common/encodedTokenAttributes';\n\nexport interface IDecorationsViewportData {\n\t/**\n\t * decorations in the viewport.\n\t */\n\treadonly decorations: ViewModelDecoration[];\n\t/**\n\t * inline decorations grouped by each line in the viewport.\n\t */\n\treadonly inlineDecorations: InlineDecoration[][];\n}\n\nexport class ViewModelDecorations implements IDisposable {\n\n\tprivate readonly editorId: number;\n\tprivate readonly model: ITextModel;\n\tprivate readonly configuration: IEditorConfiguration;\n\tprivate readonly _linesCollection: IViewModelLines;\n\tprivate readonly _coordinatesConverter: ICoordinatesConverter;\n\n\tprivate _decorationsCache: { [decorationId: string]: ViewModelDecoration };\n\n\tprivate _cachedModelDecorationsResolver: IDecorationsViewportData | null;\n\tprivate _cachedModelDecorationsResolverViewRange: Range | null;\n\n\tconstructor(editorId: number, model: ITextModel, configuration: IEditorConfiguration, linesCollection: IViewModelLines, coordinatesConverter: ICoordinatesConverter) {\n\t\tthis.editorId = editorId;\n\t\tthis.model = model;\n\t\tthis.configuration = configuration;\n\t\tthis._linesCollection = linesCollection;\n\t\tthis._coordinatesConverter = coordinatesConverter;\n\t\tthis._decorationsCache = Object.create(null);\n\t\tthis._cachedModelDecorationsResolver = null;\n\t\tthis._cachedModelDecorationsResolverViewRange = null;\n\t}\n\n\tprivate _clearCachedModelDecorationsResolver(): void {\n\t\tthis._cachedModelDecorationsResolver = null;\n\t\tthis._cachedModelDecorationsResolverViewRange = null;\n\t}\n\n\tpublic dispose(): void {\n\t\tthis._decorationsCache = Object.create(null);\n\t\tthis._clearCachedModelDecorationsResolver();\n\t}\n\n\tpublic reset(): void {\n\t\tthis._decorationsCache = Object.create(null);\n\t\tthis._clearCachedModelDecorationsResolver();\n\t}\n\n\tpublic onModelDecorationsChanged(): void {\n\t\tthis._decorationsCache = Object.create(null);\n\t\tthis._clearCachedModelDecorationsResolver();\n\t}\n\n\tpublic onLineMappingChanged(): void {\n\t\tthis._decorationsCache = Object.create(null);\n\n\t\tthis._clearCachedModelDecorationsResolver();\n\t}\n\n\tprivate _getOrCreateViewModelDecoration(modelDecoration: IModelDecoration): ViewModelDecoration {\n\t\tconst id = modelDecoration.id;\n\t\tlet r = this._decorationsCache[id];\n\t\tif (!r) {\n\t\t\tconst modelRange = modelDecoration.range;\n\t\t\tconst options = modelDecoration.options;\n\t\t\tlet viewRange: Range;\n\t\t\tif (options.isWholeLine) {\n\t\t\t\tconst start = this._coordinatesConverter.convertModelPositionToViewPosition(new Position(modelRange.startLineNumber, 1), PositionAffinity.Left, false, true);\n\t\t\t\tconst end = this._coordinatesConverter.convertModelPositionToViewPosition(new Position(modelRange.endLineNumber, this.model.getLineMaxColumn(modelRange.endLineNumber)), PositionAffinity.Right);\n\t\t\t\tviewRange = new Range(start.lineNumber, start.column, end.lineNumber, end.column);\n\t\t\t} else {\n\t\t\t\t// For backwards compatibility reasons, we want injected text before any decoration.\n\t\t\t\t// Thus, move decorations to the right.\n\t\t\t\tviewRange = this._coordinatesConverter.convertModelRangeToViewRange(modelRange, PositionAffinity.Right);\n\t\t\t}\n\t\t\tr = new ViewModelDecoration(viewRange, options);\n\t\t\tthis._decorationsCache[id] = r;\n\t\t}\n\t\treturn r;\n\t}\n\n\tpublic getMinimapDecorationsInRange(range: Range): ViewModelDecoration[] {\n\t\treturn this._getDecorationsInRange(range, true, false).decorations;\n\t}\n\n\tpublic getDecorationsViewportData(viewRange: Range): IDecorationsViewportData {\n\t\tlet cacheIsValid = (this._cachedModelDecorationsResolver !== null);\n\t\tcacheIsValid = cacheIsValid && (viewRange.equalsRange(this._cachedModelDecorationsResolverViewRange));\n\t\tif (!cacheIsValid) {\n\t\t\tthis._cachedModelDecorationsResolver = this._getDecorationsInRange(viewRange, false, false);\n\t\t\tthis._cachedModelDecorationsResolverViewRange = viewRange;\n\t\t}\n\t\treturn this._cachedModelDecorationsResolver!;\n\t}\n\n\tpublic getInlineDecorationsOnLine(lineNumber: number, onlyMinimapDecorations: boolean = false, onlyMarginDecorations: boolean = false): InlineDecoration[] {\n\t\tconst range = new Range(lineNumber, this._linesCollection.getViewLineMinColumn(lineNumber), lineNumber, this._linesCollection.getViewLineMaxColumn(lineNumber));\n\t\treturn this._getDecorationsInRange(range, onlyMinimapDecorations, onlyMarginDecorations).inlineDecorations[0];\n\t}\n\n\tprivate _getDecorationsInRange(viewRange: Range, onlyMinimapDecorations: boolean, onlyMarginDecorations: boolean): IDecorationsViewportData {\n\t\tconst modelDecorations = this._linesCollection.getDecorationsInRange(viewRange, this.editorId, filterValidationDecorations(this.configuration.options), onlyMinimapDecorations, onlyMarginDecorations);\n\t\tconst startLineNumber = viewRange.startLineNumber;\n\t\tconst endLineNumber = viewRange.endLineNumber;\n\n\t\tconst decorationsInViewport: ViewModelDecoration[] = [];\n\t\tlet decorationsInViewportLen = 0;\n\t\tconst inlineDecorations: InlineDecoration[][] = [];\n\t\tfor (let j = startLineNumber; j <= endLineNumber; j++) {\n\t\t\tinlineDecorations[j - startLineNumber] = [];\n\t\t}\n\n\t\tfor (let i = 0, len = modelDecorations.length; i < len; i++) {\n\t\t\tconst modelDecoration = modelDecorations[i];\n\t\t\tconst decorationOptions = modelDecoration.options;\n\n\t\t\tif (!isModelDecorationVisible(this.model, modelDecoration)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst viewModelDecoration = this._getOrCreateViewModelDecoration(modelDecoration);\n\t\t\tconst viewRange = viewModelDecoration.range;\n\n\t\t\tdecorationsInViewport[decorationsInViewportLen++] = viewModelDecoration;\n\n\t\t\tif (decorationOptions.inlineClassName) {\n\t\t\t\tconst inlineDecoration = new InlineDecoration(viewRange, decorationOptions.inlineClassName, decorationOptions.inlineClassNameAffectsLetterSpacing ? InlineDecorationType.RegularAffectingLetterSpacing : InlineDecorationType.Regular);\n\t\t\t\tconst intersectedStartLineNumber = Math.max(startLineNumber, viewRange.startLineNumber);\n\t\t\t\tconst intersectedEndLineNumber = Math.min(endLineNumber, viewRange.endLineNumber);\n\t\t\t\tfor (let j = intersectedStartLineNumber; j <= intersectedEndLineNumber; j++) {\n\t\t\t\t\tinlineDecorations[j - startLineNumber].push(inlineDecoration);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (decorationOptions.beforeContentClassName) {\n\t\t\t\tif (startLineNumber <= viewRange.startLineNumber && viewRange.startLineNumber <= endLineNumber) {\n\t\t\t\t\tconst inlineDecoration = new InlineDecoration(\n\t\t\t\t\t\tnew Range(viewRange.startLineNumber, viewRange.startColumn, viewRange.startLineNumber, viewRange.startColumn),\n\t\t\t\t\t\tdecorationOptions.beforeContentClassName,\n\t\t\t\t\t\tInlineDecorationType.Before\n\t\t\t\t\t);\n\t\t\t\t\tinlineDecorations[viewRange.startLineNumber - startLineNumber].push(inlineDecoration);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (decorationOptions.afterContentClassName) {\n\t\t\t\tif (startLineNumber <= viewRange.endLineNumber && viewRange.endLineNumber <= endLineNumber) {\n\t\t\t\t\tconst inlineDecoration = new InlineDecoration(\n\t\t\t\t\t\tnew Range(viewRange.endLineNumber, viewRange.endColumn, viewRange.endLineNumber, viewRange.endColumn),\n\t\t\t\t\t\tdecorationOptions.afterContentClassName,\n\t\t\t\t\t\tInlineDecorationType.After\n\t\t\t\t\t);\n\t\t\t\t\tinlineDecorations[viewRange.endLineNumber - startLineNumber].push(inlineDecoration);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tdecorations: decorationsInViewport,\n\t\t\tinlineDecorations: inlineDecorations\n\t\t};\n\t}\n}\n\nexport function isModelDecorationVisible(model: ITextModel, decoration: IModelDecoration): boolean {\n\tif (decoration.options.hideInCommentTokens && isModelDecorationInComment(model, decoration)) {\n\t\treturn false;\n\t}\n\n\tif (decoration.options.hideInStringTokens && isModelDecorationInString(model, decoration)) {\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n\nexport function isModelDecorationInComment(model: ITextModel, decoration: IModelDecoration): boolean {\n\treturn testTokensInRange(\n\t\tmodel,\n\t\tdecoration.range,\n\t\t(tokenType) => tokenType === StandardTokenType.Comment\n\t);\n}\n\nexport function isModelDecorationInString(model: ITextModel, decoration: IModelDecoration): boolean {\n\treturn testTokensInRange(\n\t\tmodel,\n\t\tdecoration.range,\n\t\t(tokenType) => tokenType === StandardTokenType.String\n\t);\n}\n\n/**\n * Calls the callback for every token that intersects the range.\n * If the callback returns `false`, iteration stops and `false` is returned.\n * Otherwise, `true` is returned.\n */\nfunction testTokensInRange(model: ITextModel, range: Range, callback: (tokenType: StandardTokenType) => boolean): boolean {\n\tfor (let lineNumber = range.startLineNumber; lineNumber <= range.endLineNumber; lineNumber++) {\n\t\tconst lineTokens = model.tokenization.getLineTokens(lineNumber);\n\t\tconst isFirstLine = lineNumber === range.startLineNumber;\n\t\tconst isEndLine = lineNumber === range.endLineNumber;\n\n\t\tlet tokenIdx = isFirstLine ? lineTokens.findTokenIndexAtOffset(range.startColumn - 1) : 0;\n\t\twhile (tokenIdx < lineTokens.getCount()) {\n\t\t\tif (isEndLine) {\n\t\t\t\tconst startOffset = lineTokens.getStartOffset(tokenIdx);\n\t\t\t\tif (startOffset > range.endColumn - 1) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst callbackResult = callback(lineTokens.getStandardTokenType(tokenIdx));\n\t\t\tif (!callbackResult) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\ttokenIdx++;\n\t\t}\n\t}\n\treturn true;\n}\n","\nimport { CancellationToken } from 'vs/base/common/cancellation';\nimport { Codicon } from 'vs/base/common/codicons';\nimport { Color } from 'vs/base/common/color';\nimport { IReadonlyVSDataTransfer } from 'vs/base/common/dataTransfer';\nimport { Event } from 'vs/base/common/event';\nimport { HierarchicalKind } from 'vs/base/common/hierarchicalKind';\nimport { IMarkdownString } from 'vs/base/common/htmlContent';\nimport { IDisposable } from 'vs/base/common/lifecycle';\nimport { ThemeIcon } from 'vs/base/common/themables';\nimport { URI, UriComponents } from 'vs/base/common/uri';\nimport { ISingleEditOperation } from 'vs/editor/common/core/editOperation';\nimport { IPosition, Position } from 'vs/editor/common/core/position';\nimport { IRange, Range } from 'vs/editor/common/core/range';\nimport { Selection } from 'vs/editor/common/core/selection';\nimport { LanguageId } from 'vs/editor/common/encodedTokenAttributes';\nimport { LanguageSelector } from 'vs/editor/common/languageSelector';\nimport * as model from 'vs/editor/common/model';\nimport { TokenizationRegistry as TokenizationRegistryImpl } from 'vs/editor/common/tokenizationRegistry';\nimport { ContiguousMultilineTokens } from 'vs/editor/common/tokens/contiguousMultilineTokens';\nimport { localize } from 'vs/nls';\nimport { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';\nimport { IMarkerData } from 'vs/platform/markers/common/markers';\n\n/**\n * @internal\n */\nexport interface ILanguageIdCodec {\n\tencodeLanguageId(languageId: string): LanguageId;\n\tdecodeLanguageId(languageId: LanguageId): string;\n}\n\nexport class Token {\n\t_tokenBrand: void = undefined;\n\n\tconstructor(\n\t\tpublic readonly offset: number,\n\t\tpublic readonly type: string,\n\t\tpublic readonly language: string,\n\t) {\n\t}\n\n\tpublic toString(): string {\n\t\treturn '(' + this.offset + ', ' + this.type + ')';\n\t}\n}\n\n/**\n * @internal\n */\nexport class TokenizationResult {\n\t_tokenizationResultBrand: void = undefined;\n\n\tconstructor(\n\t\tpublic readonly tokens: Token[],\n\t\tpublic readonly endState: IState,\n\t) {\n\t}\n}\n\n/**\n * @internal\n */\nexport class EncodedTokenizationResult {\n\t_encodedTokenizationResultBrand: void = undefined;\n\n\tconstructor(\n\t\t/**\n\t\t * The tokens in binary format. Each token occupies two array indices. For token i:\n\t\t * - at offset 2*i => startIndex\n\t\t * - at offset 2*i + 1 => metadata\n\t\t *\n\t\t */\n\t\tpublic readonly tokens: Uint32Array,\n\t\tpublic readonly endState: IState,\n\t) {\n\t}\n}\n\n/**\n * @internal\n */\nexport interface ITokenizationSupport {\n\t/**\n\t * If true, the background tokenizer will only be used to verify tokens against the default background tokenizer.\n\t * Used for debugging.\n\t */\n\treadonly backgroundTokenizerShouldOnlyVerifyTokens?: boolean;\n\n\tgetInitialState(): IState;\n\n\ttokenize(line: string, hasEOL: boolean, state: IState): TokenizationResult;\n\n\ttokenizeEncoded(line: string, hasEOL: boolean, state: IState): EncodedTokenizationResult;\n\n\t/**\n\t * Can be/return undefined if default background tokenization should be used.\n\t */\n\tcreateBackgroundTokenizer?(textModel: model.ITextModel, store: IBackgroundTokenizationStore): IBackgroundTokenizer | undefined;\n}\n\n/**\n * @internal\n */\nexport interface IBackgroundTokenizer extends IDisposable {\n\t/**\n\t * Instructs the background tokenizer to set the tokens for the given range again.\n\t *\n\t * This might be necessary if the renderer overwrote those tokens with heuristically computed ones for some viewport,\n\t * when the change does not even propagate to that viewport.\n\t */\n\trequestTokens(startLineNumber: number, endLineNumberExclusive: number): void;\n\n\treportMismatchingTokens?(lineNumber: number): void;\n}\n\n/**\n * @internal\n */\nexport interface IBackgroundTokenizationStore {\n\tsetTokens(tokens: ContiguousMultilineTokens[]): void;\n\n\tsetEndState(lineNumber: number, state: IState): void;\n\n\t/**\n\t * Should be called to indicate that the background tokenization has finished for now.\n\t * (This triggers bracket pair colorization to re-parse the bracket pairs with token information)\n\t */\n\tbackgroundTokenizationFinished(): void;\n}\n\n/**\n * The state of the tokenizer between two lines.\n * It is useful to store flags such as in multiline comment, etc.\n * The model will clone the previous line's state and pass it in to tokenize the next line.\n */\nexport interface IState {\n\tclone(): IState;\n\tequals(other: IState): boolean;\n}\n\n/**\n * A provider result represents the values a provider, like the {@link HoverProvider},\n * may return. For once this is the actual result type `T`, like `Hover`, or a thenable that resolves\n * to that type `T`. In addition, `null` and `undefined` can be returned - either directly or from a\n * thenable.\n */\nexport type ProviderResult = T | undefined | null | Thenable;\n\n/**\n * A hover represents additional information for a symbol or word. Hovers are\n * rendered in a tooltip-like widget.\n */\nexport interface Hover {\n\t/**\n\t * The contents of this hover.\n\t */\n\tcontents: IMarkdownString[];\n\n\t/**\n\t * The range to which this hover applies. When missing, the\n\t * editor will use the range at the current position or the\n\t * current position itself.\n\t */\n\trange?: IRange;\n\n\t/**\n\t * Can increase the verbosity of the hover\n\t */\n\tcanIncreaseVerbosity?: boolean;\n\n\t/**\n\t * Can decrease the verbosity of the hover\n\t */\n\tcanDecreaseVerbosity?: boolean;\n}\n\n/**\n * The hover provider interface defines the contract between extensions and\n * the [hover](https://code.visualstudio.com/docs/editor/intellisense)-feature.\n */\nexport interface HoverProvider {\n\t/**\n\t * Provide a hover for the given position, context and document. Multiple hovers at the same\n\t * position will be merged by the editor. A hover can have a range which defaults\n\t * to the word range at the position when omitted.\n\t */\n\tprovideHover(model: model.ITextModel, position: Position, token: CancellationToken, context?: HoverContext): ProviderResult;\n}\n\nexport interface HoverContext {\n\t/**\n\t * Hover verbosity request\n\t */\n\tverbosityRequest?: HoverVerbosityRequest;\n}\n\nexport interface HoverVerbosityRequest {\n\t/**\n\t * The delta by which to increase/decrease the hover verbosity level\n\t */\n\tverbosityDelta: number;\n\t/**\n\t * The previous hover for the same position\n\t */\n\tpreviousHover: THover;\n}\n\nexport enum HoverVerbosityAction {\n\t/**\n\t * Increase the verbosity of the hover\n\t */\n\tIncrease,\n\t/**\n\t * Decrease the verbosity of the hover\n\t */\n\tDecrease\n}\n\nexport const enum CompletionItemKind {\n\tMethod,\n\tFunction,\n\tConstructor,\n\tField,\n\tVariable,\n\tClass,\n\tStruct,\n\tInterface,\n\tModule,\n\tProperty,\n\tEvent,\n\tOperator,\n\tUnit,\n\tValue,\n\tConstant,\n\tEnum,\n\tEnumMember,\n\tKeyword,\n\tText,\n\tColor,\n\tFile,\n\tReference,\n\tCustomcolor,\n\tFolder,\n\tTypeParameter,\n\tUser,\n\tIssue,\n\tSnippet, // <- highest value (used for compare!)\n}\n\n/**\n * @internal\n */\nexport namespace CompletionItemKinds {\n\n\tconst byKind = new Map();\n\tbyKind.set(CompletionItemKind.Method, Codicon.symbolMethod);\n\tbyKind.set(CompletionItemKind.Function, Codicon.symbolFunction);\n\tbyKind.set(CompletionItemKind.Constructor, Codicon.symbolConstructor);\n\tbyKind.set(CompletionItemKind.Field, Codicon.symbolField);\n\tbyKind.set(CompletionItemKind.Variable, Codicon.symbolVariable);\n\tbyKind.set(CompletionItemKind.Class, Codicon.symbolClass);\n\tbyKind.set(CompletionItemKind.Struct, Codicon.symbolStruct);\n\tbyKind.set(CompletionItemKind.Interface, Codicon.symbolInterface);\n\tbyKind.set(CompletionItemKind.Module, Codicon.symbolModule);\n\tbyKind.set(CompletionItemKind.Property, Codicon.symbolProperty);\n\tbyKind.set(CompletionItemKind.Event, Codicon.symbolEvent);\n\tbyKind.set(CompletionItemKind.Operator, Codicon.symbolOperator);\n\tbyKind.set(CompletionItemKind.Unit, Codicon.symbolUnit);\n\tbyKind.set(CompletionItemKind.Value, Codicon.symbolValue);\n\tbyKind.set(CompletionItemKind.Enum, Codicon.symbolEnum);\n\tbyKind.set(CompletionItemKind.Constant, Codicon.symbolConstant);\n\tbyKind.set(CompletionItemKind.Enum, Codicon.symbolEnum);\n\tbyKind.set(CompletionItemKind.EnumMember, Codicon.symbolEnumMember);\n\tbyKind.set(CompletionItemKind.Keyword, Codicon.symbolKeyword);\n\tbyKind.set(CompletionItemKind.Snippet, Codicon.symbolSnippet);\n\tbyKind.set(CompletionItemKind.Text, Codicon.symbolText);\n\tbyKind.set(CompletionItemKind.Color, Codicon.symbolColor);\n\tbyKind.set(CompletionItemKind.File, Codicon.symbolFile);\n\tbyKind.set(CompletionItemKind.Reference, Codicon.symbolReference);\n\tbyKind.set(CompletionItemKind.Customcolor, Codicon.symbolCustomColor);\n\tbyKind.set(CompletionItemKind.Folder, Codicon.symbolFolder);\n\tbyKind.set(CompletionItemKind.TypeParameter, Codicon.symbolTypeParameter);\n\tbyKind.set(CompletionItemKind.User, Codicon.account);\n\tbyKind.set(CompletionItemKind.Issue, Codicon.issues);\n\n\t/**\n\t * @internal\n\t */\n\texport function toIcon(kind: CompletionItemKind): ThemeIcon {\n\t\tlet codicon = byKind.get(kind);\n\t\tif (!codicon) {\n\t\t\tconsole.info('No codicon found for CompletionItemKind ' + kind);\n\t\t\tcodicon = Codicon.symbolProperty;\n\t\t}\n\t\treturn codicon;\n\t}\n\n\tconst data = new Map();\n\tdata.set('method', CompletionItemKind.Method);\n\tdata.set('function', CompletionItemKind.Function);\n\tdata.set('constructor', CompletionItemKind.Constructor);\n\tdata.set('field', CompletionItemKind.Field);\n\tdata.set('variable', CompletionItemKind.Variable);\n\tdata.set('class', CompletionItemKind.Class);\n\tdata.set('struct', CompletionItemKind.Struct);\n\tdata.set('interface', CompletionItemKind.Interface);\n\tdata.set('module', CompletionItemKind.Module);\n\tdata.set('property', CompletionItemKind.Property);\n\tdata.set('event', CompletionItemKind.Event);\n\tdata.set('operator', CompletionItemKind.Operator);\n\tdata.set('unit', CompletionItemKind.Unit);\n\tdata.set('value', CompletionItemKind.Value);\n\tdata.set('constant', CompletionItemKind.Constant);\n\tdata.set('enum', CompletionItemKind.Enum);\n\tdata.set('enum-member', CompletionItemKind.EnumMember);\n\tdata.set('enumMember', CompletionItemKind.EnumMember);\n\tdata.set('keyword', CompletionItemKind.Keyword);\n\tdata.set('snippet', CompletionItemKind.Snippet);\n\tdata.set('text', CompletionItemKind.Text);\n\tdata.set('color', CompletionItemKind.Color);\n\tdata.set('file', CompletionItemKind.File);\n\tdata.set('reference', CompletionItemKind.Reference);\n\tdata.set('customcolor', CompletionItemKind.Customcolor);\n\tdata.set('folder', CompletionItemKind.Folder);\n\tdata.set('type-parameter', CompletionItemKind.TypeParameter);\n\tdata.set('typeParameter', CompletionItemKind.TypeParameter);\n\tdata.set('account', CompletionItemKind.User);\n\tdata.set('issue', CompletionItemKind.Issue);\n\n\t/**\n\t * @internal\n\t */\n\texport function fromString(value: string): CompletionItemKind;\n\t/**\n\t * @internal\n\t */\n\texport function fromString(value: string, strict: true): CompletionItemKind | undefined;\n\t/**\n\t * @internal\n\t */\n\texport function fromString(value: string, strict?: boolean): CompletionItemKind | undefined {\n\t\tlet res = data.get(value);\n\t\tif (typeof res === 'undefined' && !strict) {\n\t\t\tres = CompletionItemKind.Property;\n\t\t}\n\t\treturn res;\n\t}\n}\n\nexport interface CompletionItemLabel {\n\tlabel: string;\n\tdetail?: string;\n\tdescription?: string;\n}\n\nexport const enum CompletionItemTag {\n\tDeprecated = 1\n}\n\nexport const enum CompletionItemInsertTextRule {\n\tNone = 0,\n\n\t/**\n\t * Adjust whitespace/indentation of multiline insert texts to\n\t * match the current line indentation.\n\t */\n\tKeepWhitespace = 0b001,\n\n\t/**\n\t * `insertText` is a snippet.\n\t */\n\tInsertAsSnippet = 0b100,\n}\n\nexport interface CompletionItemRanges {\n\tinsert: IRange;\n\treplace: IRange;\n}\n\n/**\n * A completion item represents a text snippet that is\n * proposed to complete text that is being typed.\n */\nexport interface CompletionItem {\n\t/**\n\t * The label of this completion item. By default\n\t * this is also the text that is inserted when selecting\n\t * this completion.\n\t */\n\tlabel: string | CompletionItemLabel;\n\t/**\n\t * The kind of this completion item. Based on the kind\n\t * an icon is chosen by the editor.\n\t */\n\tkind: CompletionItemKind;\n\t/**\n\t * A modifier to the `kind` which affect how the item\n\t * is rendered, e.g. Deprecated is rendered with a strikeout\n\t */\n\ttags?: ReadonlyArray;\n\t/**\n\t * A human-readable string with additional information\n\t * about this item, like type or symbol information.\n\t */\n\tdetail?: string;\n\t/**\n\t * A human-readable string that represents a doc-comment.\n\t */\n\tdocumentation?: string | IMarkdownString;\n\t/**\n\t * A string that should be used when comparing this item\n\t * with other items. When `falsy` the {@link CompletionItem.label label}\n\t * is used.\n\t */\n\tsortText?: string;\n\t/**\n\t * A string that should be used when filtering a set of\n\t * completion items. When `falsy` the {@link CompletionItem.label label}\n\t * is used.\n\t */\n\tfilterText?: string;\n\t/**\n\t * Select this item when showing. *Note* that only one completion item can be selected and\n\t * that the editor decides which item that is. The rule is that the *first* item of those\n\t * that match best is selected.\n\t */\n\tpreselect?: boolean;\n\t/**\n\t * A string or snippet that should be inserted in a document when selecting\n\t * this completion.\n\t */\n\tinsertText: string;\n\t/**\n\t * Additional rules (as bitmask) that should be applied when inserting\n\t * this completion.\n\t */\n\tinsertTextRules?: CompletionItemInsertTextRule;\n\t/**\n\t * A range of text that should be replaced by this completion item.\n\t *\n\t * Defaults to a range from the start of the {@link TextDocument.getWordRangeAtPosition current word} to the\n\t * current position.\n\t *\n\t * *Note:* The range must be a {@link Range.isSingleLine single line} and it must\n\t * {@link Range.contains contain} the position at which completion has been {@link CompletionItemProvider.provideCompletionItems requested}.\n\t */\n\trange: IRange | CompletionItemRanges;\n\t/**\n\t * An optional set of characters that when pressed while this completion is active will accept it first and\n\t * then type that character. *Note* that all commit characters should have `length=1` and that superfluous\n\t * characters will be ignored.\n\t */\n\tcommitCharacters?: string[];\n\t/**\n\t * An optional array of additional text edits that are applied when\n\t * selecting this completion. Edits must not overlap with the main edit\n\t * nor with themselves.\n\t */\n\tadditionalTextEdits?: ISingleEditOperation[];\n\t/**\n\t * A command that should be run upon acceptance of this item.\n\t */\n\tcommand?: Command;\n\t/**\n\t * @internal\n\t */\n\textensionId?: ExtensionIdentifier;\n}\n\nexport interface CompletionList {\n\tsuggestions: CompletionItem[];\n\tincomplete?: boolean;\n\tdispose?(): void;\n\n\t/**\n\t * @internal\n\t */\n\tduration?: number;\n}\n\n/**\n * Info provided on partial acceptance.\n */\nexport interface PartialAcceptInfo {\n\tkind: PartialAcceptTriggerKind;\n}\n\n/**\n * How a partial acceptance was triggered.\n */\nexport const enum PartialAcceptTriggerKind {\n\tWord = 0,\n\tLine = 1,\n\tSuggest = 2,\n}\n\n/**\n * How a suggest provider was triggered.\n */\nexport const enum CompletionTriggerKind {\n\tInvoke = 0,\n\tTriggerCharacter = 1,\n\tTriggerForIncompleteCompletions = 2\n}\n/**\n * Contains additional information about the context in which\n * {@link CompletionItemProvider.provideCompletionItems completion provider} is triggered.\n */\nexport interface CompletionContext {\n\t/**\n\t * How the completion was triggered.\n\t */\n\ttriggerKind: CompletionTriggerKind;\n\t/**\n\t * Character that triggered the completion item provider.\n\t *\n\t * `undefined` if provider was not triggered by a character.\n\t */\n\ttriggerCharacter?: string;\n}\n/**\n * The completion item provider interface defines the contract between extensions and\n * the [IntelliSense](https://code.visualstudio.com/docs/editor/intellisense).\n *\n * When computing *complete* completion items is expensive, providers can optionally implement\n * the `resolveCompletionItem`-function. In that case it is enough to return completion\n * items with a {@link CompletionItem.label label} from the\n * {@link CompletionItemProvider.provideCompletionItems provideCompletionItems}-function. Subsequently,\n * when a completion item is shown in the UI and gains focus this provider is asked to resolve\n * the item, like adding {@link CompletionItem.documentation doc-comment} or {@link CompletionItem.detail details}.\n */\nexport interface CompletionItemProvider {\n\n\t/**\n\t * Used to identify completions in the (debug) UI and telemetry. This isn't the extension identifier because extensions\n\t * often contribute multiple completion item providers.\n\t *\n\t * @internal\n\t */\n\t_debugDisplayName: string;\n\n\ttriggerCharacters?: string[];\n\t/**\n\t * Provide completion items for the given position and document.\n\t */\n\tprovideCompletionItems(model: model.ITextModel, position: Position, context: CompletionContext, token: CancellationToken): ProviderResult;\n\n\t/**\n\t * Given a completion item fill in more data, like {@link CompletionItem.documentation doc-comment}\n\t * or {@link CompletionItem.detail details}.\n\t *\n\t * The editor will only resolve a completion item once.\n\t */\n\tresolveCompletionItem?(item: CompletionItem, token: CancellationToken): ProviderResult;\n}\n\n/**\n * How an {@link InlineCompletionsProvider inline completion provider} was triggered.\n */\nexport enum InlineCompletionTriggerKind {\n\t/**\n\t * Completion was triggered automatically while editing.\n\t * It is sufficient to return a single completion item in this case.\n\t */\n\tAutomatic = 0,\n\n\t/**\n\t * Completion was triggered explicitly by a user gesture.\n\t * Return multiple completion items to enable cycling through them.\n\t */\n\tExplicit = 1,\n}\n\nexport interface InlineCompletionContext {\n\n\t/**\n\t * How the completion was triggered.\n\t */\n\treadonly triggerKind: InlineCompletionTriggerKind;\n\treadonly selectedSuggestionInfo: SelectedSuggestionInfo | undefined;\n}\n\nexport class SelectedSuggestionInfo {\n\tconstructor(\n\t\tpublic readonly range: IRange,\n\t\tpublic readonly text: string,\n\t\tpublic readonly completionKind: CompletionItemKind,\n\t\tpublic readonly isSnippetText: boolean,\n\t) {\n\t}\n\n\tpublic equals(other: SelectedSuggestionInfo) {\n\t\treturn Range.lift(this.range).equalsRange(other.range)\n\t\t\t&& this.text === other.text\n\t\t\t&& this.completionKind === other.completionKind\n\t\t\t&& this.isSnippetText === other.isSnippetText;\n\t}\n}\n\nexport interface InlineCompletion {\n\t/**\n\t * The text to insert.\n\t * If the text contains a line break, the range must end at the end of a line.\n\t * If existing text should be replaced, the existing text must be a prefix of the text to insert.\n\t *\n\t * The text can also be a snippet. In that case, a preview with default parameters is shown.\n\t * When accepting the suggestion, the full snippet is inserted.\n\t*/\n\treadonly insertText: string | { snippet: string };\n\n\t/**\n\t * A text that is used to decide if this inline completion should be shown.\n\t * An inline completion is shown if the text to replace is a subword of the filter text.\n\t */\n\treadonly filterText?: string;\n\n\t/**\n\t * An optional array of additional text edits that are applied when\n\t * selecting this completion. Edits must not overlap with the main edit\n\t * nor with themselves.\n\t */\n\treadonly additionalTextEdits?: ISingleEditOperation[];\n\n\t/**\n\t * The range to replace.\n\t * Must begin and end on the same line.\n\t*/\n\treadonly range?: IRange;\n\n\treadonly command?: Command;\n\n\t/**\n\t * If set to `true`, unopened closing brackets are removed and unclosed opening brackets are closed.\n\t * Defaults to `false`.\n\t*/\n\treadonly completeBracketPairs?: boolean;\n}\n\nexport interface InlineCompletions {\n\treadonly items: readonly TItem[];\n\t/**\n\t * A list of commands associated with the inline completions of this list.\n\t */\n\treadonly commands?: Command[];\n\n\treadonly suppressSuggestions?: boolean | undefined;\n\n\t/**\n\t * When set and the user types a suggestion without derivating from it, the inline suggestion is not updated.\n\t */\n\treadonly enableForwardStability?: boolean | undefined;\n}\n\nexport type InlineCompletionProviderGroupId = string;\n\nexport interface InlineCompletionsProvider {\n\tprovideInlineCompletions(model: model.ITextModel, position: Position, context: InlineCompletionContext, token: CancellationToken): ProviderResult;\n\n\t/**\n\t * Will be called when an item is shown.\n\t * @param updatedInsertText Is useful to understand bracket completion.\n\t*/\n\thandleItemDidShow?(completions: T, item: T['items'][number], updatedInsertText: string): void;\n\n\t/**\n\t * Will be called when an item is partially accepted.\n\t */\n\thandlePartialAccept?(completions: T, item: T['items'][number], acceptedCharacters: number, info: PartialAcceptInfo): void;\n\n\t/**\n\t * Will be called when a completions list is no longer in use and can be garbage-collected.\n\t*/\n\tfreeInlineCompletions(completions: T): void;\n\n\t/**\n\t * Only used for {@link yieldsToGroupIds}.\n\t * Multiple providers can have the same group id.\n\t */\n\tgroupId?: InlineCompletionProviderGroupId;\n\n\t/**\n\t * Returns a list of preferred provider {@link groupId}s.\n\t * The current provider is only requested for completions if no provider with a preferred group id returned a result.\n\t */\n\tyieldsToGroupIds?: InlineCompletionProviderGroupId[];\n\n\ttoString?(): string;\n}\n\nexport interface CodeAction {\n\ttitle: string;\n\tcommand?: Command;\n\tedit?: WorkspaceEdit;\n\tdiagnostics?: IMarkerData[];\n\tkind?: string;\n\tisPreferred?: boolean;\n\tisAI?: boolean;\n\tdisabled?: string;\n\tranges?: IRange[];\n}\n\nexport const enum CodeActionTriggerType {\n\tInvoke = 1,\n\tAuto = 2,\n}\n\n/**\n * @internal\n */\nexport interface CodeActionContext {\n\tonly?: string;\n\ttrigger: CodeActionTriggerType;\n}\n\nexport interface CodeActionList extends IDisposable {\n\treadonly actions: ReadonlyArray;\n}\n\n/**\n * The code action interface defines the contract between extensions and\n * the [light bulb](https://code.visualstudio.com/docs/editor/editingevolved#_code-action) feature.\n * @internal\n */\nexport interface CodeActionProvider {\n\n\tdisplayName?: string;\n\n\t/**\n\t * Provide commands for the given document and range.\n\t */\n\tprovideCodeActions(model: model.ITextModel, range: Range | Selection, context: CodeActionContext, token: CancellationToken): ProviderResult;\n\n\t/**\n\t * Given a code action fill in the edit. Will only invoked when missing.\n\t */\n\tresolveCodeAction?(codeAction: CodeAction, token: CancellationToken): ProviderResult;\n\n\t/**\n\t * Optional list of CodeActionKinds that this provider returns.\n\t */\n\treadonly providedCodeActionKinds?: ReadonlyArray;\n\n\treadonly documentation?: ReadonlyArray<{ readonly kind: string; readonly command: Command }>;\n\n\t/**\n\t * @internal\n\t */\n\t_getAdditionalMenuItems?(context: CodeActionContext, actions: readonly CodeAction[]): Command[];\n}\n\n/**\n * @internal\n */\nexport interface DocumentPasteEdit {\n\treadonly title: string;\n\treadonly kind: HierarchicalKind;\n\treadonly handledMimeType?: string;\n\treadonly yieldTo?: readonly DropYieldTo[];\n\tinsertText: string | { readonly snippet: string };\n\tadditionalEdit?: WorkspaceEdit;\n}\n\n/**\n * @internal\n */\nexport enum DocumentPasteTriggerKind {\n\tAutomatic = 0,\n\tPasteAs = 1,\n}\n\n/**\n * @internal\n */\nexport interface DocumentPasteContext {\n\treadonly only?: HierarchicalKind;\n\treadonly triggerKind: DocumentPasteTriggerKind;\n}\n\n/**\n * @internal\n */\nexport interface DocumentPasteEditsSession {\n\tedits: readonly DocumentPasteEdit[];\n\tdispose(): void;\n}\n\n/**\n * @internal\n */\nexport interface DocumentPasteEditProvider {\n\treadonly id?: string;\n\treadonly copyMimeTypes?: readonly string[];\n\treadonly pasteMimeTypes?: readonly string[];\n\treadonly providedPasteEditKinds?: readonly HierarchicalKind[];\n\n\tprepareDocumentPaste?(model: model.ITextModel, ranges: readonly IRange[], dataTransfer: IReadonlyVSDataTransfer, token: CancellationToken): Promise;\n\n\tprovideDocumentPasteEdits?(model: model.ITextModel, ranges: readonly IRange[], dataTransfer: IReadonlyVSDataTransfer, context: DocumentPasteContext, token: CancellationToken): Promise;\n\n\tresolveDocumentPasteEdit?(edit: DocumentPasteEdit, token: CancellationToken): Promise;\n}\n\n/**\n * Represents a parameter of a callable-signature. A parameter can\n * have a label and a doc-comment.\n */\nexport interface ParameterInformation {\n\t/**\n\t * The label of this signature. Will be shown in\n\t * the UI.\n\t */\n\tlabel: string | [number, number];\n\t/**\n\t * The human-readable doc-comment of this signature. Will be shown\n\t * in the UI but can be omitted.\n\t */\n\tdocumentation?: string | IMarkdownString;\n}\n/**\n * Represents the signature of something callable. A signature\n * can have a label, like a function-name, a doc-comment, and\n * a set of parameters.\n */\nexport interface SignatureInformation {\n\t/**\n\t * The label of this signature. Will be shown in\n\t * the UI.\n\t */\n\tlabel: string;\n\t/**\n\t * The human-readable doc-comment of this signature. Will be shown\n\t * in the UI but can be omitted.\n\t */\n\tdocumentation?: string | IMarkdownString;\n\t/**\n\t * The parameters of this signature.\n\t */\n\tparameters: ParameterInformation[];\n\t/**\n\t * Index of the active parameter.\n\t *\n\t * If provided, this is used in place of `SignatureHelp.activeSignature`.\n\t */\n\tactiveParameter?: number;\n}\n/**\n * Signature help represents the signature of something\n * callable. There can be multiple signatures but only one\n * active and only one active parameter.\n */\nexport interface SignatureHelp {\n\t/**\n\t * One or more signatures.\n\t */\n\tsignatures: SignatureInformation[];\n\t/**\n\t * The active signature.\n\t */\n\tactiveSignature: number;\n\t/**\n\t * The active parameter of the active signature.\n\t */\n\tactiveParameter: number;\n}\n\nexport interface SignatureHelpResult extends IDisposable {\n\tvalue: SignatureHelp;\n}\n\nexport enum SignatureHelpTriggerKind {\n\tInvoke = 1,\n\tTriggerCharacter = 2,\n\tContentChange = 3,\n}\n\nexport interface SignatureHelpContext {\n\treadonly triggerKind: SignatureHelpTriggerKind;\n\treadonly triggerCharacter?: string;\n\treadonly isRetrigger: boolean;\n\treadonly activeSignatureHelp?: SignatureHelp;\n}\n\n/**\n * The signature help provider interface defines the contract between extensions and\n * the [parameter hints](https://code.visualstudio.com/docs/editor/intellisense)-feature.\n */\nexport interface SignatureHelpProvider {\n\n\treadonly signatureHelpTriggerCharacters?: ReadonlyArray;\n\treadonly signatureHelpRetriggerCharacters?: ReadonlyArray;\n\n\t/**\n\t * Provide help for the signature at the given position and document.\n\t */\n\tprovideSignatureHelp(model: model.ITextModel, position: Position, token: CancellationToken, context: SignatureHelpContext): ProviderResult;\n}\n\n/**\n * A document highlight kind.\n */\nexport enum DocumentHighlightKind {\n\t/**\n\t * A textual occurrence.\n\t */\n\tText,\n\t/**\n\t * Read-access of a symbol, like reading a variable.\n\t */\n\tRead,\n\t/**\n\t * Write-access of a symbol, like writing to a variable.\n\t */\n\tWrite\n}\n/**\n * A document highlight is a range inside a text document which deserves\n * special attention. Usually a document highlight is visualized by changing\n * the background color of its range.\n */\nexport interface DocumentHighlight {\n\t/**\n\t * The range this highlight applies to.\n\t */\n\trange: IRange;\n\t/**\n\t * The highlight kind, default is {@link DocumentHighlightKind.Text text}.\n\t */\n\tkind?: DocumentHighlightKind;\n}\n\n/**\n * Represents a set of document highlights for a specific URI.\n */\nexport interface MultiDocumentHighlight {\n\t/**\n\t * The URI of the document that the highlights belong to.\n\t */\n\turi: URI;\n\n\t/**\n\t * The set of highlights for the document.\n\t */\n\thighlights: DocumentHighlight[];\n}\n\n/**\n * The document highlight provider interface defines the contract between extensions and\n * the word-highlight-feature.\n */\nexport interface DocumentHighlightProvider {\n\t/**\n\t * Provide a set of document highlights, like all occurrences of a variable or\n\t * all exit-points of a function.\n\t */\n\tprovideDocumentHighlights(model: model.ITextModel, position: Position, token: CancellationToken): ProviderResult;\n}\n\n/**\n * A provider that can provide document highlights across multiple documents.\n */\nexport interface MultiDocumentHighlightProvider {\n\treadonly selector: LanguageSelector;\n\n\t/**\n\t * Provide a Map of URI --> document highlights, like all occurrences of a variable or\n\t * all exit-points of a function.\n\t *\n\t * Used in cases such as split view, notebooks, etc. where there can be multiple documents\n\t * with shared symbols.\n\t *\n\t * @param primaryModel The primary text model.\n\t * @param position The position at which to provide document highlights.\n\t * @param otherModels The other text models to search for document highlights.\n\t * @param token A cancellation token.\n\t * @returns A map of URI to document highlights.\n\t */\n\tprovideMultiDocumentHighlights(primaryModel: model.ITextModel, position: Position, otherModels: model.ITextModel[], token: CancellationToken): ProviderResult>;\n}\n\n/**\n * The linked editing range provider interface defines the contract between extensions and\n * the linked editing feature.\n */\nexport interface LinkedEditingRangeProvider {\n\n\t/**\n\t * Provide a list of ranges that can be edited together.\n\t */\n\tprovideLinkedEditingRanges(model: model.ITextModel, position: Position, token: CancellationToken): ProviderResult;\n}\n\n/**\n * Represents a list of ranges that can be edited together along with a word pattern to describe valid contents.\n */\nexport interface LinkedEditingRanges {\n\t/**\n\t * A list of ranges that can be edited together. The ranges must have\n\t * identical length and text content. The ranges cannot overlap\n\t */\n\tranges: IRange[];\n\n\t/**\n\t * An optional word pattern that describes valid contents for the given ranges.\n\t * If no pattern is provided, the language configuration's word pattern will be used.\n\t */\n\twordPattern?: RegExp;\n}\n\n/**\n * Value-object that contains additional information when\n * requesting references.\n */\nexport interface ReferenceContext {\n\t/**\n\t * Include the declaration of the current symbol.\n\t */\n\tincludeDeclaration: boolean;\n}\n/**\n * The reference provider interface defines the contract between extensions and\n * the [find references](https://code.visualstudio.com/docs/editor/editingevolved#_peek)-feature.\n */\nexport interface ReferenceProvider {\n\t/**\n\t * Provide a set of project-wide references for the given position and document.\n\t */\n\tprovideReferences(model: model.ITextModel, position: Position, context: ReferenceContext, token: CancellationToken): ProviderResult;\n}\n\n/**\n * Represents a location inside a resource, such as a line\n * inside a text file.\n */\nexport interface Location {\n\t/**\n\t * The resource identifier of this location.\n\t */\n\turi: URI;\n\t/**\n\t * The document range of this locations.\n\t */\n\trange: IRange;\n}\n\nexport interface LocationLink {\n\t/**\n\t * A range to select where this link originates from.\n\t */\n\toriginSelectionRange?: IRange;\n\n\t/**\n\t * The target uri this link points to.\n\t */\n\turi: URI;\n\n\t/**\n\t * The full range this link points to.\n\t */\n\trange: IRange;\n\n\t/**\n\t * A range to select this link points to. Must be contained\n\t * in `LocationLink.range`.\n\t */\n\ttargetSelectionRange?: IRange;\n}\n\n/**\n * @internal\n */\nexport function isLocationLink(thing: any): thing is LocationLink {\n\treturn thing\n\t\t&& URI.isUri((thing as LocationLink).uri)\n\t\t&& Range.isIRange((thing as LocationLink).range)\n\t\t&& (Range.isIRange((thing as LocationLink).originSelectionRange) || Range.isIRange((thing as LocationLink).targetSelectionRange));\n}\n\nexport type Definition = Location | Location[] | LocationLink[];\n\n/**\n * The definition provider interface defines the contract between extensions and\n * the [go to definition](https://code.visualstudio.com/docs/editor/editingevolved#_go-to-definition)\n * and peek definition features.\n */\nexport interface DefinitionProvider {\n\t/**\n\t * Provide the definition of the symbol at the given position and document.\n\t */\n\tprovideDefinition(model: model.ITextModel, position: Position, token: CancellationToken): ProviderResult;\n}\n\n/**\n * The definition provider interface defines the contract between extensions and\n * the [go to definition](https://code.visualstudio.com/docs/editor/editingevolved#_go-to-definition)\n * and peek definition features.\n */\nexport interface DeclarationProvider {\n\t/**\n\t * Provide the declaration of the symbol at the given position and document.\n\t */\n\tprovideDeclaration(model: model.ITextModel, position: Position, token: CancellationToken): ProviderResult;\n}\n\n/**\n * The implementation provider interface defines the contract between extensions and\n * the go to implementation feature.\n */\nexport interface ImplementationProvider {\n\t/**\n\t * Provide the implementation of the symbol at the given position and document.\n\t */\n\tprovideImplementation(model: model.ITextModel, position: Position, token: CancellationToken): ProviderResult;\n}\n\n/**\n * The type definition provider interface defines the contract between extensions and\n * the go to type definition feature.\n */\nexport interface TypeDefinitionProvider {\n\t/**\n\t * Provide the type definition of the symbol at the given position and document.\n\t */\n\tprovideTypeDefinition(model: model.ITextModel, position: Position, token: CancellationToken): ProviderResult;\n}\n\n/**\n * A symbol kind.\n */\nexport const 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\n/**\n * @internal\n */\nexport const symbolKindNames: { [symbol: number]: string } = {\n\t[SymbolKind.Array]: localize('Array', \"array\"),\n\t[SymbolKind.Boolean]: localize('Boolean', \"boolean\"),\n\t[SymbolKind.Class]: localize('Class', \"class\"),\n\t[SymbolKind.Constant]: localize('Constant', \"constant\"),\n\t[SymbolKind.Constructor]: localize('Constructor', \"constructor\"),\n\t[SymbolKind.Enum]: localize('Enum', \"enumeration\"),\n\t[SymbolKind.EnumMember]: localize('EnumMember', \"enumeration member\"),\n\t[SymbolKind.Event]: localize('Event', \"event\"),\n\t[SymbolKind.Field]: localize('Field', \"field\"),\n\t[SymbolKind.File]: localize('File', \"file\"),\n\t[SymbolKind.Function]: localize('Function', \"function\"),\n\t[SymbolKind.Interface]: localize('Interface', \"interface\"),\n\t[SymbolKind.Key]: localize('Key', \"key\"),\n\t[SymbolKind.Method]: localize('Method', \"method\"),\n\t[SymbolKind.Module]: localize('Module', \"module\"),\n\t[SymbolKind.Namespace]: localize('Namespace', \"namespace\"),\n\t[SymbolKind.Null]: localize('Null', \"null\"),\n\t[SymbolKind.Number]: localize('Number', \"number\"),\n\t[SymbolKind.Object]: localize('Object', \"object\"),\n\t[SymbolKind.Operator]: localize('Operator', \"operator\"),\n\t[SymbolKind.Package]: localize('Package', \"package\"),\n\t[SymbolKind.Property]: localize('Property', \"property\"),\n\t[SymbolKind.String]: localize('String', \"string\"),\n\t[SymbolKind.Struct]: localize('Struct', \"struct\"),\n\t[SymbolKind.TypeParameter]: localize('TypeParameter', \"type parameter\"),\n\t[SymbolKind.Variable]: localize('Variable', \"variable\"),\n};\n\n/**\n * @internal\n */\nexport function getAriaLabelForSymbol(symbolName: string, kind: SymbolKind): string {\n\treturn localize('symbolAriaLabel', '{0} ({1})', symbolName, symbolKindNames[kind]);\n}\n\nexport const enum SymbolTag {\n\tDeprecated = 1,\n}\n\n/**\n * @internal\n */\nexport namespace SymbolKinds {\n\n\tconst byKind = new Map();\n\tbyKind.set(SymbolKind.File, Codicon.symbolFile);\n\tbyKind.set(SymbolKind.Module, Codicon.symbolModule);\n\tbyKind.set(SymbolKind.Namespace, Codicon.symbolNamespace);\n\tbyKind.set(SymbolKind.Package, Codicon.symbolPackage);\n\tbyKind.set(SymbolKind.Class, Codicon.symbolClass);\n\tbyKind.set(SymbolKind.Method, Codicon.symbolMethod);\n\tbyKind.set(SymbolKind.Property, Codicon.symbolProperty);\n\tbyKind.set(SymbolKind.Field, Codicon.symbolField);\n\tbyKind.set(SymbolKind.Constructor, Codicon.symbolConstructor);\n\tbyKind.set(SymbolKind.Enum, Codicon.symbolEnum);\n\tbyKind.set(SymbolKind.Interface, Codicon.symbolInterface);\n\tbyKind.set(SymbolKind.Function, Codicon.symbolFunction);\n\tbyKind.set(SymbolKind.Variable, Codicon.symbolVariable);\n\tbyKind.set(SymbolKind.Constant, Codicon.symbolConstant);\n\tbyKind.set(SymbolKind.String, Codicon.symbolString);\n\tbyKind.set(SymbolKind.Number, Codicon.symbolNumber);\n\tbyKind.set(SymbolKind.Boolean, Codicon.symbolBoolean);\n\tbyKind.set(SymbolKind.Array, Codicon.symbolArray);\n\tbyKind.set(SymbolKind.Object, Codicon.symbolObject);\n\tbyKind.set(SymbolKind.Key, Codicon.symbolKey);\n\tbyKind.set(SymbolKind.Null, Codicon.symbolNull);\n\tbyKind.set(SymbolKind.EnumMember, Codicon.symbolEnumMember);\n\tbyKind.set(SymbolKind.Struct, Codicon.symbolStruct);\n\tbyKind.set(SymbolKind.Event, Codicon.symbolEvent);\n\tbyKind.set(SymbolKind.Operator, Codicon.symbolOperator);\n\tbyKind.set(SymbolKind.TypeParameter, Codicon.symbolTypeParameter);\n\t/**\n\t * @internal\n\t */\n\texport function toIcon(kind: SymbolKind): ThemeIcon {\n\t\tlet icon = byKind.get(kind);\n\t\tif (!icon) {\n\t\t\tconsole.info('No codicon found for SymbolKind ' + kind);\n\t\t\ticon = Codicon.symbolProperty;\n\t\t}\n\t\treturn icon;\n\t}\n}\n\nexport interface DocumentSymbol {\n\tname: string;\n\tdetail: string;\n\tkind: SymbolKind;\n\ttags: ReadonlyArray;\n\tcontainerName?: string;\n\trange: IRange;\n\tselectionRange: IRange;\n\tchildren?: DocumentSymbol[];\n}\n\n/**\n * The document symbol provider interface defines the contract between extensions and\n * the [go to symbol](https://code.visualstudio.com/docs/editor/editingevolved#_go-to-symbol)-feature.\n */\nexport interface DocumentSymbolProvider {\n\n\tdisplayName?: string;\n\n\t/**\n\t * Provide symbol information for the given document.\n\t */\n\tprovideDocumentSymbols(model: model.ITextModel, token: CancellationToken): ProviderResult;\n}\n\nexport interface TextEdit {\n\trange: IRange;\n\ttext: string;\n\teol?: model.EndOfLineSequence;\n}\n\n/** @internal */\nexport abstract class TextEdit {\n}\n\n/**\n * Interface used to format a model\n */\nexport interface FormattingOptions {\n\t/**\n\t * Size of a tab in spaces.\n\t */\n\ttabSize: number;\n\t/**\n\t * Prefer spaces over tabs.\n\t */\n\tinsertSpaces: boolean;\n}\n/**\n * The document formatting provider interface defines the contract between extensions and\n * the formatting-feature.\n */\nexport interface DocumentFormattingEditProvider {\n\n\t/**\n\t * @internal\n\t */\n\treadonly extensionId?: ExtensionIdentifier;\n\n\treadonly displayName?: string;\n\n\t/**\n\t * Provide formatting edits for a whole document.\n\t */\n\tprovideDocumentFormattingEdits(model: model.ITextModel, options: FormattingOptions, token: CancellationToken): ProviderResult;\n}\n/**\n * The document formatting provider interface defines the contract between extensions and\n * the formatting-feature.\n */\nexport interface DocumentRangeFormattingEditProvider {\n\t/**\n\t * @internal\n\t */\n\treadonly extensionId?: ExtensionIdentifier;\n\n\treadonly displayName?: string;\n\n\t/**\n\t * Provide formatting edits for a range in a document.\n\t *\n\t * The given range is a hint and providers can decide to format a smaller\n\t * or larger range. Often this is done by adjusting the start and end\n\t * of the range to full syntax nodes.\n\t */\n\tprovideDocumentRangeFormattingEdits(model: model.ITextModel, range: Range, options: FormattingOptions, token: CancellationToken): ProviderResult;\n\n\tprovideDocumentRangesFormattingEdits?(model: model.ITextModel, ranges: Range[], options: FormattingOptions, token: CancellationToken): ProviderResult;\n}\n/**\n * The document formatting provider interface defines the contract between extensions and\n * the formatting-feature.\n */\nexport interface OnTypeFormattingEditProvider {\n\n\tautoFormatTriggerCharacters: string[];\n\n\t/**\n\t * Provide formatting edits after a character has been typed.\n\t *\n\t * The given position and character should hint to the provider\n\t * what range the position to expand to, like find the matching `{`\n\t * when `}` has been entered.\n\t */\n\tprovideOnTypeFormattingEdits(model: model.ITextModel, position: Position, ch: string, options: FormattingOptions, token: CancellationToken): ProviderResult;\n}\n\n/**\n * @internal\n */\nexport interface IInplaceReplaceSupportResult {\n\tvalue: string;\n\trange: IRange;\n}\n\n/**\n * A link inside the editor.\n */\nexport interface ILink {\n\trange: IRange;\n\turl?: URI | string;\n\ttooltip?: string;\n}\n\nexport interface ILinksList {\n\tlinks: ILink[];\n\tdispose?(): void;\n}\n/**\n * A provider of links.\n */\nexport interface LinkProvider {\n\tprovideLinks(model: model.ITextModel, token: CancellationToken): ProviderResult;\n\tresolveLink?: (link: ILink, token: CancellationToken) => ProviderResult;\n}\n\n/**\n * A color in RGBA format.\n */\nexport interface IColor {\n\n\t/**\n\t * The red component in the range [0-1].\n\t */\n\treadonly red: number;\n\n\t/**\n\t * The green component in the range [0-1].\n\t */\n\treadonly green: number;\n\n\t/**\n\t * The blue component in the range [0-1].\n\t */\n\treadonly blue: number;\n\n\t/**\n\t * The alpha component in the range [0-1].\n\t */\n\treadonly alpha: number;\n}\n\n/**\n * String representations for a color\n */\nexport interface IColorPresentation {\n\t/**\n\t * The label of this color presentation. It will be shown on the color\n\t * picker header. By default this is also the text that is inserted when selecting\n\t * this color presentation.\n\t */\n\tlabel: string;\n\t/**\n\t * An {@link TextEdit edit} which is applied to a document when selecting\n\t * this presentation for the color.\n\t */\n\ttextEdit?: TextEdit;\n\t/**\n\t * An optional array of additional {@link TextEdit text edits} that are applied when\n\t * selecting this color presentation.\n\t */\n\tadditionalTextEdits?: TextEdit[];\n}\n\n/**\n * A color range is a range in a text model which represents a color.\n */\nexport interface IColorInformation {\n\n\t/**\n\t * The range within the model.\n\t */\n\trange: IRange;\n\n\t/**\n\t * The color represented in this range.\n\t */\n\tcolor: IColor;\n}\n\n/**\n * A provider of colors for editor models.\n */\nexport interface DocumentColorProvider {\n\t/**\n\t * Provides the color ranges for a specific model.\n\t */\n\tprovideDocumentColors(model: model.ITextModel, token: CancellationToken): ProviderResult;\n\t/**\n\t * Provide the string representations for a color.\n\t */\n\tprovideColorPresentations(model: model.ITextModel, colorInfo: IColorInformation, token: CancellationToken): ProviderResult;\n}\n\nexport interface SelectionRange {\n\trange: IRange;\n}\n\nexport interface SelectionRangeProvider {\n\t/**\n\t * Provide ranges that should be selected from the given position.\n\t */\n\tprovideSelectionRanges(model: model.ITextModel, positions: Position[], token: CancellationToken): ProviderResult;\n}\n\nexport interface FoldingContext {\n}\n/**\n * A provider of folding ranges for editor models.\n */\nexport interface FoldingRangeProvider {\n\n\t/**\n\t * An optional event to signal that the folding ranges from this provider have changed.\n\t */\n\tonDidChange?: Event;\n\n\t/**\n\t * Provides the folding ranges for a specific model.\n\t */\n\tprovideFoldingRanges(model: model.ITextModel, context: FoldingContext, token: CancellationToken): ProviderResult;\n}\n\nexport interface FoldingRange {\n\n\t/**\n\t * The one-based start line of the range to fold. The folded area starts after the line's last character.\n\t */\n\tstart: number;\n\n\t/**\n\t * The one-based end line of the range to fold. The folded area ends with the line's last character.\n\t */\n\tend: number;\n\n\t/**\n\t * Describes the {@link FoldingRangeKind Kind} of the folding range such as {@link FoldingRangeKind.Comment Comment} or\n\t * {@link FoldingRangeKind.Region Region}. The kind is used to categorize folding ranges and used by commands\n\t * like 'Fold all comments'. See\n\t * {@link FoldingRangeKind} for an enumeration of standardized kinds.\n\t */\n\tkind?: FoldingRangeKind;\n}\nexport class FoldingRangeKind {\n\t/**\n\t * Kind for folding range representing a comment. The value of the kind is 'comment'.\n\t */\n\tstatic readonly Comment = new FoldingRangeKind('comment');\n\t/**\n\t * Kind for folding range representing a import. The value of the kind is 'imports'.\n\t */\n\tstatic readonly Imports = new FoldingRangeKind('imports');\n\t/**\n\t * Kind for folding range representing regions (for example marked by `#region`, `#endregion`).\n\t * The value of the kind is 'region'.\n\t */\n\tstatic readonly Region = new FoldingRangeKind('region');\n\n\t/**\n\t * Returns a {@link FoldingRangeKind} for the given value.\n\t *\n\t * @param value of the kind.\n\t */\n\tstatic fromValue(value: string) {\n\t\tswitch (value) {\n\t\t\tcase 'comment': return FoldingRangeKind.Comment;\n\t\t\tcase 'imports': return FoldingRangeKind.Imports;\n\t\t\tcase 'region': return FoldingRangeKind.Region;\n\t\t}\n\t\treturn new FoldingRangeKind(value);\n\t}\n\n\t/**\n\t * Creates a new {@link FoldingRangeKind}.\n\t *\n\t * @param value of the kind.\n\t */\n\tpublic constructor(public value: string) {\n\t}\n}\n\n\nexport interface WorkspaceEditMetadata {\n\tneedsConfirmation: boolean;\n\tlabel: string;\n\tdescription?: string;\n}\n\nexport interface WorkspaceFileEditOptions {\n\toverwrite?: boolean;\n\tignoreIfNotExists?: boolean;\n\tignoreIfExists?: boolean;\n\trecursive?: boolean;\n\tcopy?: boolean;\n\tfolder?: boolean;\n\tskipTrashBin?: boolean;\n\tmaxSize?: number;\n}\n\nexport interface IWorkspaceFileEdit {\n\toldResource?: URI;\n\tnewResource?: URI;\n\toptions?: WorkspaceFileEditOptions;\n\tmetadata?: WorkspaceEditMetadata;\n}\n\nexport interface IWorkspaceTextEdit {\n\tresource: URI;\n\ttextEdit: TextEdit & { insertAsSnippet?: boolean };\n\tversionId: number | undefined;\n\tmetadata?: WorkspaceEditMetadata;\n}\n\nexport interface WorkspaceEdit {\n\tedits: Array;\n}\n\nexport interface Rejection {\n\trejectReason?: string;\n}\nexport interface RenameLocation {\n\trange: IRange;\n\ttext: string;\n}\n\nexport interface RenameProvider {\n\tprovideRenameEdits(model: model.ITextModel, position: Position, newName: string, token: CancellationToken): ProviderResult;\n\tresolveRenameLocation?(model: model.ITextModel, position: Position, token: CancellationToken): ProviderResult;\n}\n\nexport enum NewSymbolNameTag {\n\tAIGenerated = 1\n}\n\nexport enum NewSymbolNameTriggerKind {\n\tInvoke = 0,\n\tAutomatic = 1,\n}\n\nexport interface NewSymbolName {\n\treadonly newSymbolName: string;\n\treadonly tags?: readonly NewSymbolNameTag[];\n}\n\nexport interface NewSymbolNamesProvider {\n\tsupportsAutomaticNewSymbolNamesTriggerKind?: Promise;\n\tprovideNewSymbolNames(model: model.ITextModel, range: IRange, triggerKind: NewSymbolNameTriggerKind, token: CancellationToken): ProviderResult;\n}\n\nexport interface Command {\n\tid: string;\n\ttitle: string;\n\ttooltip?: string;\n\targuments?: any[];\n}\n\n/**\n * @internal\n */\nexport namespace Command {\n\n\t/**\n\t * @internal\n\t */\n\texport function is(obj: any): obj is Command {\n\t\tif (!obj || typeof obj !== 'object') {\n\t\t\treturn false;\n\t\t}\n\t\treturn typeof (obj).id === 'string' &&\n\t\t\ttypeof (obj).title === 'string';\n\t}\n}\n\nexport interface CommentAuthorInformation {\n\tname: string;\n\ticonPath?: UriComponents;\n\n}\n\nexport interface PendingCommentThread {\n\tbody: string;\n\trange: IRange | undefined;\n\turi: URI;\n\tuniqueOwner: string;\n\tisReply: boolean;\n}\n\nexport interface CodeLens {\n\trange: IRange;\n\tid?: string;\n\tcommand?: Command;\n}\n\nexport interface CodeLensList {\n\tlenses: CodeLens[];\n\tdispose(): void;\n}\n\nexport interface CodeLensProvider {\n\tonDidChange?: Event;\n\tprovideCodeLenses(model: model.ITextModel, token: CancellationToken): ProviderResult;\n\tresolveCodeLens?(model: model.ITextModel, codeLens: CodeLens, token: CancellationToken): ProviderResult;\n}\n\n\nexport enum InlayHintKind {\n\tType = 1,\n\tParameter = 2,\n}\n\nexport interface InlayHintLabelPart {\n\tlabel: string;\n\ttooltip?: string | IMarkdownString;\n\t// collapsible?: boolean;\n\tcommand?: Command;\n\tlocation?: Location;\n}\n\nexport interface InlayHint {\n\tlabel: string | InlayHintLabelPart[];\n\ttooltip?: string | IMarkdownString;\n\ttextEdits?: TextEdit[];\n\tposition: IPosition;\n\tkind?: InlayHintKind;\n\tpaddingLeft?: boolean;\n\tpaddingRight?: boolean;\n}\n\nexport interface InlayHintList {\n\thints: InlayHint[];\n\tdispose(): void;\n}\n\nexport interface InlayHintsProvider {\n\tdisplayName?: string;\n\tonDidChangeInlayHints?: Event;\n\tprovideInlayHints(model: model.ITextModel, range: Range, token: CancellationToken): ProviderResult;\n\tresolveInlayHint?(hint: InlayHint, token: CancellationToken): ProviderResult;\n}\n\nexport interface SemanticTokensLegend {\n\treadonly tokenTypes: string[];\n\treadonly tokenModifiers: string[];\n}\n\nexport interface SemanticTokens {\n\treadonly resultId?: string;\n\treadonly data: Uint32Array;\n}\n\nexport interface SemanticTokensEdit {\n\treadonly start: number;\n\treadonly deleteCount: number;\n\treadonly data?: Uint32Array;\n}\n\nexport interface SemanticTokensEdits {\n\treadonly resultId?: string;\n\treadonly edits: SemanticTokensEdit[];\n}\n\nexport interface DocumentSemanticTokensProvider {\n\tonDidChange?: Event;\n\tgetLegend(): SemanticTokensLegend;\n\tprovideDocumentSemanticTokens(model: model.ITextModel, lastResultId: string | null, token: CancellationToken): ProviderResult;\n\treleaseDocumentSemanticTokens(resultId: string | undefined): void;\n}\n\nexport interface DocumentRangeSemanticTokensProvider {\n\tgetLegend(): SemanticTokensLegend;\n\tprovideDocumentRangeSemanticTokens(model: model.ITextModel, range: Range, token: CancellationToken): ProviderResult;\n}\n\n/**\n * @internal\n */\nexport interface ITokenizationSupportChangedEvent {\n\tchangedLanguages: string[];\n\tchangedColorMap: boolean;\n}\n\n/**\n * @internal\n */\nexport interface ILazyTokenizationSupport {\n\tget tokenizationSupport(): Promise;\n}\n\n/**\n * @internal\n */\nexport class LazyTokenizationSupport implements IDisposable, ILazyTokenizationSupport {\n\tprivate _tokenizationSupport: Promise | null = null;\n\n\tconstructor(private readonly createSupport: () => Promise) {\n\t}\n\n\tdispose(): void {\n\t\tif (this._tokenizationSupport) {\n\t\t\tthis._tokenizationSupport.then((support) => {\n\t\t\t\tif (support) {\n\t\t\t\t\tsupport.dispose();\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\n\tget tokenizationSupport(): Promise {\n\t\tif (!this._tokenizationSupport) {\n\t\t\tthis._tokenizationSupport = this.createSupport();\n\t\t}\n\t\treturn this._tokenizationSupport;\n\t}\n}\n\n/**\n * @internal\n */\nexport interface ITokenizationRegistry {\n\n\t/**\n\t * An event triggered when:\n\t * - a tokenization support is registered, unregistered or changed.\n\t * - the color map is changed.\n\t */\n\tonDidChange: Event;\n\n\t/**\n\t * Fire a change event for a language.\n\t * This is useful for languages that embed other languages.\n\t */\n\thandleChange(languageIds: string[]): void;\n\n\t/**\n\t * Register a tokenization support.\n\t */\n\tregister(languageId: string, support: ITokenizationSupport): IDisposable;\n\n\t/**\n\t * Register a tokenization support factory.\n\t */\n\tregisterFactory(languageId: string, factory: ILazyTokenizationSupport): IDisposable;\n\n\t/**\n\t * Get or create the tokenization support for a language.\n\t * Returns `null` if not found.\n\t */\n\tgetOrCreate(languageId: string): Promise;\n\n\t/**\n\t * Get the tokenization support for a language.\n\t * Returns `null` if not found.\n\t */\n\tget(languageId: string): ITokenizationSupport | null;\n\n\t/**\n\t * Returns false if a factory is still pending.\n\t */\n\tisResolved(languageId: string): boolean;\n\n\t/**\n\t * Set the new color map that all tokens will use in their ColorId binary encoded bits for foreground and background.\n\t */\n\tsetColorMap(colorMap: Color[]): void;\n\n\tgetColorMap(): Color[] | null;\n\n\tgetDefaultBackground(): Color | null;\n}\n\n/**\n * @internal\n */\nexport const TokenizationRegistry: ITokenizationRegistry = new TokenizationRegistryImpl();\n\n/**\n * @internal\n */\nexport type DropYieldTo = { readonly kind: HierarchicalKind } | { readonly mimeType: string };\n\n/**\n * @internal\n */\nexport interface DocumentDropEdit {\n\treadonly title: string;\n\treadonly kind: HierarchicalKind | undefined;\n\treadonly handledMimeType?: string;\n\treadonly yieldTo?: readonly DropYieldTo[];\n\tinsertText: string | { readonly snippet: string };\n\tadditionalEdit?: WorkspaceEdit;\n}\n\n/**\n * @internal\n */\nexport interface DocumentDropEditProvider {\n\treadonly id?: string;\n\treadonly dropMimeTypes?: readonly string[];\n\n\tprovideDocumentDropEdits(model: model.ITextModel, position: IPosition, dataTransfer: IReadonlyVSDataTransfer, token: CancellationToken): ProviderResult;\n}\n\nexport interface DocumentContextItem {\n\treadonly uri: URI;\n\treadonly version: number;\n\treadonly ranges: IRange[];\n}\n\nexport interface MappedEditsContext {\n\t/** The outer array is sorted by priority - from highest to lowest. The inner arrays contain elements of the same priority. */\n\tdocuments: DocumentContextItem[][];\n}\n\nexport interface MappedEditsProvider {\n\n\t/**\n\t * Provider maps code blocks from the chat into a workspace edit.\n\t *\n\t * @param document The document to provide mapped edits for.\n\t * @param codeBlocks Code blocks that come from an LLM's reply.\n\t * \t\t\t\t\t\t\"Insert at cursor\" in the panel chat only sends one edit that the user clicks on, but inline chat can send multiple blocks and let the lang server decide what to do with them.\n\t * @param context The context for providing mapped edits.\n\t * @param token A cancellation token.\n\t * @returns A provider result of text edits.\n\t */\n\tprovideMappedEdits(\n\t\tdocument: model.ITextModel,\n\t\tcodeBlocks: string[],\n\t\tcontext: MappedEditsContext,\n\t\ttoken: CancellationToken\n\t): Promise;\n}\n\nexport interface IInlineEdit {\n\ttext: string;\n\trange: IRange;\n\taccepted?: Command;\n\trejected?: Command;\n}\n\nexport interface IInlineEditContext {\n\ttriggerKind: InlineEditTriggerKind;\n}\n\nexport enum InlineEditTriggerKind {\n\tInvoke = 0,\n\tAutomatic = 1,\n}\n\nexport interface InlineEditProvider {\n\tprovideInlineEdit(model: model.ITextModel, context: IInlineEditContext, token: CancellationToken): ProviderResult;\n\tfreeInlineEdit(edit: T): void;\n}\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\nimport { Token, TokenizationResult, EncodedTokenizationResult, IState } from 'vs/editor/common/languages';\nimport { LanguageId, FontStyle, ColorId, StandardTokenType, MetadataConsts } from 'vs/editor/common/encodedTokenAttributes';\n\nexport const NullState: IState = new class implements IState {\n\tpublic clone(): IState {\n\t\treturn this;\n\t}\n\tpublic equals(other: IState): boolean {\n\t\treturn (this === other);\n\t}\n};\n\nexport function nullTokenize(languageId: string, state: IState): TokenizationResult {\n\treturn new TokenizationResult([new Token(0, '', languageId)], state);\n}\n\nexport function nullTokenizeEncoded(languageId: LanguageId, state: IState | null): EncodedTokenizationResult {\n\tconst tokens = new Uint32Array(2);\n\ttokens[0] = 0;\n\ttokens[1] = (\n\t\t(languageId << MetadataConsts.LANGUAGEID_OFFSET)\n\t\t| (StandardTokenType.Other << MetadataConsts.TOKEN_TYPE_OFFSET)\n\t\t| (FontStyle.None << MetadataConsts.FONT_STYLE_OFFSET)\n\t\t| (ColorId.DefaultForeground << MetadataConsts.FOREGROUND_OFFSET)\n\t\t| (ColorId.DefaultBackground << MetadataConsts.BACKGROUND_OFFSET)\n\t) >>> 0;\n\n\treturn new EncodedTokenizationResult(tokens, state === null ? NullState : state);\n}\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\nimport { CharCode } from 'vs/base/common/charCode';\nimport * as strings from 'vs/base/common/strings';\nimport { IViewLineTokens, LineTokens } from 'vs/editor/common/tokens/lineTokens';\nimport { ILanguageIdCodec, IState, ITokenizationSupport, TokenizationRegistry } from 'vs/editor/common/languages';\nimport { LanguageId } from 'vs/editor/common/encodedTokenAttributes';\nimport { NullState, nullTokenizeEncoded } from 'vs/editor/common/languages/nullTokenize';\nimport { ILanguageService } from 'vs/editor/common/languages/language';\n\nexport type IReducedTokenizationSupport = Omit;\n\nconst fallback: IReducedTokenizationSupport = {\n\tgetInitialState: () => NullState,\n\ttokenizeEncoded: (buffer: string, hasEOL: boolean, state: IState) => nullTokenizeEncoded(LanguageId.Null, state)\n};\n\nexport async function tokenizeToString(languageService: ILanguageService, text: string, languageId: string | null): Promise {\n\tif (!languageId) {\n\t\treturn _tokenizeToString(text, languageService.languageIdCodec, fallback);\n\t}\n\tconst tokenizationSupport = await TokenizationRegistry.getOrCreate(languageId);\n\treturn _tokenizeToString(text, languageService.languageIdCodec, tokenizationSupport || fallback);\n}\n\nexport function tokenizeLineToHTML(text: string, viewLineTokens: IViewLineTokens, colorMap: string[], startOffset: number, endOffset: number, tabSize: number, useNbsp: boolean): string {\n\tlet result = `
    `;\n\tlet charIndex = startOffset;\n\tlet tabsCharDelta = 0;\n\n\tlet prevIsSpace = true;\n\n\tfor (let tokenIndex = 0, tokenCount = viewLineTokens.getCount(); tokenIndex < tokenCount; tokenIndex++) {\n\t\tconst tokenEndIndex = viewLineTokens.getEndOffset(tokenIndex);\n\n\t\tif (tokenEndIndex <= startOffset) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tlet partContent = '';\n\n\t\tfor (; charIndex < tokenEndIndex && charIndex < endOffset; charIndex++) {\n\t\t\tconst charCode = text.charCodeAt(charIndex);\n\n\t\t\tswitch (charCode) {\n\t\t\t\tcase CharCode.Tab: {\n\t\t\t\t\tlet insertSpacesCount = tabSize - (charIndex + tabsCharDelta) % tabSize;\n\t\t\t\t\ttabsCharDelta += insertSpacesCount - 1;\n\t\t\t\t\twhile (insertSpacesCount > 0) {\n\t\t\t\t\t\tif (useNbsp && prevIsSpace) {\n\t\t\t\t\t\t\tpartContent += ' ';\n\t\t\t\t\t\t\tprevIsSpace = false;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tpartContent += ' ';\n\t\t\t\t\t\t\tprevIsSpace = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tinsertSpacesCount--;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase CharCode.LessThan:\n\t\t\t\t\tpartContent += '<';\n\t\t\t\t\tprevIsSpace = false;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase CharCode.GreaterThan:\n\t\t\t\t\tpartContent += '>';\n\t\t\t\t\tprevIsSpace = false;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase CharCode.Ampersand:\n\t\t\t\t\tpartContent += '&';\n\t\t\t\t\tprevIsSpace = false;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase CharCode.Null:\n\t\t\t\t\tpartContent += '�';\n\t\t\t\t\tprevIsSpace = false;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase CharCode.UTF8_BOM:\n\t\t\t\tcase CharCode.LINE_SEPARATOR:\n\t\t\t\tcase CharCode.PARAGRAPH_SEPARATOR:\n\t\t\t\tcase CharCode.NEXT_LINE:\n\t\t\t\t\tpartContent += '\\ufffd';\n\t\t\t\t\tprevIsSpace = false;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase CharCode.CarriageReturn:\n\t\t\t\t\t// zero width space, because carriage return would introduce a line break\n\t\t\t\t\tpartContent += '​';\n\t\t\t\t\tprevIsSpace = false;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase CharCode.Space:\n\t\t\t\t\tif (useNbsp && prevIsSpace) {\n\t\t\t\t\t\tpartContent += ' ';\n\t\t\t\t\t\tprevIsSpace = false;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tpartContent += ' ';\n\t\t\t\t\t\tprevIsSpace = true;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tpartContent += String.fromCharCode(charCode);\n\t\t\t\t\tprevIsSpace = false;\n\t\t\t}\n\t\t}\n\n\t\tresult += `${partContent}`;\n\n\t\tif (tokenEndIndex > endOffset || charIndex >= endOffset) {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tresult += `
    `;\n\treturn result;\n}\n\nexport function _tokenizeToString(text: string, languageIdCodec: ILanguageIdCodec, tokenizationSupport: IReducedTokenizationSupport): string {\n\tlet result = `
    `;\n\tconst lines = strings.splitLines(text);\n\tlet currentState = tokenizationSupport.getInitialState();\n\tfor (let i = 0, len = lines.length; i < len; i++) {\n\t\tconst line = lines[i];\n\n\t\tif (i > 0) {\n\t\t\tresult += `
    `;\n\t\t}\n\n\t\tconst tokenizationResult = tokenizationSupport.tokenizeEncoded(line, true, currentState);\n\t\tLineTokens.convertToEndOffset(tokenizationResult.tokens, line.length);\n\t\tconst lineTokens = new LineTokens(tokenizationResult.tokens, line, languageIdCodec);\n\t\tconst viewLineTokens = lineTokens.inflate();\n\n\t\tlet startOffset = 0;\n\t\tfor (let j = 0, lenJ = viewLineTokens.getCount(); j < lenJ; j++) {\n\t\t\tconst type = viewLineTokens.getClassName(j);\n\t\t\tconst endIndex = viewLineTokens.getEndOffset(j);\n\t\t\tresult += `${strings.escape(line.substring(startOffset, endIndex))}`;\n\t\t\tstartOffset = endIndex;\n\t\t}\n\n\t\tcurrentState = tokenizationResult.endState;\n\t}\n\n\tresult += `
    `;\n\treturn result;\n}\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\nimport { IdleDeadline, runWhenGlobalIdle } from 'vs/base/common/async';\nimport { BugIndicatingError, onUnexpectedError } from 'vs/base/common/errors';\nimport { setTimeout0 } from 'vs/base/common/platform';\nimport { StopWatch } from 'vs/base/common/stopwatch';\nimport { countEOL } from 'vs/editor/common/core/eolCounter';\nimport { LineRange } from 'vs/editor/common/core/lineRange';\nimport { OffsetRange } from 'vs/editor/common/core/offsetRange';\nimport { Position } from 'vs/editor/common/core/position';\nimport { StandardTokenType } from 'vs/editor/common/encodedTokenAttributes';\nimport { EncodedTokenizationResult, IBackgroundTokenizationStore, IBackgroundTokenizer, ILanguageIdCodec, IState, ITokenizationSupport } from 'vs/editor/common/languages';\nimport { nullTokenizeEncoded } from 'vs/editor/common/languages/nullTokenize';\nimport { ITextModel } from 'vs/editor/common/model';\nimport { FixedArray } from 'vs/editor/common/model/fixedArray';\nimport { IModelContentChange } from 'vs/editor/common/textModelEvents';\nimport { ContiguousMultilineTokensBuilder } from 'vs/editor/common/tokens/contiguousMultilineTokensBuilder';\nimport { LineTokens } from 'vs/editor/common/tokens/lineTokens';\n\nconst enum Constants {\n\tCHEAP_TOKENIZATION_LENGTH_LIMIT = 2048\n}\n\nexport class TokenizerWithStateStore {\n\tprivate readonly initialState = this.tokenizationSupport.getInitialState() as TState;\n\n\tpublic readonly store: TrackingTokenizationStateStore;\n\n\tconstructor(\n\t\tlineCount: number,\n\t\tpublic readonly tokenizationSupport: ITokenizationSupport\n\t) {\n\t\tthis.store = new TrackingTokenizationStateStore(lineCount);\n\t}\n\n\tpublic getStartState(lineNumber: number): TState | null {\n\t\treturn this.store.getStartState(lineNumber, this.initialState);\n\t}\n\n\tpublic getFirstInvalidLine(): { lineNumber: number; startState: TState } | null {\n\t\treturn this.store.getFirstInvalidLine(this.initialState);\n\t}\n}\n\nexport class TokenizerWithStateStoreAndTextModel extends TokenizerWithStateStore {\n\tconstructor(\n\t\tlineCount: number,\n\t\ttokenizationSupport: ITokenizationSupport,\n\t\tpublic readonly _textModel: ITextModel,\n\t\tpublic readonly _languageIdCodec: ILanguageIdCodec\n\t) {\n\t\tsuper(lineCount, tokenizationSupport);\n\t}\n\n\tpublic updateTokensUntilLine(builder: ContiguousMultilineTokensBuilder, lineNumber: number): void {\n\t\tconst languageId = this._textModel.getLanguageId();\n\n\t\twhile (true) {\n\t\t\tconst lineToTokenize = this.getFirstInvalidLine();\n\t\t\tif (!lineToTokenize || lineToTokenize.lineNumber > lineNumber) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tconst text = this._textModel.getLineContent(lineToTokenize.lineNumber);\n\n\t\t\tconst r = safeTokenize(this._languageIdCodec, languageId, this.tokenizationSupport, text, true, lineToTokenize.startState);\n\t\t\tbuilder.add(lineToTokenize.lineNumber, r.tokens);\n\t\t\tthis.store.setEndState(lineToTokenize.lineNumber, r.endState as TState);\n\t\t}\n\t}\n\n\t/** assumes state is up to date */\n\tpublic getTokenTypeIfInsertingCharacter(position: Position, character: string): StandardTokenType {\n\t\t// TODO@hediet: use tokenizeLineWithEdit\n\t\tconst lineStartState = this.getStartState(position.lineNumber);\n\t\tif (!lineStartState) {\n\t\t\treturn StandardTokenType.Other;\n\t\t}\n\n\t\tconst languageId = this._textModel.getLanguageId();\n\t\tconst lineContent = this._textModel.getLineContent(position.lineNumber);\n\n\t\t// Create the text as if `character` was inserted\n\t\tconst text = (\n\t\t\tlineContent.substring(0, position.column - 1)\n\t\t\t+ character\n\t\t\t+ lineContent.substring(position.column - 1)\n\t\t);\n\n\t\tconst r = safeTokenize(this._languageIdCodec, languageId, this.tokenizationSupport, text, true, lineStartState);\n\t\tconst lineTokens = new LineTokens(r.tokens, text, this._languageIdCodec);\n\t\tif (lineTokens.getCount() === 0) {\n\t\t\treturn StandardTokenType.Other;\n\t\t}\n\n\t\tconst tokenIndex = lineTokens.findTokenIndexAtOffset(position.column - 1);\n\t\treturn lineTokens.getStandardTokenType(tokenIndex);\n\t}\n\n\t/** assumes state is up to date */\n\tpublic tokenizeLineWithEdit(position: Position, length: number, newText: string): LineTokens | null {\n\t\tconst lineNumber = position.lineNumber;\n\t\tconst column = position.column;\n\n\t\tconst lineStartState = this.getStartState(lineNumber);\n\t\tif (!lineStartState) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst curLineContent = this._textModel.getLineContent(lineNumber);\n\t\tconst newLineContent = curLineContent.substring(0, column - 1)\n\t\t\t+ newText + curLineContent.substring(column - 1 + length);\n\n\t\tconst languageId = this._textModel.getLanguageIdAtPosition(lineNumber, 0);\n\t\tconst result = safeTokenize(\n\t\t\tthis._languageIdCodec,\n\t\t\tlanguageId,\n\t\t\tthis.tokenizationSupport,\n\t\t\tnewLineContent,\n\t\t\ttrue,\n\t\t\tlineStartState\n\t\t);\n\n\t\tconst lineTokens = new LineTokens(result.tokens, newLineContent, this._languageIdCodec);\n\t\treturn lineTokens;\n\t}\n\n\tpublic hasAccurateTokensForLine(lineNumber: number): boolean {\n\t\tconst firstInvalidLineNumber = this.store.getFirstInvalidEndStateLineNumberOrMax();\n\t\treturn (lineNumber < firstInvalidLineNumber);\n\t}\n\n\tpublic isCheapToTokenize(lineNumber: number): boolean {\n\t\tconst firstInvalidLineNumber = this.store.getFirstInvalidEndStateLineNumberOrMax();\n\t\tif (lineNumber < firstInvalidLineNumber) {\n\t\t\treturn true;\n\t\t}\n\t\tif (lineNumber === firstInvalidLineNumber\n\t\t\t&& this._textModel.getLineLength(lineNumber) < Constants.CHEAP_TOKENIZATION_LENGTH_LIMIT) {\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/**\n\t * The result is not cached.\n\t */\n\tpublic tokenizeHeuristically(builder: ContiguousMultilineTokensBuilder, startLineNumber: number, endLineNumber: number): { heuristicTokens: boolean } {\n\t\tif (endLineNumber <= this.store.getFirstInvalidEndStateLineNumberOrMax()) {\n\t\t\t// nothing to do\n\t\t\treturn { heuristicTokens: false };\n\t\t}\n\n\t\tif (startLineNumber <= this.store.getFirstInvalidEndStateLineNumberOrMax()) {\n\t\t\t// tokenization has reached the viewport start...\n\t\t\tthis.updateTokensUntilLine(builder, endLineNumber);\n\t\t\treturn { heuristicTokens: false };\n\t\t}\n\n\t\tlet state = this.guessStartState(startLineNumber);\n\t\tconst languageId = this._textModel.getLanguageId();\n\n\t\tfor (let lineNumber = startLineNumber; lineNumber <= endLineNumber; lineNumber++) {\n\t\t\tconst text = this._textModel.getLineContent(lineNumber);\n\t\t\tconst r = safeTokenize(this._languageIdCodec, languageId, this.tokenizationSupport, text, true, state);\n\t\t\tbuilder.add(lineNumber, r.tokens);\n\t\t\tstate = r.endState;\n\t\t}\n\n\t\treturn { heuristicTokens: true };\n\t}\n\n\tprivate guessStartState(lineNumber: number): IState {\n\t\tlet nonWhitespaceColumn = this._textModel.getLineFirstNonWhitespaceColumn(lineNumber);\n\t\tconst likelyRelevantLines: string[] = [];\n\t\tlet initialState: IState | null = null;\n\t\tfor (let i = lineNumber - 1; nonWhitespaceColumn > 1 && i >= 1; i--) {\n\t\t\tconst newNonWhitespaceIndex = this._textModel.getLineFirstNonWhitespaceColumn(i);\n\t\t\t// Ignore lines full of whitespace\n\t\t\tif (newNonWhitespaceIndex === 0) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (newNonWhitespaceIndex < nonWhitespaceColumn) {\n\t\t\t\tlikelyRelevantLines.push(this._textModel.getLineContent(i));\n\t\t\t\tnonWhitespaceColumn = newNonWhitespaceIndex;\n\t\t\t\tinitialState = this.getStartState(i);\n\t\t\t\tif (initialState) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (!initialState) {\n\t\t\tinitialState = this.tokenizationSupport.getInitialState();\n\t\t}\n\t\tlikelyRelevantLines.reverse();\n\n\t\tconst languageId = this._textModel.getLanguageId();\n\t\tlet state = initialState;\n\t\tfor (const line of likelyRelevantLines) {\n\t\t\tconst r = safeTokenize(this._languageIdCodec, languageId, this.tokenizationSupport, line, false, state);\n\t\t\tstate = r.endState;\n\t\t}\n\t\treturn state;\n\t}\n}\n\n/**\n * **Invariant:**\n * If the text model is retokenized from line 1 to {@link getFirstInvalidEndStateLineNumber}() - 1,\n * then the recomputed end state for line l will be equal to {@link getEndState}(l).\n */\nexport class TrackingTokenizationStateStore {\n\tprivate readonly _tokenizationStateStore = new TokenizationStateStore();\n\tprivate readonly _invalidEndStatesLineNumbers = new RangePriorityQueueImpl();\n\n\tconstructor(private lineCount: number) {\n\t\tthis._invalidEndStatesLineNumbers.addRange(new OffsetRange(1, lineCount + 1));\n\t}\n\n\tpublic getEndState(lineNumber: number): TState | null {\n\t\treturn this._tokenizationStateStore.getEndState(lineNumber);\n\t}\n\n\t/**\n\t * @returns if the end state has changed.\n\t */\n\tpublic setEndState(lineNumber: number, state: TState): boolean {\n\t\tif (!state) {\n\t\t\tthrow new BugIndicatingError('Cannot set null/undefined state');\n\t\t}\n\n\t\tthis._invalidEndStatesLineNumbers.delete(lineNumber);\n\t\tconst r = this._tokenizationStateStore.setEndState(lineNumber, state);\n\t\tif (r && lineNumber < this.lineCount) {\n\t\t\t// because the state changed, we cannot trust the next state anymore and have to invalidate it.\n\t\t\tthis._invalidEndStatesLineNumbers.addRange(new OffsetRange(lineNumber + 1, lineNumber + 2));\n\t\t}\n\n\t\treturn r;\n\t}\n\n\tpublic acceptChange(range: LineRange, newLineCount: number): void {\n\t\tthis.lineCount += newLineCount - range.length;\n\t\tthis._tokenizationStateStore.acceptChange(range, newLineCount);\n\t\tthis._invalidEndStatesLineNumbers.addRangeAndResize(new OffsetRange(range.startLineNumber, range.endLineNumberExclusive), newLineCount);\n\t}\n\n\tpublic acceptChanges(changes: IModelContentChange[]) {\n\t\tfor (const c of changes) {\n\t\t\tconst [eolCount] = countEOL(c.text);\n\t\t\tthis.acceptChange(new LineRange(c.range.startLineNumber, c.range.endLineNumber + 1), eolCount + 1);\n\t\t}\n\t}\n\n\tpublic invalidateEndStateRange(range: LineRange): void {\n\t\tthis._invalidEndStatesLineNumbers.addRange(new OffsetRange(range.startLineNumber, range.endLineNumberExclusive));\n\t}\n\n\tpublic getFirstInvalidEndStateLineNumber(): number | null { return this._invalidEndStatesLineNumbers.min; }\n\n\tpublic getFirstInvalidEndStateLineNumberOrMax(): number {\n\t\treturn this.getFirstInvalidEndStateLineNumber() || Number.MAX_SAFE_INTEGER;\n\t}\n\n\tpublic allStatesValid(): boolean { return this._invalidEndStatesLineNumbers.min === null; }\n\n\tpublic getStartState(lineNumber: number, initialState: TState): TState | null {\n\t\tif (lineNumber === 1) { return initialState; }\n\t\treturn this.getEndState(lineNumber - 1);\n\t}\n\n\tpublic getFirstInvalidLine(initialState: TState): { lineNumber: number; startState: TState } | null {\n\t\tconst lineNumber = this.getFirstInvalidEndStateLineNumber();\n\t\tif (lineNumber === null) {\n\t\t\treturn null;\n\t\t}\n\t\tconst startState = this.getStartState(lineNumber, initialState);\n\t\tif (!startState) {\n\t\t\tthrow new BugIndicatingError('Start state must be defined');\n\t\t}\n\n\t\treturn { lineNumber, startState };\n\t}\n}\n\nexport class TokenizationStateStore {\n\tprivate readonly _lineEndStates = new FixedArray(null);\n\n\tpublic getEndState(lineNumber: number): TState | null {\n\t\treturn this._lineEndStates.get(lineNumber);\n\t}\n\n\tpublic setEndState(lineNumber: number, state: TState): boolean {\n\t\tconst oldState = this._lineEndStates.get(lineNumber);\n\t\tif (oldState && oldState.equals(state)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tthis._lineEndStates.set(lineNumber, state);\n\t\treturn true;\n\t}\n\n\tpublic acceptChange(range: LineRange, newLineCount: number): void {\n\t\tlet length = range.length;\n\t\tif (newLineCount > 0 && length > 0) {\n\t\t\t// Keep the last state, even though it is unrelated.\n\t\t\t// But if the new state happens to agree with this last state, then we know we can stop tokenizing.\n\t\t\tlength--;\n\t\t\tnewLineCount--;\n\t\t}\n\n\t\tthis._lineEndStates.replace(range.startLineNumber, length, newLineCount);\n\t}\n}\n\ninterface RangePriorityQueue {\n\tget min(): number | null;\n}\n\nexport class RangePriorityQueueImpl implements RangePriorityQueue {\n\tprivate readonly _ranges: OffsetRange[] = [];\n\n\tpublic get min(): number | null {\n\t\tif (this._ranges.length === 0) {\n\t\t\treturn null;\n\t\t}\n\t\treturn this._ranges[0].start;\n\t}\n\n\tpublic delete(value: number): void {\n\t\tconst idx = this._ranges.findIndex(r => r.contains(value));\n\t\tif (idx !== -1) {\n\t\t\tconst range = this._ranges[idx];\n\t\t\tif (range.start === value) {\n\t\t\t\tif (range.endExclusive === value + 1) {\n\t\t\t\t\tthis._ranges.splice(idx, 1);\n\t\t\t\t} else {\n\t\t\t\t\tthis._ranges[idx] = new OffsetRange(value + 1, range.endExclusive);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (range.endExclusive === value + 1) {\n\t\t\t\t\tthis._ranges[idx] = new OffsetRange(range.start, value);\n\t\t\t\t} else {\n\t\t\t\t\tthis._ranges.splice(idx, 1, new OffsetRange(range.start, value), new OffsetRange(value + 1, range.endExclusive));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic addRange(range: OffsetRange): void {\n\t\tOffsetRange.addRange(range, this._ranges);\n\t}\n\n\tpublic addRangeAndResize(range: OffsetRange, newLength: number): void {\n\t\tlet idxFirstMightBeIntersecting = 0;\n\t\twhile (!(idxFirstMightBeIntersecting >= this._ranges.length || range.start <= this._ranges[idxFirstMightBeIntersecting].endExclusive)) {\n\t\t\tidxFirstMightBeIntersecting++;\n\t\t}\n\t\tlet idxFirstIsAfter = idxFirstMightBeIntersecting;\n\t\twhile (!(idxFirstIsAfter >= this._ranges.length || range.endExclusive < this._ranges[idxFirstIsAfter].start)) {\n\t\t\tidxFirstIsAfter++;\n\t\t}\n\t\tconst delta = newLength - range.length;\n\n\t\tfor (let i = idxFirstIsAfter; i < this._ranges.length; i++) {\n\t\t\tthis._ranges[i] = this._ranges[i].delta(delta);\n\t\t}\n\n\t\tif (idxFirstMightBeIntersecting === idxFirstIsAfter) {\n\t\t\tconst newRange = new OffsetRange(range.start, range.start + newLength);\n\t\t\tif (!newRange.isEmpty) {\n\t\t\t\tthis._ranges.splice(idxFirstMightBeIntersecting, 0, newRange);\n\t\t\t}\n\t\t} else {\n\t\t\tconst start = Math.min(range.start, this._ranges[idxFirstMightBeIntersecting].start);\n\t\t\tconst endEx = Math.max(range.endExclusive, this._ranges[idxFirstIsAfter - 1].endExclusive);\n\n\t\t\tconst newRange = new OffsetRange(start, endEx + delta);\n\t\t\tif (!newRange.isEmpty) {\n\t\t\t\tthis._ranges.splice(idxFirstMightBeIntersecting, idxFirstIsAfter - idxFirstMightBeIntersecting, newRange);\n\t\t\t} else {\n\t\t\t\tthis._ranges.splice(idxFirstMightBeIntersecting, idxFirstIsAfter - idxFirstMightBeIntersecting);\n\t\t\t}\n\t\t}\n\t}\n\n\ttoString() {\n\t\treturn this._ranges.map(r => r.toString()).join(' + ');\n\t}\n}\n\n\nfunction safeTokenize(languageIdCodec: ILanguageIdCodec, languageId: string, tokenizationSupport: ITokenizationSupport | null, text: string, hasEOL: boolean, state: IState): EncodedTokenizationResult {\n\tlet r: EncodedTokenizationResult | null = null;\n\n\tif (tokenizationSupport) {\n\t\ttry {\n\t\t\tr = tokenizationSupport.tokenizeEncoded(text, hasEOL, state.clone());\n\t\t} catch (e) {\n\t\t\tonUnexpectedError(e);\n\t\t}\n\t}\n\n\tif (!r) {\n\t\tr = nullTokenizeEncoded(languageIdCodec.encodeLanguageId(languageId), state);\n\t}\n\n\tLineTokens.convertToEndOffset(r.tokens, text.length);\n\treturn r;\n}\n\nexport class DefaultBackgroundTokenizer implements IBackgroundTokenizer {\n\tprivate _isDisposed = false;\n\n\tconstructor(\n\t\tprivate readonly _tokenizerWithStateStore: TokenizerWithStateStoreAndTextModel,\n\t\tprivate readonly _backgroundTokenStore: IBackgroundTokenizationStore,\n\t) {\n\t}\n\n\tpublic dispose(): void {\n\t\tthis._isDisposed = true;\n\t}\n\n\tpublic handleChanges(): void {\n\t\tthis._beginBackgroundTokenization();\n\t}\n\n\tprivate _isScheduled = false;\n\tprivate _beginBackgroundTokenization(): void {\n\t\tif (this._isScheduled || !this._tokenizerWithStateStore._textModel.isAttachedToEditor() || !this._hasLinesToTokenize()) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._isScheduled = true;\n\t\trunWhenGlobalIdle((deadline) => {\n\t\t\tthis._isScheduled = false;\n\n\t\t\tthis._backgroundTokenizeWithDeadline(deadline);\n\t\t});\n\t}\n\n\t/**\n\t * Tokenize until the deadline occurs, but try to yield every 1-2ms.\n\t */\n\tprivate _backgroundTokenizeWithDeadline(deadline: IdleDeadline): void {\n\t\t// Read the time remaining from the `deadline` immediately because it is unclear\n\t\t// if the `deadline` object will be valid after execution leaves this function.\n\t\tconst endTime = Date.now() + deadline.timeRemaining();\n\n\t\tconst execute = () => {\n\t\t\tif (this._isDisposed || !this._tokenizerWithStateStore._textModel.isAttachedToEditor() || !this._hasLinesToTokenize()) {\n\t\t\t\t// disposed in the meantime or detached or finished\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis._backgroundTokenizeForAtLeast1ms();\n\n\t\t\tif (Date.now() < endTime) {\n\t\t\t\t// There is still time before reaching the deadline, so yield to the browser and then\n\t\t\t\t// continue execution\n\t\t\t\tsetTimeout0(execute);\n\t\t\t} else {\n\t\t\t\t// The deadline has been reached, so schedule a new idle callback if necessary\n\t\t\t\tthis._beginBackgroundTokenization();\n\t\t\t}\n\t\t};\n\t\texecute();\n\t}\n\n\t/**\n\t * Tokenize for at least 1ms.\n\t */\n\tprivate _backgroundTokenizeForAtLeast1ms(): void {\n\t\tconst lineCount = this._tokenizerWithStateStore._textModel.getLineCount();\n\t\tconst builder = new ContiguousMultilineTokensBuilder();\n\t\tconst sw = StopWatch.create(false);\n\n\t\tdo {\n\t\t\tif (sw.elapsed() > 1) {\n\t\t\t\t// the comparison is intentionally > 1 and not >= 1 to ensure that\n\t\t\t\t// a full millisecond has elapsed, given how microseconds are rounded\n\t\t\t\t// to milliseconds\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tconst tokenizedLineNumber = this._tokenizeOneInvalidLine(builder);\n\n\t\t\tif (tokenizedLineNumber >= lineCount) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t} while (this._hasLinesToTokenize());\n\n\t\tthis._backgroundTokenStore.setTokens(builder.finalize());\n\t\tthis.checkFinished();\n\t}\n\n\tprivate _hasLinesToTokenize(): boolean {\n\t\tif (!this._tokenizerWithStateStore) {\n\t\t\treturn false;\n\t\t}\n\t\treturn !this._tokenizerWithStateStore.store.allStatesValid();\n\t}\n\n\tprivate _tokenizeOneInvalidLine(builder: ContiguousMultilineTokensBuilder): number {\n\t\tconst firstInvalidLine = this._tokenizerWithStateStore?.getFirstInvalidLine();\n\t\tif (!firstInvalidLine) {\n\t\t\treturn this._tokenizerWithStateStore._textModel.getLineCount() + 1;\n\t\t}\n\t\tthis._tokenizerWithStateStore.updateTokensUntilLine(builder, firstInvalidLine.lineNumber);\n\t\treturn firstInvalidLine.lineNumber;\n\t}\n\n\tpublic checkFinished(): void {\n\t\tif (this._isDisposed) {\n\t\t\treturn;\n\t\t}\n\t\tif (this._tokenizerWithStateStore.store.allStatesValid()) {\n\t\t\tthis._backgroundTokenStore.backgroundTokenizationFinished();\n\t\t}\n\t}\n\n\tpublic requestTokens(startLineNumber: number, endLineNumberExclusive: number): void {\n\t\tthis._tokenizerWithStateStore.store.invalidateEndStateRange(new LineRange(startLineNumber, endLineNumberExclusive));\n\t}\n}\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\nimport { equals } from 'vs/base/common/arrays';\nimport { RunOnceScheduler } from 'vs/base/common/async';\nimport { CharCode } from 'vs/base/common/charCode';\nimport { BugIndicatingError, onUnexpectedError } from 'vs/base/common/errors';\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { Disposable, DisposableMap, MutableDisposable } from 'vs/base/common/lifecycle';\nimport { countEOL } from 'vs/editor/common/core/eolCounter';\nimport { LineRange } from 'vs/editor/common/core/lineRange';\nimport { IPosition, Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\nimport { IWordAtPosition, getWordAtText } from 'vs/editor/common/core/wordHelper';\nimport { StandardTokenType } from 'vs/editor/common/encodedTokenAttributes';\nimport { IBackgroundTokenizationStore, IBackgroundTokenizer, ILanguageIdCodec, IState, ITokenizationSupport, TokenizationRegistry } from 'vs/editor/common/languages';\nimport { ILanguageService } from 'vs/editor/common/languages/language';\nimport { ILanguageConfigurationService, ResolvedLanguageConfiguration } from 'vs/editor/common/languages/languageConfigurationRegistry';\nimport { IAttachedView } from 'vs/editor/common/model';\nimport { BracketPairsTextModelPart } from 'vs/editor/common/model/bracketPairsTextModelPart/bracketPairsImpl';\nimport { AttachedViews, IAttachedViewState, TextModel } from 'vs/editor/common/model/textModel';\nimport { TextModelPart } from 'vs/editor/common/model/textModelPart';\nimport { DefaultBackgroundTokenizer, TokenizerWithStateStoreAndTextModel, TrackingTokenizationStateStore } from 'vs/editor/common/model/textModelTokens';\nimport { IModelContentChangedEvent, IModelLanguageChangedEvent, IModelLanguageConfigurationChangedEvent, IModelTokensChangedEvent } from 'vs/editor/common/textModelEvents';\nimport { BackgroundTokenizationState, ITokenizationTextModelPart } from 'vs/editor/common/tokenizationTextModelPart';\nimport { ContiguousMultilineTokens } from 'vs/editor/common/tokens/contiguousMultilineTokens';\nimport { ContiguousMultilineTokensBuilder } from 'vs/editor/common/tokens/contiguousMultilineTokensBuilder';\nimport { ContiguousTokensStore } from 'vs/editor/common/tokens/contiguousTokensStore';\nimport { LineTokens } from 'vs/editor/common/tokens/lineTokens';\nimport { SparseMultilineTokens } from 'vs/editor/common/tokens/sparseMultilineTokens';\nimport { SparseTokensStore } from 'vs/editor/common/tokens/sparseTokensStore';\n\nexport class TokenizationTextModelPart extends TextModelPart implements ITokenizationTextModelPart {\n\tprivate readonly _semanticTokens: SparseTokensStore = new SparseTokensStore(this._languageService.languageIdCodec);\n\n\tprivate readonly _onDidChangeLanguage: Emitter = this._register(new Emitter());\n\tpublic readonly onDidChangeLanguage: Event = this._onDidChangeLanguage.event;\n\n\tprivate readonly _onDidChangeLanguageConfiguration: Emitter = this._register(new Emitter());\n\tpublic readonly onDidChangeLanguageConfiguration: Event = this._onDidChangeLanguageConfiguration.event;\n\n\tprivate readonly _onDidChangeTokens: Emitter = this._register(new Emitter());\n\tpublic readonly onDidChangeTokens: Event = this._onDidChangeTokens.event;\n\n\tprivate readonly grammarTokens = this._register(new GrammarTokens(this._languageService.languageIdCodec, this._textModel, () => this._languageId, this._attachedViews));\n\n\tconstructor(\n\t\tprivate readonly _languageService: ILanguageService,\n\t\tprivate readonly _languageConfigurationService: ILanguageConfigurationService,\n\t\tprivate readonly _textModel: TextModel,\n\t\tprivate readonly _bracketPairsTextModelPart: BracketPairsTextModelPart,\n\t\tprivate _languageId: string,\n\t\tprivate readonly _attachedViews: AttachedViews,\n\t) {\n\t\tsuper();\n\n\t\tthis._register(this._languageConfigurationService.onDidChange(e => {\n\t\t\tif (e.affects(this._languageId)) {\n\t\t\t\tthis._onDidChangeLanguageConfiguration.fire({});\n\t\t\t}\n\t\t}));\n\n\t\tthis._register(this.grammarTokens.onDidChangeTokens(e => {\n\t\t\tthis._emitModelTokensChangedEvent(e);\n\t\t}));\n\n\t\tthis._register(this.grammarTokens.onDidChangeBackgroundTokenizationState(e => {\n\t\t\tthis._bracketPairsTextModelPart.handleDidChangeBackgroundTokenizationState();\n\t\t}));\n\t}\n\n\tpublic handleDidChangeContent(e: IModelContentChangedEvent): void {\n\t\tif (e.isFlush) {\n\t\t\tthis._semanticTokens.flush();\n\t\t} else if (!e.isEolChange) { // We don't have to do anything on an EOL change\n\t\t\tfor (const c of e.changes) {\n\t\t\t\tconst [eolCount, firstLineLength, lastLineLength] = countEOL(c.text);\n\n\t\t\t\tthis._semanticTokens.acceptEdit(\n\t\t\t\t\tc.range,\n\t\t\t\t\teolCount,\n\t\t\t\t\tfirstLineLength,\n\t\t\t\t\tlastLineLength,\n\t\t\t\t\tc.text.length > 0 ? c.text.charCodeAt(0) : CharCode.Null\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tthis.grammarTokens.handleDidChangeContent(e);\n\t}\n\n\tpublic handleDidChangeAttached(): void {\n\t\tthis.grammarTokens.handleDidChangeAttached();\n\t}\n\n\t/**\n\t * Includes grammar and semantic tokens.\n\t */\n\tpublic getLineTokens(lineNumber: number): LineTokens {\n\t\tthis.validateLineNumber(lineNumber);\n\t\tconst syntacticTokens = this.grammarTokens.getLineTokens(lineNumber);\n\t\treturn this._semanticTokens.addSparseTokens(lineNumber, syntacticTokens);\n\t}\n\n\tprivate _emitModelTokensChangedEvent(e: IModelTokensChangedEvent): void {\n\t\tif (!this._textModel._isDisposing()) {\n\t\t\tthis._bracketPairsTextModelPart.handleDidChangeTokens(e);\n\t\t\tthis._onDidChangeTokens.fire(e);\n\t\t}\n\t}\n\n\t// #region Grammar Tokens\n\n\tprivate validateLineNumber(lineNumber: number): void {\n\t\tif (lineNumber < 1 || lineNumber > this._textModel.getLineCount()) {\n\t\t\tthrow new BugIndicatingError('Illegal value for lineNumber');\n\t\t}\n\t}\n\n\tpublic get hasTokens(): boolean {\n\t\treturn this.grammarTokens.hasTokens;\n\t}\n\n\tpublic resetTokenization() {\n\t\tthis.grammarTokens.resetTokenization();\n\t}\n\n\tpublic get backgroundTokenizationState() {\n\t\treturn this.grammarTokens.backgroundTokenizationState;\n\t}\n\n\tpublic forceTokenization(lineNumber: number): void {\n\t\tthis.validateLineNumber(lineNumber);\n\t\tthis.grammarTokens.forceTokenization(lineNumber);\n\t}\n\n\tpublic hasAccurateTokensForLine(lineNumber: number): boolean {\n\t\tthis.validateLineNumber(lineNumber);\n\t\treturn this.grammarTokens.hasAccurateTokensForLine(lineNumber);\n\t}\n\n\tpublic isCheapToTokenize(lineNumber: number): boolean {\n\t\tthis.validateLineNumber(lineNumber);\n\t\treturn this.grammarTokens.isCheapToTokenize(lineNumber);\n\t}\n\n\tpublic tokenizeIfCheap(lineNumber: number): void {\n\t\tthis.validateLineNumber(lineNumber);\n\t\tthis.grammarTokens.tokenizeIfCheap(lineNumber);\n\t}\n\n\tpublic getTokenTypeIfInsertingCharacter(lineNumber: number, column: number, character: string): StandardTokenType {\n\t\treturn this.grammarTokens.getTokenTypeIfInsertingCharacter(lineNumber, column, character);\n\t}\n\n\tpublic tokenizeLineWithEdit(position: IPosition, length: number, newText: string): LineTokens | null {\n\t\treturn this.grammarTokens.tokenizeLineWithEdit(position, length, newText);\n\t}\n\n\t// #endregion\n\n\t// #region Semantic Tokens\n\n\tpublic setSemanticTokens(tokens: SparseMultilineTokens[] | null, isComplete: boolean): void {\n\t\tthis._semanticTokens.set(tokens, isComplete);\n\n\t\tthis._emitModelTokensChangedEvent({\n\t\t\tsemanticTokensApplied: tokens !== null,\n\t\t\tranges: [{ fromLineNumber: 1, toLineNumber: this._textModel.getLineCount() }],\n\t\t});\n\t}\n\n\tpublic hasCompleteSemanticTokens(): boolean {\n\t\treturn this._semanticTokens.isComplete();\n\t}\n\n\tpublic hasSomeSemanticTokens(): boolean {\n\t\treturn !this._semanticTokens.isEmpty();\n\t}\n\n\tpublic setPartialSemanticTokens(range: Range, tokens: SparseMultilineTokens[]): void {\n\t\tif (this.hasCompleteSemanticTokens()) {\n\t\t\treturn;\n\t\t}\n\t\tconst changedRange = this._textModel.validateRange(\n\t\t\tthis._semanticTokens.setPartial(range, tokens)\n\t\t);\n\n\t\tthis._emitModelTokensChangedEvent({\n\t\t\tsemanticTokensApplied: true,\n\t\t\tranges: [\n\t\t\t\t{\n\t\t\t\t\tfromLineNumber: changedRange.startLineNumber,\n\t\t\t\t\ttoLineNumber: changedRange.endLineNumber,\n\t\t\t\t},\n\t\t\t],\n\t\t});\n\t}\n\n\t// #endregion\n\n\t// #region Utility Methods\n\n\tpublic getWordAtPosition(_position: IPosition): IWordAtPosition | null {\n\t\tthis.assertNotDisposed();\n\n\t\tconst position = this._textModel.validatePosition(_position);\n\t\tconst lineContent = this._textModel.getLineContent(position.lineNumber);\n\t\tconst lineTokens = this.getLineTokens(position.lineNumber);\n\t\tconst tokenIndex = lineTokens.findTokenIndexAtOffset(position.column - 1);\n\n\t\t// (1). First try checking right biased word\n\t\tconst [rbStartOffset, rbEndOffset] = TokenizationTextModelPart._findLanguageBoundaries(lineTokens, tokenIndex);\n\t\tconst rightBiasedWord = getWordAtText(\n\t\t\tposition.column,\n\t\t\tthis.getLanguageConfiguration(lineTokens.getLanguageId(tokenIndex)).getWordDefinition(),\n\t\t\tlineContent.substring(rbStartOffset, rbEndOffset),\n\t\t\trbStartOffset\n\t\t);\n\t\t// Make sure the result touches the original passed in position\n\t\tif (\n\t\t\trightBiasedWord &&\n\t\t\trightBiasedWord.startColumn <= _position.column &&\n\t\t\t_position.column <= rightBiasedWord.endColumn\n\t\t) {\n\t\t\treturn rightBiasedWord;\n\t\t}\n\n\t\t// (2). Else, if we were at a language boundary, check the left biased word\n\t\tif (tokenIndex > 0 && rbStartOffset === position.column - 1) {\n\t\t\t// edge case, where `position` sits between two tokens belonging to two different languages\n\t\t\tconst [lbStartOffset, lbEndOffset] = TokenizationTextModelPart._findLanguageBoundaries(\n\t\t\t\tlineTokens,\n\t\t\t\ttokenIndex - 1\n\t\t\t);\n\t\t\tconst leftBiasedWord = getWordAtText(\n\t\t\t\tposition.column,\n\t\t\t\tthis.getLanguageConfiguration(lineTokens.getLanguageId(tokenIndex - 1)).getWordDefinition(),\n\t\t\t\tlineContent.substring(lbStartOffset, lbEndOffset),\n\t\t\t\tlbStartOffset\n\t\t\t);\n\t\t\t// Make sure the result touches the original passed in position\n\t\t\tif (\n\t\t\t\tleftBiasedWord &&\n\t\t\t\tleftBiasedWord.startColumn <= _position.column &&\n\t\t\t\t_position.column <= leftBiasedWord.endColumn\n\t\t\t) {\n\t\t\t\treturn leftBiasedWord;\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tprivate getLanguageConfiguration(languageId: string): ResolvedLanguageConfiguration {\n\t\treturn this._languageConfigurationService.getLanguageConfiguration(languageId);\n\t}\n\n\tprivate static _findLanguageBoundaries(lineTokens: LineTokens, tokenIndex: number): [number, number] {\n\t\tconst languageId = lineTokens.getLanguageId(tokenIndex);\n\n\t\t// go left until a different language is hit\n\t\tlet startOffset = 0;\n\t\tfor (let i = tokenIndex; i >= 0 && lineTokens.getLanguageId(i) === languageId; i--) {\n\t\t\tstartOffset = lineTokens.getStartOffset(i);\n\t\t}\n\n\t\t// go right until a different language is hit\n\t\tlet endOffset = lineTokens.getLineContent().length;\n\t\tfor (\n\t\t\tlet i = tokenIndex, tokenCount = lineTokens.getCount();\n\t\t\ti < tokenCount && lineTokens.getLanguageId(i) === languageId;\n\t\t\ti++\n\t\t) {\n\t\t\tendOffset = lineTokens.getEndOffset(i);\n\t\t}\n\n\t\treturn [startOffset, endOffset];\n\t}\n\n\tpublic getWordUntilPosition(position: IPosition): IWordAtPosition {\n\t\tconst wordAtPosition = this.getWordAtPosition(position);\n\t\tif (!wordAtPosition) {\n\t\t\treturn { word: '', startColumn: position.column, endColumn: position.column, };\n\t\t}\n\t\treturn {\n\t\t\tword: wordAtPosition.word.substr(0, position.column - wordAtPosition.startColumn),\n\t\t\tstartColumn: wordAtPosition.startColumn,\n\t\t\tendColumn: position.column,\n\t\t};\n\t}\n\n\t// #endregion\n\n\t// #region Language Id handling\n\n\tpublic getLanguageId(): string {\n\t\treturn this._languageId;\n\t}\n\n\tpublic getLanguageIdAtPosition(lineNumber: number, column: number): string {\n\t\tconst position = this._textModel.validatePosition(new Position(lineNumber, column));\n\t\tconst lineTokens = this.getLineTokens(position.lineNumber);\n\t\treturn lineTokens.getLanguageId(lineTokens.findTokenIndexAtOffset(position.column - 1));\n\t}\n\n\tpublic setLanguageId(languageId: string, source: string = 'api'): void {\n\t\tif (this._languageId === languageId) {\n\t\t\t// There's nothing to do\n\t\t\treturn;\n\t\t}\n\n\t\tconst e: IModelLanguageChangedEvent = {\n\t\t\toldLanguage: this._languageId,\n\t\t\tnewLanguage: languageId,\n\t\t\tsource\n\t\t};\n\n\t\tthis._languageId = languageId;\n\n\t\tthis._bracketPairsTextModelPart.handleDidChangeLanguage(e);\n\t\tthis.grammarTokens.resetTokenization();\n\t\tthis._onDidChangeLanguage.fire(e);\n\t\tthis._onDidChangeLanguageConfiguration.fire({});\n\t}\n\n\t// #endregion\n}\n\nclass GrammarTokens extends Disposable {\n\tprivate _tokenizer: TokenizerWithStateStoreAndTextModel | null = null;\n\tprivate _defaultBackgroundTokenizer: DefaultBackgroundTokenizer | null = null;\n\tprivate readonly _backgroundTokenizer = this._register(new MutableDisposable());\n\n\tprivate readonly _tokens = new ContiguousTokensStore(this._languageIdCodec);\n\tprivate _debugBackgroundTokens: ContiguousTokensStore | undefined;\n\tprivate _debugBackgroundStates: TrackingTokenizationStateStore | undefined;\n\n\tprivate readonly _debugBackgroundTokenizer = this._register(new MutableDisposable());\n\n\tprivate _backgroundTokenizationState = BackgroundTokenizationState.InProgress;\n\tpublic get backgroundTokenizationState(): BackgroundTokenizationState {\n\t\treturn this._backgroundTokenizationState;\n\t}\n\n\tprivate readonly _onDidChangeBackgroundTokenizationState = this._register(new Emitter());\n\t/** @internal, should not be exposed by the text model! */\n\tpublic readonly onDidChangeBackgroundTokenizationState: Event = this._onDidChangeBackgroundTokenizationState.event;\n\n\tprivate readonly _onDidChangeTokens = this._register(new Emitter());\n\t/** @internal, should not be exposed by the text model! */\n\tpublic readonly onDidChangeTokens: Event = this._onDidChangeTokens.event;\n\n\tprivate readonly _attachedViewStates = this._register(new DisposableMap());\n\n\tconstructor(\n\t\tprivate readonly _languageIdCodec: ILanguageIdCodec,\n\t\tprivate readonly _textModel: TextModel,\n\t\tprivate getLanguageId: () => string,\n\t\tattachedViews: AttachedViews,\n\t) {\n\t\tsuper();\n\n\t\tthis._register(TokenizationRegistry.onDidChange((e) => {\n\t\t\tconst languageId = this.getLanguageId();\n\t\t\tif (e.changedLanguages.indexOf(languageId) === -1) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.resetTokenization();\n\t\t}));\n\n\t\tthis.resetTokenization();\n\n\t\tthis._register(attachedViews.onDidChangeVisibleRanges(({ view, state }) => {\n\t\t\tif (state) {\n\t\t\t\tlet existing = this._attachedViewStates.get(view);\n\t\t\t\tif (!existing) {\n\t\t\t\t\texisting = new AttachedViewHandler(() => this.refreshRanges(existing!.lineRanges));\n\t\t\t\t\tthis._attachedViewStates.set(view, existing);\n\t\t\t\t}\n\t\t\t\texisting.handleStateChange(state);\n\t\t\t} else {\n\t\t\t\tthis._attachedViewStates.deleteAndDispose(view);\n\t\t\t}\n\t\t}));\n\t}\n\n\tpublic resetTokenization(fireTokenChangeEvent: boolean = true): void {\n\t\tthis._tokens.flush();\n\t\tthis._debugBackgroundTokens?.flush();\n\t\tif (this._debugBackgroundStates) {\n\t\t\tthis._debugBackgroundStates = new TrackingTokenizationStateStore(this._textModel.getLineCount());\n\t\t}\n\t\tif (fireTokenChangeEvent) {\n\t\t\tthis._onDidChangeTokens.fire({\n\t\t\t\tsemanticTokensApplied: false,\n\t\t\t\tranges: [\n\t\t\t\t\t{\n\t\t\t\t\t\tfromLineNumber: 1,\n\t\t\t\t\t\ttoLineNumber: this._textModel.getLineCount(),\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t});\n\t\t}\n\n\t\tconst initializeTokenization = (): [ITokenizationSupport, IState] | [null, null] => {\n\t\t\tif (this._textModel.isTooLargeForTokenization()) {\n\t\t\t\treturn [null, null];\n\t\t\t}\n\t\t\tconst tokenizationSupport = TokenizationRegistry.get(this.getLanguageId());\n\t\t\tif (!tokenizationSupport) {\n\t\t\t\treturn [null, null];\n\t\t\t}\n\t\t\tlet initialState: IState;\n\t\t\ttry {\n\t\t\t\tinitialState = tokenizationSupport.getInitialState();\n\t\t\t} catch (e) {\n\t\t\t\tonUnexpectedError(e);\n\t\t\t\treturn [null, null];\n\t\t\t}\n\t\t\treturn [tokenizationSupport, initialState];\n\t\t};\n\n\t\tconst [tokenizationSupport, initialState] = initializeTokenization();\n\t\tif (tokenizationSupport && initialState) {\n\t\t\tthis._tokenizer = new TokenizerWithStateStoreAndTextModel(this._textModel.getLineCount(), tokenizationSupport, this._textModel, this._languageIdCodec);\n\t\t} else {\n\t\t\tthis._tokenizer = null;\n\t\t}\n\n\t\tthis._backgroundTokenizer.clear();\n\n\t\tthis._defaultBackgroundTokenizer = null;\n\t\tif (this._tokenizer) {\n\t\t\tconst b: IBackgroundTokenizationStore = {\n\t\t\t\tsetTokens: (tokens) => {\n\t\t\t\t\tthis.setTokens(tokens);\n\t\t\t\t},\n\t\t\t\tbackgroundTokenizationFinished: () => {\n\t\t\t\t\tif (this._backgroundTokenizationState === BackgroundTokenizationState.Completed) {\n\t\t\t\t\t\t// We already did a full tokenization and don't go back to progressing.\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tconst newState = BackgroundTokenizationState.Completed;\n\t\t\t\t\tthis._backgroundTokenizationState = newState;\n\t\t\t\t\tthis._onDidChangeBackgroundTokenizationState.fire();\n\t\t\t\t},\n\t\t\t\tsetEndState: (lineNumber, state) => {\n\t\t\t\t\tif (!this._tokenizer) { return; }\n\t\t\t\t\tconst firstInvalidEndStateLineNumber = this._tokenizer.store.getFirstInvalidEndStateLineNumber();\n\t\t\t\t\t// Don't accept states for definitely valid states, the renderer is ahead of the worker!\n\t\t\t\t\tif (firstInvalidEndStateLineNumber !== null && lineNumber >= firstInvalidEndStateLineNumber) {\n\t\t\t\t\t\tthis._tokenizer?.store.setEndState(lineNumber, state);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t};\n\n\t\t\tif (tokenizationSupport && tokenizationSupport.createBackgroundTokenizer && !tokenizationSupport.backgroundTokenizerShouldOnlyVerifyTokens) {\n\t\t\t\tthis._backgroundTokenizer.value = tokenizationSupport.createBackgroundTokenizer(this._textModel, b);\n\t\t\t}\n\t\t\tif (!this._backgroundTokenizer.value && !this._textModel.isTooLargeForTokenization()) {\n\t\t\t\tthis._backgroundTokenizer.value = this._defaultBackgroundTokenizer =\n\t\t\t\t\tnew DefaultBackgroundTokenizer(this._tokenizer, b);\n\t\t\t\tthis._defaultBackgroundTokenizer.handleChanges();\n\t\t\t}\n\n\t\t\tif (tokenizationSupport?.backgroundTokenizerShouldOnlyVerifyTokens && tokenizationSupport.createBackgroundTokenizer) {\n\t\t\t\tthis._debugBackgroundTokens = new ContiguousTokensStore(this._languageIdCodec);\n\t\t\t\tthis._debugBackgroundStates = new TrackingTokenizationStateStore(this._textModel.getLineCount());\n\t\t\t\tthis._debugBackgroundTokenizer.clear();\n\t\t\t\tthis._debugBackgroundTokenizer.value = tokenizationSupport.createBackgroundTokenizer(this._textModel, {\n\t\t\t\t\tsetTokens: (tokens) => {\n\t\t\t\t\t\tthis._debugBackgroundTokens?.setMultilineTokens(tokens, this._textModel);\n\t\t\t\t\t},\n\t\t\t\t\tbackgroundTokenizationFinished() {\n\t\t\t\t\t\t// NO OP\n\t\t\t\t\t},\n\t\t\t\t\tsetEndState: (lineNumber, state) => {\n\t\t\t\t\t\tthis._debugBackgroundStates?.setEndState(lineNumber, state);\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tthis._debugBackgroundTokens = undefined;\n\t\t\t\tthis._debugBackgroundStates = undefined;\n\t\t\t\tthis._debugBackgroundTokenizer.value = undefined;\n\t\t\t}\n\t\t}\n\n\t\tthis.refreshAllVisibleLineTokens();\n\t}\n\n\tpublic handleDidChangeAttached() {\n\t\tthis._defaultBackgroundTokenizer?.handleChanges();\n\t}\n\n\tpublic handleDidChangeContent(e: IModelContentChangedEvent): void {\n\t\tif (e.isFlush) {\n\t\t\t// Don't fire the event, as the view might not have got the text change event yet\n\t\t\tthis.resetTokenization(false);\n\t\t} else if (!e.isEolChange) { // We don't have to do anything on an EOL change\n\t\t\tfor (const c of e.changes) {\n\t\t\t\tconst [eolCount, firstLineLength] = countEOL(c.text);\n\n\t\t\t\tthis._tokens.acceptEdit(c.range, eolCount, firstLineLength);\n\t\t\t\tthis._debugBackgroundTokens?.acceptEdit(c.range, eolCount, firstLineLength);\n\t\t\t}\n\t\t\tthis._debugBackgroundStates?.acceptChanges(e.changes);\n\n\t\t\tif (this._tokenizer) {\n\t\t\t\tthis._tokenizer.store.acceptChanges(e.changes);\n\t\t\t}\n\t\t\tthis._defaultBackgroundTokenizer?.handleChanges();\n\t\t}\n\t}\n\n\tprivate setTokens(tokens: ContiguousMultilineTokens[]): { changes: { fromLineNumber: number; toLineNumber: number }[] } {\n\t\tconst { changes } = this._tokens.setMultilineTokens(tokens, this._textModel);\n\n\t\tif (changes.length > 0) {\n\t\t\tthis._onDidChangeTokens.fire({ semanticTokensApplied: false, ranges: changes, });\n\t\t}\n\n\t\treturn { changes: changes };\n\t}\n\n\tprivate refreshAllVisibleLineTokens(): void {\n\t\tconst ranges = LineRange.joinMany([...this._attachedViewStates].map(([_, s]) => s.lineRanges));\n\t\tthis.refreshRanges(ranges);\n\t}\n\n\tprivate refreshRanges(ranges: readonly LineRange[]): void {\n\t\tfor (const range of ranges) {\n\t\t\tthis.refreshRange(range.startLineNumber, range.endLineNumberExclusive - 1);\n\t\t}\n\t}\n\n\tprivate refreshRange(startLineNumber: number, endLineNumber: number): void {\n\t\tif (!this._tokenizer) {\n\t\t\treturn;\n\t\t}\n\n\t\tstartLineNumber = Math.max(1, Math.min(this._textModel.getLineCount(), startLineNumber));\n\t\tendLineNumber = Math.min(this._textModel.getLineCount(), endLineNumber);\n\n\t\tconst builder = new ContiguousMultilineTokensBuilder();\n\t\tconst { heuristicTokens } = this._tokenizer.tokenizeHeuristically(builder, startLineNumber, endLineNumber);\n\t\tconst changedTokens = this.setTokens(builder.finalize());\n\n\t\tif (heuristicTokens) {\n\t\t\t// We overrode tokens with heuristically computed ones.\n\t\t\t// Because old states might get reused (thus stopping invalidation),\n\t\t\t// we have to explicitly request the tokens for the changed ranges again.\n\t\t\tfor (const c of changedTokens.changes) {\n\t\t\t\tthis._backgroundTokenizer.value?.requestTokens(c.fromLineNumber, c.toLineNumber + 1);\n\t\t\t}\n\t\t}\n\n\t\tthis._defaultBackgroundTokenizer?.checkFinished();\n\t}\n\n\tpublic forceTokenization(lineNumber: number): void {\n\t\tconst builder = new ContiguousMultilineTokensBuilder();\n\t\tthis._tokenizer?.updateTokensUntilLine(builder, lineNumber);\n\t\tthis.setTokens(builder.finalize());\n\t\tthis._defaultBackgroundTokenizer?.checkFinished();\n\t}\n\n\tpublic hasAccurateTokensForLine(lineNumber: number): boolean {\n\t\tif (!this._tokenizer) {\n\t\t\treturn true;\n\t\t}\n\t\treturn this._tokenizer.hasAccurateTokensForLine(lineNumber);\n\t}\n\n\tpublic isCheapToTokenize(lineNumber: number): boolean {\n\t\tif (!this._tokenizer) {\n\t\t\treturn true;\n\t\t}\n\t\treturn this._tokenizer.isCheapToTokenize(lineNumber);\n\t}\n\n\tpublic tokenizeIfCheap(lineNumber: number): void {\n\t\tif (this.isCheapToTokenize(lineNumber)) {\n\t\t\tthis.forceTokenization(lineNumber);\n\t\t}\n\t}\n\n\tpublic getLineTokens(lineNumber: number): LineTokens {\n\t\tconst lineText = this._textModel.getLineContent(lineNumber);\n\t\tconst result = this._tokens.getTokens(\n\t\t\tthis._textModel.getLanguageId(),\n\t\t\tlineNumber - 1,\n\t\t\tlineText\n\t\t);\n\t\tif (this._debugBackgroundTokens && this._debugBackgroundStates && this._tokenizer) {\n\t\t\tif (this._debugBackgroundStates.getFirstInvalidEndStateLineNumberOrMax() > lineNumber && this._tokenizer.store.getFirstInvalidEndStateLineNumberOrMax() > lineNumber) {\n\t\t\t\tconst backgroundResult = this._debugBackgroundTokens.getTokens(\n\t\t\t\t\tthis._textModel.getLanguageId(),\n\t\t\t\t\tlineNumber - 1,\n\t\t\t\t\tlineText\n\t\t\t\t);\n\t\t\t\tif (!result.equals(backgroundResult) && this._debugBackgroundTokenizer.value?.reportMismatchingTokens) {\n\t\t\t\t\tthis._debugBackgroundTokenizer.value.reportMismatchingTokens(lineNumber);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tpublic getTokenTypeIfInsertingCharacter(lineNumber: number, column: number, character: string): StandardTokenType {\n\t\tif (!this._tokenizer) {\n\t\t\treturn StandardTokenType.Other;\n\t\t}\n\n\t\tconst position = this._textModel.validatePosition(new Position(lineNumber, column));\n\t\tthis.forceTokenization(position.lineNumber);\n\t\treturn this._tokenizer.getTokenTypeIfInsertingCharacter(position, character);\n\t}\n\n\tpublic tokenizeLineWithEdit(position: IPosition, length: number, newText: string): LineTokens | null {\n\t\tif (!this._tokenizer) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst validatedPosition = this._textModel.validatePosition(position);\n\t\tthis.forceTokenization(validatedPosition.lineNumber);\n\t\treturn this._tokenizer.tokenizeLineWithEdit(validatedPosition, length, newText);\n\t}\n\n\tpublic get hasTokens(): boolean {\n\t\treturn this._tokens.hasTokens;\n\t}\n}\n\nclass AttachedViewHandler extends Disposable {\n\tprivate readonly runner = this._register(new RunOnceScheduler(() => this.update(), 50));\n\n\tprivate _computedLineRanges: readonly LineRange[] = [];\n\tprivate _lineRanges: readonly LineRange[] = [];\n\tpublic get lineRanges(): readonly LineRange[] { return this._lineRanges; }\n\n\tconstructor(private readonly _refreshTokens: () => void) {\n\t\tsuper();\n\t}\n\n\tprivate update(): void {\n\t\tif (equals(this._computedLineRanges, this._lineRanges, (a, b) => a.equals(b))) {\n\t\t\treturn;\n\t\t}\n\t\tthis._computedLineRanges = this._lineRanges;\n\t\tthis._refreshTokens();\n\t}\n\n\tpublic handleStateChange(state: IAttachedViewState): void {\n\t\tthis._lineRanges = state.visibleLineRanges;\n\t\tif (state.stabilized) {\n\t\t\tthis.runner.cancel();\n\t\t\tthis.update();\n\t\t} else {\n\t\t\tthis.runner.schedule();\n\t\t}\n\t}\n}\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\nimport { CancellationTokenSource } from 'vs/base/common/cancellation';\nimport { Emitter } from 'vs/base/common/event';\nimport { KeyChord, KeyMod as ConstKeyMod } from 'vs/base/common/keyCodes';\nimport { URI } from 'vs/base/common/uri';\nimport { Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\nimport { Selection } from 'vs/editor/common/core/selection';\nimport { Token } from 'vs/editor/common/languages';\nimport * as standaloneEnums from 'vs/editor/common/standalone/standaloneEnums';\n\nexport class KeyMod {\n\tpublic static readonly CtrlCmd: number = ConstKeyMod.CtrlCmd;\n\tpublic static readonly Shift: number = ConstKeyMod.Shift;\n\tpublic static readonly Alt: number = ConstKeyMod.Alt;\n\tpublic static readonly WinCtrl: number = ConstKeyMod.WinCtrl;\n\n\tpublic static chord(firstPart: number, secondPart: number): number {\n\t\treturn KeyChord(firstPart, secondPart);\n\t}\n}\n\nexport function createMonacoBaseAPI(): typeof monaco {\n\treturn {\n\t\teditor: undefined!, // undefined override expected here\n\t\tlanguages: undefined!, // undefined override expected here\n\t\tCancellationTokenSource: CancellationTokenSource,\n\t\tEmitter: Emitter,\n\t\tKeyCode: standaloneEnums.KeyCode,\n\t\tKeyMod: KeyMod,\n\t\tPosition: Position,\n\t\tRange: Range,\n\t\tSelection: Selection,\n\t\tSelectionDirection: standaloneEnums.SelectionDirection,\n\t\tMarkerSeverity: standaloneEnums.MarkerSeverity,\n\t\tMarkerTag: standaloneEnums.MarkerTag,\n\t\tUri: URI,\n\t\tToken: Token\n\t};\n}\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\nimport { stringDiff } from 'vs/base/common/diff/diff';\nimport { IDisposable } from 'vs/base/common/lifecycle';\nimport { URI } from 'vs/base/common/uri';\nimport { IRequestHandler } from 'vs/base/common/worker/simpleWorker';\nimport { IPosition, Position } from 'vs/editor/common/core/position';\nimport { IRange, Range } from 'vs/editor/common/core/range';\nimport { EndOfLineSequence, ITextModel } from 'vs/editor/common/model';\nimport { IMirrorTextModel, IModelChangedEvent, MirrorTextModel as BaseMirrorModel } from 'vs/editor/common/model/mirrorTextModel';\nimport { ensureValidWordDefinition, getWordAtText, IWordAtPosition } from 'vs/editor/common/core/wordHelper';\nimport { IColorInformation, IInplaceReplaceSupportResult, ILink, TextEdit } from 'vs/editor/common/languages';\nimport { ILinkComputerTarget, computeLinks } from 'vs/editor/common/languages/linkComputer';\nimport { BasicInplaceReplace } from 'vs/editor/common/languages/supports/inplaceReplaceSupport';\nimport { DiffAlgorithmName, IDiffComputationResult, ILineChange, IUnicodeHighlightsResult } from 'vs/editor/common/services/editorWorker';\nimport { createMonacoBaseAPI } from 'vs/editor/common/services/editorBaseApi';\nimport { IEditorWorkerHost } from 'vs/editor/common/services/editorWorkerHost';\nimport { StopWatch } from 'vs/base/common/stopwatch';\nimport { UnicodeTextModelHighlighter, UnicodeHighlighterOptions } from 'vs/editor/common/services/unicodeTextModelHighlighter';\nimport { ILinesDiffComputer } from 'vs/editor/common/diff/linesDiffComputer';\nimport { DetailedLineRangeMapping } from '../diff/rangeMapping';\nimport { linesDiffComputers } from 'vs/editor/common/diff/linesDiffComputers';\nimport { createProxyObject, getAllMethodNames } from 'vs/base/common/objects';\nimport { IDocumentDiffProviderOptions } from 'vs/editor/common/diff/documentDiffProvider';\nimport { IDocumentColorComputerTarget, computeDefaultDocumentColors } from 'vs/editor/common/languages/defaultDocumentColorsComputer';\nimport { FindSectionHeaderOptions, SectionHeader, findSectionHeaders } from 'vs/editor/common/services/findSectionHeaders';\n\nexport interface IMirrorModel extends IMirrorTextModel {\n\treadonly uri: URI;\n\treadonly version: number;\n\tgetValue(): string;\n}\n\nexport interface IWorkerContext {\n\t/**\n\t * A proxy to the main thread host object.\n\t */\n\thost: H;\n\t/**\n\t * Get all available mirror models in this worker.\n\t */\n\tgetMirrorModels(): IMirrorModel[];\n}\n\n/**\n * @internal\n */\nexport interface IRawModelData {\n\turl: string;\n\tversionId: number;\n\tlines: string[];\n\tEOL: string;\n}\n\n/**\n * @internal\n */\nexport interface ICommonModel extends ILinkComputerTarget, IDocumentColorComputerTarget, IMirrorModel {\n\teol: string;\n\n\tgetLinesContent(): string[];\n\tgetLineCount(): number;\n\tgetLineContent(lineNumber: number): string;\n\tgetLineWords(lineNumber: number, wordDefinition: RegExp): IWordAtPosition[];\n\twords(wordDefinition: RegExp): Iterable;\n\tgetValueInRange(range: IRange): string;\n\tgetWordAtPosition(position: IPosition, wordDefinition: RegExp): Range | null;\n\toffsetAt(position: IPosition): number;\n\tpositionAt(offset: number): IPosition;\n}\n\n/**\n * Range of a word inside a model.\n * @internal\n */\ninterface IWordRange {\n\t/**\n\t * The index where the word starts.\n\t */\n\treadonly start: number;\n\t/**\n\t * The index where the word ends.\n\t */\n\treadonly end: number;\n}\n\n/**\n * @internal\n */\nclass MirrorModel extends BaseMirrorModel implements ICommonModel {\n\n\tpublic get uri(): URI {\n\t\treturn this._uri;\n\t}\n\n\tpublic get eol(): string {\n\t\treturn this._eol;\n\t}\n\n\tpublic getValue(): string {\n\t\treturn this.getText();\n\t}\n\n\tpublic findMatches(regex: RegExp): RegExpMatchArray[] {\n\t\tconst matches = [];\n\t\tfor (let i = 0; i < this._lines.length; i++) {\n\t\t\tconst line = this._lines[i];\n\t\t\tconst offsetToAdd = this.offsetAt(new Position(i + 1, 1));\n\t\t\tconst iteratorOverMatches = line.matchAll(regex);\n\t\t\tfor (const match of iteratorOverMatches) {\n\t\t\t\tif (match.index || match.index === 0) {\n\t\t\t\t\tmatch.index = match.index + offsetToAdd;\n\t\t\t\t}\n\t\t\t\tmatches.push(match);\n\t\t\t}\n\t\t}\n\t\treturn matches;\n\t}\n\n\tpublic getLinesContent(): string[] {\n\t\treturn this._lines.slice(0);\n\t}\n\n\tpublic getLineCount(): number {\n\t\treturn this._lines.length;\n\t}\n\n\tpublic getLineContent(lineNumber: number): string {\n\t\treturn this._lines[lineNumber - 1];\n\t}\n\n\tpublic getWordAtPosition(position: IPosition, wordDefinition: RegExp): Range | null {\n\n\t\tconst wordAtText = getWordAtText(\n\t\t\tposition.column,\n\t\t\tensureValidWordDefinition(wordDefinition),\n\t\t\tthis._lines[position.lineNumber - 1],\n\t\t\t0\n\t\t);\n\n\t\tif (wordAtText) {\n\t\t\treturn new Range(position.lineNumber, wordAtText.startColumn, position.lineNumber, wordAtText.endColumn);\n\t\t}\n\n\t\treturn null;\n\t}\n\n\n\tpublic words(wordDefinition: RegExp): Iterable {\n\n\t\tconst lines = this._lines;\n\t\tconst wordenize = this._wordenize.bind(this);\n\n\t\tlet lineNumber = 0;\n\t\tlet lineText = '';\n\t\tlet wordRangesIdx = 0;\n\t\tlet wordRanges: IWordRange[] = [];\n\n\t\treturn {\n\t\t\t*[Symbol.iterator]() {\n\t\t\t\twhile (true) {\n\t\t\t\t\tif (wordRangesIdx < wordRanges.length) {\n\t\t\t\t\t\tconst value = lineText.substring(wordRanges[wordRangesIdx].start, wordRanges[wordRangesIdx].end);\n\t\t\t\t\t\twordRangesIdx += 1;\n\t\t\t\t\t\tyield value;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif (lineNumber < lines.length) {\n\t\t\t\t\t\t\tlineText = lines[lineNumber];\n\t\t\t\t\t\t\twordRanges = wordenize(lineText, wordDefinition);\n\t\t\t\t\t\t\twordRangesIdx = 0;\n\t\t\t\t\t\t\tlineNumber += 1;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tbreak;\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};\n\t}\n\n\tpublic getLineWords(lineNumber: number, wordDefinition: RegExp): IWordAtPosition[] {\n\t\tconst content = this._lines[lineNumber - 1];\n\t\tconst ranges = this._wordenize(content, wordDefinition);\n\t\tconst words: IWordAtPosition[] = [];\n\t\tfor (const range of ranges) {\n\t\t\twords.push({\n\t\t\t\tword: content.substring(range.start, range.end),\n\t\t\t\tstartColumn: range.start + 1,\n\t\t\t\tendColumn: range.end + 1\n\t\t\t});\n\t\t}\n\t\treturn words;\n\t}\n\n\tprivate _wordenize(content: string, wordDefinition: RegExp): IWordRange[] {\n\t\tconst result: IWordRange[] = [];\n\t\tlet match: RegExpExecArray | null;\n\n\t\twordDefinition.lastIndex = 0; // reset lastIndex just to be sure\n\n\t\twhile (match = wordDefinition.exec(content)) {\n\t\t\tif (match[0].length === 0) {\n\t\t\t\t// it did match the empty string\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tresult.push({ start: match.index, end: match.index + match[0].length });\n\t\t}\n\t\treturn result;\n\t}\n\n\tpublic getValueInRange(range: IRange): string {\n\t\trange = this._validateRange(range);\n\n\t\tif (range.startLineNumber === range.endLineNumber) {\n\t\t\treturn this._lines[range.startLineNumber - 1].substring(range.startColumn - 1, range.endColumn - 1);\n\t\t}\n\n\t\tconst lineEnding = this._eol;\n\t\tconst startLineIndex = range.startLineNumber - 1;\n\t\tconst endLineIndex = range.endLineNumber - 1;\n\t\tconst resultLines: string[] = [];\n\n\t\tresultLines.push(this._lines[startLineIndex].substring(range.startColumn - 1));\n\t\tfor (let i = startLineIndex + 1; i < endLineIndex; i++) {\n\t\t\tresultLines.push(this._lines[i]);\n\t\t}\n\t\tresultLines.push(this._lines[endLineIndex].substring(0, range.endColumn - 1));\n\n\t\treturn resultLines.join(lineEnding);\n\t}\n\n\tpublic offsetAt(position: IPosition): number {\n\t\tposition = this._validatePosition(position);\n\t\tthis._ensureLineStarts();\n\t\treturn this._lineStarts!.getPrefixSum(position.lineNumber - 2) + (position.column - 1);\n\t}\n\n\tpublic positionAt(offset: number): IPosition {\n\t\toffset = Math.floor(offset);\n\t\toffset = Math.max(0, offset);\n\n\t\tthis._ensureLineStarts();\n\t\tconst out = this._lineStarts!.getIndexOf(offset);\n\t\tconst lineLength = this._lines[out.index].length;\n\n\t\t// Ensure we return a valid position\n\t\treturn {\n\t\t\tlineNumber: 1 + out.index,\n\t\t\tcolumn: 1 + Math.min(out.remainder, lineLength)\n\t\t};\n\t}\n\n\tprivate _validateRange(range: IRange): IRange {\n\n\t\tconst start = this._validatePosition({ lineNumber: range.startLineNumber, column: range.startColumn });\n\t\tconst end = this._validatePosition({ lineNumber: range.endLineNumber, column: range.endColumn });\n\n\t\tif (start.lineNumber !== range.startLineNumber\n\t\t\t|| start.column !== range.startColumn\n\t\t\t|| end.lineNumber !== range.endLineNumber\n\t\t\t|| end.column !== range.endColumn) {\n\n\t\t\treturn {\n\t\t\t\tstartLineNumber: start.lineNumber,\n\t\t\t\tstartColumn: start.column,\n\t\t\t\tendLineNumber: end.lineNumber,\n\t\t\t\tendColumn: end.column\n\t\t\t};\n\t\t}\n\n\t\treturn range;\n\t}\n\n\tprivate _validatePosition(position: IPosition): IPosition {\n\t\tif (!Position.isIPosition(position)) {\n\t\t\tthrow new Error('bad position');\n\t\t}\n\t\tlet { lineNumber, column } = position;\n\t\tlet hasChanged = false;\n\n\t\tif (lineNumber < 1) {\n\t\t\tlineNumber = 1;\n\t\t\tcolumn = 1;\n\t\t\thasChanged = true;\n\n\t\t} else if (lineNumber > this._lines.length) {\n\t\t\tlineNumber = this._lines.length;\n\t\t\tcolumn = this._lines[lineNumber - 1].length + 1;\n\t\t\thasChanged = true;\n\n\t\t} else {\n\t\t\tconst maxCharacter = this._lines[lineNumber - 1].length + 1;\n\t\t\tif (column < 1) {\n\t\t\t\tcolumn = 1;\n\t\t\t\thasChanged = true;\n\t\t\t}\n\t\t\telse if (column > maxCharacter) {\n\t\t\t\tcolumn = maxCharacter;\n\t\t\t\thasChanged = true;\n\t\t\t}\n\t\t}\n\n\t\tif (!hasChanged) {\n\t\t\treturn position;\n\t\t} else {\n\t\t\treturn { lineNumber, column };\n\t\t}\n\t}\n}\n\n/**\n * @internal\n */\nexport interface IForeignModuleFactory {\n\t(ctx: IWorkerContext, createData: any): any;\n}\n\ndeclare const require: any;\n\n/**\n * @internal\n */\nexport class EditorSimpleWorker implements IRequestHandler, IDisposable {\n\t_requestHandlerBrand: any;\n\n\tprotected readonly _host: IEditorWorkerHost;\n\tprivate _models: { [uri: string]: MirrorModel };\n\tprivate readonly _foreignModuleFactory: IForeignModuleFactory | null;\n\tprivate _foreignModule: any;\n\n\tconstructor(host: IEditorWorkerHost, foreignModuleFactory: IForeignModuleFactory | null) {\n\t\tthis._host = host;\n\t\tthis._models = Object.create(null);\n\t\tthis._foreignModuleFactory = foreignModuleFactory;\n\t\tthis._foreignModule = null;\n\t}\n\n\tpublic dispose(): void {\n\t\tthis._models = Object.create(null);\n\t}\n\n\tprotected _getModel(uri: string): ICommonModel {\n\t\treturn this._models[uri];\n\t}\n\n\tprivate _getModels(): ICommonModel[] {\n\t\tconst all: MirrorModel[] = [];\n\t\tObject.keys(this._models).forEach((key) => all.push(this._models[key]));\n\t\treturn all;\n\t}\n\n\tpublic acceptNewModel(data: IRawModelData): void {\n\t\tthis._models[data.url] = new MirrorModel(URI.parse(data.url), data.lines, data.EOL, data.versionId);\n\t}\n\n\tpublic acceptModelChanged(strURL: string, e: IModelChangedEvent): void {\n\t\tif (!this._models[strURL]) {\n\t\t\treturn;\n\t\t}\n\t\tconst model = this._models[strURL];\n\t\tmodel.onEvents(e);\n\t}\n\n\tpublic acceptRemovedModel(strURL: string): void {\n\t\tif (!this._models[strURL]) {\n\t\t\treturn;\n\t\t}\n\t\tdelete this._models[strURL];\n\t}\n\n\tpublic async computeUnicodeHighlights(url: string, options: UnicodeHighlighterOptions, range?: IRange): Promise {\n\t\tconst model = this._getModel(url);\n\t\tif (!model) {\n\t\t\treturn { ranges: [], hasMore: false, ambiguousCharacterCount: 0, invisibleCharacterCount: 0, nonBasicAsciiCharacterCount: 0 };\n\t\t}\n\t\treturn UnicodeTextModelHighlighter.computeUnicodeHighlights(model, options, range);\n\t}\n\n\tpublic async findSectionHeaders(url: string, options: FindSectionHeaderOptions): Promise {\n\t\tconst model = this._getModel(url);\n\t\tif (!model) {\n\t\t\treturn [];\n\t\t}\n\t\treturn findSectionHeaders(model, options);\n\t}\n\n\t// ---- BEGIN diff --------------------------------------------------------------------------\n\n\tpublic async computeDiff(originalUrl: string, modifiedUrl: string, options: IDocumentDiffProviderOptions, algorithm: DiffAlgorithmName): Promise {\n\t\tconst original = this._getModel(originalUrl);\n\t\tconst modified = this._getModel(modifiedUrl);\n\t\tif (!original || !modified) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst result = EditorSimpleWorker.computeDiff(original, modified, options, algorithm);\n\t\treturn result;\n\t}\n\n\tprivate static computeDiff(originalTextModel: ICommonModel | ITextModel, modifiedTextModel: ICommonModel | ITextModel, options: IDocumentDiffProviderOptions, algorithm: DiffAlgorithmName): IDiffComputationResult {\n\t\tconst diffAlgorithm: ILinesDiffComputer = algorithm === 'advanced' ? linesDiffComputers.getDefault() : linesDiffComputers.getLegacy();\n\n\t\tconst originalLines = originalTextModel.getLinesContent();\n\t\tconst modifiedLines = modifiedTextModel.getLinesContent();\n\n\t\tconst result = diffAlgorithm.computeDiff(originalLines, modifiedLines, options);\n\n\t\tconst identical = (result.changes.length > 0 ? false : this._modelsAreIdentical(originalTextModel, modifiedTextModel));\n\n\t\tfunction getLineChanges(changes: readonly DetailedLineRangeMapping[]): ILineChange[] {\n\t\t\treturn changes.map(m => ([m.original.startLineNumber, m.original.endLineNumberExclusive, m.modified.startLineNumber, m.modified.endLineNumberExclusive, m.innerChanges?.map(m => [\n\t\t\t\tm.originalRange.startLineNumber,\n\t\t\t\tm.originalRange.startColumn,\n\t\t\t\tm.originalRange.endLineNumber,\n\t\t\t\tm.originalRange.endColumn,\n\t\t\t\tm.modifiedRange.startLineNumber,\n\t\t\t\tm.modifiedRange.startColumn,\n\t\t\t\tm.modifiedRange.endLineNumber,\n\t\t\t\tm.modifiedRange.endColumn,\n\t\t\t])]));\n\t\t}\n\n\t\treturn {\n\t\t\tidentical,\n\t\t\tquitEarly: result.hitTimeout,\n\t\t\tchanges: getLineChanges(result.changes),\n\t\t\tmoves: result.moves.map(m => ([\n\t\t\t\tm.lineRangeMapping.original.startLineNumber,\n\t\t\t\tm.lineRangeMapping.original.endLineNumberExclusive,\n\t\t\t\tm.lineRangeMapping.modified.startLineNumber,\n\t\t\t\tm.lineRangeMapping.modified.endLineNumberExclusive,\n\t\t\t\tgetLineChanges(m.changes)\n\t\t\t])),\n\t\t};\n\t}\n\n\tprivate static _modelsAreIdentical(original: ICommonModel | ITextModel, modified: ICommonModel | ITextModel): boolean {\n\t\tconst originalLineCount = original.getLineCount();\n\t\tconst modifiedLineCount = modified.getLineCount();\n\t\tif (originalLineCount !== modifiedLineCount) {\n\t\t\treturn false;\n\t\t}\n\t\tfor (let line = 1; line <= originalLineCount; line++) {\n\t\t\tconst originalLine = original.getLineContent(line);\n\t\t\tconst modifiedLine = modified.getLineContent(line);\n\t\t\tif (originalLine !== modifiedLine) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\t// ---- END diff --------------------------------------------------------------------------\n\n\n\t// ---- BEGIN minimal edits ---------------------------------------------------------------\n\n\tprivate static readonly _diffLimit = 100000;\n\n\tpublic async computeMoreMinimalEdits(modelUrl: string, edits: TextEdit[], pretty: boolean): Promise {\n\t\tconst model = this._getModel(modelUrl);\n\t\tif (!model) {\n\t\t\treturn edits;\n\t\t}\n\n\t\tconst result: TextEdit[] = [];\n\t\tlet lastEol: EndOfLineSequence | undefined = undefined;\n\n\t\tedits = edits.slice(0).sort((a, b) => {\n\t\t\tif (a.range && b.range) {\n\t\t\t\treturn Range.compareRangesUsingStarts(a.range, b.range);\n\t\t\t}\n\t\t\t// eol only changes should go to the end\n\t\t\tconst aRng = a.range ? 0 : 1;\n\t\t\tconst bRng = b.range ? 0 : 1;\n\t\t\treturn aRng - bRng;\n\t\t});\n\n\t\t// merge adjacent edits\n\t\tlet writeIndex = 0;\n\t\tfor (let readIndex = 1; readIndex < edits.length; readIndex++) {\n\t\t\tif (Range.getEndPosition(edits[writeIndex].range).equals(Range.getStartPosition(edits[readIndex].range))) {\n\t\t\t\tedits[writeIndex].range = Range.fromPositions(Range.getStartPosition(edits[writeIndex].range), Range.getEndPosition(edits[readIndex].range));\n\t\t\t\tedits[writeIndex].text += edits[readIndex].text;\n\t\t\t} else {\n\t\t\t\twriteIndex++;\n\t\t\t\tedits[writeIndex] = edits[readIndex];\n\t\t\t}\n\t\t}\n\t\tedits.length = writeIndex + 1;\n\n\t\tfor (let { range, text, eol } of edits) {\n\n\t\t\tif (typeof eol === 'number') {\n\t\t\t\tlastEol = eol;\n\t\t\t}\n\n\t\t\tif (Range.isEmpty(range) && !text) {\n\t\t\t\t// empty change\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst original = model.getValueInRange(range);\n\t\t\ttext = text.replace(/\\r\\n|\\n|\\r/g, model.eol);\n\n\t\t\tif (original === text) {\n\t\t\t\t// noop\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// make sure diff won't take too long\n\t\t\tif (Math.max(text.length, original.length) > EditorSimpleWorker._diffLimit) {\n\t\t\t\tresult.push({ range, text });\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// compute diff between original and edit.text\n\t\t\tconst changes = stringDiff(original, text, pretty);\n\t\t\tconst editOffset = model.offsetAt(Range.lift(range).getStartPosition());\n\n\t\t\tfor (const change of changes) {\n\t\t\t\tconst start = model.positionAt(editOffset + change.originalStart);\n\t\t\t\tconst end = model.positionAt(editOffset + change.originalStart + change.originalLength);\n\t\t\t\tconst newEdit: TextEdit = {\n\t\t\t\t\ttext: text.substr(change.modifiedStart, change.modifiedLength),\n\t\t\t\t\trange: { startLineNumber: start.lineNumber, startColumn: start.column, endLineNumber: end.lineNumber, endColumn: end.column }\n\t\t\t\t};\n\n\t\t\t\tif (model.getValueInRange(newEdit.range) !== newEdit.text) {\n\t\t\t\t\tresult.push(newEdit);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (typeof lastEol === 'number') {\n\t\t\tresult.push({ eol: lastEol, text: '', range: { startLineNumber: 0, startColumn: 0, endLineNumber: 0, endColumn: 0 } });\n\t\t}\n\n\t\treturn result;\n\t}\n\n\t// ---- END minimal edits ---------------------------------------------------------------\n\n\tpublic async computeLinks(modelUrl: string): Promise {\n\t\tconst model = this._getModel(modelUrl);\n\t\tif (!model) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn computeLinks(model);\n\t}\n\n\t// --- BEGIN default document colors -----------------------------------------------------------\n\n\tpublic async computeDefaultDocumentColors(modelUrl: string): Promise {\n\t\tconst model = this._getModel(modelUrl);\n\t\tif (!model) {\n\t\t\treturn null;\n\t\t}\n\t\treturn computeDefaultDocumentColors(model);\n\t}\n\n\t// ---- BEGIN suggest --------------------------------------------------------------------------\n\n\tprivate static readonly _suggestionsLimit = 10000;\n\n\tpublic async textualSuggest(modelUrls: string[], leadingWord: string | undefined, wordDef: string, wordDefFlags: string): Promise<{ words: string[]; duration: number } | null> {\n\n\t\tconst sw = new StopWatch();\n\t\tconst wordDefRegExp = new RegExp(wordDef, wordDefFlags);\n\t\tconst seen = new Set();\n\n\t\touter: for (const url of modelUrls) {\n\t\t\tconst model = this._getModel(url);\n\t\t\tif (!model) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tfor (const word of model.words(wordDefRegExp)) {\n\t\t\t\tif (word === leadingWord || !isNaN(Number(word))) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tseen.add(word);\n\t\t\t\tif (seen.size > EditorSimpleWorker._suggestionsLimit) {\n\t\t\t\t\tbreak outer;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn { words: Array.from(seen), duration: sw.elapsed() };\n\t}\n\n\n\t// ---- END suggest --------------------------------------------------------------------------\n\n\t//#region -- word ranges --\n\n\tpublic async computeWordRanges(modelUrl: string, range: IRange, wordDef: string, wordDefFlags: string): Promise<{ [word: string]: IRange[] }> {\n\t\tconst model = this._getModel(modelUrl);\n\t\tif (!model) {\n\t\t\treturn Object.create(null);\n\t\t}\n\t\tconst wordDefRegExp = new RegExp(wordDef, wordDefFlags);\n\t\tconst result: { [word: string]: IRange[] } = Object.create(null);\n\t\tfor (let line = range.startLineNumber; line < range.endLineNumber; line++) {\n\t\t\tconst words = model.getLineWords(line, wordDefRegExp);\n\t\t\tfor (const word of words) {\n\t\t\t\tif (!isNaN(Number(word.word))) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tlet array = result[word.word];\n\t\t\t\tif (!array) {\n\t\t\t\t\tarray = [];\n\t\t\t\t\tresult[word.word] = array;\n\t\t\t\t}\n\t\t\t\tarray.push({\n\t\t\t\t\tstartLineNumber: line,\n\t\t\t\t\tstartColumn: word.startColumn,\n\t\t\t\t\tendLineNumber: line,\n\t\t\t\t\tendColumn: word.endColumn\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\t//#endregion\n\n\tpublic async navigateValueSet(modelUrl: string, range: IRange, up: boolean, wordDef: string, wordDefFlags: string): Promise {\n\t\tconst model = this._getModel(modelUrl);\n\t\tif (!model) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst wordDefRegExp = new RegExp(wordDef, wordDefFlags);\n\n\t\tif (range.startColumn === range.endColumn) {\n\t\t\trange = {\n\t\t\t\tstartLineNumber: range.startLineNumber,\n\t\t\t\tstartColumn: range.startColumn,\n\t\t\t\tendLineNumber: range.endLineNumber,\n\t\t\t\tendColumn: range.endColumn + 1\n\t\t\t};\n\t\t}\n\n\t\tconst selectionText = model.getValueInRange(range);\n\n\t\tconst wordRange = model.getWordAtPosition({ lineNumber: range.startLineNumber, column: range.startColumn }, wordDefRegExp);\n\t\tif (!wordRange) {\n\t\t\treturn null;\n\t\t}\n\t\tconst word = model.getValueInRange(wordRange);\n\t\tconst result = BasicInplaceReplace.INSTANCE.navigateValueSet(range, selectionText, wordRange, word, up);\n\t\treturn result;\n\t}\n\n\t// ---- BEGIN foreign module support --------------------------------------------------------------------------\n\n\tpublic loadForeignModule(moduleId: string, createData: any, foreignHostMethods: string[]): Promise {\n\t\tconst proxyMethodRequest = (method: string, args: any[]): Promise => {\n\t\t\treturn this._host.fhr(method, args);\n\t\t};\n\n\t\tconst foreignHost = createProxyObject(foreignHostMethods, proxyMethodRequest);\n\n\t\tconst ctx: IWorkerContext = {\n\t\t\thost: foreignHost,\n\t\t\tgetMirrorModels: (): IMirrorModel[] => {\n\t\t\t\treturn this._getModels();\n\t\t\t}\n\t\t};\n\n\t\tif (this._foreignModuleFactory) {\n\t\t\tthis._foreignModule = this._foreignModuleFactory(ctx, createData);\n\t\t\t// static foreing module\n\t\t\treturn Promise.resolve(getAllMethodNames(this._foreignModule));\n\t\t}\n\t\t// ESM-comment-begin\n\t\treturn new Promise((resolve, reject) => {\n\t\t\trequire([moduleId], (foreignModule: { create: IForeignModuleFactory }) => {\n\t\t\t\tthis._foreignModule = foreignModule.create(ctx, createData);\n\n\t\t\t\tresolve(getAllMethodNames(this._foreignModule));\n\n\t\t\t}, reject);\n\t\t});\n\t\t// ESM-comment-end\n\n\t\t// ESM-uncomment-begin\n\t\t// return Promise.reject(new Error(`Unexpected usage`));\n\t\t// ESM-uncomment-end\n\t}\n\n\t// foreign method request\n\tpublic fmr(method: string, args: any[]): Promise {\n\t\tif (!this._foreignModule || typeof this._foreignModule[method] !== 'function') {\n\t\t\treturn Promise.reject(new Error('Missing requestHandler or method: ' + method));\n\t\t}\n\n\t\ttry {\n\t\t\treturn Promise.resolve(this._foreignModule[method].apply(this._foreignModule, args));\n\t\t} catch (e) {\n\t\t\treturn Promise.reject(e);\n\t\t}\n\t}\n\n\t// ---- END foreign module support --------------------------------------------------------------------------\n}\n\n/**\n * Called on the worker side\n * @internal\n */\nexport function create(host: IEditorWorkerHost): IRequestHandler {\n\treturn new EditorSimpleWorker(host, null);\n}\n\n// This is only available in a Web Worker\ndeclare function importScripts(...urls: string[]): void;\n\nif (typeof importScripts === 'function') {\n\t// Running in a web worker\n\tglobalThis.monaco = createMonacoBaseAPI();\n}\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\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { Disposable, markAsSingleton } from 'vs/base/common/lifecycle';\nimport { RGBA8 } from 'vs/editor/common/core/rgba';\nimport { TokenizationRegistry } from 'vs/editor/common/languages';\nimport { ColorId } from 'vs/editor/common/encodedTokenAttributes';\n\nexport class MinimapTokensColorTracker extends Disposable {\n\tprivate static _INSTANCE: MinimapTokensColorTracker | null = null;\n\tpublic static getInstance(): MinimapTokensColorTracker {\n\t\tif (!this._INSTANCE) {\n\t\t\tthis._INSTANCE = markAsSingleton(new MinimapTokensColorTracker());\n\t\t}\n\t\treturn this._INSTANCE;\n\t}\n\n\tprivate _colors!: RGBA8[];\n\tprivate _backgroundIsLight!: boolean;\n\n\tprivate readonly _onDidChange = new Emitter();\n\tpublic readonly onDidChange: Event = this._onDidChange.event;\n\n\tprivate constructor() {\n\t\tsuper();\n\t\tthis._updateColorMap();\n\t\tthis._register(TokenizationRegistry.onDidChange(e => {\n\t\t\tif (e.changedColorMap) {\n\t\t\t\tthis._updateColorMap();\n\t\t\t}\n\t\t}));\n\t}\n\n\tprivate _updateColorMap(): void {\n\t\tconst colorMap = TokenizationRegistry.getColorMap();\n\t\tif (!colorMap) {\n\t\t\tthis._colors = [RGBA8.Empty];\n\t\t\tthis._backgroundIsLight = true;\n\t\t\treturn;\n\t\t}\n\t\tthis._colors = [RGBA8.Empty];\n\t\tfor (let colorId = 1; colorId < colorMap.length; colorId++) {\n\t\t\tconst source = colorMap[colorId].rgba;\n\t\t\t// Use a VM friendly data-type\n\t\t\tthis._colors[colorId] = new RGBA8(source.r, source.g, source.b, Math.round(source.a * 255));\n\t\t}\n\t\tconst backgroundLuminosity = colorMap[ColorId.DefaultBackground].getRelativeLuminance();\n\t\tthis._backgroundIsLight = backgroundLuminosity >= 0.5;\n\t\tthis._onDidChange.fire(undefined);\n\t}\n\n\tpublic getColor(colorId: ColorId): RGBA8 {\n\t\tif (colorId < 1 || colorId >= this._colors.length) {\n\t\t\t// background color (basically invisible)\n\t\t\tcolorId = ColorId.DefaultBackground;\n\t\t}\n\t\treturn this._colors[colorId];\n\t}\n\n\tpublic backgroundIsLight(): boolean {\n\t\treturn this._backgroundIsLight;\n\t}\n}\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\nimport * as nls from 'vs/nls';\nimport { onUnexpectedError } from 'vs/base/common/errors';\nimport { Selection } from 'vs/editor/common/core/selection';\nimport { EndOfLineSequence, ICursorStateComputer, IValidEditOperation, ITextModel } from 'vs/editor/common/model';\nimport { TextModel } from 'vs/editor/common/model/textModel';\nimport { IUndoRedoService, IResourceUndoRedoElement, UndoRedoElementType, IWorkspaceUndoRedoElement, UndoRedoGroup } from 'vs/platform/undoRedo/common/undoRedo';\nimport { URI } from 'vs/base/common/uri';\nimport { TextChange, compressConsecutiveTextChanges } from 'vs/editor/common/core/textChange';\nimport * as buffer from 'vs/base/common/buffer';\nimport { IDisposable } from 'vs/base/common/lifecycle';\nimport { basename } from 'vs/base/common/resources';\nimport { ISingleEditOperation } from 'vs/editor/common/core/editOperation';\n\nfunction uriGetComparisonKey(resource: URI): string {\n\treturn resource.toString();\n}\n\nexport class SingleModelEditStackData {\n\n\tpublic static create(model: ITextModel, beforeCursorState: Selection[] | null): SingleModelEditStackData {\n\t\tconst alternativeVersionId = model.getAlternativeVersionId();\n\t\tconst eol = getModelEOL(model);\n\t\treturn new SingleModelEditStackData(\n\t\t\talternativeVersionId,\n\t\t\talternativeVersionId,\n\t\t\teol,\n\t\t\teol,\n\t\t\tbeforeCursorState,\n\t\t\tbeforeCursorState,\n\t\t\t[]\n\t\t);\n\t}\n\n\tconstructor(\n\t\tpublic readonly beforeVersionId: number,\n\t\tpublic afterVersionId: number,\n\t\tpublic readonly beforeEOL: EndOfLineSequence,\n\t\tpublic afterEOL: EndOfLineSequence,\n\t\tpublic readonly beforeCursorState: Selection[] | null,\n\t\tpublic afterCursorState: Selection[] | null,\n\t\tpublic changes: TextChange[]\n\t) { }\n\n\tpublic append(model: ITextModel, textChanges: TextChange[], afterEOL: EndOfLineSequence, afterVersionId: number, afterCursorState: Selection[] | null): void {\n\t\tif (textChanges.length > 0) {\n\t\t\tthis.changes = compressConsecutiveTextChanges(this.changes, textChanges);\n\t\t}\n\t\tthis.afterEOL = afterEOL;\n\t\tthis.afterVersionId = afterVersionId;\n\t\tthis.afterCursorState = afterCursorState;\n\t}\n\n\tprivate static _writeSelectionsSize(selections: Selection[] | null): number {\n\t\treturn 4 + 4 * 4 * (selections ? selections.length : 0);\n\t}\n\n\tprivate static _writeSelections(b: Uint8Array, selections: Selection[] | null, offset: number): number {\n\t\tbuffer.writeUInt32BE(b, (selections ? selections.length : 0), offset); offset += 4;\n\t\tif (selections) {\n\t\t\tfor (const selection of selections) {\n\t\t\t\tbuffer.writeUInt32BE(b, selection.selectionStartLineNumber, offset); offset += 4;\n\t\t\t\tbuffer.writeUInt32BE(b, selection.selectionStartColumn, offset); offset += 4;\n\t\t\t\tbuffer.writeUInt32BE(b, selection.positionLineNumber, offset); offset += 4;\n\t\t\t\tbuffer.writeUInt32BE(b, selection.positionColumn, offset); offset += 4;\n\t\t\t}\n\t\t}\n\t\treturn offset;\n\t}\n\n\tprivate static _readSelections(b: Uint8Array, offset: number, dest: Selection[]): number {\n\t\tconst count = buffer.readUInt32BE(b, offset); offset += 4;\n\t\tfor (let i = 0; i < count; i++) {\n\t\t\tconst selectionStartLineNumber = buffer.readUInt32BE(b, offset); offset += 4;\n\t\t\tconst selectionStartColumn = buffer.readUInt32BE(b, offset); offset += 4;\n\t\t\tconst positionLineNumber = buffer.readUInt32BE(b, offset); offset += 4;\n\t\t\tconst positionColumn = buffer.readUInt32BE(b, offset); offset += 4;\n\t\t\tdest.push(new Selection(selectionStartLineNumber, selectionStartColumn, positionLineNumber, positionColumn));\n\t\t}\n\t\treturn offset;\n\t}\n\n\tpublic serialize(): ArrayBuffer {\n\t\tlet necessarySize = (\n\t\t\t+ 4 // beforeVersionId\n\t\t\t+ 4 // afterVersionId\n\t\t\t+ 1 // beforeEOL\n\t\t\t+ 1 // afterEOL\n\t\t\t+ SingleModelEditStackData._writeSelectionsSize(this.beforeCursorState)\n\t\t\t+ SingleModelEditStackData._writeSelectionsSize(this.afterCursorState)\n\t\t\t+ 4 // change count\n\t\t);\n\t\tfor (const change of this.changes) {\n\t\t\tnecessarySize += change.writeSize();\n\t\t}\n\n\t\tconst b = new Uint8Array(necessarySize);\n\t\tlet offset = 0;\n\t\tbuffer.writeUInt32BE(b, this.beforeVersionId, offset); offset += 4;\n\t\tbuffer.writeUInt32BE(b, this.afterVersionId, offset); offset += 4;\n\t\tbuffer.writeUInt8(b, this.beforeEOL, offset); offset += 1;\n\t\tbuffer.writeUInt8(b, this.afterEOL, offset); offset += 1;\n\t\toffset = SingleModelEditStackData._writeSelections(b, this.beforeCursorState, offset);\n\t\toffset = SingleModelEditStackData._writeSelections(b, this.afterCursorState, offset);\n\t\tbuffer.writeUInt32BE(b, this.changes.length, offset); offset += 4;\n\t\tfor (const change of this.changes) {\n\t\t\toffset = change.write(b, offset);\n\t\t}\n\t\treturn b.buffer;\n\t}\n\n\tpublic static deserialize(source: ArrayBuffer): SingleModelEditStackData {\n\t\tconst b = new Uint8Array(source);\n\t\tlet offset = 0;\n\t\tconst beforeVersionId = buffer.readUInt32BE(b, offset); offset += 4;\n\t\tconst afterVersionId = buffer.readUInt32BE(b, offset); offset += 4;\n\t\tconst beforeEOL = buffer.readUInt8(b, offset); offset += 1;\n\t\tconst afterEOL = buffer.readUInt8(b, offset); offset += 1;\n\t\tconst beforeCursorState: Selection[] = [];\n\t\toffset = SingleModelEditStackData._readSelections(b, offset, beforeCursorState);\n\t\tconst afterCursorState: Selection[] = [];\n\t\toffset = SingleModelEditStackData._readSelections(b, offset, afterCursorState);\n\t\tconst changeCount = buffer.readUInt32BE(b, offset); offset += 4;\n\t\tconst changes: TextChange[] = [];\n\t\tfor (let i = 0; i < changeCount; i++) {\n\t\t\toffset = TextChange.read(b, offset, changes);\n\t\t}\n\t\treturn new SingleModelEditStackData(\n\t\t\tbeforeVersionId,\n\t\t\tafterVersionId,\n\t\t\tbeforeEOL,\n\t\t\tafterEOL,\n\t\t\tbeforeCursorState,\n\t\t\tafterCursorState,\n\t\t\tchanges\n\t\t);\n\t}\n}\n\nexport interface IUndoRedoDelegate {\n\tprepareUndoRedo(element: MultiModelEditStackElement): Promise | IDisposable | void;\n}\n\nexport class SingleModelEditStackElement implements IResourceUndoRedoElement {\n\n\tpublic model: ITextModel | URI;\n\tprivate _data: SingleModelEditStackData | ArrayBuffer;\n\n\tpublic get type(): UndoRedoElementType.Resource {\n\t\treturn UndoRedoElementType.Resource;\n\t}\n\n\tpublic get resource(): URI {\n\t\tif (URI.isUri(this.model)) {\n\t\t\treturn this.model;\n\t\t}\n\t\treturn this.model.uri;\n\t}\n\n\tconstructor(\n\t\tpublic readonly label: string,\n\t\tpublic readonly code: string,\n\t\tmodel: ITextModel,\n\t\tbeforeCursorState: Selection[] | null\n\t) {\n\t\tthis.model = model;\n\t\tthis._data = SingleModelEditStackData.create(model, beforeCursorState);\n\t}\n\n\tpublic toString(): string {\n\t\tconst data = (this._data instanceof SingleModelEditStackData ? this._data : SingleModelEditStackData.deserialize(this._data));\n\t\treturn data.changes.map(change => change.toString()).join(', ');\n\t}\n\n\tpublic matchesResource(resource: URI): boolean {\n\t\tconst uri = (URI.isUri(this.model) ? this.model : this.model.uri);\n\t\treturn (uri.toString() === resource.toString());\n\t}\n\n\tpublic setModel(model: ITextModel | URI): void {\n\t\tthis.model = model;\n\t}\n\n\tpublic canAppend(model: ITextModel): boolean {\n\t\treturn (this.model === model && this._data instanceof SingleModelEditStackData);\n\t}\n\n\tpublic append(model: ITextModel, textChanges: TextChange[], afterEOL: EndOfLineSequence, afterVersionId: number, afterCursorState: Selection[] | null): void {\n\t\tif (this._data instanceof SingleModelEditStackData) {\n\t\t\tthis._data.append(model, textChanges, afterEOL, afterVersionId, afterCursorState);\n\t\t}\n\t}\n\n\tpublic close(): void {\n\t\tif (this._data instanceof SingleModelEditStackData) {\n\t\t\tthis._data = this._data.serialize();\n\t\t}\n\t}\n\n\tpublic open(): void {\n\t\tif (!(this._data instanceof SingleModelEditStackData)) {\n\t\t\tthis._data = SingleModelEditStackData.deserialize(this._data);\n\t\t}\n\t}\n\n\tpublic undo(): void {\n\t\tif (URI.isUri(this.model)) {\n\t\t\t// don't have a model\n\t\t\tthrow new Error(`Invalid SingleModelEditStackElement`);\n\t\t}\n\t\tif (this._data instanceof SingleModelEditStackData) {\n\t\t\tthis._data = this._data.serialize();\n\t\t}\n\t\tconst data = SingleModelEditStackData.deserialize(this._data);\n\t\tthis.model._applyUndo(data.changes, data.beforeEOL, data.beforeVersionId, data.beforeCursorState);\n\t}\n\n\tpublic redo(): void {\n\t\tif (URI.isUri(this.model)) {\n\t\t\t// don't have a model\n\t\t\tthrow new Error(`Invalid SingleModelEditStackElement`);\n\t\t}\n\t\tif (this._data instanceof SingleModelEditStackData) {\n\t\t\tthis._data = this._data.serialize();\n\t\t}\n\t\tconst data = SingleModelEditStackData.deserialize(this._data);\n\t\tthis.model._applyRedo(data.changes, data.afterEOL, data.afterVersionId, data.afterCursorState);\n\t}\n\n\tpublic heapSize(): number {\n\t\tif (this._data instanceof SingleModelEditStackData) {\n\t\t\tthis._data = this._data.serialize();\n\t\t}\n\t\treturn this._data.byteLength + 168/*heap overhead*/;\n\t}\n}\n\nexport class MultiModelEditStackElement implements IWorkspaceUndoRedoElement {\n\n\tpublic readonly type = UndoRedoElementType.Workspace;\n\tprivate _isOpen: boolean;\n\n\tprivate readonly _editStackElementsArr: SingleModelEditStackElement[];\n\tprivate readonly _editStackElementsMap: Map;\n\n\tprivate _delegate: IUndoRedoDelegate | null;\n\n\tpublic get resources(): readonly URI[] {\n\t\treturn this._editStackElementsArr.map(editStackElement => editStackElement.resource);\n\t}\n\n\tconstructor(\n\t\tpublic readonly label: string,\n\t\tpublic readonly code: string,\n\t\teditStackElements: SingleModelEditStackElement[]\n\t) {\n\t\tthis._isOpen = true;\n\t\tthis._editStackElementsArr = editStackElements.slice(0);\n\t\tthis._editStackElementsMap = new Map();\n\t\tfor (const editStackElement of this._editStackElementsArr) {\n\t\t\tconst key = uriGetComparisonKey(editStackElement.resource);\n\t\t\tthis._editStackElementsMap.set(key, editStackElement);\n\t\t}\n\t\tthis._delegate = null;\n\t}\n\n\tpublic prepareUndoRedo(): Promise | IDisposable | void {\n\t\tif (this._delegate) {\n\t\t\treturn this._delegate.prepareUndoRedo(this);\n\t\t}\n\t}\n\n\tpublic matchesResource(resource: URI): boolean {\n\t\tconst key = uriGetComparisonKey(resource);\n\t\treturn (this._editStackElementsMap.has(key));\n\t}\n\n\tpublic setModel(model: ITextModel | URI): void {\n\t\tconst key = uriGetComparisonKey(URI.isUri(model) ? model : model.uri);\n\t\tif (this._editStackElementsMap.has(key)) {\n\t\t\tthis._editStackElementsMap.get(key)!.setModel(model);\n\t\t}\n\t}\n\n\tpublic canAppend(model: ITextModel): boolean {\n\t\tif (!this._isOpen) {\n\t\t\treturn false;\n\t\t}\n\t\tconst key = uriGetComparisonKey(model.uri);\n\t\tif (this._editStackElementsMap.has(key)) {\n\t\t\tconst editStackElement = this._editStackElementsMap.get(key)!;\n\t\t\treturn editStackElement.canAppend(model);\n\t\t}\n\t\treturn false;\n\t}\n\n\tpublic append(model: ITextModel, textChanges: TextChange[], afterEOL: EndOfLineSequence, afterVersionId: number, afterCursorState: Selection[] | null): void {\n\t\tconst key = uriGetComparisonKey(model.uri);\n\t\tconst editStackElement = this._editStackElementsMap.get(key)!;\n\t\teditStackElement.append(model, textChanges, afterEOL, afterVersionId, afterCursorState);\n\t}\n\n\tpublic close(): void {\n\t\tthis._isOpen = false;\n\t}\n\n\tpublic open(): void {\n\t\t// cannot reopen\n\t}\n\n\tpublic undo(): void {\n\t\tthis._isOpen = false;\n\n\t\tfor (const editStackElement of this._editStackElementsArr) {\n\t\t\teditStackElement.undo();\n\t\t}\n\t}\n\n\tpublic redo(): void {\n\t\tfor (const editStackElement of this._editStackElementsArr) {\n\t\t\teditStackElement.redo();\n\t\t}\n\t}\n\n\tpublic heapSize(resource: URI): number {\n\t\tconst key = uriGetComparisonKey(resource);\n\t\tif (this._editStackElementsMap.has(key)) {\n\t\t\tconst editStackElement = this._editStackElementsMap.get(key)!;\n\t\t\treturn editStackElement.heapSize();\n\t\t}\n\t\treturn 0;\n\t}\n\n\tpublic split(): IResourceUndoRedoElement[] {\n\t\treturn this._editStackElementsArr;\n\t}\n\n\tpublic toString(): string {\n\t\tconst result: string[] = [];\n\t\tfor (const editStackElement of this._editStackElementsArr) {\n\t\t\tresult.push(`${basename(editStackElement.resource)}: ${editStackElement}`);\n\t\t}\n\t\treturn `{${result.join(', ')}}`;\n\t}\n}\n\nexport type EditStackElement = SingleModelEditStackElement | MultiModelEditStackElement;\n\nfunction getModelEOL(model: ITextModel): EndOfLineSequence {\n\tconst eol = model.getEOL();\n\tif (eol === '\\n') {\n\t\treturn EndOfLineSequence.LF;\n\t} else {\n\t\treturn EndOfLineSequence.CRLF;\n\t}\n}\n\nexport function isEditStackElement(element: IResourceUndoRedoElement | IWorkspaceUndoRedoElement | null): element is EditStackElement {\n\tif (!element) {\n\t\treturn false;\n\t}\n\treturn ((element instanceof SingleModelEditStackElement) || (element instanceof MultiModelEditStackElement));\n}\n\nexport class EditStack {\n\n\tprivate readonly _model: TextModel;\n\tprivate readonly _undoRedoService: IUndoRedoService;\n\n\tconstructor(model: TextModel, undoRedoService: IUndoRedoService) {\n\t\tthis._model = model;\n\t\tthis._undoRedoService = undoRedoService;\n\t}\n\n\tpublic pushStackElement(): void {\n\t\tconst lastElement = this._undoRedoService.getLastElement(this._model.uri);\n\t\tif (isEditStackElement(lastElement)) {\n\t\t\tlastElement.close();\n\t\t}\n\t}\n\n\tpublic popStackElement(): void {\n\t\tconst lastElement = this._undoRedoService.getLastElement(this._model.uri);\n\t\tif (isEditStackElement(lastElement)) {\n\t\t\tlastElement.open();\n\t\t}\n\t}\n\n\tpublic clear(): void {\n\t\tthis._undoRedoService.removeElements(this._model.uri);\n\t}\n\n\tprivate _getOrCreateEditStackElement(beforeCursorState: Selection[] | null, group: UndoRedoGroup | undefined): EditStackElement {\n\t\tconst lastElement = this._undoRedoService.getLastElement(this._model.uri);\n\t\tif (isEditStackElement(lastElement) && lastElement.canAppend(this._model)) {\n\t\t\treturn lastElement;\n\t\t}\n\t\tconst newElement = new SingleModelEditStackElement(nls.localize('edit', \"Typing\"), 'undoredo.textBufferEdit', this._model, beforeCursorState);\n\t\tthis._undoRedoService.pushElement(newElement, group);\n\t\treturn newElement;\n\t}\n\n\tpublic pushEOL(eol: EndOfLineSequence): void {\n\t\tconst editStackElement = this._getOrCreateEditStackElement(null, undefined);\n\t\tthis._model.setEOL(eol);\n\t\teditStackElement.append(this._model, [], getModelEOL(this._model), this._model.getAlternativeVersionId(), null);\n\t}\n\n\tpublic pushEditOperation(beforeCursorState: Selection[] | null, editOperations: ISingleEditOperation[], cursorStateComputer: ICursorStateComputer | null, group?: UndoRedoGroup): Selection[] | null {\n\t\tconst editStackElement = this._getOrCreateEditStackElement(beforeCursorState, group);\n\t\tconst inverseEditOperations = this._model.applyEdits(editOperations, true);\n\t\tconst afterCursorState = EditStack._computeCursorState(cursorStateComputer, inverseEditOperations);\n\t\tconst textChanges = inverseEditOperations.map((op, index) => ({ index: index, textChange: op.textChange }));\n\t\ttextChanges.sort((a, b) => {\n\t\t\tif (a.textChange.oldPosition === b.textChange.oldPosition) {\n\t\t\t\treturn a.index - b.index;\n\t\t\t}\n\t\t\treturn a.textChange.oldPosition - b.textChange.oldPosition;\n\t\t});\n\t\teditStackElement.append(this._model, textChanges.map(op => op.textChange), getModelEOL(this._model), this._model.getAlternativeVersionId(), afterCursorState);\n\t\treturn afterCursorState;\n\t}\n\n\tprivate static _computeCursorState(cursorStateComputer: ICursorStateComputer | null, inverseEditOperations: IValidEditOperation[]): Selection[] | null {\n\t\ttry {\n\t\t\treturn cursorStateComputer ? cursorStateComputer(inverseEditOperations) : null;\n\t\t} catch (e) {\n\t\t\tonUnexpectedError(e);\n\t\t\treturn null;\n\t\t}\n\t}\n}\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\nimport * as nls from 'vs/nls';\n\nexport namespace InspectTokensNLS {\n\texport const inspectTokensAction = nls.localize('inspectTokens', \"Developer: Inspect Tokens\");\n}\n\nexport namespace GoToLineNLS {\n\texport const gotoLineActionLabel = nls.localize('gotoLineActionLabel', \"Go to Line/Column...\");\n}\n\nexport namespace QuickHelpNLS {\n\texport const helpQuickAccessActionLabel = nls.localize('helpQuickAccess', \"Show all Quick Access Providers\");\n}\n\nexport namespace QuickCommandNLS {\n\texport const quickCommandActionLabel = nls.localize('quickCommandActionLabel', \"Command Palette\");\n\texport const quickCommandHelp = nls.localize('quickCommandActionHelp', \"Show And Run Commands\");\n}\n\nexport namespace QuickOutlineNLS {\n\texport const quickOutlineActionLabel = nls.localize('quickOutlineActionLabel', \"Go to Symbol...\");\n\texport const quickOutlineByCategoryActionLabel = nls.localize('quickOutlineByCategoryActionLabel', \"Go to Symbol by Category...\");\n}\n\nexport namespace StandaloneCodeEditorNLS {\n\texport const editorViewAccessibleLabel = nls.localize('editorViewAccessibleLabel', \"Editor content\");\n\texport const accessibilityHelpMessage = nls.localize('accessibilityHelpMessage', \"Press Alt+F1 for Accessibility Options.\");\n}\n\nexport namespace ToggleHighContrastNLS {\n\texport const toggleHighContrast = nls.localize('toggleHighContrast', \"Toggle High Contrast Theme\");\n}\n\nexport namespace StandaloneServicesNLS {\n\texport const bulkEditServiceSummary = nls.localize('bulkEditServiceSummary', \"Made {0} edits in {1} files\");\n}\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\nimport * as nls from 'vs/nls';\nimport { CharCode } from 'vs/base/common/charCode';\nimport * as strings from 'vs/base/common/strings';\nimport { IViewLineTokens } from 'vs/editor/common/tokens/lineTokens';\nimport { StringBuilder } from 'vs/editor/common/core/stringBuilder';\nimport { LineDecoration, LineDecorationsNormalizer } from 'vs/editor/common/viewLayout/lineDecorations';\nimport { InlineDecorationType } from 'vs/editor/common/viewModel';\nimport { LinePart, LinePartMetadata } from 'vs/editor/common/viewLayout/linePart';\n\nexport const enum RenderWhitespace {\n\tNone = 0,\n\tBoundary = 1,\n\tSelection = 2,\n\tTrailing = 3,\n\tAll = 4\n}\n\nexport class LineRange {\n\t/**\n\t * Zero-based offset on which the range starts, inclusive.\n\t */\n\tpublic readonly startOffset: number;\n\n\t/**\n\t * Zero-based offset on which the range ends, inclusive.\n\t */\n\tpublic readonly endOffset: number;\n\n\tconstructor(startIndex: number, endIndex: number) {\n\t\tthis.startOffset = startIndex;\n\t\tthis.endOffset = endIndex;\n\t}\n\n\tpublic equals(otherLineRange: LineRange) {\n\t\treturn this.startOffset === otherLineRange.startOffset\n\t\t\t&& this.endOffset === otherLineRange.endOffset;\n\t}\n}\n\nexport class RenderLineInput {\n\n\tpublic readonly useMonospaceOptimizations: boolean;\n\tpublic readonly canUseHalfwidthRightwardsArrow: boolean;\n\tpublic readonly lineContent: string;\n\tpublic readonly continuesWithWrappedLine: boolean;\n\tpublic readonly isBasicASCII: boolean;\n\tpublic readonly containsRTL: boolean;\n\tpublic readonly fauxIndentLength: number;\n\tpublic readonly lineTokens: IViewLineTokens;\n\tpublic readonly lineDecorations: LineDecoration[];\n\tpublic readonly tabSize: number;\n\tpublic readonly startVisibleColumn: number;\n\tpublic readonly spaceWidth: number;\n\tpublic readonly renderSpaceWidth: number;\n\tpublic readonly renderSpaceCharCode: number;\n\tpublic readonly stopRenderingLineAfter: number;\n\tpublic readonly renderWhitespace: RenderWhitespace;\n\tpublic readonly renderControlCharacters: boolean;\n\tpublic readonly fontLigatures: boolean;\n\n\t/**\n\t * Defined only when renderWhitespace is 'selection'. Selections are non-overlapping,\n\t * and ordered by position within the line.\n\t */\n\tpublic readonly selectionsOnLine: LineRange[] | null;\n\n\tconstructor(\n\t\tuseMonospaceOptimizations: boolean,\n\t\tcanUseHalfwidthRightwardsArrow: boolean,\n\t\tlineContent: string,\n\t\tcontinuesWithWrappedLine: boolean,\n\t\tisBasicASCII: boolean,\n\t\tcontainsRTL: boolean,\n\t\tfauxIndentLength: number,\n\t\tlineTokens: IViewLineTokens,\n\t\tlineDecorations: LineDecoration[],\n\t\ttabSize: number,\n\t\tstartVisibleColumn: number,\n\t\tspaceWidth: number,\n\t\tmiddotWidth: number,\n\t\twsmiddotWidth: number,\n\t\tstopRenderingLineAfter: number,\n\t\trenderWhitespace: 'none' | 'boundary' | 'selection' | 'trailing' | 'all',\n\t\trenderControlCharacters: boolean,\n\t\tfontLigatures: boolean,\n\t\tselectionsOnLine: LineRange[] | null\n\t) {\n\t\tthis.useMonospaceOptimizations = useMonospaceOptimizations;\n\t\tthis.canUseHalfwidthRightwardsArrow = canUseHalfwidthRightwardsArrow;\n\t\tthis.lineContent = lineContent;\n\t\tthis.continuesWithWrappedLine = continuesWithWrappedLine;\n\t\tthis.isBasicASCII = isBasicASCII;\n\t\tthis.containsRTL = containsRTL;\n\t\tthis.fauxIndentLength = fauxIndentLength;\n\t\tthis.lineTokens = lineTokens;\n\t\tthis.lineDecorations = lineDecorations.sort(LineDecoration.compare);\n\t\tthis.tabSize = tabSize;\n\t\tthis.startVisibleColumn = startVisibleColumn;\n\t\tthis.spaceWidth = spaceWidth;\n\t\tthis.stopRenderingLineAfter = stopRenderingLineAfter;\n\t\tthis.renderWhitespace = (\n\t\t\trenderWhitespace === 'all'\n\t\t\t\t? RenderWhitespace.All\n\t\t\t\t: renderWhitespace === 'boundary'\n\t\t\t\t\t? RenderWhitespace.Boundary\n\t\t\t\t\t: renderWhitespace === 'selection'\n\t\t\t\t\t\t? RenderWhitespace.Selection\n\t\t\t\t\t\t: renderWhitespace === 'trailing'\n\t\t\t\t\t\t\t? RenderWhitespace.Trailing\n\t\t\t\t\t\t\t: RenderWhitespace.None\n\t\t);\n\t\tthis.renderControlCharacters = renderControlCharacters;\n\t\tthis.fontLigatures = fontLigatures;\n\t\tthis.selectionsOnLine = selectionsOnLine && selectionsOnLine.sort((a, b) => a.startOffset < b.startOffset ? -1 : 1);\n\n\t\tconst wsmiddotDiff = Math.abs(wsmiddotWidth - spaceWidth);\n\t\tconst middotDiff = Math.abs(middotWidth - spaceWidth);\n\t\tif (wsmiddotDiff < middotDiff) {\n\t\t\tthis.renderSpaceWidth = wsmiddotWidth;\n\t\t\tthis.renderSpaceCharCode = 0x2E31; // U+2E31 - WORD SEPARATOR MIDDLE DOT\n\t\t} else {\n\t\t\tthis.renderSpaceWidth = middotWidth;\n\t\t\tthis.renderSpaceCharCode = 0xB7; // U+00B7 - MIDDLE DOT\n\t\t}\n\t}\n\n\tprivate sameSelection(otherSelections: LineRange[] | null): boolean {\n\t\tif (this.selectionsOnLine === null) {\n\t\t\treturn otherSelections === null;\n\t\t}\n\n\t\tif (otherSelections === null) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (otherSelections.length !== this.selectionsOnLine.length) {\n\t\t\treturn false;\n\t\t}\n\n\t\tfor (let i = 0; i < this.selectionsOnLine.length; i++) {\n\t\t\tif (!this.selectionsOnLine[i].equals(otherSelections[i])) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tpublic equals(other: RenderLineInput): boolean {\n\t\treturn (\n\t\t\tthis.useMonospaceOptimizations === other.useMonospaceOptimizations\n\t\t\t&& this.canUseHalfwidthRightwardsArrow === other.canUseHalfwidthRightwardsArrow\n\t\t\t&& this.lineContent === other.lineContent\n\t\t\t&& this.continuesWithWrappedLine === other.continuesWithWrappedLine\n\t\t\t&& this.isBasicASCII === other.isBasicASCII\n\t\t\t&& this.containsRTL === other.containsRTL\n\t\t\t&& this.fauxIndentLength === other.fauxIndentLength\n\t\t\t&& this.tabSize === other.tabSize\n\t\t\t&& this.startVisibleColumn === other.startVisibleColumn\n\t\t\t&& this.spaceWidth === other.spaceWidth\n\t\t\t&& this.renderSpaceWidth === other.renderSpaceWidth\n\t\t\t&& this.renderSpaceCharCode === other.renderSpaceCharCode\n\t\t\t&& this.stopRenderingLineAfter === other.stopRenderingLineAfter\n\t\t\t&& this.renderWhitespace === other.renderWhitespace\n\t\t\t&& this.renderControlCharacters === other.renderControlCharacters\n\t\t\t&& this.fontLigatures === other.fontLigatures\n\t\t\t&& LineDecoration.equalsArr(this.lineDecorations, other.lineDecorations)\n\t\t\t&& this.lineTokens.equals(other.lineTokens)\n\t\t\t&& this.sameSelection(other.selectionsOnLine)\n\t\t);\n\t}\n}\n\nconst enum CharacterMappingConstants {\n\tPART_INDEX_MASK = 0b11111111111111110000000000000000,\n\tCHAR_INDEX_MASK = 0b00000000000000001111111111111111,\n\n\tCHAR_INDEX_OFFSET = 0,\n\tPART_INDEX_OFFSET = 16\n}\n\nexport class DomPosition {\n\tconstructor(\n\t\tpublic readonly partIndex: number,\n\t\tpublic readonly charIndex: number\n\t) { }\n}\n\n/**\n * Provides a both direction mapping between a line's character and its rendered position.\n */\nexport class CharacterMapping {\n\n\tprivate static getPartIndex(partData: number): number {\n\t\treturn (partData & CharacterMappingConstants.PART_INDEX_MASK) >>> CharacterMappingConstants.PART_INDEX_OFFSET;\n\t}\n\n\tprivate static getCharIndex(partData: number): number {\n\t\treturn (partData & CharacterMappingConstants.CHAR_INDEX_MASK) >>> CharacterMappingConstants.CHAR_INDEX_OFFSET;\n\t}\n\n\tpublic readonly length: number;\n\tprivate readonly _data: Uint32Array;\n\tprivate readonly _horizontalOffset: Uint32Array;\n\n\tconstructor(length: number, partCount: number) {\n\t\tthis.length = length;\n\t\tthis._data = new Uint32Array(this.length);\n\t\tthis._horizontalOffset = new Uint32Array(this.length);\n\t}\n\n\tpublic setColumnInfo(column: number, partIndex: number, charIndex: number, horizontalOffset: number): void {\n\t\tconst partData = (\n\t\t\t(partIndex << CharacterMappingConstants.PART_INDEX_OFFSET)\n\t\t\t| (charIndex << CharacterMappingConstants.CHAR_INDEX_OFFSET)\n\t\t) >>> 0;\n\t\tthis._data[column - 1] = partData;\n\t\tthis._horizontalOffset[column - 1] = horizontalOffset;\n\t}\n\n\tpublic getHorizontalOffset(column: number): number {\n\t\tif (this._horizontalOffset.length === 0) {\n\t\t\t// No characters on this line\n\t\t\treturn 0;\n\t\t}\n\t\treturn this._horizontalOffset[column - 1];\n\t}\n\n\tprivate charOffsetToPartData(charOffset: number): number {\n\t\tif (this.length === 0) {\n\t\t\treturn 0;\n\t\t}\n\t\tif (charOffset < 0) {\n\t\t\treturn this._data[0];\n\t\t}\n\t\tif (charOffset >= this.length) {\n\t\t\treturn this._data[this.length - 1];\n\t\t}\n\t\treturn this._data[charOffset];\n\t}\n\n\tpublic getDomPosition(column: number): DomPosition {\n\t\tconst partData = this.charOffsetToPartData(column - 1);\n\t\tconst partIndex = CharacterMapping.getPartIndex(partData);\n\t\tconst charIndex = CharacterMapping.getCharIndex(partData);\n\t\treturn new DomPosition(partIndex, charIndex);\n\t}\n\n\tpublic getColumn(domPosition: DomPosition, partLength: number): number {\n\t\tconst charOffset = this.partDataToCharOffset(domPosition.partIndex, partLength, domPosition.charIndex);\n\t\treturn charOffset + 1;\n\t}\n\n\tprivate partDataToCharOffset(partIndex: number, partLength: number, charIndex: number): number {\n\t\tif (this.length === 0) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tconst searchEntry = (\n\t\t\t(partIndex << CharacterMappingConstants.PART_INDEX_OFFSET)\n\t\t\t| (charIndex << CharacterMappingConstants.CHAR_INDEX_OFFSET)\n\t\t) >>> 0;\n\n\t\tlet min = 0;\n\t\tlet max = this.length - 1;\n\t\twhile (min + 1 < max) {\n\t\t\tconst mid = ((min + max) >>> 1);\n\t\t\tconst midEntry = this._data[mid];\n\t\t\tif (midEntry === searchEntry) {\n\t\t\t\treturn mid;\n\t\t\t} else if (midEntry > searchEntry) {\n\t\t\t\tmax = mid;\n\t\t\t} else {\n\t\t\t\tmin = mid;\n\t\t\t}\n\t\t}\n\n\t\tif (min === max) {\n\t\t\treturn min;\n\t\t}\n\n\t\tconst minEntry = this._data[min];\n\t\tconst maxEntry = this._data[max];\n\n\t\tif (minEntry === searchEntry) {\n\t\t\treturn min;\n\t\t}\n\t\tif (maxEntry === searchEntry) {\n\t\t\treturn max;\n\t\t}\n\n\t\tconst minPartIndex = CharacterMapping.getPartIndex(minEntry);\n\t\tconst minCharIndex = CharacterMapping.getCharIndex(minEntry);\n\n\t\tconst maxPartIndex = CharacterMapping.getPartIndex(maxEntry);\n\t\tlet maxCharIndex: number;\n\n\t\tif (minPartIndex !== maxPartIndex) {\n\t\t\t// sitting between parts\n\t\t\tmaxCharIndex = partLength;\n\t\t} else {\n\t\t\tmaxCharIndex = CharacterMapping.getCharIndex(maxEntry);\n\t\t}\n\n\t\tconst minEntryDistance = charIndex - minCharIndex;\n\t\tconst maxEntryDistance = maxCharIndex - charIndex;\n\n\t\tif (minEntryDistance <= maxEntryDistance) {\n\t\t\treturn min;\n\t\t}\n\t\treturn max;\n\t}\n}\n\nexport const enum ForeignElementType {\n\tNone = 0,\n\tBefore = 1,\n\tAfter = 2\n}\n\nexport class RenderLineOutput {\n\t_renderLineOutputBrand: void = undefined;\n\n\treadonly characterMapping: CharacterMapping;\n\treadonly containsRTL: boolean;\n\treadonly containsForeignElements: ForeignElementType;\n\n\tconstructor(characterMapping: CharacterMapping, containsRTL: boolean, containsForeignElements: ForeignElementType) {\n\t\tthis.characterMapping = characterMapping;\n\t\tthis.containsRTL = containsRTL;\n\t\tthis.containsForeignElements = containsForeignElements;\n\t}\n}\n\nexport function renderViewLine(input: RenderLineInput, sb: StringBuilder): RenderLineOutput {\n\tif (input.lineContent.length === 0) {\n\n\t\tif (input.lineDecorations.length > 0) {\n\t\t\t// This line is empty, but it contains inline decorations\n\t\t\tsb.appendString(``);\n\n\t\t\tlet beforeCount = 0;\n\t\t\tlet afterCount = 0;\n\t\t\tlet containsForeignElements = ForeignElementType.None;\n\t\t\tfor (const lineDecoration of input.lineDecorations) {\n\t\t\t\tif (lineDecoration.type === InlineDecorationType.Before || lineDecoration.type === InlineDecorationType.After) {\n\t\t\t\t\tsb.appendString(``);\n\n\t\t\t\t\tif (lineDecoration.type === InlineDecorationType.Before) {\n\t\t\t\t\t\tcontainsForeignElements |= ForeignElementType.Before;\n\t\t\t\t\t\tbeforeCount++;\n\t\t\t\t\t}\n\t\t\t\t\tif (lineDecoration.type === InlineDecorationType.After) {\n\t\t\t\t\t\tcontainsForeignElements |= ForeignElementType.After;\n\t\t\t\t\t\tafterCount++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tsb.appendString(``);\n\n\t\t\tconst characterMapping = new CharacterMapping(1, beforeCount + afterCount);\n\t\t\tcharacterMapping.setColumnInfo(1, beforeCount, 0, 0);\n\n\t\t\treturn new RenderLineOutput(\n\t\t\t\tcharacterMapping,\n\t\t\t\tfalse,\n\t\t\t\tcontainsForeignElements\n\t\t\t);\n\t\t}\n\n\t\t// completely empty line\n\t\tsb.appendString('');\n\t\treturn new RenderLineOutput(\n\t\t\tnew CharacterMapping(0, 0),\n\t\t\tfalse,\n\t\t\tForeignElementType.None\n\t\t);\n\t}\n\n\treturn _renderLine(resolveRenderLineInput(input), sb);\n}\n\nexport class RenderLineOutput2 {\n\tconstructor(\n\t\tpublic readonly characterMapping: CharacterMapping,\n\t\tpublic readonly html: string,\n\t\tpublic readonly containsRTL: boolean,\n\t\tpublic readonly containsForeignElements: ForeignElementType\n\t) {\n\t}\n}\n\nexport function renderViewLine2(input: RenderLineInput): RenderLineOutput2 {\n\tconst sb = new StringBuilder(10000);\n\tconst out = renderViewLine(input, sb);\n\treturn new RenderLineOutput2(out.characterMapping, sb.build(), out.containsRTL, out.containsForeignElements);\n}\n\nclass ResolvedRenderLineInput {\n\tconstructor(\n\t\tpublic readonly fontIsMonospace: boolean,\n\t\tpublic readonly canUseHalfwidthRightwardsArrow: boolean,\n\t\tpublic readonly lineContent: string,\n\t\tpublic readonly len: number,\n\t\tpublic readonly isOverflowing: boolean,\n\t\tpublic readonly overflowingCharCount: number,\n\t\tpublic readonly parts: LinePart[],\n\t\tpublic readonly containsForeignElements: ForeignElementType,\n\t\tpublic readonly fauxIndentLength: number,\n\t\tpublic readonly tabSize: number,\n\t\tpublic readonly startVisibleColumn: number,\n\t\tpublic readonly containsRTL: boolean,\n\t\tpublic readonly spaceWidth: number,\n\t\tpublic readonly renderSpaceCharCode: number,\n\t\tpublic readonly renderWhitespace: RenderWhitespace,\n\t\tpublic readonly renderControlCharacters: boolean,\n\t) {\n\t\t//\n\t}\n}\n\nfunction resolveRenderLineInput(input: RenderLineInput): ResolvedRenderLineInput {\n\tconst lineContent = input.lineContent;\n\n\tlet isOverflowing: boolean;\n\tlet overflowingCharCount: number;\n\tlet len: number;\n\n\tif (input.stopRenderingLineAfter !== -1 && input.stopRenderingLineAfter < lineContent.length) {\n\t\tisOverflowing = true;\n\t\toverflowingCharCount = lineContent.length - input.stopRenderingLineAfter;\n\t\tlen = input.stopRenderingLineAfter;\n\t} else {\n\t\tisOverflowing = false;\n\t\toverflowingCharCount = 0;\n\t\tlen = lineContent.length;\n\t}\n\n\tlet tokens = transformAndRemoveOverflowing(lineContent, input.containsRTL, input.lineTokens, input.fauxIndentLength, len);\n\tif (input.renderControlCharacters && !input.isBasicASCII) {\n\t\t// Calling `extractControlCharacters` before adding (possibly empty) line parts\n\t\t// for inline decorations. `extractControlCharacters` removes empty line parts.\n\t\ttokens = extractControlCharacters(lineContent, tokens);\n\t}\n\tif (input.renderWhitespace === RenderWhitespace.All ||\n\t\tinput.renderWhitespace === RenderWhitespace.Boundary ||\n\t\t(input.renderWhitespace === RenderWhitespace.Selection && !!input.selectionsOnLine) ||\n\t\t(input.renderWhitespace === RenderWhitespace.Trailing && !input.continuesWithWrappedLine)\n\t) {\n\t\ttokens = _applyRenderWhitespace(input, lineContent, len, tokens);\n\t}\n\tlet containsForeignElements = ForeignElementType.None;\n\tif (input.lineDecorations.length > 0) {\n\t\tfor (let i = 0, len = input.lineDecorations.length; i < len; i++) {\n\t\t\tconst lineDecoration = input.lineDecorations[i];\n\t\t\tif (lineDecoration.type === InlineDecorationType.RegularAffectingLetterSpacing) {\n\t\t\t\t// Pretend there are foreign elements... although not 100% accurate.\n\t\t\t\tcontainsForeignElements |= ForeignElementType.Before;\n\t\t\t} else if (lineDecoration.type === InlineDecorationType.Before) {\n\t\t\t\tcontainsForeignElements |= ForeignElementType.Before;\n\t\t\t} else if (lineDecoration.type === InlineDecorationType.After) {\n\t\t\t\tcontainsForeignElements |= ForeignElementType.After;\n\t\t\t}\n\t\t}\n\t\ttokens = _applyInlineDecorations(lineContent, len, tokens, input.lineDecorations);\n\t}\n\tif (!input.containsRTL) {\n\t\t// We can never split RTL text, as it ruins the rendering\n\t\ttokens = splitLargeTokens(lineContent, tokens, !input.isBasicASCII || input.fontLigatures);\n\t}\n\n\treturn new ResolvedRenderLineInput(\n\t\tinput.useMonospaceOptimizations,\n\t\tinput.canUseHalfwidthRightwardsArrow,\n\t\tlineContent,\n\t\tlen,\n\t\tisOverflowing,\n\t\toverflowingCharCount,\n\t\ttokens,\n\t\tcontainsForeignElements,\n\t\tinput.fauxIndentLength,\n\t\tinput.tabSize,\n\t\tinput.startVisibleColumn,\n\t\tinput.containsRTL,\n\t\tinput.spaceWidth,\n\t\tinput.renderSpaceCharCode,\n\t\tinput.renderWhitespace,\n\t\tinput.renderControlCharacters\n\t);\n}\n\n/**\n * In the rendering phase, characters are always looped until token.endIndex.\n * Ensure that all tokens end before `len` and the last one ends precisely at `len`.\n */\nfunction transformAndRemoveOverflowing(lineContent: string, lineContainsRTL: boolean, tokens: IViewLineTokens, fauxIndentLength: number, len: number): LinePart[] {\n\tconst result: LinePart[] = [];\n\tlet resultLen = 0;\n\n\t// The faux indent part of the line should have no token type\n\tif (fauxIndentLength > 0) {\n\t\tresult[resultLen++] = new LinePart(fauxIndentLength, '', 0, false);\n\t}\n\tlet startOffset = fauxIndentLength;\n\tfor (let tokenIndex = 0, tokensLen = tokens.getCount(); tokenIndex < tokensLen; tokenIndex++) {\n\t\tconst endIndex = tokens.getEndOffset(tokenIndex);\n\t\tif (endIndex <= fauxIndentLength) {\n\t\t\t// The faux indent part of the line should have no token type\n\t\t\tcontinue;\n\t\t}\n\t\tconst type = tokens.getClassName(tokenIndex);\n\t\tif (endIndex >= len) {\n\t\t\tconst tokenContainsRTL = (lineContainsRTL ? strings.containsRTL(lineContent.substring(startOffset, len)) : false);\n\t\t\tresult[resultLen++] = new LinePart(len, type, 0, tokenContainsRTL);\n\t\t\tbreak;\n\t\t}\n\t\tconst tokenContainsRTL = (lineContainsRTL ? strings.containsRTL(lineContent.substring(startOffset, endIndex)) : false);\n\t\tresult[resultLen++] = new LinePart(endIndex, type, 0, tokenContainsRTL);\n\t\tstartOffset = endIndex;\n\t}\n\n\treturn result;\n}\n\n/**\n * written as a const enum to get value inlining.\n */\nconst enum Constants {\n\tLongToken = 50\n}\n\n/**\n * See https://github.com/microsoft/vscode/issues/6885.\n * It appears that having very large spans causes very slow reading of character positions.\n * So here we try to avoid that.\n */\nfunction splitLargeTokens(lineContent: string, tokens: LinePart[], onlyAtSpaces: boolean): LinePart[] {\n\tlet lastTokenEndIndex = 0;\n\tconst result: LinePart[] = [];\n\tlet resultLen = 0;\n\n\tif (onlyAtSpaces) {\n\t\t// Split only at spaces => we need to walk each character\n\t\tfor (let i = 0, len = tokens.length; i < len; i++) {\n\t\t\tconst token = tokens[i];\n\t\t\tconst tokenEndIndex = token.endIndex;\n\t\t\tif (lastTokenEndIndex + Constants.LongToken < tokenEndIndex) {\n\t\t\t\tconst tokenType = token.type;\n\t\t\t\tconst tokenMetadata = token.metadata;\n\t\t\t\tconst tokenContainsRTL = token.containsRTL;\n\n\t\t\t\tlet lastSpaceOffset = -1;\n\t\t\t\tlet currTokenStart = lastTokenEndIndex;\n\t\t\t\tfor (let j = lastTokenEndIndex; j < tokenEndIndex; j++) {\n\t\t\t\t\tif (lineContent.charCodeAt(j) === CharCode.Space) {\n\t\t\t\t\t\tlastSpaceOffset = j;\n\t\t\t\t\t}\n\t\t\t\t\tif (lastSpaceOffset !== -1 && j - currTokenStart >= Constants.LongToken) {\n\t\t\t\t\t\t// Split at `lastSpaceOffset` + 1\n\t\t\t\t\t\tresult[resultLen++] = new LinePart(lastSpaceOffset + 1, tokenType, tokenMetadata, tokenContainsRTL);\n\t\t\t\t\t\tcurrTokenStart = lastSpaceOffset + 1;\n\t\t\t\t\t\tlastSpaceOffset = -1;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (currTokenStart !== tokenEndIndex) {\n\t\t\t\t\tresult[resultLen++] = new LinePart(tokenEndIndex, tokenType, tokenMetadata, tokenContainsRTL);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tresult[resultLen++] = token;\n\t\t\t}\n\n\t\t\tlastTokenEndIndex = tokenEndIndex;\n\t\t}\n\t} else {\n\t\t// Split anywhere => we don't need to walk each character\n\t\tfor (let i = 0, len = tokens.length; i < len; i++) {\n\t\t\tconst token = tokens[i];\n\t\t\tconst tokenEndIndex = token.endIndex;\n\t\t\tconst diff = (tokenEndIndex - lastTokenEndIndex);\n\t\t\tif (diff > Constants.LongToken) {\n\t\t\t\tconst tokenType = token.type;\n\t\t\t\tconst tokenMetadata = token.metadata;\n\t\t\t\tconst tokenContainsRTL = token.containsRTL;\n\t\t\t\tconst piecesCount = Math.ceil(diff / Constants.LongToken);\n\t\t\t\tfor (let j = 1; j < piecesCount; j++) {\n\t\t\t\t\tconst pieceEndIndex = lastTokenEndIndex + (j * Constants.LongToken);\n\t\t\t\t\tresult[resultLen++] = new LinePart(pieceEndIndex, tokenType, tokenMetadata, tokenContainsRTL);\n\t\t\t\t}\n\t\t\t\tresult[resultLen++] = new LinePart(tokenEndIndex, tokenType, tokenMetadata, tokenContainsRTL);\n\t\t\t} else {\n\t\t\t\tresult[resultLen++] = token;\n\t\t\t}\n\t\t\tlastTokenEndIndex = tokenEndIndex;\n\t\t}\n\t}\n\n\treturn result;\n}\n\nfunction isControlCharacter(charCode: number): boolean {\n\tif (charCode < 32) {\n\t\treturn (charCode !== CharCode.Tab);\n\t}\n\tif (charCode === 127) {\n\t\t// DEL\n\t\treturn true;\n\t}\n\n\tif (\n\t\t(charCode >= 0x202A && charCode <= 0x202E)\n\t\t|| (charCode >= 0x2066 && charCode <= 0x2069)\n\t\t|| (charCode >= 0x200E && charCode <= 0x200F)\n\t\t|| charCode === 0x061C\n\t) {\n\t\t// Unicode Directional Formatting Characters\n\t\t// LRE\tU+202A\tLEFT-TO-RIGHT EMBEDDING\n\t\t// RLE\tU+202B\tRIGHT-TO-LEFT EMBEDDING\n\t\t// PDF\tU+202C\tPOP DIRECTIONAL FORMATTING\n\t\t// LRO\tU+202D\tLEFT-TO-RIGHT OVERRIDE\n\t\t// RLO\tU+202E\tRIGHT-TO-LEFT OVERRIDE\n\t\t// LRI\tU+2066\tLEFT-TO-RIGHT ISOLATE\n\t\t// RLI\tU+2067\tRIGHT-TO-LEFT ISOLATE\n\t\t// FSI\tU+2068\tFIRST STRONG ISOLATE\n\t\t// PDI\tU+2069\tPOP DIRECTIONAL ISOLATE\n\t\t// LRM\tU+200E\tLEFT-TO-RIGHT MARK\n\t\t// RLM\tU+200F\tRIGHT-TO-LEFT MARK\n\t\t// ALM\tU+061C\tARABIC LETTER MARK\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\nfunction extractControlCharacters(lineContent: string, tokens: LinePart[]): LinePart[] {\n\tconst result: LinePart[] = [];\n\tlet lastLinePart: LinePart = new LinePart(0, '', 0, false);\n\tlet charOffset = 0;\n\tfor (const token of tokens) {\n\t\tconst tokenEndIndex = token.endIndex;\n\t\tfor (; charOffset < tokenEndIndex; charOffset++) {\n\t\t\tconst charCode = lineContent.charCodeAt(charOffset);\n\t\t\tif (isControlCharacter(charCode)) {\n\t\t\t\tif (charOffset > lastLinePart.endIndex) {\n\t\t\t\t\t// emit previous part if it has text\n\t\t\t\t\tlastLinePart = new LinePart(charOffset, token.type, token.metadata, token.containsRTL);\n\t\t\t\t\tresult.push(lastLinePart);\n\t\t\t\t}\n\t\t\t\tlastLinePart = new LinePart(charOffset + 1, 'mtkcontrol', token.metadata, false);\n\t\t\t\tresult.push(lastLinePart);\n\t\t\t}\n\t\t}\n\t\tif (charOffset > lastLinePart.endIndex) {\n\t\t\t// emit previous part if it has text\n\t\t\tlastLinePart = new LinePart(tokenEndIndex, token.type, token.metadata, token.containsRTL);\n\t\t\tresult.push(lastLinePart);\n\t\t}\n\t}\n\treturn result;\n}\n\n/**\n * Whitespace is rendered by \"replacing\" tokens with a special-purpose `mtkw` type that is later recognized in the rendering phase.\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  .\n * The rendering phase will generate `style=\"width:...\"` for these tokens.\n */\nfunction _applyRenderWhitespace(input: RenderLineInput, lineContent: string, len: number, tokens: LinePart[]): LinePart[] {\n\n\tconst continuesWithWrappedLine = input.continuesWithWrappedLine;\n\tconst fauxIndentLength = input.fauxIndentLength;\n\tconst tabSize = input.tabSize;\n\tconst startVisibleColumn = input.startVisibleColumn;\n\tconst useMonospaceOptimizations = input.useMonospaceOptimizations;\n\tconst selections = input.selectionsOnLine;\n\tconst onlyBoundary = (input.renderWhitespace === RenderWhitespace.Boundary);\n\tconst onlyTrailing = (input.renderWhitespace === RenderWhitespace.Trailing);\n\tconst generateLinePartForEachWhitespace = (input.renderSpaceWidth !== input.spaceWidth);\n\n\tconst result: LinePart[] = [];\n\tlet resultLen = 0;\n\tlet tokenIndex = 0;\n\tlet tokenType = tokens[tokenIndex].type;\n\tlet tokenContainsRTL = tokens[tokenIndex].containsRTL;\n\tlet tokenEndIndex = tokens[tokenIndex].endIndex;\n\tconst tokensLength = tokens.length;\n\n\tlet lineIsEmptyOrWhitespace = false;\n\tlet firstNonWhitespaceIndex = strings.firstNonWhitespaceIndex(lineContent);\n\tlet lastNonWhitespaceIndex: number;\n\tif (firstNonWhitespaceIndex === -1) {\n\t\tlineIsEmptyOrWhitespace = true;\n\t\tfirstNonWhitespaceIndex = len;\n\t\tlastNonWhitespaceIndex = len;\n\t} else {\n\t\tlastNonWhitespaceIndex = strings.lastNonWhitespaceIndex(lineContent);\n\t}\n\n\tlet wasInWhitespace = false;\n\tlet currentSelectionIndex = 0;\n\tlet currentSelection = selections && selections[currentSelectionIndex];\n\tlet tmpIndent = startVisibleColumn % tabSize;\n\tfor (let charIndex = fauxIndentLength; charIndex < len; charIndex++) {\n\t\tconst chCode = lineContent.charCodeAt(charIndex);\n\n\t\tif (currentSelection && charIndex >= currentSelection.endOffset) {\n\t\t\tcurrentSelectionIndex++;\n\t\t\tcurrentSelection = selections && selections[currentSelectionIndex];\n\t\t}\n\n\t\tlet isInWhitespace: boolean;\n\t\tif (charIndex < firstNonWhitespaceIndex || charIndex > lastNonWhitespaceIndex) {\n\t\t\t// in leading or trailing whitespace\n\t\t\tisInWhitespace = true;\n\t\t} else if (chCode === CharCode.Tab) {\n\t\t\t// a tab character is rendered both in all and boundary cases\n\t\t\tisInWhitespace = true;\n\t\t} else if (chCode === CharCode.Space) {\n\t\t\t// hit a space character\n\t\t\tif (onlyBoundary) {\n\t\t\t\t// rendering only boundary whitespace\n\t\t\t\tif (wasInWhitespace) {\n\t\t\t\t\tisInWhitespace = true;\n\t\t\t\t} else {\n\t\t\t\t\tconst nextChCode = (charIndex + 1 < len ? lineContent.charCodeAt(charIndex + 1) : CharCode.Null);\n\t\t\t\t\tisInWhitespace = (nextChCode === CharCode.Space || nextChCode === CharCode.Tab);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tisInWhitespace = true;\n\t\t\t}\n\t\t} else {\n\t\t\tisInWhitespace = false;\n\t\t}\n\n\t\t// If rendering whitespace on selection, check that the charIndex falls within a selection\n\t\tif (isInWhitespace && selections) {\n\t\t\tisInWhitespace = !!currentSelection && currentSelection.startOffset <= charIndex && currentSelection.endOffset > charIndex;\n\t\t}\n\n\t\t// If rendering only trailing whitespace, check that the charIndex points to trailing whitespace.\n\t\tif (isInWhitespace && onlyTrailing) {\n\t\t\tisInWhitespace = lineIsEmptyOrWhitespace || charIndex > lastNonWhitespaceIndex;\n\t\t}\n\n\t\tif (isInWhitespace && tokenContainsRTL) {\n\t\t\t// If the token contains RTL text, breaking it up into multiple line parts\n\t\t\t// to render whitespace might affect the browser's bidi layout.\n\t\t\t//\n\t\t\t// We render whitespace in such tokens only if the whitespace\n\t\t\t// is the leading or the trailing whitespace of the line,\n\t\t\t// which doesn't affect the browser's bidi layout.\n\t\t\tif (charIndex >= firstNonWhitespaceIndex && charIndex <= lastNonWhitespaceIndex) {\n\t\t\t\tisInWhitespace = false;\n\t\t\t}\n\t\t}\n\n\t\tif (wasInWhitespace) {\n\t\t\t// was in whitespace token\n\t\t\tif (!isInWhitespace || (!useMonospaceOptimizations && tmpIndent >= tabSize)) {\n\t\t\t\t// leaving whitespace token or entering a new indent\n\t\t\t\tif (generateLinePartForEachWhitespace) {\n\t\t\t\t\tconst lastEndIndex = (resultLen > 0 ? result[resultLen - 1].endIndex : fauxIndentLength);\n\t\t\t\t\tfor (let i = lastEndIndex + 1; i <= charIndex; i++) {\n\t\t\t\t\t\tresult[resultLen++] = new LinePart(i, 'mtkw', LinePartMetadata.IS_WHITESPACE, false);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tresult[resultLen++] = new LinePart(charIndex, 'mtkw', LinePartMetadata.IS_WHITESPACE, false);\n\t\t\t\t}\n\t\t\t\ttmpIndent = tmpIndent % tabSize;\n\t\t\t}\n\t\t} else {\n\t\t\t// was in regular token\n\t\t\tif (charIndex === tokenEndIndex || (isInWhitespace && charIndex > fauxIndentLength)) {\n\t\t\t\tresult[resultLen++] = new LinePart(charIndex, tokenType, 0, tokenContainsRTL);\n\t\t\t\ttmpIndent = tmpIndent % tabSize;\n\t\t\t}\n\t\t}\n\n\t\tif (chCode === CharCode.Tab) {\n\t\t\ttmpIndent = tabSize;\n\t\t} else if (strings.isFullWidthCharacter(chCode)) {\n\t\t\ttmpIndent += 2;\n\t\t} else {\n\t\t\ttmpIndent++;\n\t\t}\n\n\t\twasInWhitespace = isInWhitespace;\n\n\t\twhile (charIndex === tokenEndIndex) {\n\t\t\ttokenIndex++;\n\t\t\tif (tokenIndex < tokensLength) {\n\t\t\t\ttokenType = tokens[tokenIndex].type;\n\t\t\t\ttokenContainsRTL = tokens[tokenIndex].containsRTL;\n\t\t\t\ttokenEndIndex = tokens[tokenIndex].endIndex;\n\t\t\t} else {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tlet generateWhitespace = false;\n\tif (wasInWhitespace) {\n\t\t// was in whitespace token\n\t\tif (continuesWithWrappedLine && onlyBoundary) {\n\t\t\tconst lastCharCode = (len > 0 ? lineContent.charCodeAt(len - 1) : CharCode.Null);\n\t\t\tconst prevCharCode = (len > 1 ? lineContent.charCodeAt(len - 2) : CharCode.Null);\n\t\t\tconst isSingleTrailingSpace = (lastCharCode === CharCode.Space && (prevCharCode !== CharCode.Space && prevCharCode !== CharCode.Tab));\n\t\t\tif (!isSingleTrailingSpace) {\n\t\t\t\tgenerateWhitespace = true;\n\t\t\t}\n\t\t} else {\n\t\t\tgenerateWhitespace = true;\n\t\t}\n\t}\n\n\tif (generateWhitespace) {\n\t\tif (generateLinePartForEachWhitespace) {\n\t\t\tconst lastEndIndex = (resultLen > 0 ? result[resultLen - 1].endIndex : fauxIndentLength);\n\t\t\tfor (let i = lastEndIndex + 1; i <= len; i++) {\n\t\t\t\tresult[resultLen++] = new LinePart(i, 'mtkw', LinePartMetadata.IS_WHITESPACE, false);\n\t\t\t}\n\t\t} else {\n\t\t\tresult[resultLen++] = new LinePart(len, 'mtkw', LinePartMetadata.IS_WHITESPACE, false);\n\t\t}\n\t} else {\n\t\tresult[resultLen++] = new LinePart(len, tokenType, 0, tokenContainsRTL);\n\t}\n\n\treturn result;\n}\n\n/**\n * Inline decorations are \"merged\" on top of tokens.\n * Special care must be taken when multiple inline decorations are at play and they overlap.\n */\nfunction _applyInlineDecorations(lineContent: string, len: number, tokens: LinePart[], _lineDecorations: LineDecoration[]): LinePart[] {\n\t_lineDecorations.sort(LineDecoration.compare);\n\tconst lineDecorations = LineDecorationsNormalizer.normalize(lineContent, _lineDecorations);\n\tconst lineDecorationsLen = lineDecorations.length;\n\n\tlet lineDecorationIndex = 0;\n\tconst result: LinePart[] = [];\n\tlet resultLen = 0;\n\tlet lastResultEndIndex = 0;\n\tfor (let tokenIndex = 0, len = tokens.length; tokenIndex < len; tokenIndex++) {\n\t\tconst token = tokens[tokenIndex];\n\t\tconst tokenEndIndex = token.endIndex;\n\t\tconst tokenType = token.type;\n\t\tconst tokenMetadata = token.metadata;\n\t\tconst tokenContainsRTL = token.containsRTL;\n\n\t\twhile (lineDecorationIndex < lineDecorationsLen && lineDecorations[lineDecorationIndex].startOffset < tokenEndIndex) {\n\t\t\tconst lineDecoration = lineDecorations[lineDecorationIndex];\n\n\t\t\tif (lineDecoration.startOffset > lastResultEndIndex) {\n\t\t\t\tlastResultEndIndex = lineDecoration.startOffset;\n\t\t\t\tresult[resultLen++] = new LinePart(lastResultEndIndex, tokenType, tokenMetadata, tokenContainsRTL);\n\t\t\t}\n\n\t\t\tif (lineDecoration.endOffset + 1 <= tokenEndIndex) {\n\t\t\t\t// This line decoration ends before this token ends\n\t\t\t\tlastResultEndIndex = lineDecoration.endOffset + 1;\n\t\t\t\tresult[resultLen++] = new LinePart(lastResultEndIndex, tokenType + ' ' + lineDecoration.className, tokenMetadata | lineDecoration.metadata, tokenContainsRTL);\n\t\t\t\tlineDecorationIndex++;\n\t\t\t} else {\n\t\t\t\t// This line decoration continues on to the next token\n\t\t\t\tlastResultEndIndex = tokenEndIndex;\n\t\t\t\tresult[resultLen++] = new LinePart(lastResultEndIndex, tokenType + ' ' + lineDecoration.className, tokenMetadata | lineDecoration.metadata, tokenContainsRTL);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (tokenEndIndex > lastResultEndIndex) {\n\t\t\tlastResultEndIndex = tokenEndIndex;\n\t\t\tresult[resultLen++] = new LinePart(lastResultEndIndex, tokenType, tokenMetadata, tokenContainsRTL);\n\t\t}\n\t}\n\n\tconst lastTokenEndIndex = tokens[tokens.length - 1].endIndex;\n\tif (lineDecorationIndex < lineDecorationsLen && lineDecorations[lineDecorationIndex].startOffset === lastTokenEndIndex) {\n\t\twhile (lineDecorationIndex < lineDecorationsLen && lineDecorations[lineDecorationIndex].startOffset === lastTokenEndIndex) {\n\t\t\tconst lineDecoration = lineDecorations[lineDecorationIndex];\n\t\t\tresult[resultLen++] = new LinePart(lastResultEndIndex, lineDecoration.className, lineDecoration.metadata, false);\n\t\t\tlineDecorationIndex++;\n\t\t}\n\t}\n\n\treturn result;\n}\n\n/**\n * This function is on purpose not split up into multiple functions to allow runtime type inference (i.e. performance reasons).\n * Notice how all the needed data is fully resolved and passed in (i.e. no other calls).\n */\nfunction _renderLine(input: ResolvedRenderLineInput, sb: StringBuilder): RenderLineOutput {\n\tconst fontIsMonospace = input.fontIsMonospace;\n\tconst canUseHalfwidthRightwardsArrow = input.canUseHalfwidthRightwardsArrow;\n\tconst containsForeignElements = input.containsForeignElements;\n\tconst lineContent = input.lineContent;\n\tconst len = input.len;\n\tconst isOverflowing = input.isOverflowing;\n\tconst overflowingCharCount = input.overflowingCharCount;\n\tconst parts = input.parts;\n\tconst fauxIndentLength = input.fauxIndentLength;\n\tconst tabSize = input.tabSize;\n\tconst startVisibleColumn = input.startVisibleColumn;\n\tconst containsRTL = input.containsRTL;\n\tconst spaceWidth = input.spaceWidth;\n\tconst renderSpaceCharCode = input.renderSpaceCharCode;\n\tconst renderWhitespace = input.renderWhitespace;\n\tconst renderControlCharacters = input.renderControlCharacters;\n\n\tconst characterMapping = new CharacterMapping(len + 1, parts.length);\n\tlet lastCharacterMappingDefined = false;\n\n\tlet charIndex = 0;\n\tlet visibleColumn = startVisibleColumn;\n\tlet charOffsetInPart = 0; // the character offset in the current part\n\tlet charHorizontalOffset = 0; // the character horizontal position in terms of chars relative to line start\n\n\tlet partDisplacement = 0;\n\n\tif (containsRTL) {\n\t\tsb.appendString('');\n\t} else {\n\t\tsb.appendString('');\n\t}\n\n\tfor (let partIndex = 0, tokensLen = parts.length; partIndex < tokensLen; partIndex++) {\n\n\t\tconst part = parts[partIndex];\n\t\tconst partEndIndex = part.endIndex;\n\t\tconst partType = part.type;\n\t\tconst partContainsRTL = part.containsRTL;\n\t\tconst partRendersWhitespace = (renderWhitespace !== RenderWhitespace.None && part.isWhitespace());\n\t\tconst partRendersWhitespaceWithWidth = partRendersWhitespace && !fontIsMonospace && (partType === 'mtkw'/*only whitespace*/ || !containsForeignElements);\n\t\tconst partIsEmptyAndHasPseudoAfter = (charIndex === partEndIndex && part.isPseudoAfter());\n\t\tcharOffsetInPart = 0;\n\n\t\tsb.appendString('= fauxIndentLength) {\n\t\t\t\t\t\t_visibleColumn += charWidth;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (partRendersWhitespaceWithWidth) {\n\t\t\t\tsb.appendString(' style=\"width:');\n\t\t\t\tsb.appendString(String(spaceWidth * partWidth));\n\t\t\t\tsb.appendString('px\"');\n\t\t\t}\n\t\t\tsb.appendASCIICharCode(CharCode.GreaterThan);\n\n\t\t\tfor (; charIndex < partEndIndex; charIndex++) {\n\t\t\t\tcharacterMapping.setColumnInfo(charIndex + 1, partIndex - partDisplacement, charOffsetInPart, charHorizontalOffset);\n\t\t\t\tpartDisplacement = 0;\n\t\t\t\tconst charCode = lineContent.charCodeAt(charIndex);\n\n\t\t\t\tlet producedCharacters: number;\n\t\t\t\tlet charWidth: number;\n\n\t\t\t\tif (charCode === CharCode.Tab) {\n\t\t\t\t\tproducedCharacters = (tabSize - (visibleColumn % tabSize)) | 0;\n\t\t\t\t\tcharWidth = producedCharacters;\n\n\t\t\t\t\tif (!canUseHalfwidthRightwardsArrow || charWidth > 1) {\n\t\t\t\t\t\tsb.appendCharCode(0x2192); // RIGHTWARDS ARROW\n\t\t\t\t\t} else {\n\t\t\t\t\t\tsb.appendCharCode(0xFFEB); // HALFWIDTH RIGHTWARDS ARROW\n\t\t\t\t\t}\n\t\t\t\t\tfor (let space = 2; space <= charWidth; space++) {\n\t\t\t\t\t\tsb.appendCharCode(0xA0); //  \n\t\t\t\t\t}\n\n\t\t\t\t} else { // must be CharCode.Space\n\t\t\t\t\tproducedCharacters = 2;\n\t\t\t\t\tcharWidth = 1;\n\n\t\t\t\t\tsb.appendCharCode(renderSpaceCharCode); // · or word separator middle dot\n\t\t\t\t\tsb.appendCharCode(0x200C); // ZERO WIDTH NON-JOINER\n\t\t\t\t}\n\n\t\t\t\tcharOffsetInPart += producedCharacters;\n\t\t\t\tcharHorizontalOffset += charWidth;\n\t\t\t\tif (charIndex >= fauxIndentLength) {\n\t\t\t\t\tvisibleColumn += charWidth;\n\t\t\t\t}\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tsb.appendASCIICharCode(CharCode.GreaterThan);\n\n\t\t\tfor (; charIndex < partEndIndex; charIndex++) {\n\t\t\t\tcharacterMapping.setColumnInfo(charIndex + 1, partIndex - partDisplacement, charOffsetInPart, charHorizontalOffset);\n\t\t\t\tpartDisplacement = 0;\n\t\t\t\tconst charCode = lineContent.charCodeAt(charIndex);\n\n\t\t\t\tlet producedCharacters = 1;\n\t\t\t\tlet charWidth = 1;\n\n\t\t\t\tswitch (charCode) {\n\t\t\t\t\tcase CharCode.Tab:\n\t\t\t\t\t\tproducedCharacters = (tabSize - (visibleColumn % tabSize));\n\t\t\t\t\t\tcharWidth = producedCharacters;\n\t\t\t\t\t\tfor (let space = 1; space <= producedCharacters; space++) {\n\t\t\t\t\t\t\tsb.appendCharCode(0xA0); //  \n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase CharCode.Space:\n\t\t\t\t\t\tsb.appendCharCode(0xA0); //  \n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase CharCode.LessThan:\n\t\t\t\t\t\tsb.appendString('<');\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase CharCode.GreaterThan:\n\t\t\t\t\t\tsb.appendString('>');\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase CharCode.Ampersand:\n\t\t\t\t\t\tsb.appendString('&');\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase CharCode.Null:\n\t\t\t\t\t\tif (renderControlCharacters) {\n\t\t\t\t\t\t\t// See https://unicode-table.com/en/blocks/control-pictures/\n\t\t\t\t\t\t\tsb.appendCharCode(9216);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tsb.appendString('�');\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase CharCode.UTF8_BOM:\n\t\t\t\t\tcase CharCode.LINE_SEPARATOR:\n\t\t\t\t\tcase CharCode.PARAGRAPH_SEPARATOR:\n\t\t\t\t\tcase CharCode.NEXT_LINE:\n\t\t\t\t\t\tsb.appendCharCode(0xFFFD);\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tif (strings.isFullWidthCharacter(charCode)) {\n\t\t\t\t\t\t\tcharWidth++;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// See https://unicode-table.com/en/blocks/control-pictures/\n\t\t\t\t\t\tif (renderControlCharacters && charCode < 32) {\n\t\t\t\t\t\t\tsb.appendCharCode(9216 + charCode);\n\t\t\t\t\t\t} else if (renderControlCharacters && charCode === 127) {\n\t\t\t\t\t\t\t// DEL\n\t\t\t\t\t\t\tsb.appendCharCode(9249);\n\t\t\t\t\t\t} else if (renderControlCharacters && isControlCharacter(charCode)) {\n\t\t\t\t\t\t\tsb.appendString('[U+');\n\t\t\t\t\t\t\tsb.appendString(to4CharHex(charCode));\n\t\t\t\t\t\t\tsb.appendString(']');\n\t\t\t\t\t\t\tproducedCharacters = 8;\n\t\t\t\t\t\t\tcharWidth = producedCharacters;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tsb.appendCharCode(charCode);\n\t\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tcharOffsetInPart += producedCharacters;\n\t\t\t\tcharHorizontalOffset += charWidth;\n\t\t\t\tif (charIndex >= fauxIndentLength) {\n\t\t\t\t\tvisibleColumn += charWidth;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (partIsEmptyAndHasPseudoAfter) {\n\t\t\tpartDisplacement++;\n\t\t} else {\n\t\t\tpartDisplacement = 0;\n\t\t}\n\n\t\tif (charIndex >= len && !lastCharacterMappingDefined && part.isPseudoAfter()) {\n\t\t\tlastCharacterMappingDefined = true;\n\t\t\tcharacterMapping.setColumnInfo(charIndex + 1, partIndex, charOffsetInPart, charHorizontalOffset);\n\t\t}\n\n\t\tsb.appendString('');\n\n\t}\n\n\tif (!lastCharacterMappingDefined) {\n\t\t// When getting client rects for the last character, we will position the\n\t\t// text range at the end of the span, insteaf of at the beginning of next span\n\t\tcharacterMapping.setColumnInfo(len + 1, parts.length - 1, charOffsetInPart, charHorizontalOffset);\n\t}\n\n\tif (isOverflowing) {\n\t\tsb.appendString('');\n\t\tsb.appendString(nls.localize('showMore', \"Show more ({0})\", renderOverflowingCharCount(overflowingCharCount)));\n\t\tsb.appendString('');\n\t}\n\n\tsb.appendString('');\n\n\treturn new RenderLineOutput(characterMapping, containsRTL, containsForeignElements);\n}\n\nfunction to4CharHex(n: number): string {\n\treturn n.toString(16).toUpperCase().padStart(4, '0');\n}\n\nfunction renderOverflowingCharCount(n: number): string {\n\tif (n < 1024) {\n\t\treturn nls.localize('overflow.chars', \"{0} chars\", n);\n\t}\n\tif (n < 1024 * 1024) {\n\t\treturn `${(n / 1024).toFixed(1)} KB`;\n\t}\n\treturn `${(n / 1024 / 1024).toFixed(1)} MB`;\n}\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\nimport { createTrustedTypesPolicy } from 'vs/base/browser/trustedTypes';\nimport { applyFontInfo } from 'vs/editor/browser/config/domFontInfo';\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\nimport { EditorFontLigatures, EditorOption, FindComputedEditorOptionValueById } from 'vs/editor/common/config/editorOptions';\nimport { FontInfo } from 'vs/editor/common/config/fontInfo';\nimport { StringBuilder } from 'vs/editor/common/core/stringBuilder';\nimport { ModelLineProjectionData } from 'vs/editor/common/modelLineProjectionData';\nimport { IViewLineTokens, LineTokens } from 'vs/editor/common/tokens/lineTokens';\nimport { LineDecoration } from 'vs/editor/common/viewLayout/lineDecorations';\nimport { RenderLineInput, renderViewLine } from 'vs/editor/common/viewLayout/viewLineRenderer';\nimport { InlineDecoration, ViewLineRenderingData } from 'vs/editor/common/viewModel';\n\nconst ttPolicy = createTrustedTypesPolicy('diffEditorWidget', { createHTML: value => value });\n\nexport function renderLines(source: LineSource, options: RenderOptions, decorations: InlineDecoration[], domNode: HTMLElement): RenderLinesResult {\n\tapplyFontInfo(domNode, options.fontInfo);\n\n\tconst hasCharChanges = (decorations.length > 0);\n\n\tconst sb = new StringBuilder(10000);\n\tlet maxCharsPerLine = 0;\n\tlet renderedLineCount = 0;\n\tconst viewLineCounts: number[] = [];\n\tfor (let lineIndex = 0; lineIndex < source.lineTokens.length; lineIndex++) {\n\t\tconst lineNumber = lineIndex + 1;\n\t\tconst lineTokens = source.lineTokens[lineIndex];\n\t\tconst lineBreakData = source.lineBreakData[lineIndex];\n\t\tconst actualDecorations = LineDecoration.filter(decorations, lineNumber, 1, Number.MAX_SAFE_INTEGER);\n\n\t\tif (lineBreakData) {\n\t\t\tlet lastBreakOffset = 0;\n\t\t\tfor (const breakOffset of lineBreakData.breakOffsets) {\n\t\t\t\tconst viewLineTokens = lineTokens.sliceAndInflate(lastBreakOffset, breakOffset, 0);\n\t\t\t\tmaxCharsPerLine = Math.max(maxCharsPerLine, renderOriginalLine(\n\t\t\t\t\trenderedLineCount,\n\t\t\t\t\tviewLineTokens,\n\t\t\t\t\tLineDecoration.extractWrapped(actualDecorations, lastBreakOffset, breakOffset),\n\t\t\t\t\thasCharChanges,\n\t\t\t\t\tsource.mightContainNonBasicASCII,\n\t\t\t\t\tsource.mightContainRTL,\n\t\t\t\t\toptions,\n\t\t\t\t\tsb\n\t\t\t\t));\n\t\t\t\trenderedLineCount++;\n\t\t\t\tlastBreakOffset = breakOffset;\n\t\t\t}\n\t\t\tviewLineCounts.push(lineBreakData.breakOffsets.length);\n\t\t} else {\n\t\t\tviewLineCounts.push(1);\n\t\t\tmaxCharsPerLine = Math.max(maxCharsPerLine, renderOriginalLine(\n\t\t\t\trenderedLineCount,\n\t\t\t\tlineTokens,\n\t\t\t\tactualDecorations,\n\t\t\t\thasCharChanges,\n\t\t\t\tsource.mightContainNonBasicASCII,\n\t\t\t\tsource.mightContainRTL,\n\t\t\t\toptions,\n\t\t\t\tsb,\n\t\t\t));\n\t\t\trenderedLineCount++;\n\t\t}\n\t}\n\tmaxCharsPerLine += options.scrollBeyondLastColumn;\n\n\tconst html = sb.build();\n\tconst trustedhtml = ttPolicy ? ttPolicy.createHTML(html) : html;\n\tdomNode.innerHTML = trustedhtml as string;\n\tconst minWidthInPx = (maxCharsPerLine * options.typicalHalfwidthCharacterWidth);\n\n\treturn {\n\t\theightInLines: renderedLineCount,\n\t\tminWidthInPx,\n\t\tviewLineCounts,\n\t};\n}\n\n\nexport class LineSource {\n\tconstructor(\n\t\tpublic readonly lineTokens: LineTokens[],\n\t\tpublic readonly lineBreakData: (ModelLineProjectionData | null)[],\n\t\tpublic readonly mightContainNonBasicASCII: boolean,\n\t\tpublic readonly mightContainRTL: boolean,\n\t) { }\n}\n\nexport class RenderOptions {\n\tpublic static fromEditor(editor: ICodeEditor): RenderOptions {\n\n\t\tconst modifiedEditorOptions = editor.getOptions();\n\t\tconst fontInfo = modifiedEditorOptions.get(EditorOption.fontInfo);\n\t\tconst layoutInfo = modifiedEditorOptions.get(EditorOption.layoutInfo);\n\n\t\treturn new RenderOptions(\n\t\t\teditor.getModel()?.getOptions().tabSize || 0,\n\t\t\tfontInfo,\n\t\t\tmodifiedEditorOptions.get(EditorOption.disableMonospaceOptimizations),\n\t\t\tfontInfo.typicalHalfwidthCharacterWidth,\n\t\t\tmodifiedEditorOptions.get(EditorOption.scrollBeyondLastColumn),\n\n\t\t\tmodifiedEditorOptions.get(EditorOption.lineHeight),\n\n\t\t\tlayoutInfo.decorationsWidth,\n\t\t\tmodifiedEditorOptions.get(EditorOption.stopRenderingLineAfter),\n\t\t\tmodifiedEditorOptions.get(EditorOption.renderWhitespace),\n\t\t\tmodifiedEditorOptions.get(EditorOption.renderControlCharacters),\n\t\t\tmodifiedEditorOptions.get(EditorOption.fontLigatures),\n\t\t);\n\t}\n\n\tconstructor(\n\t\tpublic readonly tabSize: number,\n\t\tpublic readonly fontInfo: FontInfo,\n\t\tpublic readonly disableMonospaceOptimizations: boolean,\n\t\tpublic readonly typicalHalfwidthCharacterWidth: number,\n\t\tpublic readonly scrollBeyondLastColumn: number,\n\t\tpublic readonly lineHeight: number,\n\t\tpublic readonly lineDecorationsWidth: number,\n\t\tpublic readonly stopRenderingLineAfter: number,\n\t\tpublic readonly renderWhitespace: FindComputedEditorOptionValueById,\n\t\tpublic readonly renderControlCharacters: boolean,\n\t\tpublic readonly fontLigatures: FindComputedEditorOptionValueById,\n\t) { }\n}\n\nexport interface RenderLinesResult {\n\tminWidthInPx: number;\n\theightInLines: number;\n\tviewLineCounts: number[];\n}\n\nfunction renderOriginalLine(\n\tviewLineIdx: number,\n\tlineTokens: IViewLineTokens,\n\tdecorations: LineDecoration[],\n\thasCharChanges: boolean,\n\tmightContainNonBasicASCII: boolean,\n\tmightContainRTL: boolean,\n\toptions: RenderOptions,\n\tsb: StringBuilder,\n): number {\n\n\tsb.appendString('
    ');\n\n\tconst lineContent = lineTokens.getLineContent();\n\tconst isBasicASCII = ViewLineRenderingData.isBasicASCII(lineContent, mightContainNonBasicASCII);\n\tconst containsRTL = ViewLineRenderingData.containsRTL(lineContent, isBasicASCII, mightContainRTL);\n\tconst output = renderViewLine(new RenderLineInput(\n\t\t(options.fontInfo.isMonospace && !options.disableMonospaceOptimizations),\n\t\toptions.fontInfo.canUseHalfwidthRightwardsArrow,\n\t\tlineContent,\n\t\tfalse,\n\t\tisBasicASCII,\n\t\tcontainsRTL,\n\t\t0,\n\t\tlineTokens,\n\t\tdecorations,\n\t\toptions.tabSize,\n\t\t0,\n\t\toptions.fontInfo.spaceWidth,\n\t\toptions.fontInfo.middotWidth,\n\t\toptions.fontInfo.wsmiddotWidth,\n\t\toptions.stopRenderingLineAfter,\n\t\toptions.renderWhitespace,\n\t\toptions.renderControlCharacters,\n\t\toptions.fontLigatures !== EditorFontLigatures.OFF,\n\t\tnull // Send no selections, original line cannot be selected\n\t), sb);\n\n\tsb.appendString('
    ');\n\n\treturn output.characterMapping.getHorizontalOffset(output.characterMapping.length);\n}\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\nimport { onUnexpectedError } from 'vs/base/common/errors';\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { IMatch } from 'vs/base/common/filters';\nimport { defaultGenerator } from 'vs/base/common/idGenerator';\nimport { dispose, IDisposable, IReference } from 'vs/base/common/lifecycle';\nimport { ResourceMap } from 'vs/base/common/map';\nimport { basename, extUri } from 'vs/base/common/resources';\nimport * as strings from 'vs/base/common/strings';\nimport { Constants } from 'vs/base/common/uint';\nimport { URI } from 'vs/base/common/uri';\nimport { Position } from 'vs/editor/common/core/position';\nimport { IRange, Range } from 'vs/editor/common/core/range';\nimport { Location, LocationLink } from 'vs/editor/common/languages';\nimport { ITextEditorModel, ITextModelService } from 'vs/editor/common/services/resolverService';\nimport { localize } from 'vs/nls';\n\nexport class OneReference {\n\n\treadonly id: string = defaultGenerator.nextId();\n\n\tprivate _range?: IRange;\n\n\tconstructor(\n\t\treadonly isProviderFirst: boolean,\n\t\treadonly parent: FileReferences,\n\t\treadonly link: LocationLink,\n\t\tprivate _rangeCallback: (ref: OneReference) => void\n\t) { }\n\n\tget uri() {\n\t\treturn this.link.uri;\n\t}\n\n\tget range(): IRange {\n\t\treturn this._range ?? this.link.targetSelectionRange ?? this.link.range;\n\t}\n\n\tset range(value: IRange) {\n\t\tthis._range = value;\n\t\tthis._rangeCallback(this);\n\t}\n\n\tget ariaMessage(): string {\n\n\t\tconst preview = this.parent.getPreview(this)?.preview(this.range);\n\n\t\tif (!preview) {\n\t\t\treturn localize(\n\t\t\t\t'aria.oneReference', \"in {0} on line {1} at column {2}\",\n\t\t\t\tbasename(this.uri), this.range.startLineNumber, this.range.startColumn\n\t\t\t);\n\t\t} else {\n\t\t\treturn localize(\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'] }, \"{0} in {1} on line {2} at column {3}\",\n\t\t\t\tpreview.value, basename(this.uri), this.range.startLineNumber, this.range.startColumn\n\t\t\t);\n\t\t}\n\t}\n}\n\nexport class FilePreview implements IDisposable {\n\n\tconstructor(\n\t\tprivate readonly _modelReference: IReference\n\t) { }\n\n\tdispose(): void {\n\t\tthis._modelReference.dispose();\n\t}\n\n\tpreview(range: IRange, n: number = 8): { value: string; highlight: IMatch } | undefined {\n\t\tconst model = this._modelReference.object.textEditorModel;\n\n\t\tif (!model) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst { startLineNumber, startColumn, endLineNumber, endColumn } = range;\n\t\tconst word = model.getWordUntilPosition({ lineNumber: startLineNumber, column: startColumn - n });\n\t\tconst beforeRange = new Range(startLineNumber, word.startColumn, startLineNumber, startColumn);\n\t\tconst afterRange = new Range(endLineNumber, endColumn, endLineNumber, Constants.MAX_SAFE_SMALL_INTEGER);\n\n\t\tconst before = model.getValueInRange(beforeRange).replace(/^\\s+/, '');\n\t\tconst inside = model.getValueInRange(range);\n\t\tconst after = model.getValueInRange(afterRange).replace(/\\s+$/, '');\n\n\t\treturn {\n\t\t\tvalue: before + inside + after,\n\t\t\thighlight: { start: before.length, end: before.length + inside.length }\n\t\t};\n\t}\n}\n\nexport class FileReferences implements IDisposable {\n\n\treadonly children: OneReference[] = [];\n\n\tprivate _previews = new ResourceMap();\n\n\tconstructor(\n\t\treadonly parent: ReferencesModel,\n\t\treadonly uri: URI\n\t) { }\n\n\tdispose(): void {\n\t\tdispose(this._previews.values());\n\t\tthis._previews.clear();\n\t}\n\n\tgetPreview(child: OneReference): FilePreview | undefined {\n\t\treturn this._previews.get(child.uri);\n\t}\n\n\tget ariaMessage(): string {\n\t\tconst len = this.children.length;\n\t\tif (len === 1) {\n\t\t\treturn localize('aria.fileReferences.1', \"1 symbol in {0}, full path {1}\", basename(this.uri), this.uri.fsPath);\n\t\t} else {\n\t\t\treturn localize('aria.fileReferences.N', \"{0} symbols in {1}, full path {2}\", len, basename(this.uri), this.uri.fsPath);\n\t\t}\n\t}\n\n\tasync resolve(textModelResolverService: ITextModelService): Promise {\n\t\tif (this._previews.size !== 0) {\n\t\t\treturn this;\n\t\t}\n\t\tfor (const child of this.children) {\n\t\t\tif (this._previews.has(child.uri)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst ref = await textModelResolverService.createModelReference(child.uri);\n\t\t\t\tthis._previews.set(child.uri, new FilePreview(ref));\n\t\t\t} catch (err) {\n\t\t\t\tonUnexpectedError(err);\n\t\t\t}\n\t\t}\n\t\treturn this;\n\t}\n}\n\nexport class ReferencesModel implements IDisposable {\n\n\tprivate readonly _links: LocationLink[];\n\tprivate readonly _title: string;\n\n\treadonly groups: FileReferences[] = [];\n\treadonly references: OneReference[] = [];\n\n\treadonly _onDidChangeReferenceRange = new Emitter();\n\treadonly onDidChangeReferenceRange: Event = this._onDidChangeReferenceRange.event;\n\n\tconstructor(links: LocationLink[], title: string) {\n\t\tthis._links = links;\n\t\tthis._title = title;\n\n\t\t// grouping and sorting\n\t\tconst [providersFirst] = links;\n\t\tlinks.sort(ReferencesModel._compareReferences);\n\n\t\tlet current: FileReferences | undefined;\n\t\tfor (const link of links) {\n\t\t\tif (!current || !extUri.isEqual(current.uri, link.uri, true)) {\n\t\t\t\t// new group\n\t\t\t\tcurrent = new FileReferences(this, link.uri);\n\t\t\t\tthis.groups.push(current);\n\t\t\t}\n\n\t\t\t// append, check for equality first!\n\t\t\tif (current.children.length === 0 || ReferencesModel._compareReferences(link, current.children[current.children.length - 1]) !== 0) {\n\n\t\t\t\tconst oneRef = new OneReference(\n\t\t\t\t\tprovidersFirst === link,\n\t\t\t\t\tcurrent,\n\t\t\t\t\tlink,\n\t\t\t\t\tref => this._onDidChangeReferenceRange.fire(ref)\n\t\t\t\t);\n\t\t\t\tthis.references.push(oneRef);\n\t\t\t\tcurrent.children.push(oneRef);\n\t\t\t}\n\t\t}\n\t}\n\n\tdispose(): void {\n\t\tdispose(this.groups);\n\t\tthis._onDidChangeReferenceRange.dispose();\n\t\tthis.groups.length = 0;\n\t}\n\n\tclone(): ReferencesModel {\n\t\treturn new ReferencesModel(this._links, this._title);\n\t}\n\n\tget title(): string {\n\t\treturn this._title;\n\t}\n\n\tget isEmpty(): boolean {\n\t\treturn this.groups.length === 0;\n\t}\n\n\tget ariaMessage(): string {\n\t\tif (this.isEmpty) {\n\t\t\treturn localize('aria.result.0', \"No results found\");\n\t\t} else if (this.references.length === 1) {\n\t\t\treturn localize('aria.result.1', \"Found 1 symbol in {0}\", this.references[0].uri.fsPath);\n\t\t} else if (this.groups.length === 1) {\n\t\t\treturn localize('aria.result.n1', \"Found {0} symbols in {1}\", this.references.length, this.groups[0].uri.fsPath);\n\t\t} else {\n\t\t\treturn localize('aria.result.nm', \"Found {0} symbols in {1} files\", this.references.length, this.groups.length);\n\t\t}\n\t}\n\n\tnextOrPreviousReference(reference: OneReference, next: boolean): OneReference {\n\n\t\tconst { parent } = reference;\n\n\t\tlet idx = parent.children.indexOf(reference);\n\t\tconst childCount = parent.children.length;\n\t\tconst groupCount = parent.parent.groups.length;\n\n\t\tif (groupCount === 1 || next && idx + 1 < childCount || !next && idx > 0) {\n\t\t\t// cycling within one file\n\t\t\tif (next) {\n\t\t\t\tidx = (idx + 1) % childCount;\n\t\t\t} else {\n\t\t\t\tidx = (idx + childCount - 1) % childCount;\n\t\t\t}\n\t\t\treturn parent.children[idx];\n\t\t}\n\n\t\tidx = parent.parent.groups.indexOf(parent);\n\t\tif (next) {\n\t\t\tidx = (idx + 1) % groupCount;\n\t\t\treturn parent.parent.groups[idx].children[0];\n\t\t} else {\n\t\t\tidx = (idx + groupCount - 1) % groupCount;\n\t\t\treturn parent.parent.groups[idx].children[parent.parent.groups[idx].children.length - 1];\n\t\t}\n\t}\n\n\tnearestReference(resource: URI, position: Position): OneReference | undefined {\n\n\t\tconst nearest = this.references.map((ref, idx) => {\n\t\t\treturn {\n\t\t\t\tidx,\n\t\t\t\tprefixLen: strings.commonPrefixLength(ref.uri.toString(), resource.toString()),\n\t\t\t\toffsetDist: Math.abs(ref.range.startLineNumber - position.lineNumber) * 100 + Math.abs(ref.range.startColumn - position.column)\n\t\t\t};\n\t\t}).sort((a, b) => {\n\t\t\tif (a.prefixLen > b.prefixLen) {\n\t\t\t\treturn -1;\n\t\t\t} else if (a.prefixLen < b.prefixLen) {\n\t\t\t\treturn 1;\n\t\t\t} else if (a.offsetDist < b.offsetDist) {\n\t\t\t\treturn -1;\n\t\t\t} else if (a.offsetDist > b.offsetDist) {\n\t\t\t\treturn 1;\n\t\t\t} else {\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t})[0];\n\n\t\tif (nearest) {\n\t\t\treturn this.references[nearest.idx];\n\t\t}\n\t\treturn undefined;\n\t}\n\n\treferenceAt(resource: URI, position: Position): OneReference | undefined {\n\t\tfor (const ref of this.references) {\n\t\t\tif (ref.uri.toString() === resource.toString()) {\n\t\t\t\tif (Range.containsPosition(ref.range, position)) {\n\t\t\t\t\treturn ref;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tfirstReference(): OneReference | undefined {\n\t\tfor (const ref of this.references) {\n\t\t\tif (ref.isProviderFirst) {\n\t\t\t\treturn ref;\n\t\t\t}\n\t\t}\n\t\treturn this.references[0];\n\t}\n\n\tprivate static _compareReferences(a: Location, b: Location): number {\n\t\treturn extUri.compare(a.uri, b.uri) || Range.compareRangesUsingStarts(a.range, b.range);\n\t}\n}\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\nimport { IDisposable } from 'vs/base/common/lifecycle';\n\nexport interface IAccessibleViewImplentation {\n}\n\nexport const AccessibleViewRegistry = new class AccessibleViewRegistry {\n\t_implementations: IAccessibleViewImplentation[] = [];\n\n\tregister(implementation: IAccessibleViewImplentation): IDisposable {\n\t\tthis._implementations.push(implementation);\n\t\treturn {\n\t\t\tdispose: () => {\n\t\t\t\tconst idx = this._implementations.indexOf(implementation);\n\t\t\t\tif (idx !== -1) {\n\t\t\t\t\tthis._implementations.splice(idx, 1);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n\n\tgetImplementations(): IAccessibleViewImplentation[] {\n\t\treturn this._implementations;\n\t}\n};\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\nimport { URI } from 'vs/base/common/uri';\nimport { ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey';\nimport { ThemeIcon } from 'vs/base/common/themables';\nimport { Categories } from './actionCommonCategories';\nimport { ICommandMetadata } from 'vs/platform/commands/common/commands';\n\nexport interface ILocalizedString {\n\n\t/**\n\t * The localized value of the string.\n\t */\n\tvalue: string;\n\n\t/**\n\t * The original (non localized value of the string)\n\t */\n\toriginal: string;\n}\n\nexport function isLocalizedString(thing: any): thing is ILocalizedString {\n\treturn thing\n\t\t&& typeof thing === 'object'\n\t\t&& typeof thing.original === 'string'\n\t\t&& typeof thing.value === 'string';\n}\n\nexport interface ICommandActionTitle extends ILocalizedString {\n\n\t/**\n\t * The title with a mnemonic designation. && precedes the mnemonic.\n\t */\n\tmnemonicTitle?: string;\n}\n\nexport type Icon = { dark?: URI; light?: URI } | ThemeIcon;\n\nexport interface ICommandActionToggleInfo {\n\n\t/**\n\t * The condition that marks the action as toggled.\n\t */\n\tcondition: ContextKeyExpression;\n\n\ticon?: Icon;\n\n\t/**\n\t * The title that goes well with a a check mark, e.g \"(check) Line Numbers\" vs \"Toggle Line Numbers\"\n\t */\n\ttitle?: string;\n\n\t/**\n\t * Like title but with a mnemonic designation.\n\t */\n\tmnemonicTitle?: string;\n}\n\nexport function isICommandActionToggleInfo(thing: ContextKeyExpression | ICommandActionToggleInfo | undefined): thing is ICommandActionToggleInfo {\n\treturn thing ? (thing).condition !== undefined : false;\n}\n\nexport interface ICommandAction {\n\tid: string;\n\ttitle: string | ICommandActionTitle;\n\tshortTitle?: string | ICommandActionTitle;\n\t/**\n\t * Metadata about this command, used for:\n\t * - API commands\n\t * - when showing keybindings that have no other UX\n\t * - when searching for commands in the Command Palette\n\t */\n\tmetadata?: ICommandMetadata;\n\tcategory?: keyof typeof Categories | ILocalizedString | string;\n\ttooltip?: string | ILocalizedString;\n\ticon?: Icon;\n\t/**\n\t * Precondition controls enablement (for example for a menu item, show\n\t * it in grey or for a command, do not allow to invoke it)\n\t */\n\tprecondition?: ContextKeyExpression;\n\n\t/**\n\t * The action is a toggle action. Define the context key expression that reflects its toggle-state\n\t * or define toggle-info including an icon and a title that goes well with a checkmark.\n\t */\n\ttoggled?: ContextKeyExpression | ICommandActionToggleInfo;\n}\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\nimport { localize2 } from 'vs/nls';\n\nexport const Categories = Object.freeze({\n\tView: localize2('view', 'View'),\n\tHelp: localize2('help', 'Help'),\n\tTest: localize2('test', 'Test'),\n\tFile: localize2('file', 'File'),\n\tPreferences: localize2('preferences', 'Preferences'),\n\tDeveloper: localize2({ key: 'developer', comment: ['A developer on Code itself or someone diagnosing issues in Code'] }, \"Developer\"),\n});\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\nimport { CharCode } from 'vs/base/common/charCode';\nimport { illegalState } from 'vs/base/common/errors';\nimport { localize } from 'vs/nls';\n\nexport const enum TokenType {\n\tLParen,\n\tRParen,\n\tNeg,\n\tEq,\n\tNotEq,\n\tLt,\n\tLtEq,\n\tGt,\n\tGtEq,\n\tRegexOp,\n\tRegexStr,\n\tTrue,\n\tFalse,\n\tIn,\n\tNot,\n\tAnd,\n\tOr,\n\tStr,\n\tQuotedStr,\n\tError,\n\tEOF,\n}\n\nexport type Token =\n\t| { type: TokenType.LParen; offset: number }\n\t| { type: TokenType.RParen; offset: number }\n\t| { type: TokenType.Neg; offset: number }\n\t| { type: TokenType.Eq; offset: number; isTripleEq: boolean }\n\t| { type: TokenType.NotEq; offset: number; isTripleEq: boolean }\n\t| { type: TokenType.Lt; offset: number }\n\t| { type: TokenType.LtEq; offset: number }\n\t| { type: TokenType.Gt; offset: number }\n\t| { type: TokenType.GtEq; offset: number }\n\t| { type: TokenType.RegexOp; offset: number }\n\t| { type: TokenType.RegexStr; offset: number; lexeme: string }\n\t| { type: TokenType.True; offset: number }\n\t| { type: TokenType.False; offset: number }\n\t| { type: TokenType.In; offset: number }\n\t| { type: TokenType.Not; offset: number }\n\t| { type: TokenType.And; offset: number }\n\t| { type: TokenType.Or; offset: number }\n\t| { type: TokenType.Str; offset: number; lexeme: string }\n\t| { type: TokenType.QuotedStr; offset: number; lexeme: string }\n\t| { type: TokenType.Error; offset: number; lexeme: string }\n\t| { type: TokenType.EOF; offset: number };\n\ntype KeywordTokenType = TokenType.Not | TokenType.In | TokenType.False | TokenType.True;\ntype TokenTypeWithoutLexeme =\n\tTokenType.LParen |\n\tTokenType.RParen |\n\tTokenType.Neg |\n\tTokenType.Lt |\n\tTokenType.LtEq |\n\tTokenType.Gt |\n\tTokenType.GtEq |\n\tTokenType.RegexOp |\n\tTokenType.True |\n\tTokenType.False |\n\tTokenType.In |\n\tTokenType.Not |\n\tTokenType.And |\n\tTokenType.Or |\n\tTokenType.EOF;\n\n/**\n * Example:\n * `foo == bar'` - note how single quote doesn't have a corresponding closing quote,\n * so it's reported as unexpected\n */\nexport type LexingError = {\n\toffset: number; /** note that this doesn't take into account escape characters from the original encoding of the string, e.g., within an extension manifest file's JSON encoding */\n\tlexeme: string;\n\tadditionalInfo?: string;\n};\n\nfunction hintDidYouMean(...meant: string[]) {\n\tswitch (meant.length) {\n\t\tcase 1:\n\t\t\treturn localize('contextkey.scanner.hint.didYouMean1', \"Did you mean {0}?\", meant[0]);\n\t\tcase 2:\n\t\t\treturn localize('contextkey.scanner.hint.didYouMean2', \"Did you mean {0} or {1}?\", meant[0], meant[1]);\n\t\tcase 3:\n\t\t\treturn localize('contextkey.scanner.hint.didYouMean3', \"Did you mean {0}, {1} or {2}?\", meant[0], meant[1], meant[2]);\n\t\tdefault: // we just don't expect that many\n\t\t\treturn undefined;\n\t}\n}\n\nconst hintDidYouForgetToOpenOrCloseQuote = localize('contextkey.scanner.hint.didYouForgetToOpenOrCloseQuote', \"Did you forget to open or close the quote?\");\nconst hintDidYouForgetToEscapeSlash = localize('contextkey.scanner.hint.didYouForgetToEscapeSlash', \"Did you forget to escape the '/' (slash) character? Put two backslashes before it to escape, e.g., '\\\\\\\\/\\'.\");\n\n/**\n * A simple scanner for context keys.\n *\n * Example:\n *\n * ```ts\n * const scanner = new Scanner().reset('resourceFileName =~ /docker/ && !config.docker.enabled');\n * const tokens = [...scanner];\n * if (scanner.errorTokens.length > 0) {\n * scanner.errorTokens.forEach(err => console.error(`Unexpected token at ${err.offset}: ${err.lexeme}\\nHint: ${err.additional}`));\n * } else {\n * // process tokens\n * }\n * ```\n */\nexport class Scanner {\n\n\tstatic getLexeme(token: Token): string {\n\t\tswitch (token.type) {\n\t\t\tcase TokenType.LParen:\n\t\t\t\treturn '(';\n\t\t\tcase TokenType.RParen:\n\t\t\t\treturn ')';\n\t\t\tcase TokenType.Neg:\n\t\t\t\treturn '!';\n\t\t\tcase TokenType.Eq:\n\t\t\t\treturn token.isTripleEq ? '===' : '==';\n\t\t\tcase TokenType.NotEq:\n\t\t\t\treturn token.isTripleEq ? '!==' : '!=';\n\t\t\tcase TokenType.Lt:\n\t\t\t\treturn '<';\n\t\t\tcase TokenType.LtEq:\n\t\t\t\treturn '<=';\n\t\t\tcase TokenType.Gt:\n\t\t\t\treturn '>=';\n\t\t\tcase TokenType.GtEq:\n\t\t\t\treturn '>=';\n\t\t\tcase TokenType.RegexOp:\n\t\t\t\treturn '=~';\n\t\t\tcase TokenType.RegexStr:\n\t\t\t\treturn token.lexeme;\n\t\t\tcase TokenType.True:\n\t\t\t\treturn 'true';\n\t\t\tcase TokenType.False:\n\t\t\t\treturn 'false';\n\t\t\tcase TokenType.In:\n\t\t\t\treturn 'in';\n\t\t\tcase TokenType.Not:\n\t\t\t\treturn 'not';\n\t\t\tcase TokenType.And:\n\t\t\t\treturn '&&';\n\t\t\tcase TokenType.Or:\n\t\t\t\treturn '||';\n\t\t\tcase TokenType.Str:\n\t\t\t\treturn token.lexeme;\n\t\t\tcase TokenType.QuotedStr:\n\t\t\t\treturn token.lexeme;\n\t\t\tcase TokenType.Error:\n\t\t\t\treturn token.lexeme;\n\t\t\tcase TokenType.EOF:\n\t\t\t\treturn 'EOF';\n\t\t\tdefault:\n\t\t\t\tthrow illegalState(`unhandled token type: ${JSON.stringify(token)}; have you forgotten to add a case?`);\n\t\t}\n\t}\n\n\tprivate static _regexFlags = new Set(['i', 'g', 's', 'm', 'y', 'u'].map(ch => ch.charCodeAt(0)));\n\n\tprivate static _keywords = new Map([\n\t\t['not', TokenType.Not],\n\t\t['in', TokenType.In],\n\t\t['false', TokenType.False],\n\t\t['true', TokenType.True],\n\t]);\n\n\tprivate _input: string = '';\n\tprivate _start: number = 0;\n\tprivate _current: number = 0;\n\tprivate _tokens: Token[] = [];\n\tprivate _errors: LexingError[] = [];\n\n\treset(value: string) {\n\t\tthis._input = value;\n\n\t\tthis._start = 0;\n\t\tthis._current = 0;\n\t\tthis._tokens = [];\n\t\tthis._errors = [];\n\n\t\treturn this;\n\t}\n\n\tscan() {\n\t\twhile (!this._isAtEnd()) {\n\n\t\t\tthis._start = this._current;\n\n\t\t\tconst ch = this._advance();\n\t\t\tswitch (ch) {\n\t\t\t\tcase CharCode.OpenParen: this._addToken(TokenType.LParen); break;\n\t\t\t\tcase CharCode.CloseParen: this._addToken(TokenType.RParen); break;\n\n\t\t\t\tcase CharCode.ExclamationMark:\n\t\t\t\t\tif (this._match(CharCode.Equals)) {\n\t\t\t\t\t\tconst isTripleEq = this._match(CharCode.Equals); // eat last `=` if `!==`\n\t\t\t\t\t\tthis._tokens.push({ type: TokenType.NotEq, offset: this._start, isTripleEq });\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis._addToken(TokenType.Neg);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase CharCode.SingleQuote: this._quotedString(); break;\n\t\t\t\tcase CharCode.Slash: this._regex(); break;\n\n\t\t\t\tcase CharCode.Equals:\n\t\t\t\t\tif (this._match(CharCode.Equals)) { // support `==`\n\t\t\t\t\t\tconst isTripleEq = this._match(CharCode.Equals); // eat last `=` if `===`\n\t\t\t\t\t\tthis._tokens.push({ type: TokenType.Eq, offset: this._start, isTripleEq });\n\t\t\t\t\t} else if (this._match(CharCode.Tilde)) {\n\t\t\t\t\t\tthis._addToken(TokenType.RegexOp);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis._error(hintDidYouMean('==', '=~'));\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase CharCode.LessThan: this._addToken(this._match(CharCode.Equals) ? TokenType.LtEq : TokenType.Lt); break;\n\n\t\t\t\tcase CharCode.GreaterThan: this._addToken(this._match(CharCode.Equals) ? TokenType.GtEq : TokenType.Gt); break;\n\n\t\t\t\tcase CharCode.Ampersand:\n\t\t\t\t\tif (this._match(CharCode.Ampersand)) {\n\t\t\t\t\t\tthis._addToken(TokenType.And);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis._error(hintDidYouMean('&&'));\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase CharCode.Pipe:\n\t\t\t\t\tif (this._match(CharCode.Pipe)) {\n\t\t\t\t\t\tthis._addToken(TokenType.Or);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis._error(hintDidYouMean('||'));\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\t// TODO@ulugbekna: 1) rewrite using a regex 2) reconsider what characters are considered whitespace, including unicode, nbsp, etc.\n\t\t\t\tcase CharCode.Space:\n\t\t\t\tcase CharCode.CarriageReturn:\n\t\t\t\tcase CharCode.Tab:\n\t\t\t\tcase CharCode.LineFeed:\n\t\t\t\tcase CharCode.NoBreakSpace: //  \n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tthis._string();\n\t\t\t}\n\t\t}\n\n\t\tthis._start = this._current;\n\t\tthis._addToken(TokenType.EOF);\n\n\t\treturn Array.from(this._tokens);\n\t}\n\n\tprivate _match(expected: number): boolean {\n\t\tif (this._isAtEnd()) {\n\t\t\treturn false;\n\t\t}\n\t\tif (this._input.charCodeAt(this._current) !== expected) {\n\t\t\treturn false;\n\t\t}\n\t\tthis._current++;\n\t\treturn true;\n\t}\n\n\tprivate _advance(): number {\n\t\treturn this._input.charCodeAt(this._current++);\n\t}\n\n\tprivate _peek(): number {\n\t\treturn this._isAtEnd() ? CharCode.Null : this._input.charCodeAt(this._current);\n\t}\n\n\tprivate _addToken(type: TokenTypeWithoutLexeme) {\n\t\tthis._tokens.push({ type, offset: this._start });\n\t}\n\n\tprivate _error(additional?: string) {\n\t\tconst offset = this._start;\n\t\tconst lexeme = this._input.substring(this._start, this._current);\n\t\tconst errToken: Token = { type: TokenType.Error, offset: this._start, lexeme };\n\t\tthis._errors.push({ offset, lexeme, additionalInfo: additional });\n\t\tthis._tokens.push(errToken);\n\t}\n\n\t// u - unicode, y - sticky // TODO@ulugbekna: we accept double quotes as part of the string rather than as a delimiter (to preserve old parser's behavior)\n\tprivate stringRe = /[a-zA-Z0-9_<>\\-\\./\\\\:\\*\\?\\+\\[\\]\\^,#@;\"%\\$\\p{L}-]+/uy;\n\tprivate _string() {\n\t\tthis.stringRe.lastIndex = this._start;\n\t\tconst match = this.stringRe.exec(this._input);\n\t\tif (match) {\n\t\t\tthis._current = this._start + match[0].length;\n\t\t\tconst lexeme = this._input.substring(this._start, this._current);\n\t\t\tconst keyword = Scanner._keywords.get(lexeme);\n\t\t\tif (keyword) {\n\t\t\t\tthis._addToken(keyword);\n\t\t\t} else {\n\t\t\t\tthis._tokens.push({ type: TokenType.Str, lexeme, offset: this._start });\n\t\t\t}\n\t\t}\n\t}\n\n\t// captures the lexeme without the leading and trailing '\n\tprivate _quotedString() {\n\t\twhile (this._peek() !== CharCode.SingleQuote && !this._isAtEnd()) { // TODO@ulugbekna: add support for escaping ' ?\n\t\t\tthis._advance();\n\t\t}\n\n\t\tif (this._isAtEnd()) {\n\t\t\tthis._error(hintDidYouForgetToOpenOrCloseQuote);\n\t\t\treturn;\n\t\t}\n\n\t\t// consume the closing '\n\t\tthis._advance();\n\n\t\tthis._tokens.push({ type: TokenType.QuotedStr, lexeme: this._input.substring(this._start + 1, this._current - 1), offset: this._start + 1 });\n\t}\n\n\t/*\n\t * Lexing a regex expression: /.../[igsmyu]*\n\t * Based on https://github.com/microsoft/TypeScript/blob/9247ef115e617805983740ba795d7a8164babf89/src/compiler/scanner.ts#L2129-L2181\n\t *\n\t * Note that we want slashes within a regex to be escaped, e.g., /file:\\\\/\\\\/\\\\// should match `file:///`\n\t */\n\tprivate _regex() {\n\t\tlet p = this._current;\n\n\t\tlet inEscape = false;\n\t\tlet inCharacterClass = false;\n\t\twhile (true) {\n\t\t\tif (p >= this._input.length) {\n\t\t\t\tthis._current = p;\n\t\t\t\tthis._error(hintDidYouForgetToEscapeSlash);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst ch = this._input.charCodeAt(p);\n\n\t\t\tif (inEscape) { // parsing an escape character\n\t\t\t\tinEscape = false;\n\t\t\t} else if (ch === CharCode.Slash && !inCharacterClass) { // end of regex\n\t\t\t\tp++;\n\t\t\t\tbreak;\n\t\t\t} else if (ch === CharCode.OpenSquareBracket) {\n\t\t\t\tinCharacterClass = true;\n\t\t\t} else if (ch === CharCode.Backslash) {\n\t\t\t\tinEscape = true;\n\t\t\t} else if (ch === CharCode.CloseSquareBracket) {\n\t\t\t\tinCharacterClass = false;\n\t\t\t}\n\t\t\tp++;\n\t\t}\n\n\t\t// Consume flags // TODO@ulugbekna: use regex instead\n\t\twhile (p < this._input.length && Scanner._regexFlags.has(this._input.charCodeAt(p))) {\n\t\t\tp++;\n\t\t}\n\n\t\tthis._current = p;\n\n\t\tconst lexeme = this._input.substring(this._start, this._current);\n\t\tthis._tokens.push({ type: TokenType.RegexStr, lexeme, offset: this._start });\n\t}\n\n\tprivate _isAtEnd() {\n\t\treturn this._current >= this._input.length;\n\t}\n}\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\nimport { IDisposable } from 'vs/base/common/lifecycle';\nimport { URI } from 'vs/base/common/uri';\n\nexport interface IResolvableEditorModel extends IDisposable {\n}\n\nexport interface IBaseUntypedEditorInput {\n}\n\nexport interface IBaseResourceEditorInput extends IBaseUntypedEditorInput {\n}\n\nexport interface IBaseTextResourceEditorInput extends IBaseResourceEditorInput {\n}\n\nexport interface IResourceEditorInput extends IBaseResourceEditorInput {\n\n\t/**\n\t * The resource URI of the resource to open.\n\t */\n\treadonly resource: URI;\n}\n\nexport interface ITextResourceEditorInput extends IResourceEditorInput, IBaseTextResourceEditorInput {\n\n\t/**\n\t * Optional options to use when opening the text input.\n\t */\n\toptions?: ITextEditorOptions;\n}\n\nexport enum EditorOpenSource {\n\n\t/**\n\t * Default: the editor is opening via a programmatic call\n\t * to the editor service API.\n\t */\n\tAPI,\n\n\t/**\n\t * Indicates that a user action triggered the opening, e.g.\n\t * via mouse or keyboard use.\n\t */\n\tUSER\n}\n\nexport interface IEditorOptions {\n\n\t/**\n\t * Tells the editor to not receive keyboard focus when the editor is being opened.\n\t *\n\t * Will also not activate the group the editor opens in unless the group is already\n\t * the active one. This behaviour can be overridden via the `activation` option.\n\t */\n\tpreserveFocus?: boolean;\n\n\t/**\n\t * Will reveal the editor if it is already opened and visible in any of the opened editor groups.\n\t *\n\t * Note that this option is just a hint that might be ignored if the user wants to open an editor explicitly\n\t * to the side of another one or into a specific editor group.\n\t */\n\trevealIfVisible?: boolean;\n\n\t/**\n\t * Will reveal the editor if it is already opened (even when not visible) in any of the opened editor groups.\n\t *\n\t * Note that this option is just a hint that might be ignored if the user wants to open an editor explicitly\n\t * to the side of another one or into a specific editor group.\n\t */\n\trevealIfOpened?: boolean;\n\n\t/**\n\t * An editor that is pinned remains in the editor stack even when another editor is being opened.\n\t * An editor that is not pinned will always get replaced by another editor that is not pinned.\n\t */\n\tpinned?: boolean;\n\n\t/**\n\t * A optional hint to signal in which context the editor opens.\n\t *\n\t * If configured to be `EditorOpenSource.USER`, this hint can be\n\t * used in various places to control the experience. For example,\n\t * if the editor to open fails with an error, a notification could\n\t * inform about this in a modal dialog. If the editor opened through\n\t * some background task, the notification would show in the background,\n\t * not as a modal dialog.\n\t */\n\tsource?: EditorOpenSource;\n}\n\nexport interface ITextEditorSelection {\n\treadonly startLineNumber: number;\n\treadonly startColumn: number;\n\treadonly endLineNumber?: number;\n\treadonly endColumn?: number;\n}\n\nexport const enum TextEditorSelectionRevealType {\n\t/**\n\t * Option to scroll vertically or horizontally as necessary and reveal a range centered vertically.\n\t */\n\tCenter = 0,\n\n\t/**\n\t * Option to scroll vertically or horizontally as necessary and reveal a range centered vertically only if it lies outside the viewport.\n\t */\n\tCenterIfOutsideViewport = 1,\n\n\t/**\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.\n\t */\n\tNearTop = 2,\n\n\t/**\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.\n\t * Only if it lies outside the viewport\n\t */\n\tNearTopIfOutsideViewport = 3,\n}\n\nexport const enum TextEditorSelectionSource {\n\n\t/**\n\t * Programmatic source indicates a selection change that\n\t * was not triggered by the user via keyboard or mouse\n\t * but through text editor APIs.\n\t */\n\tPROGRAMMATIC = 'api',\n\n\t/**\n\t * Navigation source indicates a selection change that\n\t * was caused via some command or UI component such as\n\t * an outline tree.\n\t */\n\tNAVIGATION = 'code.navigation',\n\n\t/**\n\t * Jump source indicates a selection change that\n\t * was caused from within the text editor to another\n\t * location in the same or different text editor such\n\t * as \"Go to definition\".\n\t */\n\tJUMP = 'code.jump'\n}\n\nexport interface ITextEditorOptions extends IEditorOptions {\n\n\t/**\n\t * Text editor selection.\n\t */\n\tselection?: ITextEditorSelection;\n\n\t/**\n\t * Option to control the text editor selection reveal type.\n\t * Defaults to TextEditorSelectionRevealType.Center\n\t */\n\tselectionRevealType?: TextEditorSelectionRevealType;\n\n\t/**\n\t * Source of the call that caused the selection.\n\t */\n\tselectionSource?: TextEditorSelectionSource | string;\n}\n","\n\n/**\n * **!Do not construct directly!**\n *\n * **!Only static methods because it gets serialized!**\n *\n * This represents the \"canonical\" version for an extension identifier. Extension ids\n * have to be case-insensitive (due to the marketplace), but we must ensure case\n * preservation because the extension API is already public at this time.\n *\n * For example, given an extension with the publisher `\"Hello\"` and the name `\"World\"`,\n * its canonical extension identifier is `\"Hello.World\"`. This extension could be\n * referenced in some other extension's dependencies using the string `\"hello.world\"`.\n *\n * To make matters more complicated, an extension can optionally have an UUID. When two\n * extensions have the same UUID, they are considered equal even if their identifier is different.\n */\nexport class ExtensionIdentifier {\n\tpublic readonly value: string;\n\n\t/**\n\t * Do not use directly. This is public to avoid mangling and thus\n\t * allow compatibility between running from source and a built version.\n\t */\n\treadonly _lower: string;\n\n\tconstructor(value: string) {\n\t\tthis.value = value;\n\t\tthis._lower = value.toLowerCase();\n\t}\n\n\t/**\n\t * Gives the value by which to index (for equality).\n\t */\n\tpublic static toKey(id: ExtensionIdentifier | string): string {\n\t\tif (typeof id === 'string') {\n\t\t\treturn id.toLowerCase();\n\t\t}\n\t\treturn id._lower;\n\t}\n}\n\nexport class ExtensionIdentifierSet {\n\n\tprivate readonly _set = new Set();\n\n\tconstructor(iterable?: Iterable) {\n\t\tif (iterable) {\n\t\t\tfor (const value of iterable) {\n\t\t\t\tthis.add(value);\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic add(id: ExtensionIdentifier | string): void {\n\t\tthis._set.add(ExtensionIdentifier.toKey(id));\n\t}\n\n\tpublic has(id: ExtensionIdentifier | string): boolean {\n\t\treturn this._set.has(ExtensionIdentifier.toKey(id));\n\t}\n}\n","\n\n//#endregion\n\n//#region Utilities\n\nexport enum FileKind {\n\tFILE,\n\tFOLDER,\n\tROOT_FOLDER\n}\n\n//#endregion\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\nimport { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';\n\nexport function showHistoryKeybindingHint(keybindingService: IKeybindingService): boolean {\n\treturn keybindingService.lookupKeybinding('history.showPrevious')?.getElectronAccelerator() === 'Up' && keybindingService.lookupKeybinding('history.showNext')?.getElectronAccelerator() === 'Down';\n}\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\nexport class SyncDescriptor {\n\n\treadonly ctor: any;\n\treadonly staticArguments: any[];\n\treadonly supportsDelayedInstantiation: boolean;\n\n\tconstructor(ctor: new (...args: any[]) => T, staticArguments: any[] = [], supportsDelayedInstantiation: boolean = false) {\n\t\tthis.ctor = ctor;\n\t\tthis.staticArguments = staticArguments;\n\t\tthis.supportsDelayedInstantiation = supportsDelayedInstantiation;\n\t}\n}\n\nexport interface SyncDescriptor0 {\n\treadonly ctor: new () => T;\n}\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\nimport { SyncDescriptor } from './descriptors';\nimport { BrandedService, ServiceIdentifier } from './instantiation';\n\nconst _registry: [ServiceIdentifier, SyncDescriptor][] = [];\n\nexport const enum InstantiationType {\n\t/**\n\t * Instantiate this service as soon as a consumer depends on it. _Note_ that this\n\t * is more costly as some upfront work is done that is likely not needed\n\t */\n\tEager = 0,\n\n\t/**\n\t * Instantiate this service as soon as a consumer uses it. This is the _better_\n\t * way of registering a service.\n\t */\n\tDelayed = 1\n}\n\nexport function registerSingleton(id: ServiceIdentifier, ctor: new (...services: Services) => T, supportsDelayedInstantiation: InstantiationType): void;\nexport function registerSingleton(id: ServiceIdentifier, descriptor: SyncDescriptor): void;\nexport function registerSingleton(id: ServiceIdentifier, ctorOrDescriptor: { new(...services: Services): T } | SyncDescriptor, supportsDelayedInstantiation?: boolean | InstantiationType): void {\n\tif (!(ctorOrDescriptor instanceof SyncDescriptor)) {\n\t\tctorOrDescriptor = new SyncDescriptor(ctorOrDescriptor as new (...args: any[]) => T, [], Boolean(supportsDelayedInstantiation));\n\t}\n\n\t_registry.push([id, ctorOrDescriptor]);\n}\n\nexport function getSingletonServiceDescriptors(): [ServiceIdentifier, SyncDescriptor][] {\n\treturn _registry;\n}\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\nexport class Node {\n\n\n\treadonly incoming = new Map>();\n\treadonly outgoing = new Map>();\n\n\tconstructor(\n\t\treadonly key: string,\n\t\treadonly data: T\n\t) { }\n}\n\nexport class Graph {\n\n\tprivate readonly _nodes = new Map>();\n\n\tconstructor(private readonly _hashFn: (element: T) => string) {\n\t\t// empty\n\t}\n\n\troots(): Node[] {\n\t\tconst ret: Node[] = [];\n\t\tfor (const node of this._nodes.values()) {\n\t\t\tif (node.outgoing.size === 0) {\n\t\t\t\tret.push(node);\n\t\t\t}\n\t\t}\n\t\treturn ret;\n\t}\n\n\tinsertEdge(from: T, to: T): void {\n\t\tconst fromNode = this.lookupOrInsertNode(from);\n\t\tconst toNode = this.lookupOrInsertNode(to);\n\n\t\tfromNode.outgoing.set(toNode.key, toNode);\n\t\ttoNode.incoming.set(fromNode.key, fromNode);\n\t}\n\n\tremoveNode(data: T): void {\n\t\tconst key = this._hashFn(data);\n\t\tthis._nodes.delete(key);\n\t\tfor (const node of this._nodes.values()) {\n\t\t\tnode.outgoing.delete(key);\n\t\t\tnode.incoming.delete(key);\n\t\t}\n\t}\n\n\tlookupOrInsertNode(data: T): Node {\n\t\tconst key = this._hashFn(data);\n\t\tlet node = this._nodes.get(key);\n\n\t\tif (!node) {\n\t\t\tnode = new Node(key, data);\n\t\t\tthis._nodes.set(key, node);\n\t\t}\n\n\t\treturn node;\n\t}\n\n\tisEmpty(): boolean {\n\t\treturn this._nodes.size === 0;\n\t}\n\n\ttoString(): string {\n\t\tconst data: string[] = [];\n\t\tfor (const [key, value] of this._nodes) {\n\t\t\tdata.push(`${key}\\n\\t(-> incoming)[${[...value.incoming.keys()].join(', ')}]\\n\\t(outgoing ->)[${[...value.outgoing.keys()].join(',')}]\\n`);\n\n\t\t}\n\t\treturn data.join('\\n');\n\t}\n\n\t/**\n\t * This is brute force and slow and **only** be used\n\t * to trouble shoot.\n\t */\n\tfindCycleSlow() {\n\t\tfor (const [id, node] of this._nodes) {\n\t\t\tconst seen = new Set([id]);\n\t\t\tconst res = this._findCycle(node, seen);\n\t\t\tif (res) {\n\t\t\t\treturn res;\n\t\t\t}\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tprivate _findCycle(node: Node, seen: Set): string | undefined {\n\t\tfor (const [id, outgoing] of node.outgoing) {\n\t\t\tif (seen.has(id)) {\n\t\t\t\treturn [...seen, id].join(' -> ');\n\t\t\t}\n\t\t\tseen.add(id);\n\t\t\tconst value = this._findCycle(outgoing, seen);\n\t\t\tif (value) {\n\t\t\t\treturn value;\n\t\t\t}\n\t\t\tseen.delete(id);\n\t\t}\n\t\treturn undefined;\n\t}\n}\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\nimport { DisposableStore } from 'vs/base/common/lifecycle';\nimport * as descriptors from './descriptors';\nimport { ServiceCollection } from './serviceCollection';\n\n// ------ internal util\n\nexport namespace _util {\n\n\texport const serviceIds = new Map>();\n\n\texport const DI_TARGET = '$di$target';\n\texport const DI_DEPENDENCIES = '$di$dependencies';\n\n\texport function getServiceDependencies(ctor: any): { id: ServiceIdentifier; index: number }[] {\n\t\treturn ctor[DI_DEPENDENCIES] || [];\n\t}\n}\n\n// --- interfaces ------\n\nexport type BrandedService = { _serviceBrand: undefined };\n\nexport interface IConstructorSignature {\n\tnew (...args: [...Args, ...Services]): T;\n}\n\nexport interface ServicesAccessor {\n\tget(id: ServiceIdentifier): T;\n}\n\nexport const IInstantiationService = createDecorator('instantiationService');\n\n/**\n * Given a list of arguments as a tuple, attempt to extract the leading, non-service arguments\n * to their own tuple.\n */\nexport type GetLeadingNonServiceArgs =\n\tTArgs extends [] ? []\n\t: TArgs extends [...infer TFirst, BrandedService] ? GetLeadingNonServiceArgs\n\t: TArgs;\n\nexport interface IInstantiationService {\n\n\treadonly _serviceBrand: undefined;\n\n\t/**\n\t * Synchronously creates an instance that is denoted by the descriptor\n\t */\n\tcreateInstance(descriptor: descriptors.SyncDescriptor0): T;\n\tcreateInstance any, R extends InstanceType>(ctor: Ctor, ...args: GetLeadingNonServiceArgs>): R;\n\n\t/**\n\t * Calls a function with a service accessor.\n\t */\n\tinvokeFunction(fn: (accessor: ServicesAccessor, ...args: TS) => R, ...args: TS): R;\n\n\t/**\n\t * Creates a child of this service which inherits all current services\n\t * and adds/overwrites the given services.\n\t *\n\t * NOTE that the returned child is `disposable` and should be disposed when not used\n\t * anymore. This will also dispose all the services that this service has created.\n\t */\n\tcreateChild(services: ServiceCollection, store?: DisposableStore): IInstantiationService;\n\n\t/**\n\t * Disposes this instantiation service.\n\t *\n\t * - Will dispose all services that this instantiation service has created.\n\t * - Will dispose all its children but not its parent.\n\t * - Will NOT dispose services-instances that this service has been created with\n\t * - Will NOT dispose consumer-instances this service has created\n\t */\n\tdispose(): void;\n}\n\n\n/**\n * Identifies a service of type `T`.\n */\nexport interface ServiceIdentifier {\n\t(...args: any[]): void;\n\ttype: T;\n}\n\nfunction storeServiceDependency(id: Function, target: Function, index: number): void {\n\tif ((target as any)[_util.DI_TARGET] === target) {\n\t\t(target as any)[_util.DI_DEPENDENCIES].push({ id, index });\n\t} else {\n\t\t(target as any)[_util.DI_DEPENDENCIES] = [{ id, index }];\n\t\t(target as any)[_util.DI_TARGET] = target;\n\t}\n}\n\n/**\n * The *only* valid way to create a {{ServiceIdentifier}}.\n */\nexport function createDecorator(serviceId: string): ServiceIdentifier {\n\n\tif (_util.serviceIds.has(serviceId)) {\n\t\treturn _util.serviceIds.get(serviceId)!;\n\t}\n\n\tconst id = function (target: Function, key: string, index: number): any {\n\t\tif (arguments.length !== 3) {\n\t\t\tthrow new Error('@IServiceName-decorator can only be used to decorate a parameter');\n\t\t}\n\t\tstoreServiceDependency(id, target, index);\n\t};\n\n\tid.toString = () => serviceId;\n\n\t_util.serviceIds.set(serviceId, id);\n\treturn id;\n}\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\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\nimport { TextEdit, WorkspaceEdit, WorkspaceEditMetadata, IWorkspaceFileEdit, WorkspaceFileEditOptions, IWorkspaceTextEdit } from 'vs/editor/common/languages';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\nimport { URI } from 'vs/base/common/uri';\nimport { isObject } from 'vs/base/common/types';\nimport { CancellationToken } from 'vs/base/common/cancellation';\n\nexport const IBulkEditService = createDecorator('IWorkspaceEditService');\n\nexport class ResourceEdit {\n\n\tprotected constructor(readonly metadata?: WorkspaceEditMetadata) { }\n\n\tstatic convert(edit: WorkspaceEdit): ResourceEdit[] {\n\n\t\treturn edit.edits.map(edit => {\n\t\t\tif (ResourceTextEdit.is(edit)) {\n\t\t\t\treturn ResourceTextEdit.lift(edit);\n\t\t\t}\n\n\t\t\tif (ResourceFileEdit.is(edit)) {\n\t\t\t\treturn ResourceFileEdit.lift(edit);\n\t\t\t}\n\t\t\tthrow new Error('Unsupported edit');\n\t\t});\n\t}\n}\n\nexport class ResourceTextEdit extends ResourceEdit implements IWorkspaceTextEdit {\n\n\tstatic is(candidate: any): candidate is IWorkspaceTextEdit {\n\t\tif (candidate instanceof ResourceTextEdit) {\n\t\t\treturn true;\n\t\t}\n\t\treturn isObject(candidate)\n\t\t\t&& URI.isUri((candidate).resource)\n\t\t\t&& isObject((candidate).textEdit);\n\t}\n\n\tstatic lift(edit: IWorkspaceTextEdit): ResourceTextEdit {\n\t\tif (edit instanceof ResourceTextEdit) {\n\t\t\treturn edit;\n\t\t} else {\n\t\t\treturn new ResourceTextEdit(edit.resource, edit.textEdit, edit.versionId, edit.metadata);\n\t\t}\n\t}\n\n\tconstructor(\n\t\treadonly resource: URI,\n\t\treadonly textEdit: TextEdit & { insertAsSnippet?: boolean },\n\t\treadonly versionId: number | undefined = undefined,\n\t\tmetadata?: WorkspaceEditMetadata,\n\t) {\n\t\tsuper(metadata);\n\t}\n}\n\nexport class ResourceFileEdit extends ResourceEdit implements IWorkspaceFileEdit {\n\n\tstatic is(candidate: any): candidate is IWorkspaceFileEdit {\n\t\tif (candidate instanceof ResourceFileEdit) {\n\t\t\treturn true;\n\t\t} else {\n\t\t\treturn isObject(candidate)\n\t\t\t\t&& (Boolean((candidate).newResource) || Boolean((candidate).oldResource));\n\t\t}\n\t}\n\n\tstatic lift(edit: IWorkspaceFileEdit): ResourceFileEdit {\n\t\tif (edit instanceof ResourceFileEdit) {\n\t\t\treturn edit;\n\t\t} else {\n\t\t\treturn new ResourceFileEdit(edit.oldResource, edit.newResource, edit.options, edit.metadata);\n\t\t}\n\t}\n\n\tconstructor(\n\t\treadonly oldResource: URI | undefined,\n\t\treadonly newResource: URI | undefined,\n\t\treadonly options: WorkspaceFileEditOptions = {},\n\t\tmetadata?: WorkspaceEditMetadata\n\t) {\n\t\tsuper(metadata);\n\t}\n}\n\nexport interface IBulkEditOptions {\n\teditor?: ICodeEditor;\n\ttoken?: CancellationToken;\n\tshowPreview?: boolean;\n\tlabel?: string;\n\tcode?: string;\n\tquotableLabel?: string;\n\trespectAutoSaveConfig?: boolean;\n}\n\nexport interface IBulkEditResult {\n\tariaSummary: string;\n\tisApplied: boolean;\n}\n\nexport interface IBulkEditService {\n\treadonly _serviceBrand: undefined;\n\n\thasPreviewHandler(): boolean;\n\n\tapply(edit: ResourceEdit[] | WorkspaceEdit, options?: IBulkEditOptions): Promise;\n}\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\nimport { Event } from 'vs/base/common/event';\nimport { ICodeEditor, IDiffEditor } from 'vs/editor/browser/editorBrowser';\nimport { ITextResourceEditorInput } from 'vs/platform/editor/common/editor';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\nimport { URI } from 'vs/base/common/uri';\nimport { IDisposable } from 'vs/base/common/lifecycle';\n\nexport const ICodeEditorService = createDecorator('codeEditorService');\n\nexport interface ICodeEditorService {\n\treadonly _serviceBrand: undefined;\n\treadonly onCodeEditorAdd: Event;\n\treadonly onCodeEditorRemove: Event;\n\treadonly onDiffEditorAdd: Event;\n\treadonly onDiffEditorRemove: Event;\n\n\twillCreateCodeEditor(): void;\n\taddCodeEditor(editor: ICodeEditor): void;\n\tremoveCodeEditor(editor: ICodeEditor): void;\n\tlistCodeEditors(): readonly ICodeEditor[];\n\n\twillCreateDiffEditor(): void;\n\taddDiffEditor(editor: IDiffEditor): void;\n\tlistDiffEditors(): readonly IDiffEditor[];\n\n\t/**\n\t * Returns the current focused code editor (if the focus is in the editor or in an editor widget) or null.\n\t */\n\tgetFocusedCodeEditor(): ICodeEditor | null;\n\tremoveDecorationType(key: string): void;\n\n\tsetModelProperty(resource: URI, key: string, value: any): void;\n\tgetModelProperty(resource: URI, key: string): any;\n\n\tgetActiveCodeEditor(): ICodeEditor | null;\n\topenCodeEditor(input: ITextResourceEditorInput, source: ICodeEditor | null, sideBySide?: boolean): Promise;\n\tregisterCodeEditorOpenHandler(handler: ICodeEditorOpenHandler): IDisposable;\n}\n\nexport interface ICodeEditorOpenHandler {\n\t(input: ITextResourceEditorInput, source: ICodeEditor | null, sideBySide?: boolean): Promise;\n}\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\nimport { $, addDisposableListener, getWindow, h, reset } from 'vs/base/browser/dom';\nimport { renderIcon, renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels';\nimport { Codicon } from 'vs/base/common/codicons';\nimport { MarkdownString } from 'vs/base/common/htmlContent';\nimport { Disposable, IDisposable } from 'vs/base/common/lifecycle';\nimport { IObservable, IReader, autorun, derived, derivedWithStore, observableFromEvent, observableValue, transaction } from 'vs/base/common/observable';\nimport { derivedDisposable } from 'vs/base/common/observableInternal/derived';\nimport { ThemeIcon } from 'vs/base/common/themables';\nimport { isDefined } from 'vs/base/common/types';\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\nimport { DiffEditorEditors } from 'vs/editor/browser/widget/diffEditor/components/diffEditorEditors';\nimport { DiffEditorOptions } from 'vs/editor/browser/widget/diffEditor/diffEditorOptions';\nimport { DiffEditorViewModel, RevealPreference, UnchangedRegion } from 'vs/editor/browser/widget/diffEditor/diffEditorViewModel';\nimport { IObservableViewZone, PlaceholderViewZone, ViewZoneOverlayWidget, applyObservableDecorations, applyStyle } from 'vs/editor/browser/widget/diffEditor/utils';\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\nimport { LineRange } from 'vs/editor/common/core/lineRange';\nimport { Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\nimport { CursorChangeReason } from 'vs/editor/common/cursorEvents';\nimport { SymbolKind, SymbolKinds } from 'vs/editor/common/languages';\nimport { IModelDecorationOptions, IModelDeltaDecoration, ITextModel } from 'vs/editor/common/model';\nimport { localize } from 'vs/nls';\nimport { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';\n\n/**\n * Make sure to add the view zones to the editor!\n */\nexport class HideUnchangedRegionsFeature extends Disposable {\n\tprivate static readonly _breadcrumbsSourceFactory = observableValue<((textModel: ITextModel, instantiationService: IInstantiationService) => IDiffEditorBreadcrumbsSource) | undefined>('breadcrumbsSourceFactory', undefined);\n\tpublic static setBreadcrumbsSourceFactory(factory: (textModel: ITextModel, instantiationService: IInstantiationService) => IDiffEditorBreadcrumbsSource) {\n\t\tthis._breadcrumbsSourceFactory.set(factory, undefined);\n\t}\n\n\tprivate readonly _modifiedOutlineSource = derivedDisposable(this, (reader) => {\n\t\tconst m = this._editors.modifiedModel.read(reader);\n\t\tconst factory = HideUnchangedRegionsFeature._breadcrumbsSourceFactory.read(reader);\n\t\treturn (!m || !factory) ? undefined : factory(m, this._instantiationService);\n\t});\n\n\tpublic readonly viewZones: IObservable<{\n\t\torigViewZones: IObservableViewZone[];\n\t\tmodViewZones: IObservableViewZone[];\n\t}>;\n\n\tprivate _isUpdatingHiddenAreas = false;\n\tpublic get isUpdatingHiddenAreas() { return this._isUpdatingHiddenAreas; }\n\n\tconstructor(\n\t\tprivate readonly _editors: DiffEditorEditors,\n\t\tprivate readonly _diffModel: IObservable,\n\t\tprivate readonly _options: DiffEditorOptions,\n\t\t@IInstantiationService private readonly _instantiationService: IInstantiationService,\n\t) {\n\t\tsuper();\n\n\t\tthis._register(this._editors.original.onDidChangeCursorPosition(e => {\n\t\t\tif (e.reason === CursorChangeReason.ContentFlush) { return; }\n\t\t\tconst m = this._diffModel.get();\n\t\t\ttransaction(tx => {\n\t\t\t\tfor (const s of this._editors.original.getSelections() || []) {\n\t\t\t\t\tm?.ensureOriginalLineIsVisible(s.getStartPosition().lineNumber, RevealPreference.FromCloserSide, tx);\n\t\t\t\t\tm?.ensureOriginalLineIsVisible(s.getEndPosition().lineNumber, RevealPreference.FromCloserSide, tx);\n\t\t\t\t}\n\t\t\t});\n\t\t}));\n\n\t\tthis._register(this._editors.modified.onDidChangeCursorPosition(e => {\n\t\t\tif (e.reason === CursorChangeReason.ContentFlush) { return; }\n\t\t\tconst m = this._diffModel.get();\n\t\t\ttransaction(tx => {\n\t\t\t\tfor (const s of this._editors.modified.getSelections() || []) {\n\t\t\t\t\tm?.ensureModifiedLineIsVisible(s.getStartPosition().lineNumber, RevealPreference.FromCloserSide, tx);\n\t\t\t\t\tm?.ensureModifiedLineIsVisible(s.getEndPosition().lineNumber, RevealPreference.FromCloserSide, tx);\n\t\t\t\t}\n\t\t\t});\n\t\t}));\n\n\t\tconst unchangedRegions = this._diffModel.map((m, reader) => {\n\t\t\tconst regions = m?.unchangedRegions.read(reader) ?? [];\n\t\t\tif (regions.length === 1 && regions[0].modifiedLineNumber === 1 && regions[0].lineCount === this._editors.modifiedModel.read(reader)?.getLineCount()) {\n\t\t\t\treturn [];\n\t\t\t}\n\t\t\treturn regions;\n\t\t});\n\n\t\tthis.viewZones = derivedWithStore(this, (reader, store) => {\n\t\t\t/** @description view Zones */\n\t\t\tconst modifiedOutlineSource = this._modifiedOutlineSource.read(reader);\n\t\t\tif (!modifiedOutlineSource) { return { origViewZones: [], modViewZones: [] }; }\n\n\t\t\tconst origViewZones: IObservableViewZone[] = [];\n\t\t\tconst modViewZones: IObservableViewZone[] = [];\n\t\t\tconst sideBySide = this._options.renderSideBySide.read(reader);\n\n\t\t\tconst curUnchangedRegions = unchangedRegions.read(reader);\n\t\t\tfor (const r of curUnchangedRegions) {\n\t\t\t\tif (r.shouldHideControls(reader)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t{\n\t\t\t\t\tconst d = derived(this, reader => /** @description hiddenOriginalRangeStart */ r.getHiddenOriginalRange(reader).startLineNumber - 1);\n\t\t\t\t\tconst origVz = new PlaceholderViewZone(d, 24);\n\t\t\t\t\torigViewZones.push(origVz);\n\t\t\t\t\tstore.add(new CollapsedCodeOverlayWidget(\n\t\t\t\t\t\tthis._editors.original,\n\t\t\t\t\t\torigVz,\n\t\t\t\t\t\tr,\n\t\t\t\t\t\tr.originalUnchangedRange,\n\t\t\t\t\t\t!sideBySide,\n\t\t\t\t\t\tmodifiedOutlineSource,\n\t\t\t\t\t\tl => this._diffModel.get()!.ensureModifiedLineIsVisible(l, RevealPreference.FromBottom, undefined),\n\t\t\t\t\t\tthis._options,\n\t\t\t\t\t));\n\t\t\t\t}\n\t\t\t\t{\n\t\t\t\t\tconst d = derived(this, reader => /** @description hiddenModifiedRangeStart */ r.getHiddenModifiedRange(reader).startLineNumber - 1);\n\t\t\t\t\tconst modViewZone = new PlaceholderViewZone(d, 24);\n\t\t\t\t\tmodViewZones.push(modViewZone);\n\t\t\t\t\tstore.add(new CollapsedCodeOverlayWidget(\n\t\t\t\t\t\tthis._editors.modified,\n\t\t\t\t\t\tmodViewZone,\n\t\t\t\t\t\tr,\n\t\t\t\t\t\tr.modifiedUnchangedRange,\n\t\t\t\t\t\tfalse,\n\t\t\t\t\t\tmodifiedOutlineSource,\n\t\t\t\t\t\tl => this._diffModel.get()!.ensureModifiedLineIsVisible(l, RevealPreference.FromBottom, undefined),\n\t\t\t\t\t\tthis._options,\n\t\t\t\t\t));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn { origViewZones, modViewZones, };\n\t\t});\n\n\n\t\tconst unchangedLinesDecoration: IModelDecorationOptions = {\n\t\t\tdescription: 'unchanged lines',\n\t\t\tclassName: 'diff-unchanged-lines',\n\t\t\tisWholeLine: true,\n\t\t};\n\t\tconst unchangedLinesDecorationShow: IModelDecorationOptions = {\n\t\t\tdescription: 'Fold Unchanged',\n\t\t\tglyphMarginHoverMessage: new MarkdownString(undefined, { isTrusted: true, supportThemeIcons: true })\n\t\t\t\t.appendMarkdown(localize('foldUnchanged', 'Fold Unchanged Region')),\n\t\t\tglyphMarginClassName: 'fold-unchanged ' + ThemeIcon.asClassName(Codicon.fold),\n\t\t\tzIndex: 10001,\n\t\t};\n\n\t\tthis._register(applyObservableDecorations(this._editors.original, derived(this, reader => {\n\t\t\t/** @description decorations */\n\t\t\tconst curUnchangedRegions = unchangedRegions.read(reader);\n\t\t\tconst result = curUnchangedRegions.map(r => ({\n\t\t\t\trange: r.originalUnchangedRange.toInclusiveRange()!,\n\t\t\t\toptions: unchangedLinesDecoration,\n\t\t\t}));\n\t\t\tfor (const r of curUnchangedRegions) {\n\t\t\t\tif (r.shouldHideControls(reader)) {\n\t\t\t\t\tresult.push({\n\t\t\t\t\t\trange: Range.fromPositions(new Position(r.originalLineNumber, 1)),\n\t\t\t\t\t\toptions: unchangedLinesDecorationShow,\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\tthis._register(applyObservableDecorations(this._editors.modified, derived(this, reader => {\n\t\t\t/** @description decorations */\n\t\t\tconst curUnchangedRegions = unchangedRegions.read(reader);\n\t\t\tconst result = curUnchangedRegions.map(r => ({\n\t\t\t\trange: r.modifiedUnchangedRange.toInclusiveRange()!,\n\t\t\t\toptions: unchangedLinesDecoration,\n\t\t\t}));\n\t\t\tfor (const r of curUnchangedRegions) {\n\t\t\t\tif (r.shouldHideControls(reader)) {\n\t\t\t\t\tresult.push({\n\t\t\t\t\t\trange: LineRange.ofLength(r.modifiedLineNumber, 1).toInclusiveRange()!,\n\t\t\t\t\t\toptions: unchangedLinesDecorationShow,\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\tthis._register(autorun((reader) => {\n\t\t\t/** @description update folded unchanged regions */\n\t\t\tconst curUnchangedRegions = unchangedRegions.read(reader);\n\t\t\tthis._isUpdatingHiddenAreas = true;\n\t\t\ttry {\n\t\t\t\tthis._editors.original.setHiddenAreas(curUnchangedRegions.map(r => r.getHiddenOriginalRange(reader).toInclusiveRange()).filter(isDefined));\n\t\t\t\tthis._editors.modified.setHiddenAreas(curUnchangedRegions.map(r => r.getHiddenModifiedRange(reader).toInclusiveRange()).filter(isDefined));\n\t\t\t} finally {\n\t\t\t\tthis._isUpdatingHiddenAreas = false;\n\t\t\t}\n\t\t}));\n\n\t\tthis._register(this._editors.modified.onMouseUp(event => {\n\t\t\tif (!event.event.rightButton && event.target.position && event.target.element?.className.includes('fold-unchanged')) {\n\t\t\t\tconst lineNumber = event.target.position.lineNumber;\n\t\t\t\tconst model = this._diffModel.get();\n\t\t\t\tif (!model) { return; }\n\t\t\t\tconst region = model.unchangedRegions.get().find(r => r.modifiedUnchangedRange.includes(lineNumber));\n\t\t\t\tif (!region) { return; }\n\t\t\t\tregion.collapseAll(undefined);\n\t\t\t\tevent.event.stopPropagation();\n\t\t\t\tevent.event.preventDefault();\n\t\t\t}\n\t\t}));\n\n\t\tthis._register(this._editors.original.onMouseUp(event => {\n\t\t\tif (!event.event.rightButton && event.target.position && event.target.element?.className.includes('fold-unchanged')) {\n\t\t\t\tconst lineNumber = event.target.position.lineNumber;\n\t\t\t\tconst model = this._diffModel.get();\n\t\t\t\tif (!model) { return; }\n\t\t\t\tconst region = model.unchangedRegions.get().find(r => r.originalUnchangedRange.includes(lineNumber));\n\t\t\t\tif (!region) { return; }\n\t\t\t\tregion.collapseAll(undefined);\n\t\t\t\tevent.event.stopPropagation();\n\t\t\t\tevent.event.preventDefault();\n\t\t\t}\n\t\t}));\n\t}\n}\n\nclass CollapsedCodeOverlayWidget extends ViewZoneOverlayWidget {\n\tprivate readonly _nodes = h('div.diff-hidden-lines', [\n\t\th('div.top@top', { title: localize('diff.hiddenLines.top', 'Click or drag to show more above') }),\n\t\th('div.center@content', { style: { display: 'flex' } }, [\n\t\t\th('div@first', { style: { display: 'flex', justifyContent: 'center', alignItems: 'center', flexShrink: '0' } },\n\t\t\t\t[$('a', { title: localize('showUnchangedRegion', 'Show Unchanged Region'), role: 'button', onclick: () => { this._unchangedRegion.showAll(undefined); } },\n\t\t\t\t\t...renderLabelWithIcons('$(unfold)'))]\n\t\t\t),\n\t\t\th('div@others', { style: { display: 'flex', justifyContent: 'center', alignItems: 'center' } }),\n\t\t]),\n\t\th('div.bottom@bottom', { title: localize('diff.bottom', 'Click or drag to show more below'), role: 'button' }),\n\t]);\n\n\tconstructor(\n\t\tprivate readonly _editor: ICodeEditor,\n\t\t_viewZone: PlaceholderViewZone,\n\t\tprivate readonly _unchangedRegion: UnchangedRegion,\n\t\tprivate readonly _unchangedRegionRange: LineRange,\n\t\tprivate readonly _hide: boolean,\n\t\tprivate readonly _modifiedOutlineSource: IDiffEditorBreadcrumbsSource,\n\t\tprivate readonly _revealModifiedHiddenLine: (lineNumber: number) => void,\n\t\tprivate readonly _options: DiffEditorOptions,\n\t) {\n\t\tconst root = h('div.diff-hidden-lines-widget');\n\t\tsuper(_editor, _viewZone, root.root);\n\t\troot.root.appendChild(this._nodes.root);\n\n\t\tconst layoutInfo = observableFromEvent(this._editor.onDidLayoutChange, () =>\n\t\t\tthis._editor.getLayoutInfo()\n\t\t);\n\n\t\tif (!this._hide) {\n\t\t\tthis._register(applyStyle(this._nodes.first, { width: layoutInfo.map((l) => l.contentLeft) }));\n\t\t} else {\n\t\t\treset(this._nodes.first);\n\t\t}\n\n\t\tthis._register(autorun(reader => {\n\t\t\t/** @description Update CollapsedCodeOverlayWidget canMove* css classes */\n\t\t\tconst isFullyRevealed = this._unchangedRegion.visibleLineCountTop.read(reader) + this._unchangedRegion.visibleLineCountBottom.read(reader) === this._unchangedRegion.lineCount;\n\n\t\t\tthis._nodes.bottom.classList.toggle('canMoveTop', !isFullyRevealed);\n\t\t\tthis._nodes.bottom.classList.toggle('canMoveBottom', this._unchangedRegion.visibleLineCountBottom.read(reader) > 0);\n\t\t\tthis._nodes.top.classList.toggle('canMoveTop', this._unchangedRegion.visibleLineCountTop.read(reader) > 0);\n\t\t\tthis._nodes.top.classList.toggle('canMoveBottom', !isFullyRevealed);\n\t\t\tconst isDragged = this._unchangedRegion.isDragged.read(reader);\n\t\t\tconst domNode = this._editor.getDomNode();\n\t\t\tif (domNode) {\n\t\t\t\tdomNode.classList.toggle('draggingUnchangedRegion', !!isDragged);\n\t\t\t\tif (isDragged === 'top') {\n\t\t\t\t\tdomNode.classList.toggle('canMoveTop', this._unchangedRegion.visibleLineCountTop.read(reader) > 0);\n\t\t\t\t\tdomNode.classList.toggle('canMoveBottom', !isFullyRevealed);\n\t\t\t\t} else if (isDragged === 'bottom') {\n\t\t\t\t\tdomNode.classList.toggle('canMoveTop', !isFullyRevealed);\n\t\t\t\t\tdomNode.classList.toggle('canMoveBottom', this._unchangedRegion.visibleLineCountBottom.read(reader) > 0);\n\t\t\t\t} else {\n\t\t\t\t\tdomNode.classList.toggle('canMoveTop', false);\n\t\t\t\t\tdomNode.classList.toggle('canMoveBottom', false);\n\t\t\t\t}\n\t\t\t}\n\t\t}));\n\n\t\tconst editor = this._editor;\n\n\t\tthis._register(addDisposableListener(this._nodes.top, 'mousedown', e => {\n\t\t\tif (e.button !== 0) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis._nodes.top.classList.toggle('dragging', true);\n\t\t\tthis._nodes.root.classList.toggle('dragging', true);\n\t\t\te.preventDefault();\n\t\t\tconst startTop = e.clientY;\n\t\t\tlet didMove = false;\n\t\t\tconst cur = this._unchangedRegion.visibleLineCountTop.get();\n\t\t\tthis._unchangedRegion.isDragged.set('top', undefined);\n\n\t\t\tconst window = getWindow(this._nodes.top);\n\n\t\t\tconst mouseMoveListener = addDisposableListener(window, 'mousemove', e => {\n\t\t\t\tconst currentTop = e.clientY;\n\t\t\t\tconst delta = currentTop - startTop;\n\t\t\t\tdidMove = didMove || Math.abs(delta) > 2;\n\t\t\t\tconst lineDelta = Math.round(delta / editor.getOption(EditorOption.lineHeight));\n\t\t\t\tconst newVal = Math.max(0, Math.min(cur + lineDelta, this._unchangedRegion.getMaxVisibleLineCountTop()));\n\t\t\t\tthis._unchangedRegion.visibleLineCountTop.set(newVal, undefined);\n\t\t\t});\n\n\t\t\tconst mouseUpListener = addDisposableListener(window, 'mouseup', e => {\n\t\t\t\tif (!didMove) {\n\t\t\t\t\tthis._unchangedRegion.showMoreAbove(this._options.hideUnchangedRegionsRevealLineCount.get(), undefined);\n\t\t\t\t}\n\t\t\t\tthis._nodes.top.classList.toggle('dragging', false);\n\t\t\t\tthis._nodes.root.classList.toggle('dragging', false);\n\t\t\t\tthis._unchangedRegion.isDragged.set(undefined, undefined);\n\t\t\t\tmouseMoveListener.dispose();\n\t\t\t\tmouseUpListener.dispose();\n\t\t\t});\n\t\t}));\n\n\t\tthis._register(addDisposableListener(this._nodes.bottom, 'mousedown', e => {\n\t\t\tif (e.button !== 0) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis._nodes.bottom.classList.toggle('dragging', true);\n\t\t\tthis._nodes.root.classList.toggle('dragging', true);\n\t\t\te.preventDefault();\n\t\t\tconst startTop = e.clientY;\n\t\t\tlet didMove = false;\n\t\t\tconst cur = this._unchangedRegion.visibleLineCountBottom.get();\n\t\t\tthis._unchangedRegion.isDragged.set('bottom', undefined);\n\n\t\t\tconst window = getWindow(this._nodes.bottom);\n\n\t\t\tconst mouseMoveListener = addDisposableListener(window, 'mousemove', e => {\n\t\t\t\tconst currentTop = e.clientY;\n\t\t\t\tconst delta = currentTop - startTop;\n\t\t\t\tdidMove = didMove || Math.abs(delta) > 2;\n\t\t\t\tconst lineDelta = Math.round(delta / editor.getOption(EditorOption.lineHeight));\n\t\t\t\tconst newVal = Math.max(0, Math.min(cur - lineDelta, this._unchangedRegion.getMaxVisibleLineCountBottom()));\n\t\t\t\tconst top = this._unchangedRegionRange.endLineNumberExclusive > editor.getModel()!.getLineCount()\n\t\t\t\t\t? editor.getContentHeight()\n\t\t\t\t\t: editor.getTopForLineNumber(this._unchangedRegionRange.endLineNumberExclusive);\n\t\t\t\tthis._unchangedRegion.visibleLineCountBottom.set(newVal, undefined);\n\t\t\t\tconst top2 = this._unchangedRegionRange.endLineNumberExclusive > editor.getModel()!.getLineCount()\n\t\t\t\t\t? editor.getContentHeight()\n\t\t\t\t\t: editor.getTopForLineNumber(this._unchangedRegionRange.endLineNumberExclusive);\n\t\t\t\teditor.setScrollTop(editor.getScrollTop() + (top2 - top));\n\t\t\t});\n\n\t\t\tconst mouseUpListener = addDisposableListener(window, 'mouseup', e => {\n\t\t\t\tthis._unchangedRegion.isDragged.set(undefined, undefined);\n\n\t\t\t\tif (!didMove) {\n\t\t\t\t\tconst top = editor.getTopForLineNumber(this._unchangedRegionRange.endLineNumberExclusive);\n\n\t\t\t\t\tthis._unchangedRegion.showMoreBelow(this._options.hideUnchangedRegionsRevealLineCount.get(), undefined);\n\t\t\t\t\tconst top2 = editor.getTopForLineNumber(this._unchangedRegionRange.endLineNumberExclusive);\n\t\t\t\t\teditor.setScrollTop(editor.getScrollTop() + (top2 - top));\n\t\t\t\t}\n\t\t\t\tthis._nodes.bottom.classList.toggle('dragging', false);\n\t\t\t\tthis._nodes.root.classList.toggle('dragging', false);\n\t\t\t\tmouseMoveListener.dispose();\n\t\t\t\tmouseUpListener.dispose();\n\t\t\t});\n\t\t}));\n\n\t\tthis._register(autorun(reader => {\n\t\t\t/** @description update labels */\n\n\t\t\tconst children: HTMLElement[] = [];\n\t\t\tif (!this._hide) {\n\t\t\t\tconst lineCount = _unchangedRegion.getHiddenModifiedRange(reader).length;\n\t\t\t\tconst linesHiddenText = localize('hiddenLines', '{0} hidden lines', lineCount);\n\t\t\t\tconst span = $('span', { title: localize('diff.hiddenLines.expandAll', 'Double click to unfold') }, linesHiddenText);\n\t\t\t\tspan.addEventListener('dblclick', e => {\n\t\t\t\t\tif (e.button !== 0) { return; }\n\t\t\t\t\te.preventDefault();\n\t\t\t\t\tthis._unchangedRegion.showAll(undefined);\n\t\t\t\t});\n\t\t\t\tchildren.push(span);\n\n\t\t\t\tconst range = this._unchangedRegion.getHiddenModifiedRange(reader);\n\t\t\t\tconst items = this._modifiedOutlineSource.getBreadcrumbItems(range, reader);\n\n\t\t\t\tif (items.length > 0) {\n\t\t\t\t\tchildren.push($('span', undefined, '\\u00a0\\u00a0|\\u00a0\\u00a0'));\n\n\t\t\t\t\tfor (let i = 0; i < items.length; i++) {\n\t\t\t\t\t\tconst item = items[i];\n\t\t\t\t\t\tconst icon = SymbolKinds.toIcon(item.kind);\n\t\t\t\t\t\tconst divItem = h('div.breadcrumb-item', {\n\t\t\t\t\t\t\tstyle: { display: 'flex', alignItems: 'center' },\n\t\t\t\t\t\t}, [\n\t\t\t\t\t\t\trenderIcon(icon),\n\t\t\t\t\t\t\t'\\u00a0',\n\t\t\t\t\t\t\titem.name,\n\t\t\t\t\t\t\t...(i === items.length - 1\n\t\t\t\t\t\t\t\t? []\n\t\t\t\t\t\t\t\t: [renderIcon(Codicon.chevronRight)]\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t]).root;\n\t\t\t\t\t\tchildren.push(divItem);\n\t\t\t\t\t\tdivItem.onclick = () => {\n\t\t\t\t\t\t\tthis._revealModifiedHiddenLine(item.startLineNumber);\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treset(this._nodes.others, ...children);\n\t\t}));\n\t}\n}\n\nexport interface IDiffEditorBreadcrumbsSource extends IDisposable {\n\tgetBreadcrumbItems(startRange: LineRange, reader: IReader): { name: string; kind: SymbolKind; startLineNumber: number }[];\n}\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\nimport { Event } from 'vs/base/common/event';\nimport { URI } from 'vs/base/common/uri';\nimport { ILanguageIdCodec } from 'vs/editor/common/languages';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\n\nexport const ILanguageService = createDecorator('languageService');\n\nexport interface ILanguageExtensionPoint {\n\tid: string;\n\textensions?: string[];\n\tfilenames?: string[];\n\tfilenamePatterns?: string[];\n\tfirstLine?: string;\n\taliases?: string[];\n\tmimetypes?: string[];\n\tconfiguration?: URI;\n\t/**\n\t * @internal\n\t */\n\ticon?: ILanguageIcon;\n}\n\nexport interface ILanguageSelection {\n\treadonly languageId: string;\n\treadonly onDidChange: Event;\n}\n\nexport interface ILanguageIcon {\n}\n\nexport interface ILanguageService {\n\treadonly _serviceBrand: undefined;\n\n\t/**\n\t * A codec which can encode and decode a string `languageId` as a number.\n\t */\n\treadonly languageIdCodec: ILanguageIdCodec;\n\n\t/**\n\t * An event emitted when basic language features are requested for the first time.\n\t * This event is emitted when embedded languages are encountered (e.g. JS code block inside Markdown)\n\t * or when a language is associated to a text model.\n\t *\n\t * **Note**: Basic language features refers to language configuration related features.\n\t * **Note**: This event is a superset of `onDidRequestRichLanguageFeatures`\n\t */\n\tonDidRequestBasicLanguageFeatures: Event;\n\n\t/**\n\t * An event emitted when rich language features are requested for the first time.\n\t * This event is emitted when a language is associated to a text model.\n\t *\n\t * **Note**: Rich language features refers to tokenizers, language features based on providers, etc.\n\t * **Note**: This event is a subset of `onDidRequestRichLanguageFeatures`\n\t */\n\tonDidRequestRichLanguageFeatures: Event;\n\n\t/**\n\t * Check if `languageId` is registered.\n\t */\n\tisRegisteredLanguageId(languageId: string): boolean;\n\n\t/**\n\t * Look up a language by its name case insensitive.\n\t */\n\tgetLanguageIdByLanguageName(languageName: string): string | null;\n\n\t/**\n\t * Look up a language by its mime type.\n\t */\n\tgetLanguageIdByMimeType(mimeType: string | null | undefined): string | null;\n\n\t/**\n\t * Guess the language id for a resource.\n\t */\n\tguessLanguageIdByFilepathOrFirstLine(resource: URI, firstLine?: string): string | null;\n\n\t/**\n\t * Will fall back to 'plaintext' if `languageId` is unknown.\n\t */\n\tcreateById(languageId: string | null | undefined): ILanguageSelection;\n\n\t/**\n\t * Will fall back to 'plaintext' if the `languageId` cannot be determined.\n\t */\n\tcreateByFilepathOrFirstLine(resource: URI | null, firstLine?: string): ILanguageSelection;\n\n\t/**\n\t * Request basic language features for a language.\n\t */\n\trequestBasicLanguageFeatures(languageId: string): void;\n\n\t/**\n\t * Request rich language features for a language.\n\t */\n\trequestRichLanguageFeatures(languageId: string): void;\n\n}\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\nimport { URI } from 'vs/base/common/uri';\nimport { IRange } from 'vs/editor/common/core/range';\nimport { IDocumentDiff, IDocumentDiffProviderOptions } from 'vs/editor/common/diff/documentDiffProvider';\nimport { IInplaceReplaceSupportResult, TextEdit } from 'vs/editor/common/languages';\nimport { UnicodeHighlighterOptions } from 'vs/editor/common/services/unicodeTextModelHighlighter';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\nimport { SectionHeader, FindSectionHeaderOptions } from 'vs/editor/common/services/findSectionHeaders';\n\nexport const IEditorWorkerService = createDecorator('editorWorkerService');\n\nexport type DiffAlgorithmName = 'legacy' | 'advanced';\n\nexport interface IEditorWorkerService {\n\treadonly _serviceBrand: undefined;\n\n\tcanComputeUnicodeHighlights(uri: URI): boolean;\n\tcomputedUnicodeHighlights(uri: URI, options: UnicodeHighlighterOptions, range?: IRange): Promise;\n\n\t/** Implementation in {@link EditorSimpleWorker.computeDiff} */\n\tcomputeDiff(original: URI, modified: URI, options: IDocumentDiffProviderOptions, algorithm: DiffAlgorithmName): Promise;\n\n\tcomputeMoreMinimalEdits(resource: URI, edits: TextEdit[] | null | undefined, pretty?: boolean): Promise;\n\n\tcanComputeWordRanges(resource: URI): boolean;\n\tcomputeWordRanges(resource: URI, range: IRange): Promise<{ [word: string]: IRange[] } | null>;\n\n\tcanNavigateValueSet(resource: URI): boolean;\n\tnavigateValueSet(resource: URI, range: IRange, up: boolean): Promise;\n\n\tfindSectionHeaders(uri: URI, options: FindSectionHeaderOptions): Promise;\n}\n\nexport interface IDiffComputationResult {\n\tquitEarly: boolean;\n\tchanges: ILineChange[];\n\tidentical: boolean;\n\tmoves: ITextMove[];\n}\n\nexport type ILineChange = [\n\toriginalStartLine: number,\n\toriginalEndLine: number,\n\tmodifiedStartLine: number,\n\tmodifiedEndLine: number,\n\tcharChanges: ICharChange[] | undefined,\n];\n\nexport type ICharChange = [\n\toriginalStartLine: number,\n\toriginalStartColumn: number,\n\toriginalEndLine: number,\n\toriginalEndColumn: number,\n\n\tmodifiedStartLine: number,\n\tmodifiedStartColumn: number,\n\tmodifiedEndLine: number,\n\tmodifiedEndColumn: number,\n];\n\nexport type ITextMove = [\n\toriginalStartLine: number,\n\toriginalEndLine: number,\n\tmodifiedStartLine: number,\n\tmodifiedEndLine: number,\n\tchanges: ILineChange[],\n];\n\nexport interface IUnicodeHighlightsResult {\n\tranges: IRange[];\n\thasMore: boolean;\n\tnonBasicAsciiCharacterCount: number;\n\tinvisibleCharacterCount: number;\n\tambiguousCharacterCount: number;\n}\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\nimport { LanguageFeatureRegistry } from 'vs/editor/common/languageFeatureRegistry';\nimport { CodeActionProvider, CodeLensProvider, CompletionItemProvider, DeclarationProvider, DefinitionProvider, DocumentColorProvider, DocumentFormattingEditProvider, DocumentHighlightProvider, DocumentDropEditProvider, DocumentPasteEditProvider, DocumentRangeFormattingEditProvider, DocumentRangeSemanticTokensProvider, DocumentSemanticTokensProvider, DocumentSymbolProvider, FoldingRangeProvider, HoverProvider, ImplementationProvider, InlayHintsProvider, InlineCompletionsProvider, LinkedEditingRangeProvider, LinkProvider, MultiDocumentHighlightProvider, NewSymbolNamesProvider, OnTypeFormattingEditProvider, ReferenceProvider, RenameProvider, SelectionRangeProvider, SignatureHelpProvider, TypeDefinitionProvider, InlineEditProvider } from 'vs/editor/common/languages';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\n\nexport const ILanguageFeaturesService = createDecorator('ILanguageFeaturesService');\n\nexport interface ILanguageFeaturesService {\n\n\treadonly _serviceBrand: undefined;\n\n\treadonly referenceProvider: LanguageFeatureRegistry;\n\n\treadonly definitionProvider: LanguageFeatureRegistry;\n\n\treadonly typeDefinitionProvider: LanguageFeatureRegistry;\n\n\treadonly declarationProvider: LanguageFeatureRegistry;\n\n\treadonly implementationProvider: LanguageFeatureRegistry;\n\n\treadonly codeActionProvider: LanguageFeatureRegistry;\n\n\treadonly documentPasteEditProvider: LanguageFeatureRegistry;\n\n\treadonly renameProvider: LanguageFeatureRegistry;\n\n\treadonly newSymbolNamesProvider: LanguageFeatureRegistry;\n\n\treadonly documentFormattingEditProvider: LanguageFeatureRegistry;\n\n\treadonly documentRangeFormattingEditProvider: LanguageFeatureRegistry;\n\n\treadonly onTypeFormattingEditProvider: LanguageFeatureRegistry;\n\n\treadonly documentSymbolProvider: LanguageFeatureRegistry;\n\n\treadonly inlayHintsProvider: LanguageFeatureRegistry;\n\n\treadonly colorProvider: LanguageFeatureRegistry;\n\n\treadonly codeLensProvider: LanguageFeatureRegistry;\n\n\treadonly signatureHelpProvider: LanguageFeatureRegistry;\n\n\treadonly hoverProvider: LanguageFeatureRegistry;\n\n\treadonly documentHighlightProvider: LanguageFeatureRegistry;\n\n\treadonly multiDocumentHighlightProvider: LanguageFeatureRegistry;\n\n\treadonly documentRangeSemanticTokensProvider: LanguageFeatureRegistry;\n\n\treadonly documentSemanticTokensProvider: LanguageFeatureRegistry;\n\n\treadonly selectionRangeProvider: LanguageFeatureRegistry;\n\n\treadonly foldingRangeProvider: LanguageFeatureRegistry;\n\n\treadonly linkProvider: LanguageFeatureRegistry;\n\n\treadonly inlineCompletionsProvider: LanguageFeatureRegistry;\n\n\treadonly inlineEditProvider: LanguageFeatureRegistry;\n\n\treadonly completionProvider: LanguageFeatureRegistry;\n\n\treadonly linkedEditingRangeProvider: LanguageFeatureRegistry;\n\n\treadonly documentDropEditProvider: LanguageFeatureRegistry;\n}\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\nimport { URI } from 'vs/base/common/uri';\nimport { LanguageFeatureRegistry, NotebookInfo, NotebookInfoResolver } from 'vs/editor/common/languageFeatureRegistry';\nimport { CodeActionProvider, CodeLensProvider, CompletionItemProvider, DocumentPasteEditProvider, DeclarationProvider, DefinitionProvider, DocumentColorProvider, DocumentFormattingEditProvider, MultiDocumentHighlightProvider, DocumentHighlightProvider, DocumentDropEditProvider, DocumentRangeFormattingEditProvider, DocumentRangeSemanticTokensProvider, DocumentSemanticTokensProvider, DocumentSymbolProvider, FoldingRangeProvider, HoverProvider, ImplementationProvider, InlayHintsProvider, InlineCompletionsProvider, LinkedEditingRangeProvider, LinkProvider, OnTypeFormattingEditProvider, ReferenceProvider, RenameProvider, SelectionRangeProvider, SignatureHelpProvider, TypeDefinitionProvider, NewSymbolNamesProvider, InlineEditProvider } from 'vs/editor/common/languages';\nimport { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';\nimport { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions';\n\nexport class LanguageFeaturesService implements ILanguageFeaturesService {\n\n\tdeclare _serviceBrand: undefined;\n\n\treadonly referenceProvider = new LanguageFeatureRegistry(this._score.bind(this));\n\treadonly renameProvider = new LanguageFeatureRegistry(this._score.bind(this));\n\treadonly newSymbolNamesProvider = new LanguageFeatureRegistry(this._score.bind(this));\n\treadonly codeActionProvider = new LanguageFeatureRegistry(this._score.bind(this));\n\treadonly definitionProvider = new LanguageFeatureRegistry(this._score.bind(this));\n\treadonly typeDefinitionProvider = new LanguageFeatureRegistry(this._score.bind(this));\n\treadonly declarationProvider = new LanguageFeatureRegistry(this._score.bind(this));\n\treadonly implementationProvider = new LanguageFeatureRegistry(this._score.bind(this));\n\treadonly documentSymbolProvider = new LanguageFeatureRegistry(this._score.bind(this));\n\treadonly inlayHintsProvider = new LanguageFeatureRegistry(this._score.bind(this));\n\treadonly colorProvider = new LanguageFeatureRegistry(this._score.bind(this));\n\treadonly codeLensProvider = new LanguageFeatureRegistry(this._score.bind(this));\n\treadonly documentFormattingEditProvider = new LanguageFeatureRegistry(this._score.bind(this));\n\treadonly documentRangeFormattingEditProvider = new LanguageFeatureRegistry(this._score.bind(this));\n\treadonly onTypeFormattingEditProvider = new LanguageFeatureRegistry(this._score.bind(this));\n\treadonly signatureHelpProvider = new LanguageFeatureRegistry(this._score.bind(this));\n\treadonly hoverProvider = new LanguageFeatureRegistry(this._score.bind(this));\n\treadonly documentHighlightProvider = new LanguageFeatureRegistry(this._score.bind(this));\n\treadonly multiDocumentHighlightProvider = new LanguageFeatureRegistry(this._score.bind(this));\n\treadonly selectionRangeProvider = new LanguageFeatureRegistry(this._score.bind(this));\n\treadonly foldingRangeProvider = new LanguageFeatureRegistry(this._score.bind(this));\n\treadonly linkProvider = new LanguageFeatureRegistry(this._score.bind(this));\n\treadonly inlineCompletionsProvider = new LanguageFeatureRegistry(this._score.bind(this));\n\treadonly inlineEditProvider = new LanguageFeatureRegistry(this._score.bind(this));\n\treadonly completionProvider = new LanguageFeatureRegistry(this._score.bind(this));\n\treadonly linkedEditingRangeProvider = new LanguageFeatureRegistry(this._score.bind(this));\n\treadonly documentRangeSemanticTokensProvider = new LanguageFeatureRegistry(this._score.bind(this));\n\treadonly documentSemanticTokensProvider = new LanguageFeatureRegistry(this._score.bind(this));\n\treadonly documentDropEditProvider = new LanguageFeatureRegistry(this._score.bind(this));\n\treadonly documentPasteEditProvider = new LanguageFeatureRegistry(this._score.bind(this));\n\n\tprivate _notebookTypeResolver?: NotebookInfoResolver;\n\n\tprivate _score(uri: URI): NotebookInfo | undefined {\n\t\treturn this._notebookTypeResolver?.(uri);\n\t}\n\n}\n\nregisterSingleton(ILanguageFeaturesService, LanguageFeaturesService, InstantiationType.Delayed);\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\nimport { IModelDecoration } from 'vs/editor/common/model';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\nimport { IMarker } from 'vs/platform/markers/common/markers';\nimport { URI } from 'vs/base/common/uri';\n\nexport const IMarkerDecorationsService = createDecorator('markerDecorationsService');\n\nexport interface IMarkerDecorationsService {\n\treadonly _serviceBrand: undefined;\n\n\tgetMarker(uri: URI, decoration: IModelDecoration): IMarker | null;\n}\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\nimport { Event } from 'vs/base/common/event';\nimport { URI } from 'vs/base/common/uri';\nimport { ITextBufferFactory, ITextModel, ITextModelCreationOptions } from 'vs/editor/common/model';\nimport { ILanguageSelection } from 'vs/editor/common/languages/language';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\nimport { DocumentSemanticTokensProvider, DocumentRangeSemanticTokensProvider } from 'vs/editor/common/languages';\n\nexport const IModelService = createDecorator('modelService');\n\nexport type DocumentTokensProvider = DocumentSemanticTokensProvider | DocumentRangeSemanticTokensProvider;\n\nexport interface IModelService {\n\treadonly _serviceBrand: undefined;\n\n\tcreateModel(value: string | ITextBufferFactory, languageSelection: ILanguageSelection | null, resource?: URI, isForSimpleWidget?: boolean): ITextModel;\n\n\tgetModels(): ITextModel[];\n\n\tgetCreationOptions(language: string, resource: URI, isForSimpleWidget: boolean): ITextModelCreationOptions;\n\n\tgetModel(resource: URI): ITextModel | null;\n\n\tonModelAdded: Event;\n\n\tonModelRemoved: Event;\n\n\tonModelLanguageChanged: Event<{ model: ITextModel; oldLanguageId: string }>;\n}\n","\nimport { IReference } from 'vs/base/common/lifecycle';\nimport { URI } from 'vs/base/common/uri';\nimport { ITextModel } from 'vs/editor/common/model';\nimport { IResolvableEditorModel } from 'vs/platform/editor/common/editor';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\n\nexport const ITextModelService = createDecorator('textModelService');\n\nexport interface ITextModelService {\n\treadonly _serviceBrand: undefined;\n\n\t/**\n\t * Provided a resource URI, it will return a model reference\n\t * which should be disposed once not needed anymore.\n\t */\n\tcreateModelReference(resource: URI): Promise>;\n}\n\nexport interface ITextEditorModel extends IResolvableEditorModel {\n\n\t/**\n\t * Provides access to the underlying `ITextModel`.\n\t */\n\treadonly textEditorModel: ITextModel | null;\n}\n\nexport interface IResolvedTextEditorModel extends ITextEditorModel {\n\n\t/**\n\t * Same as ITextEditorModel#textEditorModel, but never null.\n\t */\n\treadonly textEditorModel: ITextModel;\n}\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\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\nimport { DocumentSemanticTokensProvider, DocumentRangeSemanticTokensProvider } from 'vs/editor/common/languages';\nimport { SemanticTokensProviderStyling } from 'vs/editor/common/services/semanticTokensProviderStyling';\n\nexport const ISemanticTokensStylingService = createDecorator('semanticTokensStylingService');\n\nexport type DocumentTokensProvider = DocumentSemanticTokensProvider | DocumentRangeSemanticTokensProvider;\n\nexport interface ISemanticTokensStylingService {\n\treadonly _serviceBrand: undefined;\n\n\tgetStyling(provider: DocumentTokensProvider): SemanticTokensProviderStyling;\n}\n","\nimport { URI } from 'vs/base/common/uri';\nimport { IPosition } from 'vs/editor/common/core/position';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\n\nexport const ITextResourceConfigurationService = createDecorator('textResourceConfigurationService');\n\nexport interface ITextResourceConfigurationChangeEvent {\n\n\t/**\n\t * All affected keys. Also includes language overrides and keys changed under language overrides.\n\t */\n\treadonly affectedKeys: ReadonlySet;\n\n\t/**\n\t * Returns `true` if the given section has changed for the given resource.\n\t *\n\t * Example: To check if the configuration section has changed for a given resource use `e.affectsConfiguration(resource, section)`.\n\t *\n\t * @param resource Resource for which the configuration has to be checked.\n\t * @param section Section of the configuration\n\t */\n\taffectsConfiguration(resource: URI | undefined, section: string): boolean;\n}\n\nexport interface ITextResourceConfigurationService {\n\n\treadonly _serviceBrand: undefined;\n\n\t/**\n\t * Fetches the value of the section for the given resource by applying language overrides.\n\t * Value can be of native type or an object keyed off the section name.\n\t *\n\t * @param resource - Resource for which the configuration has to be fetched.\n\t * @param position - Position in the resource for which configuration has to be fetched.\n\t * @param section - Section of the configuration.\n\t *\n\t */\n\tgetValue(resource: URI | undefined, section?: string): T;\n\tgetValue(resource: URI | undefined, position?: IPosition, section?: string): T;\n\n}\n\nexport const ITextResourcePropertiesService = createDecorator('textResourcePropertiesService');\n\nexport interface ITextResourcePropertiesService {\n\n\treadonly _serviceBrand: undefined;\n\n\t/**\n\t * Returns the End of Line characters for the given resource\n\t */\n\tgetEOL(resource: URI, language?: string): string;\n}\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\nimport { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\nimport { VSDataTransfer } from 'vs/base/common/dataTransfer';\nimport { ITreeViewsDnDService as ITreeViewsDnDServiceCommon, TreeViewsDnDService } from 'vs/editor/common/services/treeViewsDnd';\n\nexport interface ITreeViewsDnDService extends ITreeViewsDnDServiceCommon { }\nexport const ITreeViewsDnDService = createDecorator('treeViewsDndService');\nregisterSingleton(ITreeViewsDnDService, TreeViewsDnDService, InstantiationType.Delayed);\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\nimport { URI } from 'vs/base/common/uri';\nimport { ResourceTextEdit } from 'vs/editor/browser/services/bulkEditService';\nimport { DocumentDropEdit, DocumentPasteEdit, DropYieldTo, WorkspaceEdit } from 'vs/editor/common/languages';\nimport { Range } from 'vs/editor/common/core/range';\nimport { SnippetParser } from 'vs/editor/contrib/snippet/browser/snippetParser';\nimport { HierarchicalKind } from 'vs/base/common/hierarchicalKind';\n\n/**\n * Given a {@link DropOrPasteEdit} and set of ranges, creates a {@link WorkspaceEdit} that applies the insert text from\n * the {@link DropOrPasteEdit} at each range plus any additional edits.\n */\nexport function createCombinedWorkspaceEdit(uri: URI, ranges: readonly Range[], edit: DocumentPasteEdit | DocumentDropEdit): WorkspaceEdit {\n\t// If the edit insert text is empty, skip applying at each range\n\tif (typeof edit.insertText === 'string' ? edit.insertText === '' : edit.insertText.snippet === '') {\n\t\treturn {\n\t\t\tedits: edit.additionalEdit?.edits ?? []\n\t\t};\n\t}\n\n\treturn {\n\t\tedits: [\n\t\t\t...ranges.map(range =>\n\t\t\t\tnew ResourceTextEdit(uri,\n\t\t\t\t\t{ range, text: typeof edit.insertText === 'string' ? SnippetParser.escape(edit.insertText) + '$0' : edit.insertText.snippet, insertAsSnippet: true }\n\t\t\t\t)),\n\t\t\t...(edit.additionalEdit?.edits ?? [])\n\t\t]\n\t};\n}\n\nexport function sortEditsByYieldTo(edits: readonly T[]): T[] {\n\tfunction yieldsTo(yTo: DropYieldTo, other: T): boolean {\n\t\tif ('mimeType' in yTo) {\n\t\t\treturn yTo.mimeType === other.handledMimeType;\n\t\t}\n\t\treturn !!other.kind && yTo.kind.contains(other.kind);\n\t}\n\n\t// Build list of nodes each node yields to\n\tconst yieldsToMap = new Map();\n\tfor (const edit of edits) {\n\t\tfor (const yTo of edit.yieldTo ?? []) {\n\t\t\tfor (const other of edits) {\n\t\t\t\tif (other === edit) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (yieldsTo(yTo, other)) {\n\t\t\t\t\tlet arr = yieldsToMap.get(edit);\n\t\t\t\t\tif (!arr) {\n\t\t\t\t\t\tarr = [];\n\t\t\t\t\t\tyieldsToMap.set(edit, arr);\n\t\t\t\t\t}\n\t\t\t\t\tarr.push(other);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif (!yieldsToMap.size) {\n\t\treturn Array.from(edits);\n\t}\n\n\t// Topological sort\n\tconst visited = new Set();\n\tconst tempStack: T[] = [];\n\n\tfunction visit(nodes: T[]): T[] {\n\t\tif (!nodes.length) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst node = nodes[0];\n\t\tif (tempStack.includes(node)) {\n\t\t\tconsole.warn('Yield to cycle detected', node);\n\t\t\treturn nodes;\n\t\t}\n\n\t\tif (visited.has(node)) {\n\t\t\treturn visit(nodes.slice(1));\n\t\t}\n\n\t\tlet pre: T[] = [];\n\t\tconst yTo = yieldsToMap.get(node);\n\t\tif (yTo) {\n\t\t\ttempStack.push(node);\n\t\t\tpre = visit(yTo);\n\t\t\ttempStack.pop();\n\t\t}\n\n\t\tvisited.add(node);\n\n\t\treturn [...pre, node, ...visit(nodes.slice(1))];\n\t}\n\n\treturn visit(Array.from(edits));\n}\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\nimport { createTrustedTypesPolicy } from 'vs/base/browser/trustedTypes';\nimport { Event } from 'vs/base/common/event';\nimport { Disposable, toDisposable } from 'vs/base/common/lifecycle';\nimport { IObservable, autorun, derived, observableFromEvent, observableSignalFromEvent, observableValue } from 'vs/base/common/observable';\nimport * as strings from 'vs/base/common/strings';\nimport 'vs/css!./ghostText';\nimport { applyFontInfo } from 'vs/editor/browser/config/domFontInfo';\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\nimport { EditorFontLigatures, EditorOption, IComputedEditorOptions } from 'vs/editor/common/config/editorOptions';\nimport { Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\nimport { StringBuilder } from 'vs/editor/common/core/stringBuilder';\nimport { ILanguageIdCodec } from 'vs/editor/common/languages';\nimport { ILanguageService } from 'vs/editor/common/languages/language';\nimport { IModelDeltaDecoration, ITextModel, InjectedTextCursorStops, PositionAffinity } from 'vs/editor/common/model';\nimport { LineTokens } from 'vs/editor/common/tokens/lineTokens';\nimport { LineDecoration } from 'vs/editor/common/viewLayout/lineDecorations';\nimport { RenderLineInput, renderViewLine } from 'vs/editor/common/viewLayout/viewLineRenderer';\nimport { InlineDecorationType } from 'vs/editor/common/viewModel';\nimport { GhostText, GhostTextReplacement } from 'vs/editor/contrib/inlineCompletions/browser/ghostText';\nimport { ColumnRange, applyObservableDecorations } from 'vs/editor/contrib/inlineCompletions/browser/utils';\n\nexport const GHOST_TEXT_DESCRIPTION = 'ghost-text';\nexport interface IGhostTextWidgetModel {\n\treadonly targetTextModel: IObservable;\n\treadonly ghostText: IObservable;\n\treadonly minReservedLineCount: IObservable;\n}\n\nexport class GhostTextWidget extends Disposable {\n\tprivate readonly isDisposed = observableValue(this, false);\n\tprivate readonly currentTextModel = observableFromEvent(this.editor.onDidChangeModel, () => /** @description editor.model */ this.editor.getModel());\n\n\tconstructor(\n\t\tprivate readonly editor: ICodeEditor,\n\t\tprivate readonly model: IGhostTextWidgetModel,\n\t\t@ILanguageService private readonly languageService: ILanguageService,\n\t) {\n\t\tsuper();\n\n\t\tthis._register(toDisposable(() => { this.isDisposed.set(true, undefined); }));\n\t\tthis._register(applyObservableDecorations(this.editor, this.decorations));\n\t}\n\n\tprivate readonly uiState = derived(this, reader => {\n\t\tif (this.isDisposed.read(reader)) {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst textModel = this.currentTextModel.read(reader);\n\t\tif (textModel !== this.model.targetTextModel.read(reader)) {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst ghostText = this.model.ghostText.read(reader);\n\t\tif (!ghostText) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst replacedRange = ghostText instanceof GhostTextReplacement ? ghostText.columnRange : undefined;\n\n\t\tconst inlineTexts: { column: number; text: string; preview: boolean }[] = [];\n\t\tconst additionalLines: LineData[] = [];\n\n\t\tfunction addToAdditionalLines(lines: readonly string[], className: string | undefined) {\n\t\t\tif (additionalLines.length > 0) {\n\t\t\t\tconst lastLine = additionalLines[additionalLines.length - 1];\n\t\t\t\tif (className) {\n\t\t\t\t\tlastLine.decorations.push(new LineDecoration(lastLine.content.length + 1, lastLine.content.length + 1 + lines[0].length, className, InlineDecorationType.Regular));\n\t\t\t\t}\n\t\t\t\tlastLine.content += lines[0];\n\n\t\t\t\tlines = lines.slice(1);\n\t\t\t}\n\t\t\tfor (const line of lines) {\n\t\t\t\tadditionalLines.push({\n\t\t\t\t\tcontent: line,\n\t\t\t\t\tdecorations: className ? [new LineDecoration(1, line.length + 1, className, InlineDecorationType.Regular)] : []\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tconst textBufferLine = textModel.getLineContent(ghostText.lineNumber);\n\n\t\tlet hiddenTextStartColumn: number | undefined = undefined;\n\t\tlet lastIdx = 0;\n\t\tfor (const part of ghostText.parts) {\n\t\t\tlet lines = part.lines;\n\t\t\tif (hiddenTextStartColumn === undefined) {\n\t\t\t\tinlineTexts.push({\n\t\t\t\t\tcolumn: part.column,\n\t\t\t\t\ttext: lines[0],\n\t\t\t\t\tpreview: part.preview,\n\t\t\t\t});\n\t\t\t\tlines = lines.slice(1);\n\t\t\t} else {\n\t\t\t\taddToAdditionalLines([textBufferLine.substring(lastIdx, part.column - 1)], undefined);\n\t\t\t}\n\n\t\t\tif (lines.length > 0) {\n\t\t\t\taddToAdditionalLines(lines, GHOST_TEXT_DESCRIPTION);\n\t\t\t\tif (hiddenTextStartColumn === undefined && part.column <= textBufferLine.length) {\n\t\t\t\t\thiddenTextStartColumn = part.column;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlastIdx = part.column - 1;\n\t\t}\n\t\tif (hiddenTextStartColumn !== undefined) {\n\t\t\taddToAdditionalLines([textBufferLine.substring(lastIdx)], undefined);\n\t\t}\n\n\t\tconst hiddenRange = hiddenTextStartColumn !== undefined ? new ColumnRange(hiddenTextStartColumn, textBufferLine.length + 1) : undefined;\n\n\t\treturn {\n\t\t\treplacedRange,\n\t\t\tinlineTexts,\n\t\t\tadditionalLines,\n\t\t\thiddenRange,\n\t\t\tlineNumber: ghostText.lineNumber,\n\t\t\tadditionalReservedLineCount: this.model.minReservedLineCount.read(reader),\n\t\t\ttargetTextModel: textModel,\n\t\t};\n\t});\n\n\tprivate readonly decorations = derived(this, reader => {\n\t\tconst uiState = this.uiState.read(reader);\n\t\tif (!uiState) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst decorations: IModelDeltaDecoration[] = [];\n\n\t\tif (uiState.replacedRange) {\n\t\t\tdecorations.push({\n\t\t\t\trange: uiState.replacedRange.toRange(uiState.lineNumber),\n\t\t\t\toptions: { inlineClassName: 'inline-completion-text-to-replace', description: 'GhostTextReplacement' }\n\t\t\t});\n\t\t}\n\n\t\tif (uiState.hiddenRange) {\n\t\t\tdecorations.push({\n\t\t\t\trange: uiState.hiddenRange.toRange(uiState.lineNumber),\n\t\t\t\toptions: { inlineClassName: 'ghost-text-hidden', description: 'ghost-text-hidden', }\n\t\t\t});\n\t\t}\n\n\t\tfor (const p of uiState.inlineTexts) {\n\t\t\tdecorations.push({\n\t\t\t\trange: Range.fromPositions(new Position(uiState.lineNumber, p.column)),\n\t\t\t\toptions: {\n\t\t\t\t\tdescription: GHOST_TEXT_DESCRIPTION,\n\t\t\t\t\tafter: { content: p.text, inlineClassName: p.preview ? 'ghost-text-decoration-preview' : 'ghost-text-decoration', cursorStops: InjectedTextCursorStops.Left },\n\t\t\t\t\tshowIfCollapsed: true,\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\treturn decorations;\n\t});\n\n\tprivate readonly additionalLinesWidget = this._register(\n\t\tnew AdditionalLinesWidget(\n\t\t\tthis.editor,\n\t\t\tthis.languageService.languageIdCodec,\n\t\t\tderived(reader => {\n\t\t\t\t/** @description lines */\n\t\t\t\tconst uiState = this.uiState.read(reader);\n\t\t\t\treturn uiState ? {\n\t\t\t\t\tlineNumber: uiState.lineNumber,\n\t\t\t\t\tadditionalLines: uiState.additionalLines,\n\t\t\t\t\tminReservedLineCount: uiState.additionalReservedLineCount,\n\t\t\t\t\ttargetTextModel: uiState.targetTextModel,\n\t\t\t\t} : undefined;\n\t\t\t})\n\t\t)\n\t);\n\n\tpublic ownsViewZone(viewZoneId: string): boolean {\n\t\treturn this.additionalLinesWidget.viewZoneId === viewZoneId;\n\t}\n}\n\nexport class AdditionalLinesWidget extends Disposable {\n\tprivate _viewZoneId: string | undefined = undefined;\n\tpublic get viewZoneId(): string | undefined { return this._viewZoneId; }\n\n\tprivate readonly editorOptionsChanged = observableSignalFromEvent('editorOptionChanged', Event.filter(\n\t\tthis.editor.onDidChangeConfiguration,\n\t\te => e.hasChanged(EditorOption.disableMonospaceOptimizations)\n\t\t\t|| e.hasChanged(EditorOption.stopRenderingLineAfter)\n\t\t\t|| e.hasChanged(EditorOption.renderWhitespace)\n\t\t\t|| e.hasChanged(EditorOption.renderControlCharacters)\n\t\t\t|| e.hasChanged(EditorOption.fontLigatures)\n\t\t\t|| e.hasChanged(EditorOption.fontInfo)\n\t\t\t|| e.hasChanged(EditorOption.lineHeight)\n\t));\n\n\tconstructor(\n\t\tprivate readonly editor: ICodeEditor,\n\t\tprivate readonly languageIdCodec: ILanguageIdCodec,\n\t\tprivate readonly lines: IObservable<{ targetTextModel: ITextModel; lineNumber: number; additionalLines: LineData[]; minReservedLineCount: number } | undefined>\n\t) {\n\t\tsuper();\n\n\t\tthis._register(autorun(reader => {\n\t\t\t/** @description update view zone */\n\t\t\tconst lines = this.lines.read(reader);\n\t\t\tthis.editorOptionsChanged.read(reader);\n\n\t\t\tif (lines) {\n\t\t\t\tthis.updateLines(lines.lineNumber, lines.additionalLines, lines.minReservedLineCount);\n\t\t\t} else {\n\t\t\t\tthis.clear();\n\t\t\t}\n\t\t}));\n\t}\n\n\tpublic override dispose(): void {\n\t\tsuper.dispose();\n\t\tthis.clear();\n\t}\n\n\tprivate clear(): void {\n\t\tthis.editor.changeViewZones((changeAccessor) => {\n\t\t\tif (this._viewZoneId) {\n\t\t\t\tchangeAccessor.removeZone(this._viewZoneId);\n\t\t\t\tthis._viewZoneId = undefined;\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate updateLines(lineNumber: number, additionalLines: LineData[], minReservedLineCount: number): void {\n\t\tconst textModel = this.editor.getModel();\n\t\tif (!textModel) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst { tabSize } = textModel.getOptions();\n\n\t\tthis.editor.changeViewZones((changeAccessor) => {\n\t\t\tif (this._viewZoneId) {\n\t\t\t\tchangeAccessor.removeZone(this._viewZoneId);\n\t\t\t\tthis._viewZoneId = undefined;\n\t\t\t}\n\n\t\t\tconst heightInLines = Math.max(additionalLines.length, minReservedLineCount);\n\t\t\tif (heightInLines > 0) {\n\t\t\t\tconst domNode = document.createElement('div');\n\t\t\t\trenderLines(domNode, tabSize, additionalLines, this.editor.getOptions(), this.languageIdCodec);\n\n\t\t\t\tthis._viewZoneId = changeAccessor.addZone({\n\t\t\t\t\tafterLineNumber: lineNumber,\n\t\t\t\t\theightInLines: heightInLines,\n\t\t\t\t\tdomNode,\n\t\t\t\t\tafterColumnAffinity: PositionAffinity.Right\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\t}\n}\n\nexport interface LineData {\n\tcontent: string; // Must not contain a linebreak!\n\tdecorations: LineDecoration[];\n}\n\nfunction renderLines(domNode: HTMLElement, tabSize: number, lines: LineData[], opts: IComputedEditorOptions, languageIdCodec: ILanguageIdCodec): void {\n\tconst disableMonospaceOptimizations = opts.get(EditorOption.disableMonospaceOptimizations);\n\tconst stopRenderingLineAfter = opts.get(EditorOption.stopRenderingLineAfter);\n\t// To avoid visual confusion, we don't want to render visible whitespace\n\tconst renderWhitespace = 'none';\n\tconst renderControlCharacters = opts.get(EditorOption.renderControlCharacters);\n\tconst fontLigatures = opts.get(EditorOption.fontLigatures);\n\tconst fontInfo = opts.get(EditorOption.fontInfo);\n\tconst lineHeight = opts.get(EditorOption.lineHeight);\n\n\tconst sb = new StringBuilder(10000);\n\tsb.appendString('
    ');\n\n\tfor (let i = 0, len = lines.length; i < len; i++) {\n\t\tconst lineData = lines[i];\n\t\tconst line = lineData.content;\n\t\tsb.appendString('
    ');\n\n\t\tconst isBasicASCII = strings.isBasicASCII(line);\n\t\tconst containsRTL = strings.containsRTL(line);\n\t\tconst lineTokens = LineTokens.createEmpty(line, languageIdCodec);\n\n\t\trenderViewLine(new RenderLineInput(\n\t\t\t(fontInfo.isMonospace && !disableMonospaceOptimizations),\n\t\t\tfontInfo.canUseHalfwidthRightwardsArrow,\n\t\t\tline,\n\t\t\tfalse,\n\t\t\tisBasicASCII,\n\t\t\tcontainsRTL,\n\t\t\t0,\n\t\t\tlineTokens,\n\t\t\tlineData.decorations,\n\t\t\ttabSize,\n\t\t\t0,\n\t\t\tfontInfo.spaceWidth,\n\t\t\tfontInfo.middotWidth,\n\t\t\tfontInfo.wsmiddotWidth,\n\t\t\tstopRenderingLineAfter,\n\t\t\trenderWhitespace,\n\t\t\trenderControlCharacters,\n\t\t\tfontLigatures !== EditorFontLigatures.OFF,\n\t\t\tnull\n\t\t), sb);\n\n\t\tsb.appendString('
    ');\n\t}\n\tsb.appendString('
    ');\n\n\tapplyFontInfo(domNode, fontInfo);\n\tconst html = sb.build();\n\tconst trustedhtml = ttPolicy ? ttPolicy.createHTML(html) : html;\n\tdomNode.innerHTML = trustedhtml as string;\n}\n\nexport const ttPolicy = createTrustedTypesPolicy('editorGhostText', { createHTML: value => value });\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\nimport { Disposable, toDisposable } from 'vs/base/common/lifecycle';\nimport { IObservable, derived, observableFromEvent, observableValue } from 'vs/base/common/observable';\nimport 'vs/css!./inlineEdit';\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\nimport { Position } from 'vs/editor/common/core/position';\nimport { IRange, Range } from 'vs/editor/common/core/range';\nimport { ILanguageService } from 'vs/editor/common/languages/language';\nimport { IModelDeltaDecoration, ITextModel, InjectedTextCursorStops } from 'vs/editor/common/model';\nimport { LineDecoration } from 'vs/editor/common/viewLayout/lineDecorations';\nimport { InlineDecorationType } from 'vs/editor/common/viewModel';\nimport { AdditionalLinesWidget, LineData } from 'vs/editor/contrib/inlineCompletions/browser/ghostTextWidget';\nimport { GhostText } from 'vs/editor/contrib/inlineCompletions/browser/ghostText';\nimport { ColumnRange, applyObservableDecorations } from 'vs/editor/contrib/inlineCompletions/browser/utils';\n\nexport const INLINE_EDIT_DESCRIPTION = 'inline-edit';\nexport interface IGhostTextWidgetModel {\n\treadonly targetTextModel: IObservable;\n\treadonly ghostText: IObservable;\n\treadonly minReservedLineCount: IObservable;\n\treadonly range: IObservable;\n\treadonly backgroundColoring: IObservable;\n}\n\nexport class GhostTextWidget extends Disposable {\n\tprivate readonly isDisposed = observableValue(this, false);\n\tprivate readonly currentTextModel = observableFromEvent(this.editor.onDidChangeModel, () => /** @description editor.model */ this.editor.getModel());\n\n\tconstructor(\n\t\tprivate readonly editor: ICodeEditor,\n\t\treadonly model: IGhostTextWidgetModel,\n\t\t@ILanguageService private readonly languageService: ILanguageService,\n\t) {\n\t\tsuper();\n\n\t\tthis._register(toDisposable(() => { this.isDisposed.set(true, undefined); }));\n\t\tthis._register(applyObservableDecorations(this.editor, this.decorations));\n\t}\n\n\tprivate readonly uiState = derived(this, reader => {\n\t\tif (this.isDisposed.read(reader)) {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst textModel = this.currentTextModel.read(reader);\n\t\tif (textModel !== this.model.targetTextModel.read(reader)) {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst ghostText = this.model.ghostText.read(reader);\n\t\tif (!ghostText) {\n\t\t\treturn undefined;\n\t\t}\n\n\n\t\tlet range = this.model.range?.read(reader);\n\t\t//if range is empty, we want to remove it\n\t\tif (range && range.startLineNumber === range.endLineNumber && range.startColumn === range.endColumn) {\n\t\t\trange = undefined;\n\t\t}\n\t\t//check if both range and text are single line - in this case we want to do inline replacement\n\t\t//rather than replacing whole lines\n\t\tconst isSingleLine = (range ? range.startLineNumber === range.endLineNumber : true) && ghostText.parts.length === 1 && ghostText.parts[0].lines.length === 1;\n\n\t\t//check if we're just removing code\n\t\tconst isPureRemove = ghostText.parts.length === 1 && ghostText.parts[0].lines.every(l => l.length === 0);\n\n\t\tconst inlineTexts: { column: number; text: string; preview: boolean }[] = [];\n\t\tconst additionalLines: LineData[] = [];\n\n\t\tfunction addToAdditionalLines(lines: readonly string[], className: string | undefined) {\n\t\t\tif (additionalLines.length > 0) {\n\t\t\t\tconst lastLine = additionalLines[additionalLines.length - 1];\n\t\t\t\tif (className) {\n\t\t\t\t\tlastLine.decorations.push(new LineDecoration(lastLine.content.length + 1, lastLine.content.length + 1 + lines[0].length, className, InlineDecorationType.Regular));\n\t\t\t\t}\n\t\t\t\tlastLine.content += lines[0];\n\n\t\t\t\tlines = lines.slice(1);\n\t\t\t}\n\t\t\tfor (const line of lines) {\n\t\t\t\tadditionalLines.push({\n\t\t\t\t\tcontent: line,\n\t\t\t\t\tdecorations: className ? [new LineDecoration(1, line.length + 1, className, InlineDecorationType.Regular)] : []\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tconst textBufferLine = textModel.getLineContent(ghostText.lineNumber);\n\n\t\tlet hiddenTextStartColumn: number | undefined = undefined;\n\t\tlet lastIdx = 0;\n\t\tif (!isPureRemove) {\n\t\t\tfor (const part of ghostText.parts) {\n\t\t\t\tlet lines = part.lines;\n\t\t\t\t//If remove range is set, we want to push all new liens to virtual area\n\t\t\t\tif (range && !isSingleLine) {\n\t\t\t\t\taddToAdditionalLines(lines, INLINE_EDIT_DESCRIPTION);\n\t\t\t\t\tlines = [];\n\t\t\t\t}\n\t\t\t\tif (hiddenTextStartColumn === undefined) {\n\t\t\t\t\tinlineTexts.push({\n\t\t\t\t\t\tcolumn: part.column,\n\t\t\t\t\t\ttext: lines[0],\n\t\t\t\t\t\tpreview: part.preview,\n\t\t\t\t\t});\n\t\t\t\t\tlines = lines.slice(1);\n\t\t\t\t} else {\n\t\t\t\t\taddToAdditionalLines([textBufferLine.substring(lastIdx, part.column - 1)], undefined);\n\t\t\t\t}\n\n\t\t\t\tif (lines.length > 0) {\n\t\t\t\t\taddToAdditionalLines(lines, INLINE_EDIT_DESCRIPTION);\n\t\t\t\t\tif (hiddenTextStartColumn === undefined && part.column <= textBufferLine.length) {\n\t\t\t\t\t\thiddenTextStartColumn = part.column;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tlastIdx = part.column - 1;\n\t\t\t}\n\t\t\tif (hiddenTextStartColumn !== undefined) {\n\t\t\t\taddToAdditionalLines([textBufferLine.substring(lastIdx)], undefined);\n\t\t\t}\n\t\t}\n\n\t\tconst hiddenRange = hiddenTextStartColumn !== undefined ? new ColumnRange(hiddenTextStartColumn, textBufferLine.length + 1) : undefined;\n\n\t\tconst lineNumber =\n\t\t\t(isSingleLine || !range) ? ghostText.lineNumber : range.endLineNumber - 1;\n\n\t\treturn {\n\t\t\tinlineTexts,\n\t\t\tadditionalLines,\n\t\t\thiddenRange,\n\t\t\tlineNumber,\n\t\t\tadditionalReservedLineCount: this.model.minReservedLineCount.read(reader),\n\t\t\ttargetTextModel: textModel,\n\t\t\trange,\n\t\t\tisSingleLine,\n\t\t\tisPureRemove,\n\t\t\tbackgroundColoring: this.model.backgroundColoring.read(reader)\n\t\t};\n\t});\n\n\tprivate readonly decorations = derived(this, reader => {\n\t\tconst uiState = this.uiState.read(reader);\n\t\tif (!uiState) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst decorations: IModelDeltaDecoration[] = [];\n\n\t\tif (uiState.hiddenRange) {\n\t\t\tdecorations.push({\n\t\t\t\trange: uiState.hiddenRange.toRange(uiState.lineNumber),\n\t\t\t\toptions: { inlineClassName: 'inline-edit-hidden', description: 'inline-edit-hidden', }\n\t\t\t});\n\t\t}\n\n\t\tif (uiState.range) {\n\t\t\tconst ranges = [];\n\t\t\tif (uiState.isSingleLine) {\n\t\t\t\tranges.push(uiState.range);\n\t\t\t}\n\t\t\telse if (uiState.isPureRemove) {\n\t\t\t\tconst lines = uiState.range.endLineNumber - uiState.range.startLineNumber;\n\t\t\t\tfor (let i = 0; i < lines; i++) {\n\t\t\t\t\tconst line = uiState.range.startLineNumber + i;\n\t\t\t\t\tconst firstNonWhitespace = uiState.targetTextModel.getLineFirstNonWhitespaceColumn(line);\n\t\t\t\t\tconst lastNonWhitespace = uiState.targetTextModel.getLineLastNonWhitespaceColumn(line);\n\t\t\t\t\tconst range = new Range(line, firstNonWhitespace, line, lastNonWhitespace);\n\t\t\t\t\tranges.push(range);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tconst lines = uiState.range.endLineNumber - uiState.range.startLineNumber;\n\t\t\t\tfor (let i = 0; i < lines; i++) {\n\t\t\t\t\tconst line = uiState.range.startLineNumber + i;\n\t\t\t\t\tconst firstNonWhitespace = uiState.targetTextModel.getLineFirstNonWhitespaceColumn(line);\n\t\t\t\t\tconst lastNonWhitespace = uiState.targetTextModel.getLineLastNonWhitespaceColumn(line);\n\t\t\t\t\tconst range = new Range(line, firstNonWhitespace, line, lastNonWhitespace);\n\t\t\t\t\tranges.push(range);\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst className = uiState.backgroundColoring ? 'inline-edit-remove backgroundColoring' : 'inline-edit-remove';\n\t\t\tfor (const range of ranges) {\n\t\t\t\tdecorations.push({\n\t\t\t\t\trange,\n\t\t\t\t\toptions: { inlineClassName: className, description: 'inline-edit-remove', }\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tfor (const p of uiState.inlineTexts) {\n\n\t\t\tdecorations.push({\n\t\t\t\trange: Range.fromPositions(new Position(uiState.lineNumber, p.column)),\n\t\t\t\toptions: {\n\t\t\t\t\tdescription: INLINE_EDIT_DESCRIPTION,\n\t\t\t\t\tafter: { content: p.text, inlineClassName: p.preview ? 'inline-edit-decoration-preview' : 'inline-edit-decoration', cursorStops: InjectedTextCursorStops.Left },\n\t\t\t\t\tshowIfCollapsed: true,\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\treturn decorations;\n\t});\n\n\tprivate readonly additionalLinesWidget = this._register(\n\t\tnew AdditionalLinesWidget(\n\t\t\tthis.editor,\n\t\t\tthis.languageService.languageIdCodec,\n\t\t\tderived(reader => {\n\t\t\t\t/** @description lines */\n\t\t\t\tconst uiState = this.uiState.read(reader);\n\t\t\t\treturn uiState && !uiState.isPureRemove ? {\n\t\t\t\t\tlineNumber: uiState.lineNumber,\n\t\t\t\t\tadditionalLines: uiState.additionalLines,\n\t\t\t\t\tminReservedLineCount: uiState.additionalReservedLineCount,\n\t\t\t\t\ttargetTextModel: uiState.targetTextModel,\n\t\t\t\t} : undefined;\n\t\t\t})\n\t\t)\n\t);\n\n\tpublic ownsViewZone(viewZoneId: string): boolean {\n\t\treturn this.additionalLinesWidget.viewZoneId === viewZoneId;\n\t}\n}\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\nimport { Color } from 'vs/base/common/color';\nimport { ITokenThemeRule, TokenTheme } from 'vs/editor/common/languages/supports/tokenization';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\nimport { IColorTheme, IThemeService } from 'vs/platform/theme/common/themeService';\n\nexport const IStandaloneThemeService = createDecorator('themeService');\n\nexport type BuiltinTheme = 'vs' | 'vs-dark' | 'hc-black' | 'hc-light';\nexport type IColors = { [colorId: string]: string };\n\nexport interface IStandaloneThemeData {\n\tbase: BuiltinTheme;\n\tinherit: boolean;\n\trules: ITokenThemeRule[];\n\tencodedTokensColors?: string[];\n\tcolors: IColors;\n}\n\nexport interface IStandaloneTheme extends IColorTheme {\n\ttokenTheme: TokenTheme;\n\tthemeName: string;\n}\n\nexport interface IStandaloneThemeService extends IThemeService {\n\treadonly _serviceBrand: undefined;\n\n\tsetTheme(themeName: string): void;\n\n\tsetAutoDetectHighContrast(autoDetectHighContrast: boolean): void;\n\n\tdefineTheme(themeName: string, themeData: IStandaloneThemeData): void;\n\n\tgetColorTheme(): IStandaloneTheme;\n\n\tsetColorMapOverride(colorMapOverride: Color[] | null): void;\n\n}\n","\nimport { localize } from 'vs/nls';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\n\nexport const IAccessibilitySignalService = createDecorator('accessibilitySignalService');\n\nexport interface IAccessibilitySignalService {\n\treadonly _serviceBrand: undefined;\n\tplaySignal(signal: AccessibilitySignal, options?: IAccessbilitySignalOptions): Promise;\n}\n\n/** Make sure you understand the doc comments of the method you want to call when using this token! */\nexport const AcknowledgeDocCommentsToken = Symbol('AcknowledgeDocCommentsToken');\n\nexport interface IAccessbilitySignalOptions {\n\n\t/**\n\t * The source that triggered the signal (e.g. \"diffEditor.cursorPositionChanged\").\n\t */\n\tsource?: string;\n\n\t/**\n\t * For actions like save or format, depending on the\n\t * configured value, we will only\n\t * play the sound if the user triggered the action.\n\t */\n\tuserGesture?: boolean;\n}\n\n/**\n * Corresponds to the audio files in ./media.\n*/\nexport class Sound {\n\tprivate static register(options: { fileName: string }): Sound {\n\t\tconst sound = new Sound(options.fileName);\n\t\treturn sound;\n\t}\n\n\tpublic static readonly error = Sound.register({ fileName: 'error.mp3' });\n\tpublic static readonly warning = Sound.register({ fileName: 'warning.mp3' });\n\tpublic static readonly success = Sound.register({ fileName: 'success.mp3' });\n\tpublic static readonly foldedArea = Sound.register({ fileName: 'foldedAreas.mp3' });\n\tpublic static readonly break = Sound.register({ fileName: 'break.mp3' });\n\tpublic static readonly quickFixes = Sound.register({ fileName: 'quickFixes.mp3' });\n\tpublic static readonly taskCompleted = Sound.register({ fileName: 'taskCompleted.mp3' });\n\tpublic static readonly taskFailed = Sound.register({ fileName: 'taskFailed.mp3' });\n\tpublic static readonly terminalBell = Sound.register({ fileName: 'terminalBell.mp3' });\n\tpublic static readonly diffLineInserted = Sound.register({ fileName: 'diffLineInserted.mp3' });\n\tpublic static readonly diffLineDeleted = Sound.register({ fileName: 'diffLineDeleted.mp3' });\n\tpublic static readonly diffLineModified = Sound.register({ fileName: 'diffLineModified.mp3' });\n\tpublic static readonly chatRequestSent = Sound.register({ fileName: 'chatRequestSent.mp3' });\n\tpublic static readonly chatResponseReceived1 = Sound.register({ fileName: 'chatResponseReceived1.mp3' });\n\tpublic static readonly chatResponseReceived2 = Sound.register({ fileName: 'chatResponseReceived2.mp3' });\n\tpublic static readonly chatResponseReceived3 = Sound.register({ fileName: 'chatResponseReceived3.mp3' });\n\tpublic static readonly chatResponseReceived4 = Sound.register({ fileName: 'chatResponseReceived4.mp3' });\n\tpublic static readonly clear = Sound.register({ fileName: 'clear.mp3' });\n\tpublic static readonly save = Sound.register({ fileName: 'save.mp3' });\n\tpublic static readonly format = Sound.register({ fileName: 'format.mp3' });\n\tpublic static readonly voiceRecordingStarted = Sound.register({ fileName: 'voiceRecordingStarted.mp3' });\n\tpublic static readonly voiceRecordingStopped = Sound.register({ fileName: 'voiceRecordingStopped.mp3' });\n\tpublic static readonly progress = Sound.register({ fileName: 'progress.mp3' });\n\n\tprivate constructor(public readonly fileName: string) { }\n}\n\nexport class SoundSource {\n\tconstructor(\n\t\tpublic readonly randomOneOf: Sound[]\n\t) { }\n}\n\nexport class AccessibilitySignal {\n\tprivate constructor(\n\t\tpublic readonly sound: SoundSource,\n\t\tpublic readonly name: string,\n\t\tpublic readonly legacySoundSettingsKey: string | undefined,\n\t\tpublic readonly settingsKey: string,\n\t\tpublic readonly legacyAnnouncementSettingsKey: string | undefined,\n\t\tpublic readonly announcementMessage: string | undefined,\n\t\tpublic readonly delaySettingsKey: string | undefined\n\t) { }\n\n\tprivate static _signals = new Set();\n\tprivate static register(options: {\n\t\tname: string;\n\t\tsound: Sound | {\n\t\t\t/**\n\t\t\t * Gaming and other apps often play a sound variant when the same event happens again\n\t\t\t * for an improved experience. This option enables playing a random sound.\n\t\t\t */\n\t\t\trandomOneOf: Sound[];\n\t\t};\n\t\tlegacySoundSettingsKey?: string;\n\t\tsettingsKey: string;\n\t\tlegacyAnnouncementSettingsKey?: string;\n\t\tannouncementMessage?: string;\n\t\tdelaySettingsKey?: string;\n\t}): AccessibilitySignal {\n\t\tconst soundSource = new SoundSource('randomOneOf' in options.sound ? options.sound.randomOneOf : [options.sound]);\n\t\tconst signal = new AccessibilitySignal(\n\t\t\tsoundSource,\n\t\t\toptions.name,\n\t\t\toptions.legacySoundSettingsKey,\n\t\t\toptions.settingsKey,\n\t\t\toptions.legacyAnnouncementSettingsKey,\n\t\t\toptions.announcementMessage,\n\t\t\toptions.delaySettingsKey\n\t\t);\n\t\tAccessibilitySignal._signals.add(signal);\n\t\treturn signal;\n\t}\n\n\tpublic static readonly errorAtPosition = AccessibilitySignal.register({\n\t\tname: localize('accessibilitySignals.positionHasError.name', 'Error at Position'),\n\t\tsound: Sound.error,\n\t\tannouncementMessage: localize('accessibility.signals.positionHasError', 'Error'),\n\t\tsettingsKey: 'accessibility.signals.positionHasError',\n\t\tdelaySettingsKey: 'accessibility.signalOptions.delays.errorAtPosition'\n\t});\n\tpublic static readonly warningAtPosition = AccessibilitySignal.register({\n\t\tname: localize('accessibilitySignals.positionHasWarning.name', 'Warning at Position'),\n\t\tsound: Sound.warning,\n\t\tannouncementMessage: localize('accessibility.signals.positionHasWarning', 'Warning'),\n\t\tsettingsKey: 'accessibility.signals.positionHasWarning',\n\t\tdelaySettingsKey: 'accessibility.signalOptions.delays.warningAtPosition'\n\t});\n\n\tpublic static readonly errorOnLine = AccessibilitySignal.register({\n\t\tname: localize('accessibilitySignals.lineHasError.name', 'Error on Line'),\n\t\tsound: Sound.error,\n\t\tlegacySoundSettingsKey: 'audioCues.lineHasError',\n\t\tlegacyAnnouncementSettingsKey: 'accessibility.alert.error',\n\t\tannouncementMessage: localize('accessibility.signals.lineHasError', 'Error on Line'),\n\t\tsettingsKey: 'accessibility.signals.lineHasError',\n\t});\n\n\tpublic static readonly warningOnLine = AccessibilitySignal.register({\n\t\tname: localize('accessibilitySignals.lineHasWarning.name', 'Warning on Line'),\n\t\tsound: Sound.warning,\n\t\tlegacySoundSettingsKey: 'audioCues.lineHasWarning',\n\t\tlegacyAnnouncementSettingsKey: 'accessibility.alert.warning',\n\t\tannouncementMessage: localize('accessibility.signals.lineHasWarning', 'Warning on Line'),\n\t\tsettingsKey: 'accessibility.signals.lineHasWarning',\n\t});\n\tpublic static readonly foldedArea = AccessibilitySignal.register({\n\t\tname: localize('accessibilitySignals.lineHasFoldedArea.name', 'Folded Area on Line'),\n\t\tsound: Sound.foldedArea,\n\t\tlegacySoundSettingsKey: 'audioCues.lineHasFoldedArea',\n\t\tlegacyAnnouncementSettingsKey: 'accessibility.alert.foldedArea',\n\t\tannouncementMessage: localize('accessibility.signals.lineHasFoldedArea', 'Folded'),\n\t\tsettingsKey: 'accessibility.signals.lineHasFoldedArea',\n\t});\n\tpublic static readonly break = AccessibilitySignal.register({\n\t\tname: localize('accessibilitySignals.lineHasBreakpoint.name', 'Breakpoint on Line'),\n\t\tsound: Sound.break,\n\t\tlegacySoundSettingsKey: 'audioCues.lineHasBreakpoint',\n\t\tlegacyAnnouncementSettingsKey: 'accessibility.alert.breakpoint',\n\t\tannouncementMessage: localize('accessibility.signals.lineHasBreakpoint', 'Breakpoint'),\n\t\tsettingsKey: 'accessibility.signals.lineHasBreakpoint',\n\t});\n\tpublic static readonly inlineSuggestion = AccessibilitySignal.register({\n\t\tname: localize('accessibilitySignals.lineHasInlineSuggestion.name', 'Inline Suggestion on Line'),\n\t\tsound: Sound.quickFixes,\n\t\tlegacySoundSettingsKey: 'audioCues.lineHasInlineSuggestion',\n\t\tsettingsKey: 'accessibility.signals.lineHasInlineSuggestion',\n\t});\n\n\tpublic static readonly terminalQuickFix = AccessibilitySignal.register({\n\t\tname: localize('accessibilitySignals.terminalQuickFix.name', 'Terminal Quick Fix'),\n\t\tsound: Sound.quickFixes,\n\t\tlegacySoundSettingsKey: 'audioCues.terminalQuickFix',\n\t\tlegacyAnnouncementSettingsKey: 'accessibility.alert.terminalQuickFix',\n\t\tannouncementMessage: localize('accessibility.signals.terminalQuickFix', 'Quick Fix'),\n\t\tsettingsKey: 'accessibility.signals.terminalQuickFix',\n\t});\n\n\tpublic static readonly onDebugBreak = AccessibilitySignal.register({\n\t\tname: localize('accessibilitySignals.onDebugBreak.name', 'Debugger Stopped on Breakpoint'),\n\t\tsound: Sound.break,\n\t\tlegacySoundSettingsKey: 'audioCues.onDebugBreak',\n\t\tlegacyAnnouncementSettingsKey: 'accessibility.alert.onDebugBreak',\n\t\tannouncementMessage: localize('accessibility.signals.onDebugBreak', 'Breakpoint'),\n\t\tsettingsKey: 'accessibility.signals.onDebugBreak',\n\t});\n\n\tpublic static readonly noInlayHints = AccessibilitySignal.register({\n\t\tname: localize('accessibilitySignals.noInlayHints', 'No Inlay Hints on Line'),\n\t\tsound: Sound.error,\n\t\tlegacySoundSettingsKey: 'audioCues.noInlayHints',\n\t\tlegacyAnnouncementSettingsKey: 'accessibility.alert.noInlayHints',\n\t\tannouncementMessage: localize('accessibility.signals.noInlayHints', 'No Inlay Hints'),\n\t\tsettingsKey: 'accessibility.signals.noInlayHints',\n\t});\n\n\tpublic static readonly taskCompleted = AccessibilitySignal.register({\n\t\tname: localize('accessibilitySignals.taskCompleted', 'Task Completed'),\n\t\tsound: Sound.taskCompleted,\n\t\tlegacySoundSettingsKey: 'audioCues.taskCompleted',\n\t\tlegacyAnnouncementSettingsKey: 'accessibility.alert.taskCompleted',\n\t\tannouncementMessage: localize('accessibility.signals.taskCompleted', 'Task Completed'),\n\t\tsettingsKey: 'accessibility.signals.taskCompleted',\n\t});\n\n\tpublic static readonly taskFailed = AccessibilitySignal.register({\n\t\tname: localize('accessibilitySignals.taskFailed', 'Task Failed'),\n\t\tsound: Sound.taskFailed,\n\t\tlegacySoundSettingsKey: 'audioCues.taskFailed',\n\t\tlegacyAnnouncementSettingsKey: 'accessibility.alert.taskFailed',\n\t\tannouncementMessage: localize('accessibility.signals.taskFailed', 'Task Failed'),\n\t\tsettingsKey: 'accessibility.signals.taskFailed',\n\t});\n\n\tpublic static readonly terminalCommandFailed = AccessibilitySignal.register({\n\t\tname: localize('accessibilitySignals.terminalCommandFailed', 'Terminal Command Failed'),\n\t\tsound: Sound.error,\n\t\tlegacySoundSettingsKey: 'audioCues.terminalCommandFailed',\n\t\tlegacyAnnouncementSettingsKey: 'accessibility.alert.terminalCommandFailed',\n\t\tannouncementMessage: localize('accessibility.signals.terminalCommandFailed', 'Command Failed'),\n\t\tsettingsKey: 'accessibility.signals.terminalCommandFailed',\n\t});\n\n\tpublic static readonly terminalCommandSucceeded = AccessibilitySignal.register({\n\t\tname: localize('accessibilitySignals.terminalCommandSucceeded', 'Terminal Command Succeeded'),\n\t\tsound: Sound.success,\n\t\tannouncementMessage: localize('accessibility.signals.terminalCommandSucceeded', 'Command Succeeded'),\n\t\tsettingsKey: 'accessibility.signals.terminalCommandSucceeded',\n\t});\n\n\tpublic static readonly terminalBell = AccessibilitySignal.register({\n\t\tname: localize('accessibilitySignals.terminalBell', 'Terminal Bell'),\n\t\tsound: Sound.terminalBell,\n\t\tlegacySoundSettingsKey: 'audioCues.terminalBell',\n\t\tlegacyAnnouncementSettingsKey: 'accessibility.alert.terminalBell',\n\t\tannouncementMessage: localize('accessibility.signals.terminalBell', 'Terminal Bell'),\n\t\tsettingsKey: 'accessibility.signals.terminalBell',\n\t});\n\n\tpublic static readonly notebookCellCompleted = AccessibilitySignal.register({\n\t\tname: localize('accessibilitySignals.notebookCellCompleted', 'Notebook Cell Completed'),\n\t\tsound: Sound.taskCompleted,\n\t\tlegacySoundSettingsKey: 'audioCues.notebookCellCompleted',\n\t\tlegacyAnnouncementSettingsKey: 'accessibility.alert.notebookCellCompleted',\n\t\tannouncementMessage: localize('accessibility.signals.notebookCellCompleted', 'Notebook Cell Completed'),\n\t\tsettingsKey: 'accessibility.signals.notebookCellCompleted',\n\t});\n\n\tpublic static readonly notebookCellFailed = AccessibilitySignal.register({\n\t\tname: localize('accessibilitySignals.notebookCellFailed', 'Notebook Cell Failed'),\n\t\tsound: Sound.taskFailed,\n\t\tlegacySoundSettingsKey: 'audioCues.notebookCellFailed',\n\t\tlegacyAnnouncementSettingsKey: 'accessibility.alert.notebookCellFailed',\n\t\tannouncementMessage: localize('accessibility.signals.notebookCellFailed', 'Notebook Cell Failed'),\n\t\tsettingsKey: 'accessibility.signals.notebookCellFailed',\n\t});\n\n\tpublic static readonly diffLineInserted = AccessibilitySignal.register({\n\t\tname: localize('accessibilitySignals.diffLineInserted', 'Diff Line Inserted'),\n\t\tsound: Sound.diffLineInserted,\n\t\tlegacySoundSettingsKey: 'audioCues.diffLineInserted',\n\t\tsettingsKey: 'accessibility.signals.diffLineInserted',\n\t});\n\n\tpublic static readonly diffLineDeleted = AccessibilitySignal.register({\n\t\tname: localize('accessibilitySignals.diffLineDeleted', 'Diff Line Deleted'),\n\t\tsound: Sound.diffLineDeleted,\n\t\tlegacySoundSettingsKey: 'audioCues.diffLineDeleted',\n\t\tsettingsKey: 'accessibility.signals.diffLineDeleted',\n\t});\n\n\tpublic static readonly diffLineModified = AccessibilitySignal.register({\n\t\tname: localize('accessibilitySignals.diffLineModified', 'Diff Line Modified'),\n\t\tsound: Sound.diffLineModified,\n\t\tlegacySoundSettingsKey: 'audioCues.diffLineModified',\n\t\tsettingsKey: 'accessibility.signals.diffLineModified',\n\t});\n\n\tpublic static readonly chatRequestSent = AccessibilitySignal.register({\n\t\tname: localize('accessibilitySignals.chatRequestSent', 'Chat Request Sent'),\n\t\tsound: Sound.chatRequestSent,\n\t\tlegacySoundSettingsKey: 'audioCues.chatRequestSent',\n\t\tlegacyAnnouncementSettingsKey: 'accessibility.alert.chatRequestSent',\n\t\tannouncementMessage: localize('accessibility.signals.chatRequestSent', 'Chat Request Sent'),\n\t\tsettingsKey: 'accessibility.signals.chatRequestSent',\n\t});\n\n\tpublic static readonly chatResponseReceived = AccessibilitySignal.register({\n\t\tname: localize('accessibilitySignals.chatResponseReceived', 'Chat Response Received'),\n\t\tlegacySoundSettingsKey: 'audioCues.chatResponseReceived',\n\t\tsound: {\n\t\t\trandomOneOf: [\n\t\t\t\tSound.chatResponseReceived1,\n\t\t\t\tSound.chatResponseReceived2,\n\t\t\t\tSound.chatResponseReceived3,\n\t\t\t\tSound.chatResponseReceived4\n\t\t\t]\n\t\t},\n\t\tsettingsKey: 'accessibility.signals.chatResponseReceived'\n\t});\n\n\tpublic static readonly progress = AccessibilitySignal.register({\n\t\tname: localize('accessibilitySignals.progress', 'Progress'),\n\t\tsound: Sound.progress,\n\t\tlegacySoundSettingsKey: 'audioCues.chatResponsePending',\n\t\tlegacyAnnouncementSettingsKey: 'accessibility.alert.progress',\n\t\tannouncementMessage: localize('accessibility.signals.progress', 'Progress'),\n\t\tsettingsKey: 'accessibility.signals.progress'\n\t});\n\n\tpublic static readonly clear = AccessibilitySignal.register({\n\t\tname: localize('accessibilitySignals.clear', 'Clear'),\n\t\tsound: Sound.clear,\n\t\tlegacySoundSettingsKey: 'audioCues.clear',\n\t\tlegacyAnnouncementSettingsKey: 'accessibility.alert.clear',\n\t\tannouncementMessage: localize('accessibility.signals.clear', 'Clear'),\n\t\tsettingsKey: 'accessibility.signals.clear'\n\t});\n\n\tpublic static readonly save = AccessibilitySignal.register({\n\t\tname: localize('accessibilitySignals.save', 'Save'),\n\t\tsound: Sound.save,\n\t\tlegacySoundSettingsKey: 'audioCues.save',\n\t\tlegacyAnnouncementSettingsKey: 'accessibility.alert.save',\n\t\tannouncementMessage: localize('accessibility.signals.save', 'Save'),\n\t\tsettingsKey: 'accessibility.signals.save'\n\t});\n\n\tpublic static readonly format = AccessibilitySignal.register({\n\t\tname: localize('accessibilitySignals.format', 'Format'),\n\t\tsound: Sound.format,\n\t\tlegacySoundSettingsKey: 'audioCues.format',\n\t\tlegacyAnnouncementSettingsKey: 'accessibility.alert.format',\n\t\tannouncementMessage: localize('accessibility.signals.format', 'Format'),\n\t\tsettingsKey: 'accessibility.signals.format'\n\t});\n\n\tpublic static readonly voiceRecordingStarted = AccessibilitySignal.register({\n\t\tname: localize('accessibilitySignals.voiceRecordingStarted', 'Voice Recording Started'),\n\t\tsound: Sound.voiceRecordingStarted,\n\t\tlegacySoundSettingsKey: 'audioCues.voiceRecordingStarted',\n\t\tsettingsKey: 'accessibility.signals.voiceRecordingStarted'\n\t});\n\n\tpublic static readonly voiceRecordingStopped = AccessibilitySignal.register({\n\t\tname: localize('accessibilitySignals.voiceRecordingStopped', 'Voice Recording Stopped'),\n\t\tsound: Sound.voiceRecordingStopped,\n\t\tlegacySoundSettingsKey: 'audioCues.voiceRecordingStopped',\n\t\tsettingsKey: 'accessibility.signals.voiceRecordingStopped'\n\t});\n}\n\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\nimport { URI } from 'vs/base/common/uri';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\n\nexport const IClipboardService = createDecorator('clipboardService');\n\nexport interface IClipboardService {\n\n\treadonly _serviceBrand: undefined;\n\n\t/**\n\t * Writes text to the system clipboard.\n\t */\n\twriteText(text: string, type?: string): Promise;\n\n\t/**\n\t * Reads the content of the clipboard in plain text\n\t */\n\treadText(type?: string): Promise;\n\n\t/**\n\t * Reads text from the system find pasteboard.\n\t */\n\treadFindText(): Promise;\n\n\t/**\n\t * Writes text to the system find pasteboard.\n\t */\n\twriteFindText(text: string): Promise;\n\n\t/**\n\t * Writes resources to the system clipboard.\n\t */\n\twriteResources(resources: URI[]): Promise;\n\n\t/**\n\t * Reads resources from the system clipboard.\n\t */\n\treadResources(): Promise;\n}\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\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { Iterable } from 'vs/base/common/iterator';\nimport { IJSONSchema } from 'vs/base/common/jsonSchema';\nimport { IDisposable, toDisposable } from 'vs/base/common/lifecycle';\nimport { LinkedList } from 'vs/base/common/linkedList';\nimport { TypeConstraint, validateConstraints } from 'vs/base/common/types';\nimport { ILocalizedString } from 'vs/platform/action/common/action';\nimport { createDecorator, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';\n\nexport const ICommandService = createDecorator('commandService');\n\nexport interface ICommandEvent {\n\tcommandId: string;\n\targs: any[];\n}\n\nexport interface ICommandService {\n\treadonly _serviceBrand: undefined;\n\tonDidExecuteCommand: Event;\n\texecuteCommand(commandId: string, ...args: any[]): Promise;\n}\n\nexport type ICommandsMap = Map;\n\nexport interface ICommandHandler {\n\t(accessor: ServicesAccessor, ...args: any[]): void;\n}\n\nexport interface ICommand {\n\tid: string;\n\thandler: ICommandHandler;\n\tmetadata?: ICommandMetadata | null;\n}\n\nexport interface ICommandMetadata {\n\t/**\n\t * NOTE: Please use an ILocalizedString. string is in the type for backcompat for now.\n\t * A short summary of what the command does. This will be used in:\n\t * - API commands\n\t * - when showing keybindings that have no other UX\n\t * - when searching for commands in the Command Palette\n\t */\n\treadonly description: ILocalizedString | string;\n\treadonly args?: ReadonlyArray<{\n\t\treadonly name: string;\n\t\treadonly isOptional?: boolean;\n\t\treadonly description?: string;\n\t\treadonly constraint?: TypeConstraint;\n\t\treadonly schema?: IJSONSchema;\n\t}>;\n}\n\nexport interface ICommandRegistry {\n\tregisterCommand(id: string, command: ICommandHandler): IDisposable;\n\tregisterCommand(command: ICommand): IDisposable;\n\tregisterCommandAlias(oldId: string, newId: string): IDisposable;\n\tgetCommand(id: string): ICommand | undefined;\n}\n\nexport const CommandsRegistry: ICommandRegistry = new class implements ICommandRegistry {\n\n\tprivate readonly _commands = new Map>();\n\n\tprivate readonly _onDidRegisterCommand = new Emitter();\n\treadonly onDidRegisterCommand: Event = this._onDidRegisterCommand.event;\n\n\tregisterCommand(idOrCommand: string | ICommand, handler?: ICommandHandler): IDisposable {\n\n\t\tif (!idOrCommand) {\n\t\t\tthrow new Error(`invalid command`);\n\t\t}\n\n\t\tif (typeof idOrCommand === 'string') {\n\t\t\tif (!handler) {\n\t\t\t\tthrow new Error(`invalid command`);\n\t\t\t}\n\t\t\treturn this.registerCommand({ id: idOrCommand, handler });\n\t\t}\n\n\t\t// add argument validation if rich command metadata is provided\n\t\tif (idOrCommand.metadata && Array.isArray(idOrCommand.metadata.args)) {\n\t\t\tconst constraints: Array = [];\n\t\t\tfor (const arg of idOrCommand.metadata.args) {\n\t\t\t\tconstraints.push(arg.constraint);\n\t\t\t}\n\t\t\tconst actualHandler = idOrCommand.handler;\n\t\t\tidOrCommand.handler = function (accessor, ...args: any[]) {\n\t\t\t\tvalidateConstraints(args, constraints);\n\t\t\t\treturn actualHandler(accessor, ...args);\n\t\t\t};\n\t\t}\n\n\t\t// find a place to store the command\n\t\tconst { id } = idOrCommand;\n\n\t\tlet commands = this._commands.get(id);\n\t\tif (!commands) {\n\t\t\tcommands = new LinkedList();\n\t\t\tthis._commands.set(id, commands);\n\t\t}\n\n\t\tconst removeFn = commands.unshift(idOrCommand);\n\n\t\tconst ret = toDisposable(() => {\n\t\t\tremoveFn();\n\t\t\tconst command = this._commands.get(id);\n\t\t\tif (command?.isEmpty()) {\n\t\t\t\tthis._commands.delete(id);\n\t\t\t}\n\t\t});\n\n\t\t// tell the world about this command\n\t\tthis._onDidRegisterCommand.fire(id);\n\n\t\treturn ret;\n\t}\n\n\tregisterCommandAlias(oldId: string, newId: string): IDisposable {\n\t\treturn CommandsRegistry.registerCommand(oldId, (accessor, ...args) => accessor.get(ICommandService).executeCommand(newId, ...args));\n\t}\n\n\tgetCommand(id: string): ICommand | undefined {\n\t\tconst list = this._commands.get(id);\n\t\tif (!list || list.isEmpty()) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn Iterable.first(list);\n\t}\n\n\tgetCommands(): ICommandsMap {\n\t\tconst result = new Map();\n\t\tfor (const key of this._commands.keys()) {\n\t\t\tconst command = this.getCommand(key);\n\t\t\tif (command) {\n\t\t\t\tresult.set(key, command);\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n};\n\nCommandsRegistry.registerCommand('noop', () => { });\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\nimport { CancellationToken } from 'vs/base/common/cancellation';\nimport { illegalArgument, onUnexpectedExternalError } from 'vs/base/common/errors';\nimport { DisposableStore } from 'vs/base/common/lifecycle';\nimport { assertType } from 'vs/base/common/types';\nimport { URI } from 'vs/base/common/uri';\nimport { ITextModel } from 'vs/editor/common/model';\nimport { CodeLens, CodeLensList, CodeLensProvider } from 'vs/editor/common/languages';\nimport { IModelService } from 'vs/editor/common/services/model';\nimport { CommandsRegistry } from 'vs/platform/commands/common/commands';\nimport { LanguageFeatureRegistry } from 'vs/editor/common/languageFeatureRegistry';\nimport { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';\n\nexport interface CodeLensItem {\n\tsymbol: CodeLens;\n\tprovider: CodeLensProvider;\n}\n\nexport class CodeLensModel {\n\n\tlenses: CodeLensItem[] = [];\n\n\tprivate readonly _disposables = new DisposableStore();\n\n\tdispose(): void {\n\t\tthis._disposables.dispose();\n\t}\n\n\tget isDisposed(): boolean {\n\t\treturn this._disposables.isDisposed;\n\t}\n\n\tadd(list: CodeLensList, provider: CodeLensProvider): void {\n\t\tthis._disposables.add(list);\n\t\tfor (const symbol of list.lenses) {\n\t\t\tthis.lenses.push({ symbol, provider });\n\t\t}\n\t}\n}\n\nexport async function getCodeLensModel(registry: LanguageFeatureRegistry, model: ITextModel, token: CancellationToken): Promise {\n\n\tconst provider = registry.ordered(model);\n\tconst providerRanks = new Map();\n\tconst result = new CodeLensModel();\n\n\tconst promises = provider.map(async (provider, i) => {\n\n\t\tproviderRanks.set(provider, i);\n\n\t\ttry {\n\t\t\tconst list = await Promise.resolve(provider.provideCodeLenses(model, token));\n\t\t\tif (list) {\n\t\t\t\tresult.add(list, provider);\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tonUnexpectedExternalError(err);\n\t\t}\n\t});\n\n\tawait Promise.all(promises);\n\n\tresult.lenses = result.lenses.sort((a, b) => {\n\t\t// sort by lineNumber, provider-rank, and column\n\t\tif (a.symbol.range.startLineNumber < b.symbol.range.startLineNumber) {\n\t\t\treturn -1;\n\t\t} else if (a.symbol.range.startLineNumber > b.symbol.range.startLineNumber) {\n\t\t\treturn 1;\n\t\t} else if ((providerRanks.get(a.provider)!) < (providerRanks.get(b.provider)!)) {\n\t\t\treturn -1;\n\t\t} else if ((providerRanks.get(a.provider)!) > (providerRanks.get(b.provider)!)) {\n\t\t\treturn 1;\n\t\t} else if (a.symbol.range.startColumn < b.symbol.range.startColumn) {\n\t\t\treturn -1;\n\t\t} else if (a.symbol.range.startColumn > b.symbol.range.startColumn) {\n\t\t\treturn 1;\n\t\t} else {\n\t\t\treturn 0;\n\t\t}\n\t});\n\treturn result;\n}\n\nCommandsRegistry.registerCommand('_executeCodeLensProvider', function (accessor, ...args: [URI, number | undefined | null]) {\n\tlet [uri, itemResolveCount] = args;\n\tassertType(URI.isUri(uri));\n\tassertType(typeof itemResolveCount === 'number' || !itemResolveCount);\n\n\tconst { codeLensProvider } = accessor.get(ILanguageFeaturesService);\n\n\tconst model = accessor.get(IModelService).getModel(uri);\n\tif (!model) {\n\t\tthrow illegalArgument();\n\t}\n\n\tconst result: CodeLens[] = [];\n\tconst disposables = new DisposableStore();\n\treturn getCodeLensModel(codeLensProvider, model, CancellationToken.None).then(value => {\n\n\t\tdisposables.add(value);\n\t\tconst resolve: Promise[] = [];\n\n\t\tfor (const item of value.lenses) {\n\t\t\tif (itemResolveCount === undefined || itemResolveCount === null || Boolean(item.symbol.command)) {\n\t\t\t\tresult.push(item.symbol);\n\t\t\t} else if (itemResolveCount-- > 0 && item.provider.resolveCodeLens) {\n\t\t\t\tresolve.push(Promise.resolve(item.provider.resolveCodeLens(model, item.symbol, CancellationToken.None)).then(symbol => result.push(symbol || item.symbol)));\n\t\t\t}\n\t\t}\n\n\t\treturn Promise.all(resolve);\n\n\t}).then(() => {\n\t\treturn result;\n\t}).finally(() => {\n\t\t// make sure to return results, then (on next tick)\n\t\t// dispose the results\n\t\tsetTimeout(() => disposables.dispose(), 100);\n\t});\n});\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\nimport { coalesce } from 'vs/base/common/arrays';\nimport { CancellationToken } from 'vs/base/common/cancellation';\nimport { onUnexpectedExternalError } from 'vs/base/common/errors';\nimport { DisposableStore, isDisposable } from 'vs/base/common/lifecycle';\nimport { assertType } from 'vs/base/common/types';\nimport { URI } from 'vs/base/common/uri';\nimport { IRange, Range } from 'vs/editor/common/core/range';\nimport { ITextModel } from 'vs/editor/common/model';\nimport { ILink, ILinksList, LinkProvider } from 'vs/editor/common/languages';\nimport { IModelService } from 'vs/editor/common/services/model';\nimport { CommandsRegistry } from 'vs/platform/commands/common/commands';\nimport { LanguageFeatureRegistry } from 'vs/editor/common/languageFeatureRegistry';\nimport { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';\n\nexport class Link implements ILink {\n\n\tprivate _link: ILink;\n\tprivate readonly _provider: LinkProvider;\n\n\tconstructor(link: ILink, provider: LinkProvider) {\n\t\tthis._link = link;\n\t\tthis._provider = provider;\n\t}\n\n\ttoJSON(): ILink {\n\t\treturn {\n\t\t\trange: this.range,\n\t\t\turl: this.url,\n\t\t\ttooltip: this.tooltip\n\t\t};\n\t}\n\n\tget range(): IRange {\n\t\treturn this._link.range;\n\t}\n\n\tget url(): URI | string | undefined {\n\t\treturn this._link.url;\n\t}\n\n\tget tooltip(): string | undefined {\n\t\treturn this._link.tooltip;\n\t}\n\n\tasync resolve(token: CancellationToken): Promise {\n\t\tif (this._link.url) {\n\t\t\treturn this._link.url;\n\t\t}\n\n\t\tif (typeof this._provider.resolveLink === 'function') {\n\t\t\treturn Promise.resolve(this._provider.resolveLink(this._link, token)).then(value => {\n\t\t\t\tthis._link = value || this._link;\n\t\t\t\tif (this._link.url) {\n\t\t\t\t\t// recurse\n\t\t\t\t\treturn this.resolve(token);\n\t\t\t\t}\n\n\t\t\t\treturn Promise.reject(new Error('missing'));\n\t\t\t});\n\t\t}\n\n\t\treturn Promise.reject(new Error('missing'));\n\t}\n}\n\nexport class LinksList {\n\n\treadonly links: Link[];\n\n\tprivate readonly _disposables = new DisposableStore();\n\n\tconstructor(tuples: [ILinksList, LinkProvider][]) {\n\n\t\tlet links: Link[] = [];\n\t\tfor (const [list, provider] of tuples) {\n\t\t\t// merge all links\n\t\t\tconst newLinks = list.links.map(link => new Link(link, provider));\n\t\t\tlinks = LinksList._union(links, newLinks);\n\t\t\t// register disposables\n\t\t\tif (isDisposable(list)) {\n\t\t\t\tthis._disposables.add(list);\n\t\t\t}\n\t\t}\n\t\tthis.links = links;\n\t}\n\n\tdispose(): void {\n\t\tthis._disposables.dispose();\n\t\tthis.links.length = 0;\n\t}\n\n\tprivate static _union(oldLinks: Link[], newLinks: Link[]): Link[] {\n\t\t// reunite oldLinks with newLinks and remove duplicates\n\t\tconst result: Link[] = [];\n\t\tlet oldIndex: number;\n\t\tlet oldLen: number;\n\t\tlet newIndex: number;\n\t\tlet newLen: number;\n\n\t\tfor (oldIndex = 0, newIndex = 0, oldLen = oldLinks.length, newLen = newLinks.length; oldIndex < oldLen && newIndex < newLen;) {\n\t\t\tconst oldLink = oldLinks[oldIndex];\n\t\t\tconst newLink = newLinks[newIndex];\n\n\t\t\tif (Range.areIntersectingOrTouching(oldLink.range, newLink.range)) {\n\t\t\t\t// Remove the oldLink\n\t\t\t\toldIndex++;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst comparisonResult = Range.compareRangesUsingStarts(oldLink.range, newLink.range);\n\n\t\t\tif (comparisonResult < 0) {\n\t\t\t\t// oldLink is before\n\t\t\t\tresult.push(oldLink);\n\t\t\t\toldIndex++;\n\t\t\t} else {\n\t\t\t\t// newLink is before\n\t\t\t\tresult.push(newLink);\n\t\t\t\tnewIndex++;\n\t\t\t}\n\t\t}\n\n\t\tfor (; oldIndex < oldLen; oldIndex++) {\n\t\t\tresult.push(oldLinks[oldIndex]);\n\t\t}\n\t\tfor (; newIndex < newLen; newIndex++) {\n\t\t\tresult.push(newLinks[newIndex]);\n\t\t}\n\n\t\treturn result;\n\t}\n\n}\n\nexport function getLinks(providers: LanguageFeatureRegistry, model: ITextModel, token: CancellationToken): Promise {\n\n\tconst lists: [ILinksList, LinkProvider][] = [];\n\n\t// ask all providers for links in parallel\n\tconst promises = providers.ordered(model).reverse().map((provider, i) => {\n\t\treturn Promise.resolve(provider.provideLinks(model, token)).then(result => {\n\t\t\tif (result) {\n\t\t\t\tlists[i] = [result, provider];\n\t\t\t}\n\t\t}, onUnexpectedExternalError);\n\t});\n\n\treturn Promise.all(promises).then(() => {\n\t\tconst result = new LinksList(coalesce(lists));\n\t\tif (!token.isCancellationRequested) {\n\t\t\treturn result;\n\t\t}\n\t\tresult.dispose();\n\t\treturn new LinksList([]);\n\t});\n}\n\n\nCommandsRegistry.registerCommand('_executeLinkProvider', async (accessor, ...args): Promise => {\n\tlet [uri, resolveCount] = args;\n\tassertType(uri instanceof URI);\n\n\tif (typeof resolveCount !== 'number') {\n\t\tresolveCount = 0;\n\t}\n\n\tconst { linkProvider } = accessor.get(ILanguageFeaturesService);\n\tconst model = accessor.get(IModelService).getModel(uri);\n\tif (!model) {\n\t\treturn [];\n\t}\n\tconst list = await getLinks(linkProvider, model, CancellationToken.None);\n\tif (!list) {\n\t\treturn [];\n\t}\n\n\t// resolve links\n\tfor (let i = 0; i < Math.min(resolveCount, list.links.length); i++) {\n\t\tawait list.links[i].resolve(CancellationToken.None);\n\t}\n\n\tconst result = list.links.slice(0);\n\tlist.dispose();\n\treturn result;\n});\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\nimport { CancellationToken } from 'vs/base/common/cancellation';\nimport { onUnexpectedExternalError } from 'vs/base/common/errors';\nimport { URI } from 'vs/base/common/uri';\nimport { ITextModel } from 'vs/editor/common/model';\nimport { DocumentSemanticTokensProvider, SemanticTokens, SemanticTokensEdits, SemanticTokensLegend, DocumentRangeSemanticTokensProvider } from 'vs/editor/common/languages';\nimport { IModelService } from 'vs/editor/common/services/model';\nimport { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands';\nimport { assertType } from 'vs/base/common/types';\nimport { VSBuffer } from 'vs/base/common/buffer';\nimport { encodeSemanticTokensDto } from 'vs/editor/common/services/semanticTokensDto';\nimport { Range } from 'vs/editor/common/core/range';\nimport { LanguageFeatureRegistry } from 'vs/editor/common/languageFeatureRegistry';\nimport { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';\n\nexport function isSemanticTokens(v: SemanticTokens | SemanticTokensEdits): v is SemanticTokens {\n\treturn v && !!((v).data);\n}\n\nexport function isSemanticTokensEdits(v: SemanticTokens | SemanticTokensEdits): v is SemanticTokensEdits {\n\treturn v && Array.isArray((v).edits);\n}\n\nexport class DocumentSemanticTokensResult {\n\tconstructor(\n\t\tpublic readonly provider: DocumentSemanticTokensProvider,\n\t\tpublic readonly tokens: SemanticTokens | SemanticTokensEdits | null,\n\t\tpublic readonly error: any\n\t) { }\n}\n\nexport function hasDocumentSemanticTokensProvider(registry: LanguageFeatureRegistry, model: ITextModel): boolean {\n\treturn registry.has(model);\n}\n\nfunction getDocumentSemanticTokensProviders(registry: LanguageFeatureRegistry, model: ITextModel): DocumentSemanticTokensProvider[] {\n\tconst groups = registry.orderedGroups(model);\n\treturn (groups.length > 0 ? groups[0] : []);\n}\n\nexport async function getDocumentSemanticTokens(registry: LanguageFeatureRegistry, model: ITextModel, lastProvider: DocumentSemanticTokensProvider | null, lastResultId: string | null, token: CancellationToken): Promise {\n\tconst providers = getDocumentSemanticTokensProviders(registry, model);\n\n\t// Get tokens from all providers at the same time.\n\tconst results = await Promise.all(providers.map(async (provider) => {\n\t\tlet result: SemanticTokens | SemanticTokensEdits | null | undefined;\n\t\tlet error: any = null;\n\t\ttry {\n\t\t\tresult = await provider.provideDocumentSemanticTokens(model, (provider === lastProvider ? lastResultId : null), token);\n\t\t} catch (err) {\n\t\t\terror = err;\n\t\t\tresult = null;\n\t\t}\n\n\t\tif (!result || (!isSemanticTokens(result) && !isSemanticTokensEdits(result))) {\n\t\t\tresult = null;\n\t\t}\n\n\t\treturn new DocumentSemanticTokensResult(provider, result, error);\n\t}));\n\n\t// Try to return the first result with actual tokens or\n\t// the first result which threw an error (!!)\n\tfor (const result of results) {\n\t\tif (result.error) {\n\t\t\tthrow result.error;\n\t\t}\n\t\tif (result.tokens) {\n\t\t\treturn result;\n\t\t}\n\t}\n\n\t// Return the first result, even if it doesn't have tokens\n\tif (results.length > 0) {\n\t\treturn results[0];\n\t}\n\n\treturn null;\n}\n\nfunction _getDocumentSemanticTokensProviderHighestGroup(registry: LanguageFeatureRegistry, model: ITextModel): DocumentSemanticTokensProvider[] | null {\n\tconst result = registry.orderedGroups(model);\n\treturn (result.length > 0 ? result[0] : null);\n}\n\nclass DocumentRangeSemanticTokensResult {\n\tconstructor(\n\t\tpublic readonly provider: DocumentRangeSemanticTokensProvider,\n\t\tpublic readonly tokens: SemanticTokens | null,\n\t) { }\n}\n\nexport function hasDocumentRangeSemanticTokensProvider(providers: LanguageFeatureRegistry, model: ITextModel): boolean {\n\treturn providers.has(model);\n}\n\nfunction getDocumentRangeSemanticTokensProviders(providers: LanguageFeatureRegistry, model: ITextModel): DocumentRangeSemanticTokensProvider[] {\n\tconst groups = providers.orderedGroups(model);\n\treturn (groups.length > 0 ? groups[0] : []);\n}\n\nexport async function getDocumentRangeSemanticTokens(registry: LanguageFeatureRegistry, model: ITextModel, range: Range, token: CancellationToken): Promise {\n\tconst providers = getDocumentRangeSemanticTokensProviders(registry, model);\n\n\t// Get tokens from all providers at the same time.\n\tconst results = await Promise.all(providers.map(async (provider) => {\n\t\tlet result: SemanticTokens | null | undefined;\n\t\ttry {\n\t\t\tresult = await provider.provideDocumentRangeSemanticTokens(model, range, token);\n\t\t} catch (err) {\n\t\t\tonUnexpectedExternalError(err);\n\t\t\tresult = null;\n\t\t}\n\n\t\tif (!result || !isSemanticTokens(result)) {\n\t\t\tresult = null;\n\t\t}\n\n\t\treturn new DocumentRangeSemanticTokensResult(provider, result);\n\t}));\n\n\t// Try to return the first result with actual tokens\n\tfor (const result of results) {\n\t\tif (result.tokens) {\n\t\t\treturn result;\n\t\t}\n\t}\n\n\t// Return the first result, even if it doesn't have tokens\n\tif (results.length > 0) {\n\t\treturn results[0];\n\t}\n\n\treturn null;\n}\n\nCommandsRegistry.registerCommand('_provideDocumentSemanticTokensLegend', async (accessor, ...args): Promise => {\n\tconst [uri] = args;\n\tassertType(uri instanceof URI);\n\n\tconst model = accessor.get(IModelService).getModel(uri);\n\tif (!model) {\n\t\treturn undefined;\n\t}\n\tconst { documentSemanticTokensProvider } = accessor.get(ILanguageFeaturesService);\n\n\tconst providers = _getDocumentSemanticTokensProviderHighestGroup(documentSemanticTokensProvider, model);\n\tif (!providers) {\n\t\t// there is no provider => fall back to a document range semantic tokens provider\n\t\treturn accessor.get(ICommandService).executeCommand('_provideDocumentRangeSemanticTokensLegend', uri);\n\t}\n\n\treturn providers[0].getLegend();\n});\n\nCommandsRegistry.registerCommand('_provideDocumentSemanticTokens', async (accessor, ...args): Promise => {\n\tconst [uri] = args;\n\tassertType(uri instanceof URI);\n\n\tconst model = accessor.get(IModelService).getModel(uri);\n\tif (!model) {\n\t\treturn undefined;\n\t}\n\tconst { documentSemanticTokensProvider } = accessor.get(ILanguageFeaturesService);\n\tif (!hasDocumentSemanticTokensProvider(documentSemanticTokensProvider, model)) {\n\t\t// there is no provider => fall back to a document range semantic tokens provider\n\t\treturn accessor.get(ICommandService).executeCommand('_provideDocumentRangeSemanticTokens', uri, model.getFullModelRange());\n\t}\n\n\tconst r = await getDocumentSemanticTokens(documentSemanticTokensProvider, model, null, null, CancellationToken.None);\n\tif (!r) {\n\t\treturn undefined;\n\t}\n\n\tconst { provider, tokens } = r;\n\n\tif (!tokens || !isSemanticTokens(tokens)) {\n\t\treturn undefined;\n\t}\n\n\tconst buff = encodeSemanticTokensDto({\n\t\tid: 0,\n\t\ttype: 'full',\n\t\tdata: tokens.data\n\t});\n\tif (tokens.resultId) {\n\t\tprovider.releaseDocumentSemanticTokens(tokens.resultId);\n\t}\n\treturn buff;\n});\n\nCommandsRegistry.registerCommand('_provideDocumentRangeSemanticTokensLegend', async (accessor, ...args): Promise => {\n\tconst [uri, range] = args;\n\tassertType(uri instanceof URI);\n\n\tconst model = accessor.get(IModelService).getModel(uri);\n\tif (!model) {\n\t\treturn undefined;\n\t}\n\tconst { documentRangeSemanticTokensProvider } = accessor.get(ILanguageFeaturesService);\n\tconst providers = getDocumentRangeSemanticTokensProviders(documentRangeSemanticTokensProvider, model);\n\tif (providers.length === 0) {\n\t\t// no providers\n\t\treturn undefined;\n\t}\n\n\tif (providers.length === 1) {\n\t\t// straight forward case, just a single provider\n\t\treturn providers[0].getLegend();\n\t}\n\n\tif (!range || !Range.isIRange(range)) {\n\t\t// if no range is provided, we cannot support multiple providers\n\t\t// as we cannot fall back to the one which would give results\n\t\t// => return the first legend for backwards compatibility and print a warning\n\t\tconsole.warn(`provideDocumentRangeSemanticTokensLegend might be out-of-sync with provideDocumentRangeSemanticTokens unless a range argument is passed in`);\n\t\treturn providers[0].getLegend();\n\t}\n\n\tconst result = await getDocumentRangeSemanticTokens(documentRangeSemanticTokensProvider, model, Range.lift(range), CancellationToken.None);\n\tif (!result) {\n\t\treturn undefined;\n\t}\n\n\treturn result.provider.getLegend();\n});\n\nCommandsRegistry.registerCommand('_provideDocumentRangeSemanticTokens', async (accessor, ...args): Promise => {\n\tconst [uri, range] = args;\n\tassertType(uri instanceof URI);\n\tassertType(Range.isIRange(range));\n\n\tconst model = accessor.get(IModelService).getModel(uri);\n\tif (!model) {\n\t\treturn undefined;\n\t}\n\tconst { documentRangeSemanticTokensProvider } = accessor.get(ILanguageFeaturesService);\n\n\tconst result = await getDocumentRangeSemanticTokens(documentRangeSemanticTokensProvider, model, Range.lift(range), CancellationToken.None);\n\tif (!result || !result.tokens) {\n\t\t// there is no provider or it didn't return tokens\n\t\treturn undefined;\n\t}\n\n\treturn encodeSemanticTokensDto({\n\t\tid: 0,\n\t\ttype: 'full',\n\t\tdata: result.tokens.data\n\t});\n});\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\nimport { Event } from 'vs/base/common/event';\nimport { URI, UriComponents } from 'vs/base/common/uri';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\n\nexport const IConfigurationService = createDecorator('configurationService');\n\nexport interface IConfigurationOverrides {\n\toverrideIdentifier?: string | null;\n\tresource?: URI | null;\n}\n\nexport type IConfigurationUpdateOverrides = Omit & { overrideIdentifiers?: string[] | null };\n\nexport const enum ConfigurationTarget {\n\tAPPLICATION = 1,\n\tUSER,\n\tUSER_LOCAL,\n\tUSER_REMOTE,\n\tWORKSPACE,\n\tWORKSPACE_FOLDER,\n\tDEFAULT,\n\tMEMORY\n}\n\nexport interface IConfigurationChange {\n\tkeys: string[];\n\toverrides: [string, string[]][];\n}\n\nexport interface IConfigurationChangeEvent {\n\n\treadonly source: ConfigurationTarget;\n\treadonly affectedKeys: ReadonlySet;\n\treadonly change: IConfigurationChange;\n\n\taffectsConfiguration(configuration: string, overrides?: IConfigurationOverrides): boolean;\n}\n\nexport interface IInspectValue {\n\treadonly value?: T;\n\treadonly override?: T;\n\treadonly overrides?: { readonly identifiers: string[]; readonly value: T }[];\n}\n\nexport interface IConfigurationValue {\n\treadonly user?: IInspectValue;\n}\n\nexport interface IConfigurationUpdateOptions {\n}\n\nexport interface IConfigurationService {\n\treadonly _serviceBrand: undefined;\n\n\tonDidChangeConfiguration: Event;\n\n\t/**\n\t * Fetches the value of the section for the given overrides.\n\t * Value can be of native type or an object keyed off the section name.\n\t *\n\t * @param section - Section of the configuration. Can be `null` or `undefined`.\n\t * @param overrides - Overrides that has to be applied while fetching\n\t *\n\t */\n\tgetValue(): T;\n\tgetValue(section: string): T;\n\tgetValue(overrides: IConfigurationOverrides): T;\n\tgetValue(section: string, overrides: IConfigurationOverrides): T;\n\n\t/**\n\t * Update a configuration value.\n\t *\n\t * Use `target` to update the configuration in a specific `ConfigurationTarget`.\n\t *\n\t * Use `overrides` to update the configuration for a resource or for override identifiers or both.\n\t *\n\t * Passing a resource through overrides will update the configuration in the workspace folder containing that resource.\n\t *\n\t * *Note 1:* Updating configuration to a default value will remove the configuration from the requested target. If not target is passed, it will be removed from all writeable targets.\n\t *\n\t * *Note 2:* Use `undefined` value to remove the configuration from the given target. If not target is passed, it will be removed from all writeable targets.\n\t *\n\t * Use `donotNotifyError` and set it to `true` to surpresss errors.\n\t *\n\t * @param key setting to be updated\n\t * @param value The new value\n\t */\n\tupdateValue(key: string, value: any): Promise;\n\tupdateValue(key: string, value: any, target: ConfigurationTarget): Promise;\n\tupdateValue(key: string, value: any, overrides: IConfigurationOverrides | IConfigurationUpdateOverrides): Promise;\n\tupdateValue(key: string, value: any, overrides: IConfigurationOverrides | IConfigurationUpdateOverrides, target: ConfigurationTarget, options?: IConfigurationUpdateOptions): Promise;\n\n\tinspect(key: string, overrides?: IConfigurationOverrides): IConfigurationValue>;\n}\n\nexport interface IConfigurationModel {\n\tcontents: any;\n\tkeys: string[];\n\toverrides: IOverrides[];\n}\n\nexport interface IOverrides {\n\tkeys: string[];\n\tcontents: any;\n\tidentifiers: string[];\n}\n\nexport interface IConfigurationData {\n\tdefaults: IConfigurationModel;\n\tpolicy: IConfigurationModel;\n\tapplication: IConfigurationModel;\n\tuser: IConfigurationModel;\n\tworkspace: IConfigurationModel;\n\tfolders: [UriComponents, IConfigurationModel][];\n}\n\nexport function toValuesTree(properties: { [qualifiedKey: string]: any }, conflictReporter: (message: string) => void): any {\n\tconst root = Object.create(null);\n\n\tfor (const key in properties) {\n\t\taddToValueTree(root, key, properties[key], conflictReporter);\n\t}\n\n\treturn root;\n}\n\nexport function addToValueTree(settingsTreeRoot: any, key: string, value: any, conflictReporter: (message: string) => void): void {\n\tconst segments = key.split('.');\n\tconst last = segments.pop()!;\n\n\tlet curr = settingsTreeRoot;\n\tfor (let i = 0; i < segments.length; i++) {\n\t\tconst s = segments[i];\n\t\tlet obj = curr[s];\n\t\tswitch (typeof obj) {\n\t\t\tcase 'undefined':\n\t\t\t\tobj = curr[s] = Object.create(null);\n\t\t\t\tbreak;\n\t\t\tcase 'object':\n\t\t\t\tif (obj === null) {\n\t\t\t\t\tconflictReporter(`Ignoring ${key} as ${segments.slice(0, i + 1).join('.')} is null`);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tconflictReporter(`Ignoring ${key} as ${segments.slice(0, i + 1).join('.')} is ${JSON.stringify(obj)}`);\n\t\t\t\treturn;\n\t\t}\n\t\tcurr = obj;\n\t}\n\n\tif (typeof curr === 'object' && curr !== null) {\n\t\ttry {\n\t\t\tcurr[last] = value; // workaround https://github.com/microsoft/vscode/issues/13606\n\t\t} catch (e) {\n\t\t\tconflictReporter(`Ignoring ${key} as ${segments.join('.')} is ${JSON.stringify(curr)}`);\n\t\t}\n\t} else {\n\t\tconflictReporter(`Ignoring ${key} as ${segments.join('.')} is ${JSON.stringify(curr)}`);\n\t}\n}\n\nexport function removeFromValueTree(valueTree: any, key: string): void {\n\tconst segments = key.split('.');\n\tdoRemoveFromValueTree(valueTree, segments);\n}\n\nfunction doRemoveFromValueTree(valueTree: any, segments: string[]): void {\n\tconst first = segments.shift()!;\n\tif (segments.length === 0) {\n\t\t// Reached last segment\n\t\tdelete valueTree[first];\n\t\treturn;\n\t}\n\n\tif (Object.keys(valueTree).indexOf(first) !== -1) {\n\t\tconst value = valueTree[first];\n\t\tif (typeof value === 'object' && !Array.isArray(value)) {\n\t\t\tdoRemoveFromValueTree(value, segments);\n\t\t\tif (Object.keys(value).length === 0) {\n\t\t\t\tdelete valueTree[first];\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * A helper function to get the configuration value with a specific settings path (e.g. config.some.setting)\n */\nexport function getConfigurationValue(config: any, settingPath: string, defaultValue?: T): T {\n\tfunction accessSetting(config: any, path: string[]): any {\n\t\tlet current = config;\n\t\tfor (const component of path) {\n\t\t\tif (typeof current !== 'object' || current === null) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tcurrent = current[component];\n\t\t}\n\t\treturn current;\n\t}\n\n\tconst path = settingPath.split('.');\n\tconst result = accessSetting(config, path);\n\n\treturn typeof result === 'undefined' ? defaultValue : result;\n}\n\nexport function getLanguageTagSettingPlainKey(settingKey: string) {\n\treturn settingKey.replace(/[\\[\\]]/g, '');\n}\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 * Create a syntax highighter with a fully declarative JSON style lexer description\n * using regular expressions.\n */\n\nimport { Disposable, IDisposable } from 'vs/base/common/lifecycle';\nimport * as languages from 'vs/editor/common/languages';\nimport { NullState, nullTokenizeEncoded, nullTokenize } from 'vs/editor/common/languages/nullTokenize';\nimport { TokenTheme } from 'vs/editor/common/languages/supports/tokenization';\nimport { ILanguageService } from 'vs/editor/common/languages/language';\nimport * as monarchCommon from 'vs/editor/standalone/common/monarch/monarchCommon';\nimport { IStandaloneThemeService } from 'vs/editor/standalone/common/standaloneTheme';\nimport { IConfigurationService } from 'vs/platform/configuration/common/configuration';\nimport { LanguageId, MetadataConsts } from 'vs/editor/common/encodedTokenAttributes';\n\nconst CACHE_STACK_DEPTH = 5;\n\n/**\n * Reuse the same stack elements up to a certain depth.\n */\nclass MonarchStackElementFactory {\n\n\tprivate static readonly _INSTANCE = new MonarchStackElementFactory(CACHE_STACK_DEPTH);\n\tpublic static create(parent: MonarchStackElement | null, state: string): MonarchStackElement {\n\t\treturn this._INSTANCE.create(parent, state);\n\t}\n\n\tprivate readonly _maxCacheDepth: number;\n\tprivate readonly _entries: { [stackElementId: string]: MonarchStackElement };\n\n\tconstructor(maxCacheDepth: number) {\n\t\tthis._maxCacheDepth = maxCacheDepth;\n\t\tthis._entries = Object.create(null);\n\t}\n\n\tpublic create(parent: MonarchStackElement | null, state: string): MonarchStackElement {\n\t\tif (parent !== null && parent.depth >= this._maxCacheDepth) {\n\t\t\t// no caching above a certain depth\n\t\t\treturn new MonarchStackElement(parent, state);\n\t\t}\n\t\tlet stackElementId = MonarchStackElement.getStackElementId(parent);\n\t\tif (stackElementId.length > 0) {\n\t\t\tstackElementId += '|';\n\t\t}\n\t\tstackElementId += state;\n\n\t\tlet result = this._entries[stackElementId];\n\t\tif (result) {\n\t\t\treturn result;\n\t\t}\n\t\tresult = new MonarchStackElement(parent, state);\n\t\tthis._entries[stackElementId] = result;\n\t\treturn result;\n\t}\n}\n\nclass MonarchStackElement {\n\n\tpublic readonly parent: MonarchStackElement | null;\n\tpublic readonly state: string;\n\tpublic readonly depth: number;\n\n\tconstructor(parent: MonarchStackElement | null, state: string) {\n\t\tthis.parent = parent;\n\t\tthis.state = state;\n\t\tthis.depth = (this.parent ? this.parent.depth : 0) + 1;\n\t}\n\n\tpublic static getStackElementId(element: MonarchStackElement | null): string {\n\t\tlet result = '';\n\t\twhile (element !== null) {\n\t\t\tif (result.length > 0) {\n\t\t\t\tresult += '|';\n\t\t\t}\n\t\t\tresult += element.state;\n\t\t\telement = element.parent;\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate static _equals(a: MonarchStackElement | null, b: MonarchStackElement | null): boolean {\n\t\twhile (a !== null && b !== null) {\n\t\t\tif (a === b) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (a.state !== b.state) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\ta = a.parent;\n\t\t\tb = b.parent;\n\t\t}\n\t\tif (a === null && b === null) {\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tpublic equals(other: MonarchStackElement): boolean {\n\t\treturn MonarchStackElement._equals(this, other);\n\t}\n\n\tpublic push(state: string): MonarchStackElement {\n\t\treturn MonarchStackElementFactory.create(this, state);\n\t}\n\n\tpublic pop(): MonarchStackElement | null {\n\t\treturn this.parent;\n\t}\n\n\tpublic popall(): MonarchStackElement {\n\t\tlet result: MonarchStackElement = this;\n\t\twhile (result.parent) {\n\t\t\tresult = result.parent;\n\t\t}\n\t\treturn result;\n\t}\n\n\tpublic switchTo(state: string): MonarchStackElement {\n\t\treturn MonarchStackElementFactory.create(this.parent, state);\n\t}\n}\n\nclass EmbeddedLanguageData {\n\tpublic readonly languageId: string;\n\tpublic readonly state: languages.IState;\n\n\tconstructor(languageId: string, state: languages.IState) {\n\t\tthis.languageId = languageId;\n\t\tthis.state = state;\n\t}\n\n\tpublic equals(other: EmbeddedLanguageData): boolean {\n\t\treturn (\n\t\t\tthis.languageId === other.languageId\n\t\t\t&& this.state.equals(other.state)\n\t\t);\n\t}\n\n\tpublic clone(): EmbeddedLanguageData {\n\t\tconst stateClone = this.state.clone();\n\t\t// save an object\n\t\tif (stateClone === this.state) {\n\t\t\treturn this;\n\t\t}\n\t\treturn new EmbeddedLanguageData(this.languageId, this.state);\n\t}\n}\n\n/**\n * Reuse the same line states up to a certain depth.\n */\nclass MonarchLineStateFactory {\n\n\tprivate static readonly _INSTANCE = new MonarchLineStateFactory(CACHE_STACK_DEPTH);\n\tpublic static create(stack: MonarchStackElement, embeddedLanguageData: EmbeddedLanguageData | null): MonarchLineState {\n\t\treturn this._INSTANCE.create(stack, embeddedLanguageData);\n\t}\n\n\tprivate readonly _maxCacheDepth: number;\n\tprivate readonly _entries: { [stackElementId: string]: MonarchLineState };\n\n\tconstructor(maxCacheDepth: number) {\n\t\tthis._maxCacheDepth = maxCacheDepth;\n\t\tthis._entries = Object.create(null);\n\t}\n\n\tpublic create(stack: MonarchStackElement, embeddedLanguageData: EmbeddedLanguageData | null): MonarchLineState {\n\t\tif (embeddedLanguageData !== null) {\n\t\t\t// no caching when embedding\n\t\t\treturn new MonarchLineState(stack, embeddedLanguageData);\n\t\t}\n\t\tif (stack !== null && stack.depth >= this._maxCacheDepth) {\n\t\t\t// no caching above a certain depth\n\t\t\treturn new MonarchLineState(stack, embeddedLanguageData);\n\t\t}\n\t\tconst stackElementId = MonarchStackElement.getStackElementId(stack);\n\n\t\tlet result = this._entries[stackElementId];\n\t\tif (result) {\n\t\t\treturn result;\n\t\t}\n\t\tresult = new MonarchLineState(stack, null);\n\t\tthis._entries[stackElementId] = result;\n\t\treturn result;\n\t}\n}\n\nclass MonarchLineState implements languages.IState {\n\n\tpublic readonly stack: MonarchStackElement;\n\tpublic readonly embeddedLanguageData: EmbeddedLanguageData | null;\n\n\tconstructor(\n\t\tstack: MonarchStackElement,\n\t\tembeddedLanguageData: EmbeddedLanguageData | null\n\t) {\n\t\tthis.stack = stack;\n\t\tthis.embeddedLanguageData = embeddedLanguageData;\n\t}\n\n\tpublic clone(): languages.IState {\n\t\tconst embeddedlanguageDataClone = this.embeddedLanguageData ? this.embeddedLanguageData.clone() : null;\n\t\t// save an object\n\t\tif (embeddedlanguageDataClone === this.embeddedLanguageData) {\n\t\t\treturn this;\n\t\t}\n\t\treturn MonarchLineStateFactory.create(this.stack, this.embeddedLanguageData);\n\t}\n\n\tpublic equals(other: languages.IState): boolean {\n\t\tif (!(other instanceof MonarchLineState)) {\n\t\t\treturn false;\n\t\t}\n\t\tif (!this.stack.equals(other.stack)) {\n\t\t\treturn false;\n\t\t}\n\t\tif (this.embeddedLanguageData === null && other.embeddedLanguageData === null) {\n\t\t\treturn true;\n\t\t}\n\t\tif (this.embeddedLanguageData === null || other.embeddedLanguageData === null) {\n\t\t\treturn false;\n\t\t}\n\t\treturn this.embeddedLanguageData.equals(other.embeddedLanguageData);\n\t}\n}\n\ninterface IMonarchTokensCollector {\n\tenterLanguage(languageId: string): void;\n\temit(startOffset: number, type: string): void;\n\tnestedLanguageTokenize(embeddedLanguageLine: string, hasEOL: boolean, embeddedLanguageData: EmbeddedLanguageData, offsetDelta: number): languages.IState;\n}\n\nclass MonarchClassicTokensCollector implements IMonarchTokensCollector {\n\n\tprivate _tokens: languages.Token[];\n\tprivate _languageId: string | null;\n\tprivate _lastTokenType: string | null;\n\tprivate _lastTokenLanguage: string | null;\n\n\tconstructor() {\n\t\tthis._tokens = [];\n\t\tthis._languageId = null;\n\t\tthis._lastTokenType = null;\n\t\tthis._lastTokenLanguage = null;\n\t}\n\n\tpublic enterLanguage(languageId: string): void {\n\t\tthis._languageId = languageId;\n\t}\n\n\tpublic emit(startOffset: number, type: string): void {\n\t\tif (this._lastTokenType === type && this._lastTokenLanguage === this._languageId) {\n\t\t\treturn;\n\t\t}\n\t\tthis._lastTokenType = type;\n\t\tthis._lastTokenLanguage = this._languageId;\n\t\tthis._tokens.push(new languages.Token(startOffset, type, this._languageId!));\n\t}\n\n\tpublic nestedLanguageTokenize(embeddedLanguageLine: string, hasEOL: boolean, embeddedLanguageData: EmbeddedLanguageData, offsetDelta: number): languages.IState {\n\t\tconst nestedLanguageId = embeddedLanguageData.languageId;\n\t\tconst embeddedModeState = embeddedLanguageData.state;\n\n\t\tconst nestedLanguageTokenizationSupport = languages.TokenizationRegistry.get(nestedLanguageId);\n\t\tif (!nestedLanguageTokenizationSupport) {\n\t\t\tthis.enterLanguage(nestedLanguageId);\n\t\t\tthis.emit(offsetDelta, '');\n\t\t\treturn embeddedModeState;\n\t\t}\n\n\t\tconst nestedResult = nestedLanguageTokenizationSupport.tokenize(embeddedLanguageLine, hasEOL, embeddedModeState);\n\t\tif (offsetDelta !== 0) {\n\t\t\tfor (const token of nestedResult.tokens) {\n\t\t\t\tthis._tokens.push(new languages.Token(token.offset + offsetDelta, token.type, token.language));\n\t\t\t}\n\t\t} else {\n\t\t\tthis._tokens = this._tokens.concat(nestedResult.tokens);\n\t\t}\n\t\tthis._lastTokenType = null;\n\t\tthis._lastTokenLanguage = null;\n\t\tthis._languageId = null;\n\t\treturn nestedResult.endState;\n\t}\n\n\tpublic finalize(endState: MonarchLineState): languages.TokenizationResult {\n\t\treturn new languages.TokenizationResult(this._tokens, endState);\n\t}\n}\n\nclass MonarchModernTokensCollector implements IMonarchTokensCollector {\n\n\tprivate readonly _languageService: ILanguageService;\n\tprivate readonly _theme: TokenTheme;\n\tprivate _prependTokens: Uint32Array | null;\n\tprivate _tokens: number[];\n\tprivate _currentLanguageId: LanguageId;\n\tprivate _lastTokenMetadata: number;\n\n\tconstructor(languageService: ILanguageService, theme: TokenTheme) {\n\t\tthis._languageService = languageService;\n\t\tthis._theme = theme;\n\t\tthis._prependTokens = null;\n\t\tthis._tokens = [];\n\t\tthis._currentLanguageId = LanguageId.Null;\n\t\tthis._lastTokenMetadata = 0;\n\t}\n\n\tpublic enterLanguage(languageId: string): void {\n\t\tthis._currentLanguageId = this._languageService.languageIdCodec.encodeLanguageId(languageId);\n\t}\n\n\tpublic emit(startOffset: number, type: string): void {\n\t\tconst metadata = this._theme.match(this._currentLanguageId, type) | MetadataConsts.BALANCED_BRACKETS_MASK;\n\t\tif (this._lastTokenMetadata === metadata) {\n\t\t\treturn;\n\t\t}\n\t\tthis._lastTokenMetadata = metadata;\n\t\tthis._tokens.push(startOffset);\n\t\tthis._tokens.push(metadata);\n\t}\n\n\tprivate static _merge(a: Uint32Array | null, b: number[], c: Uint32Array | null): Uint32Array {\n\t\tconst aLen = (a !== null ? a.length : 0);\n\t\tconst bLen = b.length;\n\t\tconst cLen = (c !== null ? c.length : 0);\n\n\t\tif (aLen === 0 && bLen === 0 && cLen === 0) {\n\t\t\treturn new Uint32Array(0);\n\t\t}\n\t\tif (aLen === 0 && bLen === 0) {\n\t\t\treturn c!;\n\t\t}\n\t\tif (bLen === 0 && cLen === 0) {\n\t\t\treturn a!;\n\t\t}\n\n\t\tconst result = new Uint32Array(aLen + bLen + cLen);\n\t\tif (a !== null) {\n\t\t\tresult.set(a);\n\t\t}\n\t\tfor (let i = 0; i < bLen; i++) {\n\t\t\tresult[aLen + i] = b[i];\n\t\t}\n\t\tif (c !== null) {\n\t\t\tresult.set(c, aLen + bLen);\n\t\t}\n\t\treturn result;\n\t}\n\n\tpublic nestedLanguageTokenize(embeddedLanguageLine: string, hasEOL: boolean, embeddedLanguageData: EmbeddedLanguageData, offsetDelta: number): languages.IState {\n\t\tconst nestedLanguageId = embeddedLanguageData.languageId;\n\t\tconst embeddedModeState = embeddedLanguageData.state;\n\n\t\tconst nestedLanguageTokenizationSupport = languages.TokenizationRegistry.get(nestedLanguageId);\n\t\tif (!nestedLanguageTokenizationSupport) {\n\t\t\tthis.enterLanguage(nestedLanguageId);\n\t\t\tthis.emit(offsetDelta, '');\n\t\t\treturn embeddedModeState;\n\t\t}\n\n\t\tconst nestedResult = nestedLanguageTokenizationSupport.tokenizeEncoded(embeddedLanguageLine, hasEOL, embeddedModeState);\n\t\tif (offsetDelta !== 0) {\n\t\t\tfor (let i = 0, len = nestedResult.tokens.length; i < len; i += 2) {\n\t\t\t\tnestedResult.tokens[i] += offsetDelta;\n\t\t\t}\n\t\t}\n\n\t\tthis._prependTokens = MonarchModernTokensCollector._merge(this._prependTokens, this._tokens, nestedResult.tokens);\n\t\tthis._tokens = [];\n\t\tthis._currentLanguageId = 0;\n\t\tthis._lastTokenMetadata = 0;\n\t\treturn nestedResult.endState;\n\t}\n\n\tpublic finalize(endState: MonarchLineState): languages.EncodedTokenizationResult {\n\t\treturn new languages.EncodedTokenizationResult(\n\t\t\tMonarchModernTokensCollector._merge(this._prependTokens, this._tokens, null),\n\t\t\tendState\n\t\t);\n\t}\n}\n\nexport type ILoadStatus = { loaded: true } | { loaded: false; promise: Promise };\n\nexport class MonarchTokenizer extends Disposable implements languages.ITokenizationSupport, IDisposable {\n\n\tprivate readonly _languageService: ILanguageService;\n\tprivate readonly _standaloneThemeService: IStandaloneThemeService;\n\tprivate readonly _languageId: string;\n\tprivate readonly _lexer: monarchCommon.ILexer;\n\tprivate readonly _embeddedLanguages: { [languageId: string]: boolean };\n\tpublic embeddedLoaded: Promise;\n\tprivate _maxTokenizationLineLength: number;\n\n\tconstructor(languageService: ILanguageService, standaloneThemeService: IStandaloneThemeService, languageId: string, lexer: monarchCommon.ILexer, @IConfigurationService private readonly _configurationService: IConfigurationService) {\n\t\tsuper();\n\t\tthis._languageService = languageService;\n\t\tthis._standaloneThemeService = standaloneThemeService;\n\t\tthis._languageId = languageId;\n\t\tthis._lexer = lexer;\n\t\tthis._embeddedLanguages = Object.create(null);\n\t\tthis.embeddedLoaded = Promise.resolve(undefined);\n\n\t\t// Set up listening for embedded modes\n\t\tlet emitting = false;\n\t\tthis._register(languages.TokenizationRegistry.onDidChange((e) => {\n\t\t\tif (emitting) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tlet isOneOfMyEmbeddedModes = false;\n\t\t\tfor (let i = 0, len = e.changedLanguages.length; i < len; i++) {\n\t\t\t\tconst language = e.changedLanguages[i];\n\t\t\t\tif (this._embeddedLanguages[language]) {\n\t\t\t\t\tisOneOfMyEmbeddedModes = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (isOneOfMyEmbeddedModes) {\n\t\t\t\temitting = true;\n\t\t\t\tlanguages.TokenizationRegistry.handleChange([this._languageId]);\n\t\t\t\temitting = false;\n\t\t\t}\n\t\t}));\n\t\tthis._maxTokenizationLineLength = this._configurationService.getValue('editor.maxTokenizationLineLength', {\n\t\t\toverrideIdentifier: this._languageId\n\t\t});\n\t\tthis._register(this._configurationService.onDidChangeConfiguration(e => {\n\t\t\tif (e.affectsConfiguration('editor.maxTokenizationLineLength')) {\n\t\t\t\tthis._maxTokenizationLineLength = this._configurationService.getValue('editor.maxTokenizationLineLength', {\n\t\t\t\t\toverrideIdentifier: this._languageId\n\t\t\t\t});\n\t\t\t}\n\t\t}));\n\t}\n\n\tpublic getLoadStatus(): ILoadStatus {\n\t\tconst promises: Thenable[] = [];\n\t\tfor (const nestedLanguageId in this._embeddedLanguages) {\n\t\t\tconst tokenizationSupport = languages.TokenizationRegistry.get(nestedLanguageId);\n\t\t\tif (tokenizationSupport) {\n\t\t\t\t// The nested language is already loaded\n\t\t\t\tif (tokenizationSupport instanceof MonarchTokenizer) {\n\t\t\t\t\tconst nestedModeStatus = tokenizationSupport.getLoadStatus();\n\t\t\t\t\tif (nestedModeStatus.loaded === false) {\n\t\t\t\t\t\tpromises.push(nestedModeStatus.promise);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (!languages.TokenizationRegistry.isResolved(nestedLanguageId)) {\n\t\t\t\t// The nested language is in the process of being loaded\n\t\t\t\tpromises.push(languages.TokenizationRegistry.getOrCreate(nestedLanguageId));\n\t\t\t}\n\t\t}\n\n\t\tif (promises.length === 0) {\n\t\t\treturn {\n\t\t\t\tloaded: true\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\tloaded: false,\n\t\t\tpromise: Promise.all(promises).then(_ => undefined)\n\t\t};\n\t}\n\n\tpublic getInitialState(): languages.IState {\n\t\tconst rootState = MonarchStackElementFactory.create(null, this._lexer.start!);\n\t\treturn MonarchLineStateFactory.create(rootState, null);\n\t}\n\n\tpublic tokenize(line: string, hasEOL: boolean, lineState: languages.IState): languages.TokenizationResult {\n\t\tif (line.length >= this._maxTokenizationLineLength) {\n\t\t\treturn nullTokenize(this._languageId, lineState);\n\t\t}\n\t\tconst tokensCollector = new MonarchClassicTokensCollector();\n\t\tconst endLineState = this._tokenize(line, hasEOL, lineState, tokensCollector);\n\t\treturn tokensCollector.finalize(endLineState);\n\t}\n\n\tpublic tokenizeEncoded(line: string, hasEOL: boolean, lineState: languages.IState): languages.EncodedTokenizationResult {\n\t\tif (line.length >= this._maxTokenizationLineLength) {\n\t\t\treturn nullTokenizeEncoded(this._languageService.languageIdCodec.encodeLanguageId(this._languageId), lineState);\n\t\t}\n\t\tconst tokensCollector = new MonarchModernTokensCollector(this._languageService, this._standaloneThemeService.getColorTheme().tokenTheme);\n\t\tconst endLineState = this._tokenize(line, hasEOL, lineState, tokensCollector);\n\t\treturn tokensCollector.finalize(endLineState);\n\t}\n\n\tprivate _tokenize(line: string, hasEOL: boolean, lineState: MonarchLineState, collector: IMonarchTokensCollector): MonarchLineState {\n\t\tif (lineState.embeddedLanguageData) {\n\t\t\treturn this._nestedTokenize(line, hasEOL, lineState, 0, collector);\n\t\t} else {\n\t\t\treturn this._myTokenize(line, hasEOL, lineState, 0, collector);\n\t\t}\n\t}\n\n\tprivate _findLeavingNestedLanguageOffset(line: string, state: MonarchLineState): number {\n\t\tlet rules: monarchCommon.IRule[] | null = this._lexer.tokenizer[state.stack.state];\n\t\tif (!rules) {\n\t\t\trules = monarchCommon.findRules(this._lexer, state.stack.state); // do parent matching\n\t\t\tif (!rules) {\n\t\t\t\tthrow monarchCommon.createError(this._lexer, 'tokenizer state is not defined: ' + state.stack.state);\n\t\t\t}\n\t\t}\n\n\t\tlet popOffset = -1;\n\t\tlet hasEmbeddedPopRule = false;\n\n\t\tfor (const rule of rules) {\n\t\t\tif (!monarchCommon.isIAction(rule.action) || rule.action.nextEmbedded !== '@pop') {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\thasEmbeddedPopRule = true;\n\n\t\t\tlet regex = rule.resolveRegex(state.stack.state);\n\t\t\tconst regexSource = regex.source;\n\t\t\tif (regexSource.substr(0, 4) === '^(?:' && regexSource.substr(regexSource.length - 1, 1) === ')') {\n\t\t\t\tconst flags = (regex.ignoreCase ? 'i' : '') + (regex.unicode ? 'u' : '');\n\t\t\t\tregex = new RegExp(regexSource.substr(4, regexSource.length - 5), flags);\n\t\t\t}\n\n\t\t\tconst result = line.search(regex);\n\t\t\tif (result === -1 || (result !== 0 && rule.matchOnlyAtLineStart)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (popOffset === -1 || result < popOffset) {\n\t\t\t\tpopOffset = result;\n\t\t\t}\n\t\t}\n\n\t\tif (!hasEmbeddedPopRule) {\n\t\t\tthrow monarchCommon.createError(this._lexer, 'no rule containing nextEmbedded: \"@pop\" in tokenizer embedded state: ' + state.stack.state);\n\t\t}\n\n\t\treturn popOffset;\n\t}\n\n\tprivate _nestedTokenize(line: string, hasEOL: boolean, lineState: MonarchLineState, offsetDelta: number, tokensCollector: IMonarchTokensCollector): MonarchLineState {\n\n\t\tconst popOffset = this._findLeavingNestedLanguageOffset(line, lineState);\n\n\t\tif (popOffset === -1) {\n\t\t\t// tokenization will not leave nested language\n\t\t\tconst nestedEndState = tokensCollector.nestedLanguageTokenize(line, hasEOL, lineState.embeddedLanguageData!, offsetDelta);\n\t\t\treturn MonarchLineStateFactory.create(lineState.stack, new EmbeddedLanguageData(lineState.embeddedLanguageData!.languageId, nestedEndState));\n\t\t}\n\n\t\tconst nestedLanguageLine = line.substring(0, popOffset);\n\t\tif (nestedLanguageLine.length > 0) {\n\t\t\t// tokenize with the nested language\n\t\t\ttokensCollector.nestedLanguageTokenize(nestedLanguageLine, false, lineState.embeddedLanguageData!, offsetDelta);\n\t\t}\n\n\t\tconst restOfTheLine = line.substring(popOffset);\n\t\treturn this._myTokenize(restOfTheLine, hasEOL, lineState, offsetDelta + popOffset, tokensCollector);\n\t}\n\n\tprivate _safeRuleName(rule: monarchCommon.IRule | null): string {\n\t\tif (rule) {\n\t\t\treturn rule.name;\n\t\t}\n\t\treturn '(unknown)';\n\t}\n\n\tprivate _myTokenize(lineWithoutLF: string, hasEOL: boolean, lineState: MonarchLineState, offsetDelta: number, tokensCollector: IMonarchTokensCollector): MonarchLineState {\n\t\ttokensCollector.enterLanguage(this._languageId);\n\n\t\tconst lineWithoutLFLength = lineWithoutLF.length;\n\t\tconst line = (hasEOL && this._lexer.includeLF ? lineWithoutLF + '\\n' : lineWithoutLF);\n\t\tconst lineLength = line.length;\n\n\t\tlet embeddedLanguageData = lineState.embeddedLanguageData;\n\t\tlet stack = lineState.stack;\n\t\tlet pos = 0;\n\n\t\t// regular expression group matching\n\t\t// these never need cloning or equality since they are only used within a line match\n\t\tinterface GroupMatching {\n\t\t\tmatches: string[];\n\t\t\trule: monarchCommon.IRule | null;\n\t\t\tgroups: { action: monarchCommon.FuzzyAction; matched: string }[];\n\t\t}\n\t\tlet groupMatching: GroupMatching | null = null;\n\n\t\t// See https://github.com/microsoft/monaco-editor/issues/1235\n\t\t// Evaluate rules at least once for an empty line\n\t\tlet forceEvaluation = true;\n\n\t\twhile (forceEvaluation || pos < lineLength) {\n\n\t\t\tconst pos0 = pos;\n\t\t\tconst stackLen0 = stack.depth;\n\t\t\tconst groupLen0 = groupMatching ? groupMatching.groups.length : 0;\n\t\t\tconst state = stack.state;\n\n\t\t\tlet matches: string[] | null = null;\n\t\t\tlet matched: string | null = null;\n\t\t\tlet action: monarchCommon.FuzzyAction | monarchCommon.FuzzyAction[] | null = null;\n\t\t\tlet rule: monarchCommon.IRule | null = null;\n\n\t\t\tlet enteringEmbeddedLanguage: string | null = null;\n\n\t\t\t// check if we need to process group matches first\n\t\t\tif (groupMatching) {\n\t\t\t\tmatches = groupMatching.matches;\n\t\t\t\tconst groupEntry = groupMatching.groups.shift()!;\n\t\t\t\tmatched = groupEntry.matched;\n\t\t\t\taction = groupEntry.action;\n\t\t\t\trule = groupMatching.rule;\n\n\t\t\t\t// cleanup if necessary\n\t\t\t\tif (groupMatching.groups.length === 0) {\n\t\t\t\t\tgroupMatching = null;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// otherwise we match on the token stream\n\n\t\t\t\tif (!forceEvaluation && pos >= lineLength) {\n\t\t\t\t\t// nothing to do\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tforceEvaluation = false;\n\n\t\t\t\t// get the rules for this state\n\t\t\t\tlet rules: monarchCommon.IRule[] | null = this._lexer.tokenizer[state];\n\t\t\t\tif (!rules) {\n\t\t\t\t\trules = monarchCommon.findRules(this._lexer, state); // do parent matching\n\t\t\t\t\tif (!rules) {\n\t\t\t\t\t\tthrow monarchCommon.createError(this._lexer, 'tokenizer state is not defined: ' + state);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// try each rule until we match\n\t\t\t\tconst restOfLine = line.substr(pos);\n\t\t\t\tfor (const rule of rules) {\n\t\t\t\t\tif (pos === 0 || !rule.matchOnlyAtLineStart) {\n\t\t\t\t\t\tmatches = restOfLine.match(rule.resolveRegex(state));\n\t\t\t\t\t\tif (matches) {\n\t\t\t\t\t\t\tmatched = matches[0];\n\t\t\t\t\t\t\taction = rule.action;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// We matched 'rule' with 'matches' and 'action'\n\t\t\tif (!matches) {\n\t\t\t\tmatches = [''];\n\t\t\t\tmatched = '';\n\t\t\t}\n\n\t\t\tif (!action) {\n\t\t\t\t// bad: we didn't match anything, and there is no action to take\n\t\t\t\t// we need to advance the stream or we get progress trouble\n\t\t\t\tif (pos < lineLength) {\n\t\t\t\t\tmatches = [line.charAt(pos)];\n\t\t\t\t\tmatched = matches[0];\n\t\t\t\t}\n\t\t\t\taction = this._lexer.defaultToken;\n\t\t\t}\n\n\t\t\tif (matched === null) {\n\t\t\t\t// should never happen, needed for strict null checking\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// advance stream\n\t\t\tpos += matched.length;\n\n\t\t\t// maybe call action function (used for 'cases')\n\t\t\twhile (monarchCommon.isFuzzyAction(action) && monarchCommon.isIAction(action) && action.test) {\n\t\t\t\taction = action.test(matched, matches, state, pos === lineLength);\n\t\t\t}\n\n\t\t\tlet result: monarchCommon.FuzzyAction | monarchCommon.FuzzyAction[] | null = null;\n\t\t\t// set the result: either a string or an array of actions\n\t\t\tif (typeof action === 'string' || Array.isArray(action)) {\n\t\t\t\tresult = action;\n\t\t\t} else if (action.group) {\n\t\t\t\tresult = action.group;\n\t\t\t} else if (action.token !== null && action.token !== undefined) {\n\n\t\t\t\t// do $n replacements?\n\t\t\t\tif (action.tokenSubst) {\n\t\t\t\t\tresult = monarchCommon.substituteMatches(this._lexer, action.token, matched, matches, state);\n\t\t\t\t} else {\n\t\t\t\t\tresult = action.token;\n\t\t\t\t}\n\n\t\t\t\t// enter embedded language?\n\t\t\t\tif (action.nextEmbedded) {\n\t\t\t\t\tif (action.nextEmbedded === '@pop') {\n\t\t\t\t\t\tif (!embeddedLanguageData) {\n\t\t\t\t\t\t\tthrow monarchCommon.createError(this._lexer, 'cannot pop embedded language if not inside one');\n\t\t\t\t\t\t}\n\t\t\t\t\t\tembeddedLanguageData = null;\n\t\t\t\t\t} else if (embeddedLanguageData) {\n\t\t\t\t\t\tthrow monarchCommon.createError(this._lexer, 'cannot enter embedded language from within an embedded language');\n\t\t\t\t\t} else {\n\t\t\t\t\t\tenteringEmbeddedLanguage = monarchCommon.substituteMatches(this._lexer, action.nextEmbedded, matched, matches, state);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// state transformations\n\t\t\t\tif (action.goBack) { // back up the stream..\n\t\t\t\t\tpos = Math.max(0, pos - action.goBack);\n\t\t\t\t}\n\n\t\t\t\tif (action.switchTo && typeof action.switchTo === 'string') {\n\t\t\t\t\tlet nextState = monarchCommon.substituteMatches(this._lexer, action.switchTo, matched, matches, state); // switch state without a push...\n\t\t\t\t\tif (nextState[0] === '@') {\n\t\t\t\t\t\tnextState = nextState.substr(1); // peel off starting '@'\n\t\t\t\t\t}\n\t\t\t\t\tif (!monarchCommon.findRules(this._lexer, nextState)) {\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));\n\t\t\t\t\t} else {\n\t\t\t\t\t\tstack = stack.switchTo(nextState);\n\t\t\t\t\t}\n\t\t\t\t} else if (action.transform && typeof action.transform === 'function') {\n\t\t\t\t\tthrow monarchCommon.createError(this._lexer, 'action.transform not supported');\n\t\t\t\t} else if (action.next) {\n\t\t\t\t\tif (action.next === '@push') {\n\t\t\t\t\t\tif (stack.depth >= this._lexer.maxStack) {\n\t\t\t\t\t\t\tthrow monarchCommon.createError(this._lexer, 'maximum tokenizer stack size reached: [' +\n\t\t\t\t\t\t\t\tstack.state + ',' + stack.parent!.state + ',...]');\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tstack = stack.push(state);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (action.next === '@pop') {\n\t\t\t\t\t\tif (stack.depth <= 1) {\n\t\t\t\t\t\t\tthrow monarchCommon.createError(this._lexer, 'trying to pop an empty stack in rule: ' + this._safeRuleName(rule));\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tstack = stack.pop()!;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (action.next === '@popall') {\n\t\t\t\t\t\tstack = stack.popall();\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlet nextState = monarchCommon.substituteMatches(this._lexer, action.next, matched, matches, state);\n\t\t\t\t\t\tif (nextState[0] === '@') {\n\t\t\t\t\t\t\tnextState = nextState.substr(1); // peel off starting '@'\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (!monarchCommon.findRules(this._lexer, nextState)) {\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));\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tstack = stack.push(nextState);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (action.log && typeof (action.log) === 'string') {\n\t\t\t\t\tmonarchCommon.log(this._lexer, this._lexer.languageId + ': ' + monarchCommon.substituteMatches(this._lexer, action.log, matched, matches, state));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// check result\n\t\t\tif (result === null) {\n\t\t\t\tthrow monarchCommon.createError(this._lexer, 'lexer rule has no well-defined action in rule: ' + this._safeRuleName(rule));\n\t\t\t}\n\n\t\t\tconst computeNewStateForEmbeddedLanguage = (enteringEmbeddedLanguage: string) => {\n\t\t\t\t// support language names, mime types, and language ids\n\t\t\t\tconst languageId = (\n\t\t\t\t\tthis._languageService.getLanguageIdByLanguageName(enteringEmbeddedLanguage)\n\t\t\t\t\t|| this._languageService.getLanguageIdByMimeType(enteringEmbeddedLanguage)\n\t\t\t\t\t|| enteringEmbeddedLanguage\n\t\t\t\t);\n\n\t\t\t\tconst embeddedLanguageData = this._getNestedEmbeddedLanguageData(languageId);\n\n\t\t\t\tif (pos < lineLength) {\n\t\t\t\t\t// there is content from the embedded language on this line\n\t\t\t\t\tconst restOfLine = lineWithoutLF.substr(pos);\n\t\t\t\t\treturn this._nestedTokenize(restOfLine, hasEOL, MonarchLineStateFactory.create(stack, embeddedLanguageData), offsetDelta + pos, tokensCollector);\n\t\t\t\t} else {\n\t\t\t\t\treturn MonarchLineStateFactory.create(stack, embeddedLanguageData);\n\t\t\t\t}\n\t\t\t};\n\n\t\t\t// is the result a group match?\n\t\t\tif (Array.isArray(result)) {\n\t\t\t\tif (groupMatching && groupMatching.groups.length > 0) {\n\t\t\t\t\tthrow monarchCommon.createError(this._lexer, 'groups cannot be nested: ' + this._safeRuleName(rule));\n\t\t\t\t}\n\t\t\t\tif (matches.length !== result.length + 1) {\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));\n\t\t\t\t}\n\t\t\t\tlet totalLen = 0;\n\t\t\t\tfor (let i = 1; i < matches.length; i++) {\n\t\t\t\t\ttotalLen += matches[i].length;\n\t\t\t\t}\n\t\t\t\tif (totalLen !== matched.length) {\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));\n\t\t\t\t}\n\n\t\t\t\tgroupMatching = {\n\t\t\t\t\trule: rule,\n\t\t\t\t\tmatches: matches,\n\t\t\t\t\tgroups: []\n\t\t\t\t};\n\t\t\t\tfor (let i = 0; i < result.length; i++) {\n\t\t\t\t\tgroupMatching.groups[i] = {\n\t\t\t\t\t\taction: result[i],\n\t\t\t\t\t\tmatched: matches[i + 1]\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tpos -= matched.length;\n\t\t\t\t// call recursively to initiate first result match\n\t\t\t\tcontinue;\n\t\t\t} else {\n\t\t\t\t// regular result\n\n\t\t\t\t// check for '@rematch'\n\t\t\t\tif (result === '@rematch') {\n\t\t\t\t\tpos -= matched.length;\n\t\t\t\t\tmatched = ''; // better set the next state too..\n\t\t\t\t\tmatches = null;\n\t\t\t\t\tresult = '';\n\n\t\t\t\t\t// Even though `@rematch` was specified, if `nextEmbedded` also specified,\n\t\t\t\t\t// a state transition should occur.\n\t\t\t\t\tif (enteringEmbeddedLanguage !== null) {\n\t\t\t\t\t\treturn computeNewStateForEmbeddedLanguage(enteringEmbeddedLanguage);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// check progress\n\t\t\t\tif (matched.length === 0) {\n\t\t\t\t\tif (lineLength === 0 || stackLen0 !== stack.depth || state !== stack.state || (!groupMatching ? 0 : groupMatching.groups.length) !== groupLen0) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthrow monarchCommon.createError(this._lexer, 'no progress in tokenizer in rule: ' + this._safeRuleName(rule));\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// return the result (and check for brace matching)\n\t\t\t\t// todo: for efficiency we could pre-sanitize tokenPostfix and substitutions\n\t\t\t\tlet tokenType: string | null = null;\n\t\t\t\tif (monarchCommon.isString(result) && result.indexOf('@brackets') === 0) {\n\t\t\t\t\tconst rest = result.substr('@brackets'.length);\n\t\t\t\t\tconst bracket = findBracket(this._lexer, matched);\n\t\t\t\t\tif (!bracket) {\n\t\t\t\t\t\tthrow monarchCommon.createError(this._lexer, '@brackets token returned but no bracket defined as: ' + matched);\n\t\t\t\t\t}\n\t\t\t\t\ttokenType = monarchCommon.sanitize(bracket.token + rest);\n\t\t\t\t} else {\n\t\t\t\t\tconst token = (result === '' ? '' : result + this._lexer.tokenPostfix);\n\t\t\t\t\ttokenType = monarchCommon.sanitize(token);\n\t\t\t\t}\n\n\t\t\t\tif (pos0 < lineWithoutLFLength) {\n\t\t\t\t\ttokensCollector.emit(pos0 + offsetDelta, tokenType);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (enteringEmbeddedLanguage !== null) {\n\t\t\t\treturn computeNewStateForEmbeddedLanguage(enteringEmbeddedLanguage);\n\t\t\t}\n\t\t}\n\n\t\treturn MonarchLineStateFactory.create(stack, embeddedLanguageData);\n\t}\n\n\tprivate _getNestedEmbeddedLanguageData(languageId: string): EmbeddedLanguageData {\n\t\tif (!this._languageService.isRegisteredLanguageId(languageId)) {\n\t\t\treturn new EmbeddedLanguageData(languageId, NullState);\n\t\t}\n\n\t\tif (languageId !== this._languageId) {\n\t\t\t// Fire language loading event\n\t\t\tthis._languageService.requestBasicLanguageFeatures(languageId);\n\t\t\tlanguages.TokenizationRegistry.getOrCreate(languageId);\n\t\t\tthis._embeddedLanguages[languageId] = true;\n\t\t}\n\n\t\tconst tokenizationSupport = languages.TokenizationRegistry.get(languageId);\n\t\tif (tokenizationSupport) {\n\t\t\treturn new EmbeddedLanguageData(languageId, tokenizationSupport.getInitialState());\n\t\t}\n\n\t\treturn new EmbeddedLanguageData(languageId, NullState);\n\t}\n}\n\n/**\n * Searches for a bracket in the 'brackets' attribute that matches the input.\n */\nfunction findBracket(lexer: monarchCommon.ILexer, matched: string) {\n\tif (!matched) {\n\t\treturn null;\n\t}\n\tmatched = monarchCommon.fixCase(lexer, matched);\n\n\tconst brackets = lexer.brackets;\n\tfor (const bracket of brackets) {\n\t\tif (bracket.open === matched) {\n\t\t\treturn { token: bracket.token, bracketType: monarchCommon.MonarchBracket.Open };\n\t\t}\n\t\telse if (bracket.close === matched) {\n\t\t\treturn { token: bracket.token, bracketType: monarchCommon.MonarchBracket.Close };\n\t\t}\n\t}\n\treturn null;\n}\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\nimport { createTrustedTypesPolicy } from 'vs/base/browser/trustedTypes';\nimport * as strings from 'vs/base/common/strings';\nimport { ColorId, FontStyle, MetadataConsts } from 'vs/editor/common/encodedTokenAttributes';\nimport { ILanguageIdCodec, ITokenizationSupport, TokenizationRegistry } from 'vs/editor/common/languages';\nimport { ILanguageService } from 'vs/editor/common/languages/language';\nimport { ITextModel } from 'vs/editor/common/model';\nimport { IViewLineTokens, LineTokens } from 'vs/editor/common/tokens/lineTokens';\nimport { RenderLineInput, renderViewLine2 as renderViewLine } from 'vs/editor/common/viewLayout/viewLineRenderer';\nimport { ViewLineRenderingData } from 'vs/editor/common/viewModel';\nimport { MonarchTokenizer } from 'vs/editor/standalone/common/monarch/monarchLexer';\nimport { IStandaloneThemeService } from 'vs/editor/standalone/common/standaloneTheme';\n\nconst ttPolicy = createTrustedTypesPolicy('standaloneColorizer', { createHTML: value => value });\n\nexport interface IColorizerOptions {\n\ttabSize?: number;\n}\n\nexport interface IColorizerElementOptions extends IColorizerOptions {\n\ttheme?: string;\n\tmimeType?: string;\n}\n\nexport class Colorizer {\n\n\tpublic static colorizeElement(themeService: IStandaloneThemeService, languageService: ILanguageService, domNode: HTMLElement, options: IColorizerElementOptions): Promise {\n\t\toptions = options || {};\n\t\tconst theme = options.theme || 'vs';\n\t\tconst mimeType = options.mimeType || domNode.getAttribute('lang') || domNode.getAttribute('data-lang');\n\t\tif (!mimeType) {\n\t\t\tconsole.error('Mode not detected');\n\t\t\treturn Promise.resolve();\n\t\t}\n\t\tconst languageId = languageService.getLanguageIdByMimeType(mimeType) || mimeType;\n\n\t\tthemeService.setTheme(theme);\n\n\t\tconst text = domNode.firstChild ? domNode.firstChild.nodeValue : '';\n\t\tdomNode.className += ' ' + theme;\n\t\tconst render = (str: string) => {\n\t\t\tconst trustedhtml = ttPolicy?.createHTML(str) ?? str;\n\t\t\tdomNode.innerHTML = trustedhtml as string;\n\t\t};\n\t\treturn this.colorize(languageService, text || '', languageId, options).then(render, (err) => console.error(err));\n\t}\n\n\tpublic static async colorize(languageService: ILanguageService, text: string, languageId: string, options: IColorizerOptions | null | undefined): Promise {\n\t\tconst languageIdCodec = languageService.languageIdCodec;\n\t\tlet tabSize = 4;\n\t\tif (options && typeof options.tabSize === 'number') {\n\t\t\ttabSize = options.tabSize;\n\t\t}\n\n\t\tif (strings.startsWithUTF8BOM(text)) {\n\t\t\ttext = text.substr(1);\n\t\t}\n\t\tconst lines = strings.splitLines(text);\n\t\tif (!languageService.isRegisteredLanguageId(languageId)) {\n\t\t\treturn _fakeColorize(lines, tabSize, languageIdCodec);\n\t\t}\n\n\t\tconst tokenizationSupport = await TokenizationRegistry.getOrCreate(languageId);\n\t\tif (tokenizationSupport) {\n\t\t\treturn _colorize(lines, tabSize, tokenizationSupport, languageIdCodec);\n\t\t}\n\n\t\treturn _fakeColorize(lines, tabSize, languageIdCodec);\n\t}\n\n\tpublic static colorizeLine(line: string, mightContainNonBasicASCII: boolean, mightContainRTL: boolean, tokens: IViewLineTokens, tabSize: number = 4): string {\n\t\tconst isBasicASCII = ViewLineRenderingData.isBasicASCII(line, mightContainNonBasicASCII);\n\t\tconst containsRTL = ViewLineRenderingData.containsRTL(line, isBasicASCII, mightContainRTL);\n\t\tconst renderResult = renderViewLine(new RenderLineInput(\n\t\t\tfalse,\n\t\t\ttrue,\n\t\t\tline,\n\t\t\tfalse,\n\t\t\tisBasicASCII,\n\t\t\tcontainsRTL,\n\t\t\t0,\n\t\t\ttokens,\n\t\t\t[],\n\t\t\ttabSize,\n\t\t\t0,\n\t\t\t0,\n\t\t\t0,\n\t\t\t0,\n\t\t\t-1,\n\t\t\t'none',\n\t\t\tfalse,\n\t\t\tfalse,\n\t\t\tnull\n\t\t));\n\t\treturn renderResult.html;\n\t}\n\n\tpublic static colorizeModelLine(model: ITextModel, lineNumber: number, tabSize: number = 4): string {\n\t\tconst content = model.getLineContent(lineNumber);\n\t\tmodel.tokenization.forceTokenization(lineNumber);\n\t\tconst tokens = model.tokenization.getLineTokens(lineNumber);\n\t\tconst inflatedTokens = tokens.inflate();\n\t\treturn this.colorizeLine(content, model.mightContainNonBasicASCII(), model.mightContainRTL(), inflatedTokens, tabSize);\n\t}\n}\n\nfunction _colorize(lines: string[], tabSize: number, tokenizationSupport: ITokenizationSupport, languageIdCodec: ILanguageIdCodec): Promise {\n\treturn new Promise((c, e) => {\n\t\tconst execute = () => {\n\t\t\tconst result = _actualColorize(lines, tabSize, tokenizationSupport, languageIdCodec);\n\t\t\tif (tokenizationSupport instanceof MonarchTokenizer) {\n\t\t\t\tconst status = tokenizationSupport.getLoadStatus();\n\t\t\t\tif (status.loaded === false) {\n\t\t\t\t\tstatus.promise.then(execute, e);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\tc(result);\n\t\t};\n\t\texecute();\n\t});\n}\n\nfunction _fakeColorize(lines: string[], tabSize: number, languageIdCodec: ILanguageIdCodec): string {\n\tlet html: string[] = [];\n\n\tconst defaultMetadata = (\n\t\t(FontStyle.None << MetadataConsts.FONT_STYLE_OFFSET)\n\t\t| (ColorId.DefaultForeground << MetadataConsts.FOREGROUND_OFFSET)\n\t\t| (ColorId.DefaultBackground << MetadataConsts.BACKGROUND_OFFSET)\n\t) >>> 0;\n\n\tconst tokens = new Uint32Array(2);\n\ttokens[0] = 0;\n\ttokens[1] = defaultMetadata;\n\n\tfor (let i = 0, length = lines.length; i < length; i++) {\n\t\tconst line = lines[i];\n\n\t\ttokens[0] = line.length;\n\t\tconst lineTokens = new LineTokens(tokens, line, languageIdCodec);\n\n\t\tconst isBasicASCII = ViewLineRenderingData.isBasicASCII(line, /* check for basic ASCII */true);\n\t\tconst containsRTL = ViewLineRenderingData.containsRTL(line, isBasicASCII, /* check for RTL */true);\n\t\tconst renderResult = renderViewLine(new RenderLineInput(\n\t\t\tfalse,\n\t\t\ttrue,\n\t\t\tline,\n\t\t\tfalse,\n\t\t\tisBasicASCII,\n\t\t\tcontainsRTL,\n\t\t\t0,\n\t\t\tlineTokens,\n\t\t\t[],\n\t\t\ttabSize,\n\t\t\t0,\n\t\t\t0,\n\t\t\t0,\n\t\t\t0,\n\t\t\t-1,\n\t\t\t'none',\n\t\t\tfalse,\n\t\t\tfalse,\n\t\t\tnull\n\t\t));\n\n\t\thtml = html.concat(renderResult.html);\n\t\thtml.push('
    ');\n\t}\n\n\treturn html.join('');\n}\n\nfunction _actualColorize(lines: string[], tabSize: number, tokenizationSupport: ITokenizationSupport, languageIdCodec: ILanguageIdCodec): string {\n\tlet html: string[] = [];\n\tlet state = tokenizationSupport.getInitialState();\n\n\tfor (let i = 0, length = lines.length; i < length; i++) {\n\t\tconst line = lines[i];\n\t\tconst tokenizeResult = tokenizationSupport.tokenizeEncoded(line, true, state);\n\t\tLineTokens.convertToEndOffset(tokenizeResult.tokens, line.length);\n\t\tconst lineTokens = new LineTokens(tokenizeResult.tokens, line, languageIdCodec);\n\t\tconst isBasicASCII = ViewLineRenderingData.isBasicASCII(line, /* check for basic ASCII */true);\n\t\tconst containsRTL = ViewLineRenderingData.containsRTL(line, isBasicASCII, /* check for RTL */true);\n\t\tconst renderResult = renderViewLine(new RenderLineInput(\n\t\t\tfalse,\n\t\t\ttrue,\n\t\t\tline,\n\t\t\tfalse,\n\t\t\tisBasicASCII,\n\t\t\tcontainsRTL,\n\t\t\t0,\n\t\t\tlineTokens.inflate(),\n\t\t\t[],\n\t\t\ttabSize,\n\t\t\t0,\n\t\t\t0,\n\t\t\t0,\n\t\t\t0,\n\t\t\t-1,\n\t\t\t'none',\n\t\t\tfalse,\n\t\t\tfalse,\n\t\t\tnull\n\t\t));\n\n\t\thtml = html.concat(renderResult.html);\n\t\thtml.push('
    ');\n\n\t\tstate = tokenizeResult.endState;\n\t}\n\n\treturn html.join('');\n}\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\nimport { CharCode } from 'vs/base/common/charCode';\nimport { Event } from 'vs/base/common/event';\nimport { isChrome, isEdge, isFirefox, isLinux, isMacintosh, isSafari, isWeb, isWindows } from 'vs/base/common/platform';\nimport { isFalsyOrWhitespace } from 'vs/base/common/strings';\nimport { Scanner, Token, TokenType } from 'vs/platform/contextkey/common/scanner';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\nimport { localize } from 'vs/nls';\nimport { IDisposable } from 'vs/base/common/lifecycle';\n\nconst CONSTANT_VALUES = new Map();\nCONSTANT_VALUES.set('false', false);\nCONSTANT_VALUES.set('true', true);\nCONSTANT_VALUES.set('isMac', isMacintosh);\nCONSTANT_VALUES.set('isLinux', isLinux);\nCONSTANT_VALUES.set('isWindows', isWindows);\nCONSTANT_VALUES.set('isWeb', isWeb);\nCONSTANT_VALUES.set('isMacNative', isMacintosh && !isWeb);\nCONSTANT_VALUES.set('isEdge', isEdge);\nCONSTANT_VALUES.set('isFirefox', isFirefox);\nCONSTANT_VALUES.set('isChrome', isChrome);\nCONSTANT_VALUES.set('isSafari', isSafari);\n\nconst hasOwnProperty = Object.prototype.hasOwnProperty;\n\nexport const enum ContextKeyExprType {\n\tFalse = 0,\n\tTrue = 1,\n\tDefined = 2,\n\tNot = 3,\n\tEquals = 4,\n\tNotEquals = 5,\n\tAnd = 6,\n\tRegex = 7,\n\tNotRegex = 8,\n\tOr = 9,\n\tIn = 10,\n\tNotIn = 11,\n\tGreater = 12,\n\tGreaterEquals = 13,\n\tSmaller = 14,\n\tSmallerEquals = 15,\n}\n\nexport interface IContextKeyExpression {\n\n}\n\nexport type ContextKeyExpression = (\n\tContextKeyFalseExpr | ContextKeyTrueExpr | ContextKeyDefinedExpr | ContextKeyNotExpr\n\t| ContextKeyEqualsExpr | ContextKeyNotEqualsExpr | ContextKeyRegexExpr\n\t| ContextKeyNotRegexExpr | ContextKeyAndExpr | ContextKeyOrExpr | ContextKeyInExpr\n\t| ContextKeyNotInExpr | ContextKeyGreaterExpr | ContextKeyGreaterEqualsExpr\n\t| ContextKeySmallerExpr | ContextKeySmallerEqualsExpr\n);\n\n\n/*\n\nSyntax grammar:\n\n```ebnf\n\nexpression ::= or\n\nor ::= and { '||' and }*\n\nand ::= term { '&&' term }*\n\nterm ::=\n\t| '!' (KEY | true | false | parenthesized)\n\t| primary\n\nprimary ::=\n\t| 'true'\n\t| 'false'\n\t| parenthesized\n\t| KEY '=~' REGEX\n\t| KEY [ ('==' | '!=' | '<' | '<=' | '>' | '>=' | 'not' 'in' | 'in') value ]\n\nparenthesized ::=\n\t| '(' expression ')'\n\nvalue ::=\n\t| 'true'\n\t| 'false'\n\t| 'in' \t// we support `in` as a value because there's an extension that uses it, ie \"when\": \"languageId == in\"\n\t| VALUE \t\t// matched by the same regex as KEY; consider putting the value in single quotes if it's a string (e.g., with spaces)\n\t| SINGLE_QUOTED_STR\n\t| EMPTY_STR \t// this allows \"when\": \"foo == \" which's used by existing extensions\n\n```\n*/\n\nexport type ParserConfig = {\n\t/**\n\t * with this option enabled, the parser can recover from regex parsing errors, e.g., unescaped slashes: `/src//` is accepted as `/src\\//` would be\n\t */\n\tregexParsingWithErrorRecovery: boolean;\n};\n\nconst defaultConfig: ParserConfig = {\n\tregexParsingWithErrorRecovery: true\n};\n\nexport type ParsingError = {\n\tmessage: string;\n\toffset: number;\n\tlexeme: string;\n\tadditionalInfo?: string;\n};\n\nconst errorEmptyString = localize('contextkey.parser.error.emptyString', \"Empty context key expression\");\nconst hintEmptyString = localize('contextkey.parser.error.emptyString.hint', \"Did you forget to write an expression? You can also put 'false' or 'true' to always evaluate to false or true, respectively.\");\nconst errorNoInAfterNot = localize('contextkey.parser.error.noInAfterNot', \"'in' after 'not'.\");\nconst errorClosingParenthesis = localize('contextkey.parser.error.closingParenthesis', \"closing parenthesis ')'\");\nconst errorUnexpectedToken = localize('contextkey.parser.error.unexpectedToken', \"Unexpected token\");\nconst hintUnexpectedToken = localize('contextkey.parser.error.unexpectedToken.hint', \"Did you forget to put && or || before the token?\");\nconst errorUnexpectedEOF = localize('contextkey.parser.error.unexpectedEOF', \"Unexpected end of expression\");\nconst hintUnexpectedEOF = localize('contextkey.parser.error.unexpectedEOF.hint', \"Did you forget to put a context key?\");\n\n/**\n * A parser for context key expressions.\n *\n * Example:\n * ```ts\n * const parser = new Parser();\n * const expr = parser.parse('foo == \"bar\" && baz == true');\n *\n * if (expr === undefined) {\n * \t// there were lexing or parsing errors\n * \t// process lexing errors with `parser.lexingErrors`\n * // process parsing errors with `parser.parsingErrors`\n * } else {\n * \t// expr is a valid expression\n * }\n * ```\n */\nexport class Parser {\n\t// Note: this doesn't produce an exact syntax tree but a normalized one\n\t// ContextKeyExpression's that we use as AST nodes do not expose constructors that do not normalize\n\n\tprivate static _parseError = new Error();\n\n\t// lifetime note: `_scanner` lives as long as the parser does, i.e., is not reset between calls to `parse`\n\tprivate readonly _scanner = new Scanner();\n\n\t// lifetime note: `_tokens`, `_current`, and `_parsingErrors` must be reset between calls to `parse`\n\tprivate _tokens: Token[] = [];\n\tprivate _current = 0; \t\t\t\t\t// invariant: 0 <= this._current < this._tokens.length ; any incrementation of this value must first call `_isAtEnd`\n\tprivate _parsingErrors: ParsingError[] = [];\n\n\tconstructor(private readonly _config: ParserConfig = defaultConfig) {\n\t}\n\n\t/**\n\t * Parse a context key expression.\n\t *\n\t * @param input the expression to parse\n\t * @returns the parsed expression or `undefined` if there's an error - call `lexingErrors` and `parsingErrors` to see the errors\n\t */\n\tparse(input: string): ContextKeyExpression | undefined {\n\n\t\tif (input === '') {\n\t\t\tthis._parsingErrors.push({ message: errorEmptyString, offset: 0, lexeme: '', additionalInfo: hintEmptyString });\n\t\t\treturn undefined;\n\t\t}\n\n\t\tthis._tokens = this._scanner.reset(input).scan();\n\t\t// @ulugbekna: we do not stop parsing if there are lexing errors to be able to reconstruct regexes with unescaped slashes; TODO@ulugbekna: make this respect config option for recovery\n\n\t\tthis._current = 0;\n\t\tthis._parsingErrors = [];\n\n\t\ttry {\n\t\t\tconst expr = this._expr();\n\t\t\tif (!this._isAtEnd()) {\n\t\t\t\tconst peek = this._peek();\n\t\t\t\tconst additionalInfo = peek.type === TokenType.Str ? hintUnexpectedToken : undefined;\n\t\t\t\tthis._parsingErrors.push({ message: errorUnexpectedToken, offset: peek.offset, lexeme: Scanner.getLexeme(peek), additionalInfo });\n\t\t\t\tthrow Parser._parseError;\n\t\t\t}\n\t\t\treturn expr;\n\t\t} catch (e) {\n\t\t\tif (!(e === Parser._parseError)) {\n\t\t\t\tthrow e;\n\t\t\t}\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\tprivate _expr(): ContextKeyExpression | undefined {\n\t\treturn this._or();\n\t}\n\n\tprivate _or(): ContextKeyExpression | undefined {\n\t\tconst expr = [this._and()];\n\n\t\twhile (this._matchOne(TokenType.Or)) {\n\t\t\tconst right = this._and();\n\t\t\texpr.push(right);\n\t\t}\n\n\t\treturn expr.length === 1 ? expr[0] : ContextKeyExpr.or(...expr);\n\t}\n\n\tprivate _and(): ContextKeyExpression | undefined {\n\t\tconst expr = [this._term()];\n\n\t\twhile (this._matchOne(TokenType.And)) {\n\t\t\tconst right = this._term();\n\t\t\texpr.push(right);\n\t\t}\n\n\t\treturn expr.length === 1 ? expr[0] : ContextKeyExpr.and(...expr);\n\t}\n\n\tprivate _term(): ContextKeyExpression | undefined {\n\t\tif (this._matchOne(TokenType.Neg)) {\n\t\t\tconst peek = this._peek();\n\t\t\tswitch (peek.type) {\n\t\t\t\tcase TokenType.True:\n\t\t\t\t\tthis._advance();\n\t\t\t\t\treturn ContextKeyFalseExpr.INSTANCE;\n\t\t\t\tcase TokenType.False:\n\t\t\t\t\tthis._advance();\n\t\t\t\t\treturn ContextKeyTrueExpr.INSTANCE;\n\t\t\t\tcase TokenType.LParen: {\n\t\t\t\t\tthis._advance();\n\t\t\t\t\tconst expr = this._expr();\n\t\t\t\t\tthis._consume(TokenType.RParen, errorClosingParenthesis);\n\t\t\t\t\treturn expr?.negate();\n\t\t\t\t}\n\t\t\t\tcase TokenType.Str:\n\t\t\t\t\tthis._advance();\n\t\t\t\t\treturn ContextKeyNotExpr.create(peek.lexeme);\n\t\t\t\tdefault:\n\t\t\t\t\tthrow this._errExpectedButGot(`KEY | true | false | '(' expression ')'`, peek);\n\t\t\t}\n\t\t}\n\t\treturn this._primary();\n\t}\n\n\tprivate _primary(): ContextKeyExpression | undefined {\n\n\t\tconst peek = this._peek();\n\t\tswitch (peek.type) {\n\t\t\tcase TokenType.True:\n\t\t\t\tthis._advance();\n\t\t\t\treturn ContextKeyExpr.true();\n\n\t\t\tcase TokenType.False:\n\t\t\t\tthis._advance();\n\t\t\t\treturn ContextKeyExpr.false();\n\n\t\t\tcase TokenType.LParen: {\n\t\t\t\tthis._advance();\n\t\t\t\tconst expr = this._expr();\n\t\t\t\tthis._consume(TokenType.RParen, errorClosingParenthesis);\n\t\t\t\treturn expr;\n\t\t\t}\n\n\t\t\tcase TokenType.Str: {\n\t\t\t\t// KEY\n\t\t\t\tconst key = peek.lexeme;\n\t\t\t\tthis._advance();\n\n\t\t\t\t// =~ regex\n\t\t\t\tif (this._matchOne(TokenType.RegexOp)) {\n\n\t\t\t\t\t// @ulugbekna: we need to reconstruct the regex from the tokens because some extensions use unescaped slashes in regexes\n\t\t\t\t\tconst expr = this._peek();\n\n\t\t\t\t\tif (!this._config.regexParsingWithErrorRecovery) {\n\t\t\t\t\t\tthis._advance();\n\t\t\t\t\t\tif (expr.type !== TokenType.RegexStr) {\n\t\t\t\t\t\t\tthrow this._errExpectedButGot(`REGEX`, expr);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst regexLexeme = expr.lexeme;\n\t\t\t\t\t\tconst closingSlashIndex = regexLexeme.lastIndexOf('/');\n\t\t\t\t\t\tconst flags = closingSlashIndex === regexLexeme.length - 1 ? undefined : this._removeFlagsGY(regexLexeme.substring(closingSlashIndex + 1));\n\t\t\t\t\t\tlet regexp: RegExp | null;\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tregexp = new RegExp(regexLexeme.substring(1, closingSlashIndex), flags);\n\t\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\t\tthrow this._errExpectedButGot(`REGEX`, expr);\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn ContextKeyRegexExpr.create(key, regexp);\n\t\t\t\t\t}\n\n\t\t\t\t\tswitch (expr.type) {\n\t\t\t\t\t\tcase TokenType.RegexStr:\n\t\t\t\t\t\tcase TokenType.Error: { // also handle an ErrorToken in case of smth such as /(/file)/\n\t\t\t\t\t\t\tconst lexemeReconstruction = [expr.lexeme]; // /REGEX/ or /REGEX/FLAGS\n\t\t\t\t\t\t\tthis._advance();\n\n\t\t\t\t\t\t\tlet followingToken = this._peek();\n\t\t\t\t\t\t\tlet parenBalance = 0;\n\t\t\t\t\t\t\tfor (let i = 0; i < expr.lexeme.length; i++) {\n\t\t\t\t\t\t\t\tif (expr.lexeme.charCodeAt(i) === CharCode.OpenParen) {\n\t\t\t\t\t\t\t\t\tparenBalance++;\n\t\t\t\t\t\t\t\t} else if (expr.lexeme.charCodeAt(i) === CharCode.CloseParen) {\n\t\t\t\t\t\t\t\t\tparenBalance--;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\twhile (!this._isAtEnd() && followingToken.type !== TokenType.And && followingToken.type !== TokenType.Or) {\n\t\t\t\t\t\t\t\tswitch (followingToken.type) {\n\t\t\t\t\t\t\t\t\tcase TokenType.LParen:\n\t\t\t\t\t\t\t\t\t\tparenBalance++;\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\tcase TokenType.RParen:\n\t\t\t\t\t\t\t\t\t\tparenBalance--;\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\tcase TokenType.RegexStr:\n\t\t\t\t\t\t\t\t\tcase TokenType.QuotedStr:\n\t\t\t\t\t\t\t\t\t\tfor (let i = 0; i < followingToken.lexeme.length; i++) {\n\t\t\t\t\t\t\t\t\t\t\tif (followingToken.lexeme.charCodeAt(i) === CharCode.OpenParen) {\n\t\t\t\t\t\t\t\t\t\t\t\tparenBalance++;\n\t\t\t\t\t\t\t\t\t\t\t} else if (expr.lexeme.charCodeAt(i) === CharCode.CloseParen) {\n\t\t\t\t\t\t\t\t\t\t\t\tparenBalance--;\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif (parenBalance < 0) {\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tlexemeReconstruction.push(Scanner.getLexeme(followingToken));\n\t\t\t\t\t\t\t\tthis._advance();\n\t\t\t\t\t\t\t\tfollowingToken = this._peek();\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tconst regexLexeme = lexemeReconstruction.join('');\n\t\t\t\t\t\t\tconst closingSlashIndex = regexLexeme.lastIndexOf('/');\n\t\t\t\t\t\t\tconst flags = closingSlashIndex === regexLexeme.length - 1 ? undefined : this._removeFlagsGY(regexLexeme.substring(closingSlashIndex + 1));\n\t\t\t\t\t\t\tlet regexp: RegExp | null;\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tregexp = new RegExp(regexLexeme.substring(1, closingSlashIndex), flags);\n\t\t\t\t\t\t\t} catch (e) {\n\t\t\t\t\t\t\t\tthrow this._errExpectedButGot(`REGEX`, expr);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn ContextKeyExpr.regex(key, regexp);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcase TokenType.QuotedStr: {\n\t\t\t\t\t\t\tconst serializedValue = expr.lexeme;\n\t\t\t\t\t\t\tthis._advance();\n\t\t\t\t\t\t\t// replicate old regex parsing behavior\n\n\t\t\t\t\t\t\tlet regex: RegExp | null = null;\n\n\t\t\t\t\t\t\tif (!isFalsyOrWhitespace(serializedValue)) {\n\t\t\t\t\t\t\t\tconst start = serializedValue.indexOf('/');\n\t\t\t\t\t\t\t\tconst end = serializedValue.lastIndexOf('/');\n\t\t\t\t\t\t\t\tif (start !== end && start >= 0) {\n\n\t\t\t\t\t\t\t\t\tconst value = serializedValue.slice(start + 1, end);\n\t\t\t\t\t\t\t\t\tconst caseIgnoreFlag = serializedValue[end + 1] === 'i' ? 'i' : '';\n\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\tregex = new RegExp(value, caseIgnoreFlag);\n\t\t\t\t\t\t\t\t\t} catch (_e) {\n\t\t\t\t\t\t\t\t\t\tthrow this._errExpectedButGot(`REGEX`, expr);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (regex === null) {\n\t\t\t\t\t\t\t\tthrow this._errExpectedButGot('REGEX', expr);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\treturn ContextKeyRegexExpr.create(key, regex);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\tthrow this._errExpectedButGot('REGEX', this._peek());\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// [ 'not' 'in' value ]\n\t\t\t\tif (this._matchOne(TokenType.Not)) {\n\t\t\t\t\tthis._consume(TokenType.In, errorNoInAfterNot);\n\t\t\t\t\tconst right = this._value();\n\t\t\t\t\treturn ContextKeyExpr.notIn(key, right);\n\t\t\t\t}\n\n\t\t\t\t// [ ('==' | '!=' | '<' | '<=' | '>' | '>=' | 'in') value ]\n\t\t\t\tconst maybeOp = this._peek().type;\n\t\t\t\tswitch (maybeOp) {\n\t\t\t\t\tcase TokenType.Eq: {\n\t\t\t\t\t\tthis._advance();\n\n\t\t\t\t\t\tconst right = this._value();\n\t\t\t\t\t\tif (this._previous().type === TokenType.QuotedStr) { // to preserve old parser behavior: \"foo == 'true'\" is preserved as \"foo == 'true'\", but \"foo == true\" is optimized as \"foo\"\n\t\t\t\t\t\t\treturn ContextKeyExpr.equals(key, right);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tswitch (right) {\n\t\t\t\t\t\t\tcase 'true':\n\t\t\t\t\t\t\t\treturn ContextKeyExpr.has(key);\n\t\t\t\t\t\t\tcase 'false':\n\t\t\t\t\t\t\t\treturn ContextKeyExpr.not(key);\n\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\treturn ContextKeyExpr.equals(key, right);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tcase TokenType.NotEq: {\n\t\t\t\t\t\tthis._advance();\n\n\t\t\t\t\t\tconst right = this._value();\n\t\t\t\t\t\tif (this._previous().type === TokenType.QuotedStr) { // same as above with \"foo != 'true'\"\n\t\t\t\t\t\t\treturn ContextKeyExpr.notEquals(key, right);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tswitch (right) {\n\t\t\t\t\t\t\tcase 'true':\n\t\t\t\t\t\t\t\treturn ContextKeyExpr.not(key);\n\t\t\t\t\t\t\tcase 'false':\n\t\t\t\t\t\t\t\treturn ContextKeyExpr.has(key);\n\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\treturn ContextKeyExpr.notEquals(key, right);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t// TODO: ContextKeyExpr.smaller(key, right) accepts only `number` as `right` AND during eval of this node, we just eval to `false` if `right` is not a number\n\t\t\t\t\t// consequently, package.json linter should _warn_ the user if they're passing undesired things to ops\n\t\t\t\t\tcase TokenType.Lt:\n\t\t\t\t\t\tthis._advance();\n\t\t\t\t\t\treturn ContextKeySmallerExpr.create(key, this._value());\n\n\t\t\t\t\tcase TokenType.LtEq:\n\t\t\t\t\t\tthis._advance();\n\t\t\t\t\t\treturn ContextKeySmallerEqualsExpr.create(key, this._value());\n\n\t\t\t\t\tcase TokenType.Gt:\n\t\t\t\t\t\tthis._advance();\n\t\t\t\t\t\treturn ContextKeyGreaterExpr.create(key, this._value());\n\n\t\t\t\t\tcase TokenType.GtEq:\n\t\t\t\t\t\tthis._advance();\n\t\t\t\t\t\treturn ContextKeyGreaterEqualsExpr.create(key, this._value());\n\n\t\t\t\t\tcase TokenType.In:\n\t\t\t\t\t\tthis._advance();\n\t\t\t\t\t\treturn ContextKeyExpr.in(key, this._value());\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\treturn ContextKeyExpr.has(key);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tcase TokenType.EOF:\n\t\t\t\tthis._parsingErrors.push({ message: errorUnexpectedEOF, offset: peek.offset, lexeme: '', additionalInfo: hintUnexpectedEOF });\n\t\t\t\tthrow Parser._parseError;\n\n\t\t\tdefault:\n\t\t\t\tthrow this._errExpectedButGot(`true | false | KEY \\n\\t| KEY '=~' REGEX \\n\\t| KEY ('==' | '!=' | '<' | '<=' | '>' | '>=' | 'in' | 'not' 'in') value`, this._peek());\n\n\t\t}\n\t}\n\n\tprivate _value(): string {\n\t\tconst token = this._peek();\n\t\tswitch (token.type) {\n\t\t\tcase TokenType.Str:\n\t\t\tcase TokenType.QuotedStr:\n\t\t\t\tthis._advance();\n\t\t\t\treturn token.lexeme;\n\t\t\tcase TokenType.True:\n\t\t\t\tthis._advance();\n\t\t\t\treturn 'true';\n\t\t\tcase TokenType.False:\n\t\t\t\tthis._advance();\n\t\t\t\treturn 'false';\n\t\t\tcase TokenType.In: // we support `in` as a value, e.g., \"when\": \"languageId == in\" - exists in existing extensions\n\t\t\t\tthis._advance();\n\t\t\t\treturn 'in';\n\t\t\tdefault:\n\t\t\t\t// this allows \"when\": \"foo == \" which's used by existing extensions\n\t\t\t\t// we do not call `_advance` on purpose - we don't want to eat unintended tokens\n\t\t\t\treturn '';\n\t\t}\n\t}\n\n\tprivate _flagsGYRe = /g|y/g;\n\tprivate _removeFlagsGY(flags: string): string {\n\t\treturn flags.replaceAll(this._flagsGYRe, '');\n\t}\n\n\t// careful: this can throw if current token is the initial one (ie index = 0)\n\tprivate _previous() {\n\t\treturn this._tokens[this._current - 1];\n\t}\n\n\tprivate _matchOne(token: TokenType) {\n\t\tif (this._check(token)) {\n\t\t\tthis._advance();\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tprivate _advance() {\n\t\tif (!this._isAtEnd()) {\n\t\t\tthis._current++;\n\t\t}\n\t\treturn this._previous();\n\t}\n\n\tprivate _consume(type: TokenType, message: string) {\n\t\tif (this._check(type)) {\n\t\t\treturn this._advance();\n\t\t}\n\n\t\tthrow this._errExpectedButGot(message, this._peek());\n\t}\n\n\tprivate _errExpectedButGot(expected: string, got: Token, additionalInfo?: string) {\n\t\tconst message = localize('contextkey.parser.error.expectedButGot', \"Expected: {0}\\nReceived: '{1}'.\", expected, Scanner.getLexeme(got));\n\t\tconst offset = got.offset;\n\t\tconst lexeme = Scanner.getLexeme(got);\n\t\tthis._parsingErrors.push({ message, offset, lexeme, additionalInfo });\n\t\treturn Parser._parseError;\n\t}\n\n\tprivate _check(type: TokenType) {\n\t\treturn this._peek().type === type;\n\t}\n\n\tprivate _peek() {\n\t\treturn this._tokens[this._current];\n\t}\n\n\tprivate _isAtEnd() {\n\t\treturn this._peek().type === TokenType.EOF;\n\t}\n}\n\nexport abstract class ContextKeyExpr {\n\n\tpublic static false(): ContextKeyExpression {\n\t\treturn ContextKeyFalseExpr.INSTANCE;\n\t}\n\tpublic static true(): ContextKeyExpression {\n\t\treturn ContextKeyTrueExpr.INSTANCE;\n\t}\n\tpublic static has(key: string): ContextKeyExpression {\n\t\treturn ContextKeyDefinedExpr.create(key);\n\t}\n\tpublic static equals(key: string, value: any): ContextKeyExpression {\n\t\treturn ContextKeyEqualsExpr.create(key, value);\n\t}\n\tpublic static notEquals(key: string, value: any): ContextKeyExpression {\n\t\treturn ContextKeyNotEqualsExpr.create(key, value);\n\t}\n\tpublic static regex(key: string, value: RegExp): ContextKeyExpression {\n\t\treturn ContextKeyRegexExpr.create(key, value);\n\t}\n\tpublic static in(key: string, value: string): ContextKeyExpression {\n\t\treturn ContextKeyInExpr.create(key, value);\n\t}\n\tpublic static notIn(key: string, value: string): ContextKeyExpression {\n\t\treturn ContextKeyNotInExpr.create(key, value);\n\t}\n\tpublic static not(key: string): ContextKeyExpression {\n\t\treturn ContextKeyNotExpr.create(key);\n\t}\n\tpublic static and(...expr: Array): ContextKeyExpression | undefined {\n\t\treturn ContextKeyAndExpr.create(expr, null, true);\n\t}\n\tpublic static or(...expr: Array): ContextKeyExpression | undefined {\n\t\treturn ContextKeyOrExpr.create(expr, null, true);\n\t}\n\n\tprivate static _parser = new Parser({ regexParsingWithErrorRecovery: false });\n\tpublic static deserialize(serialized: string | null | undefined): ContextKeyExpression | undefined {\n\t\tif (serialized === undefined || serialized === null) { // an empty string needs to be handled by the parser to get a corresponding parsing error reported\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst expr = this._parser.parse(serialized);\n\t\treturn expr;\n\t}\n\n}\n\nexport function expressionsAreEqualWithConstantSubstitution(a: ContextKeyExpression | null | undefined, b: ContextKeyExpression | null | undefined): boolean {\n\tconst aExpr = a ? a.substituteConstants() : undefined;\n\tconst bExpr = b ? b.substituteConstants() : undefined;\n\tif (!aExpr && !bExpr) {\n\t\treturn true;\n\t}\n\tif (!aExpr || !bExpr) {\n\t\treturn false;\n\t}\n\treturn aExpr.equals(bExpr);\n}\n\nfunction cmp(a: ContextKeyExpression, b: ContextKeyExpression): number {\n\treturn a.cmp(b);\n}\n\nexport class ContextKeyFalseExpr implements IContextKeyExpression {\n\tpublic static INSTANCE = new ContextKeyFalseExpr();\n\n\tpublic readonly type = ContextKeyExprType.False;\n\n\tprotected constructor() {\n\t}\n\n\tpublic cmp(other: ContextKeyExpression): number {\n\t\treturn this.type - other.type;\n\t}\n\n\tpublic equals(other: ContextKeyExpression): boolean {\n\t\treturn (other.type === this.type);\n\t}\n\n\tpublic substituteConstants(): ContextKeyExpression | undefined {\n\t\treturn this;\n\t}\n\n\tpublic evaluate(context: IContext): boolean {\n\t\treturn false;\n\t}\n\n\tpublic serialize(): string {\n\t\treturn 'false';\n\t}\n\n\tpublic keys(): string[] {\n\t\treturn [];\n\t}\n\n\tpublic negate(): ContextKeyExpression {\n\t\treturn ContextKeyTrueExpr.INSTANCE;\n\t}\n}\n\nexport class ContextKeyTrueExpr implements IContextKeyExpression {\n\tpublic static INSTANCE = new ContextKeyTrueExpr();\n\n\tpublic readonly type = ContextKeyExprType.True;\n\n\tprotected constructor() {\n\t}\n\n\tpublic cmp(other: ContextKeyExpression): number {\n\t\treturn this.type - other.type;\n\t}\n\n\tpublic equals(other: ContextKeyExpression): boolean {\n\t\treturn (other.type === this.type);\n\t}\n\n\tpublic substituteConstants(): ContextKeyExpression | undefined {\n\t\treturn this;\n\t}\n\n\tpublic evaluate(context: IContext): boolean {\n\t\treturn true;\n\t}\n\n\tpublic serialize(): string {\n\t\treturn 'true';\n\t}\n\n\tpublic keys(): string[] {\n\t\treturn [];\n\t}\n\n\tpublic negate(): ContextKeyExpression {\n\t\treturn ContextKeyFalseExpr.INSTANCE;\n\t}\n}\n\nexport class ContextKeyDefinedExpr implements IContextKeyExpression {\n\tpublic static create(key: string, negated: ContextKeyExpression | null = null): ContextKeyExpression {\n\t\tconst constantValue = CONSTANT_VALUES.get(key);\n\t\tif (typeof constantValue === 'boolean') {\n\t\t\treturn constantValue ? ContextKeyTrueExpr.INSTANCE : ContextKeyFalseExpr.INSTANCE;\n\t\t}\n\t\treturn new ContextKeyDefinedExpr(key, negated);\n\t}\n\n\tpublic readonly type = ContextKeyExprType.Defined;\n\n\tprotected constructor(\n\t\treadonly key: string,\n\t\tprivate negated: ContextKeyExpression | null\n\t) {\n\t}\n\n\tpublic cmp(other: ContextKeyExpression): number {\n\t\tif (other.type !== this.type) {\n\t\t\treturn this.type - other.type;\n\t\t}\n\t\treturn cmp1(this.key, other.key);\n\t}\n\n\tpublic equals(other: ContextKeyExpression): boolean {\n\t\tif (other.type === this.type) {\n\t\t\treturn (this.key === other.key);\n\t\t}\n\t\treturn false;\n\t}\n\n\tpublic substituteConstants(): ContextKeyExpression | undefined {\n\t\tconst constantValue = CONSTANT_VALUES.get(this.key);\n\t\tif (typeof constantValue === 'boolean') {\n\t\t\treturn constantValue ? ContextKeyTrueExpr.INSTANCE : ContextKeyFalseExpr.INSTANCE;\n\t\t}\n\t\treturn this;\n\t}\n\n\tpublic evaluate(context: IContext): boolean {\n\t\treturn (!!context.getValue(this.key));\n\t}\n\n\tpublic serialize(): string {\n\t\treturn this.key;\n\t}\n\n\tpublic keys(): string[] {\n\t\treturn [this.key];\n\t}\n\n\tpublic negate(): ContextKeyExpression {\n\t\tif (!this.negated) {\n\t\t\tthis.negated = ContextKeyNotExpr.create(this.key, this);\n\t\t}\n\t\treturn this.negated;\n\t}\n}\n\nexport class ContextKeyEqualsExpr implements IContextKeyExpression {\n\n\tpublic static create(key: string, value: any, negated: ContextKeyExpression | null = null): ContextKeyExpression {\n\t\tif (typeof value === 'boolean') {\n\t\t\treturn (value ? ContextKeyDefinedExpr.create(key, negated) : ContextKeyNotExpr.create(key, negated));\n\t\t}\n\t\tconst constantValue = CONSTANT_VALUES.get(key);\n\t\tif (typeof constantValue === 'boolean') {\n\t\t\tconst trueValue = constantValue ? 'true' : 'false';\n\t\t\treturn (value === trueValue ? ContextKeyTrueExpr.INSTANCE : ContextKeyFalseExpr.INSTANCE);\n\t\t}\n\t\treturn new ContextKeyEqualsExpr(key, value, negated);\n\t}\n\n\tpublic readonly type = ContextKeyExprType.Equals;\n\n\tprivate constructor(\n\t\tprivate readonly key: string,\n\t\tprivate readonly value: any,\n\t\tprivate negated: ContextKeyExpression | null\n\t) {\n\t}\n\n\tpublic cmp(other: ContextKeyExpression): number {\n\t\tif (other.type !== this.type) {\n\t\t\treturn this.type - other.type;\n\t\t}\n\t\treturn cmp2(this.key, this.value, other.key, other.value);\n\t}\n\n\tpublic equals(other: ContextKeyExpression): boolean {\n\t\tif (other.type === this.type) {\n\t\t\treturn (this.key === other.key && this.value === other.value);\n\t\t}\n\t\treturn false;\n\t}\n\n\tpublic substituteConstants(): ContextKeyExpression | undefined {\n\t\tconst constantValue = CONSTANT_VALUES.get(this.key);\n\t\tif (typeof constantValue === 'boolean') {\n\t\t\tconst trueValue = constantValue ? 'true' : 'false';\n\t\t\treturn (this.value === trueValue ? ContextKeyTrueExpr.INSTANCE : ContextKeyFalseExpr.INSTANCE);\n\t\t}\n\t\treturn this;\n\t}\n\n\tpublic evaluate(context: IContext): boolean {\n\t\t// Intentional ==\n\t\t// eslint-disable-next-line eqeqeq\n\t\treturn (context.getValue(this.key) == this.value);\n\t}\n\n\tpublic serialize(): string {\n\t\treturn `${this.key} == '${this.value}'`;\n\t}\n\n\tpublic keys(): string[] {\n\t\treturn [this.key];\n\t}\n\n\tpublic negate(): ContextKeyExpression {\n\t\tif (!this.negated) {\n\t\t\tthis.negated = ContextKeyNotEqualsExpr.create(this.key, this.value, this);\n\t\t}\n\t\treturn this.negated;\n\t}\n}\n\nexport class ContextKeyInExpr implements IContextKeyExpression {\n\n\tpublic static create(key: string, valueKey: string): ContextKeyInExpr {\n\t\treturn new ContextKeyInExpr(key, valueKey);\n\t}\n\n\tpublic readonly type = ContextKeyExprType.In;\n\tprivate negated: ContextKeyExpression | null = null;\n\n\tprivate constructor(\n\t\tprivate readonly key: string,\n\t\tprivate readonly valueKey: string,\n\t) {\n\t}\n\n\tpublic cmp(other: ContextKeyExpression): number {\n\t\tif (other.type !== this.type) {\n\t\t\treturn this.type - other.type;\n\t\t}\n\t\treturn cmp2(this.key, this.valueKey, other.key, other.valueKey);\n\t}\n\n\tpublic equals(other: ContextKeyExpression): boolean {\n\t\tif (other.type === this.type) {\n\t\t\treturn (this.key === other.key && this.valueKey === other.valueKey);\n\t\t}\n\t\treturn false;\n\t}\n\n\tpublic substituteConstants(): ContextKeyExpression | undefined {\n\t\treturn this;\n\t}\n\n\tpublic evaluate(context: IContext): boolean {\n\t\tconst source = context.getValue(this.valueKey);\n\n\t\tconst item = context.getValue(this.key);\n\n\t\tif (Array.isArray(source)) {\n\t\t\treturn source.includes(item as any);\n\t\t}\n\n\t\tif (typeof item === 'string' && typeof source === 'object' && source !== null) {\n\t\t\treturn hasOwnProperty.call(source, item);\n\t\t}\n\t\treturn false;\n\t}\n\n\tpublic serialize(): string {\n\t\treturn `${this.key} in '${this.valueKey}'`;\n\t}\n\n\tpublic keys(): string[] {\n\t\treturn [this.key, this.valueKey];\n\t}\n\n\tpublic negate(): ContextKeyExpression {\n\t\tif (!this.negated) {\n\t\t\tthis.negated = ContextKeyNotInExpr.create(this.key, this.valueKey);\n\t\t}\n\t\treturn this.negated;\n\t}\n}\n\nexport class ContextKeyNotInExpr implements IContextKeyExpression {\n\n\tpublic static create(key: string, valueKey: string): ContextKeyNotInExpr {\n\t\treturn new ContextKeyNotInExpr(key, valueKey);\n\t}\n\n\tpublic readonly type = ContextKeyExprType.NotIn;\n\n\tprivate readonly _negated: ContextKeyInExpr;\n\n\tprivate constructor(\n\t\tprivate readonly key: string,\n\t\tprivate readonly valueKey: string,\n\t) {\n\t\tthis._negated = ContextKeyInExpr.create(key, valueKey);\n\t}\n\n\tpublic cmp(other: ContextKeyExpression): number {\n\t\tif (other.type !== this.type) {\n\t\t\treturn this.type - other.type;\n\t\t}\n\t\treturn this._negated.cmp(other._negated);\n\t}\n\n\tpublic equals(other: ContextKeyExpression): boolean {\n\t\tif (other.type === this.type) {\n\t\t\treturn this._negated.equals(other._negated);\n\t\t}\n\t\treturn false;\n\t}\n\n\tpublic substituteConstants(): ContextKeyExpression | undefined {\n\t\treturn this;\n\t}\n\n\tpublic evaluate(context: IContext): boolean {\n\t\treturn !this._negated.evaluate(context);\n\t}\n\n\tpublic serialize(): string {\n\t\treturn `${this.key} not in '${this.valueKey}'`;\n\t}\n\n\tpublic keys(): string[] {\n\t\treturn this._negated.keys();\n\t}\n\n\tpublic negate(): ContextKeyExpression {\n\t\treturn this._negated;\n\t}\n}\n\nexport class ContextKeyNotEqualsExpr implements IContextKeyExpression {\n\n\tpublic static create(key: string, value: any, negated: ContextKeyExpression | null = null): ContextKeyExpression {\n\t\tif (typeof value === 'boolean') {\n\t\t\tif (value) {\n\t\t\t\treturn ContextKeyNotExpr.create(key, negated);\n\t\t\t}\n\t\t\treturn ContextKeyDefinedExpr.create(key, negated);\n\t\t}\n\t\tconst constantValue = CONSTANT_VALUES.get(key);\n\t\tif (typeof constantValue === 'boolean') {\n\t\t\tconst falseValue = constantValue ? 'true' : 'false';\n\t\t\treturn (value === falseValue ? ContextKeyFalseExpr.INSTANCE : ContextKeyTrueExpr.INSTANCE);\n\t\t}\n\t\treturn new ContextKeyNotEqualsExpr(key, value, negated);\n\t}\n\n\tpublic readonly type = ContextKeyExprType.NotEquals;\n\n\tprivate constructor(\n\t\tprivate readonly key: string,\n\t\tprivate readonly value: any,\n\t\tprivate negated: ContextKeyExpression | null\n\t) {\n\t}\n\n\tpublic cmp(other: ContextKeyExpression): number {\n\t\tif (other.type !== this.type) {\n\t\t\treturn this.type - other.type;\n\t\t}\n\t\treturn cmp2(this.key, this.value, other.key, other.value);\n\t}\n\n\tpublic equals(other: ContextKeyExpression): boolean {\n\t\tif (other.type === this.type) {\n\t\t\treturn (this.key === other.key && this.value === other.value);\n\t\t}\n\t\treturn false;\n\t}\n\n\tpublic substituteConstants(): ContextKeyExpression | undefined {\n\t\tconst constantValue = CONSTANT_VALUES.get(this.key);\n\t\tif (typeof constantValue === 'boolean') {\n\t\t\tconst falseValue = constantValue ? 'true' : 'false';\n\t\t\treturn (this.value === falseValue ? ContextKeyFalseExpr.INSTANCE : ContextKeyTrueExpr.INSTANCE);\n\t\t}\n\t\treturn this;\n\t}\n\n\tpublic evaluate(context: IContext): boolean {\n\t\t// Intentional !=\n\t\t// eslint-disable-next-line eqeqeq\n\t\treturn (context.getValue(this.key) != this.value);\n\t}\n\n\tpublic serialize(): string {\n\t\treturn `${this.key} != '${this.value}'`;\n\t}\n\n\tpublic keys(): string[] {\n\t\treturn [this.key];\n\t}\n\n\tpublic negate(): ContextKeyExpression {\n\t\tif (!this.negated) {\n\t\t\tthis.negated = ContextKeyEqualsExpr.create(this.key, this.value, this);\n\t\t}\n\t\treturn this.negated;\n\t}\n}\n\nexport class ContextKeyNotExpr implements IContextKeyExpression {\n\n\tpublic static create(key: string, negated: ContextKeyExpression | null = null): ContextKeyExpression {\n\t\tconst constantValue = CONSTANT_VALUES.get(key);\n\t\tif (typeof constantValue === 'boolean') {\n\t\t\treturn (constantValue ? ContextKeyFalseExpr.INSTANCE : ContextKeyTrueExpr.INSTANCE);\n\t\t}\n\t\treturn new ContextKeyNotExpr(key, negated);\n\t}\n\n\tpublic readonly type = ContextKeyExprType.Not;\n\n\tprivate constructor(\n\t\tprivate readonly key: string,\n\t\tprivate negated: ContextKeyExpression | null\n\t) {\n\t}\n\n\tpublic cmp(other: ContextKeyExpression): number {\n\t\tif (other.type !== this.type) {\n\t\t\treturn this.type - other.type;\n\t\t}\n\t\treturn cmp1(this.key, other.key);\n\t}\n\n\tpublic equals(other: ContextKeyExpression): boolean {\n\t\tif (other.type === this.type) {\n\t\t\treturn (this.key === other.key);\n\t\t}\n\t\treturn false;\n\t}\n\n\tpublic substituteConstants(): ContextKeyExpression | undefined {\n\t\tconst constantValue = CONSTANT_VALUES.get(this.key);\n\t\tif (typeof constantValue === 'boolean') {\n\t\t\treturn (constantValue ? ContextKeyFalseExpr.INSTANCE : ContextKeyTrueExpr.INSTANCE);\n\t\t}\n\t\treturn this;\n\t}\n\n\tpublic evaluate(context: IContext): boolean {\n\t\treturn (!context.getValue(this.key));\n\t}\n\n\tpublic serialize(): string {\n\t\treturn `!${this.key}`;\n\t}\n\n\tpublic keys(): string[] {\n\t\treturn [this.key];\n\t}\n\n\tpublic negate(): ContextKeyExpression {\n\t\tif (!this.negated) {\n\t\t\tthis.negated = ContextKeyDefinedExpr.create(this.key, this);\n\t\t}\n\t\treturn this.negated;\n\t}\n}\n\nfunction withFloatOrStr(value: any, callback: (value: number | string) => T): T | ContextKeyFalseExpr {\n\tif (typeof value === 'string') {\n\t\tconst n = parseFloat(value);\n\t\tif (!isNaN(n)) {\n\t\t\tvalue = n;\n\t\t}\n\t}\n\tif (typeof value === 'string' || typeof value === 'number') {\n\t\treturn callback(value);\n\t}\n\treturn ContextKeyFalseExpr.INSTANCE;\n}\n\nexport class ContextKeyGreaterExpr implements IContextKeyExpression {\n\n\tpublic static create(key: string, _value: any, negated: ContextKeyExpression | null = null): ContextKeyExpression {\n\t\treturn withFloatOrStr(_value, (value) => new ContextKeyGreaterExpr(key, value, negated));\n\t}\n\n\tpublic readonly type = ContextKeyExprType.Greater;\n\n\tprivate constructor(\n\t\tprivate readonly key: string,\n\t\tprivate readonly value: number | string,\n\t\tprivate negated: ContextKeyExpression | null\n\t) { }\n\n\tpublic cmp(other: ContextKeyExpression): number {\n\t\tif (other.type !== this.type) {\n\t\t\treturn this.type - other.type;\n\t\t}\n\t\treturn cmp2(this.key, this.value, other.key, other.value);\n\t}\n\n\tpublic equals(other: ContextKeyExpression): boolean {\n\t\tif (other.type === this.type) {\n\t\t\treturn (this.key === other.key && this.value === other.value);\n\t\t}\n\t\treturn false;\n\t}\n\n\tpublic substituteConstants(): ContextKeyExpression | undefined {\n\t\treturn this;\n\t}\n\n\tpublic evaluate(context: IContext): boolean {\n\t\tif (typeof this.value === 'string') {\n\t\t\treturn false;\n\t\t}\n\t\treturn (parseFloat(context.getValue(this.key)) > this.value);\n\t}\n\n\tpublic serialize(): string {\n\t\treturn `${this.key} > ${this.value}`;\n\t}\n\n\tpublic keys(): string[] {\n\t\treturn [this.key];\n\t}\n\n\tpublic negate(): ContextKeyExpression {\n\t\tif (!this.negated) {\n\t\t\tthis.negated = ContextKeySmallerEqualsExpr.create(this.key, this.value, this);\n\t\t}\n\t\treturn this.negated;\n\t}\n}\n\nexport class ContextKeyGreaterEqualsExpr implements IContextKeyExpression {\n\n\tpublic static create(key: string, _value: any, negated: ContextKeyExpression | null = null): ContextKeyExpression {\n\t\treturn withFloatOrStr(_value, (value) => new ContextKeyGreaterEqualsExpr(key, value, negated));\n\t}\n\n\tpublic readonly type = ContextKeyExprType.GreaterEquals;\n\n\tprivate constructor(\n\t\tprivate readonly key: string,\n\t\tprivate readonly value: number | string,\n\t\tprivate negated: ContextKeyExpression | null\n\t) { }\n\n\tpublic cmp(other: ContextKeyExpression): number {\n\t\tif (other.type !== this.type) {\n\t\t\treturn this.type - other.type;\n\t\t}\n\t\treturn cmp2(this.key, this.value, other.key, other.value);\n\t}\n\n\tpublic equals(other: ContextKeyExpression): boolean {\n\t\tif (other.type === this.type) {\n\t\t\treturn (this.key === other.key && this.value === other.value);\n\t\t}\n\t\treturn false;\n\t}\n\n\tpublic substituteConstants(): ContextKeyExpression | undefined {\n\t\treturn this;\n\t}\n\n\tpublic evaluate(context: IContext): boolean {\n\t\tif (typeof this.value === 'string') {\n\t\t\treturn false;\n\t\t}\n\t\treturn (parseFloat(context.getValue(this.key)) >= this.value);\n\t}\n\n\tpublic serialize(): string {\n\t\treturn `${this.key} >= ${this.value}`;\n\t}\n\n\tpublic keys(): string[] {\n\t\treturn [this.key];\n\t}\n\n\tpublic negate(): ContextKeyExpression {\n\t\tif (!this.negated) {\n\t\t\tthis.negated = ContextKeySmallerExpr.create(this.key, this.value, this);\n\t\t}\n\t\treturn this.negated;\n\t}\n}\n\nexport class ContextKeySmallerExpr implements IContextKeyExpression {\n\n\tpublic static create(key: string, _value: any, negated: ContextKeyExpression | null = null): ContextKeyExpression {\n\t\treturn withFloatOrStr(_value, (value) => new ContextKeySmallerExpr(key, value, negated));\n\t}\n\n\tpublic readonly type = ContextKeyExprType.Smaller;\n\n\tprivate constructor(\n\t\tprivate readonly key: string,\n\t\tprivate readonly value: number | string,\n\t\tprivate negated: ContextKeyExpression | null\n\t) {\n\t}\n\n\tpublic cmp(other: ContextKeyExpression): number {\n\t\tif (other.type !== this.type) {\n\t\t\treturn this.type - other.type;\n\t\t}\n\t\treturn cmp2(this.key, this.value, other.key, other.value);\n\t}\n\n\tpublic equals(other: ContextKeyExpression): boolean {\n\t\tif (other.type === this.type) {\n\t\t\treturn (this.key === other.key && this.value === other.value);\n\t\t}\n\t\treturn false;\n\t}\n\n\tpublic substituteConstants(): ContextKeyExpression | undefined {\n\t\treturn this;\n\t}\n\n\tpublic evaluate(context: IContext): boolean {\n\t\tif (typeof this.value === 'string') {\n\t\t\treturn false;\n\t\t}\n\t\treturn (parseFloat(context.getValue(this.key)) < this.value);\n\t}\n\n\tpublic serialize(): string {\n\t\treturn `${this.key} < ${this.value}`;\n\t}\n\n\tpublic keys(): string[] {\n\t\treturn [this.key];\n\t}\n\n\tpublic negate(): ContextKeyExpression {\n\t\tif (!this.negated) {\n\t\t\tthis.negated = ContextKeyGreaterEqualsExpr.create(this.key, this.value, this);\n\t\t}\n\t\treturn this.negated;\n\t}\n}\n\nexport class ContextKeySmallerEqualsExpr implements IContextKeyExpression {\n\n\tpublic static create(key: string, _value: any, negated: ContextKeyExpression | null = null): ContextKeyExpression {\n\t\treturn withFloatOrStr(_value, (value) => new ContextKeySmallerEqualsExpr(key, value, negated));\n\t}\n\n\tpublic readonly type = ContextKeyExprType.SmallerEquals;\n\n\tprivate constructor(\n\t\tprivate readonly key: string,\n\t\tprivate readonly value: number | string,\n\t\tprivate negated: ContextKeyExpression | null\n\t) {\n\t}\n\n\tpublic cmp(other: ContextKeyExpression): number {\n\t\tif (other.type !== this.type) {\n\t\t\treturn this.type - other.type;\n\t\t}\n\t\treturn cmp2(this.key, this.value, other.key, other.value);\n\t}\n\n\tpublic equals(other: ContextKeyExpression): boolean {\n\t\tif (other.type === this.type) {\n\t\t\treturn (this.key === other.key && this.value === other.value);\n\t\t}\n\t\treturn false;\n\t}\n\n\tpublic substituteConstants(): ContextKeyExpression | undefined {\n\t\treturn this;\n\t}\n\n\tpublic evaluate(context: IContext): boolean {\n\t\tif (typeof this.value === 'string') {\n\t\t\treturn false;\n\t\t}\n\t\treturn (parseFloat(context.getValue(this.key)) <= this.value);\n\t}\n\n\tpublic serialize(): string {\n\t\treturn `${this.key} <= ${this.value}`;\n\t}\n\n\tpublic keys(): string[] {\n\t\treturn [this.key];\n\t}\n\n\tpublic negate(): ContextKeyExpression {\n\t\tif (!this.negated) {\n\t\t\tthis.negated = ContextKeyGreaterExpr.create(this.key, this.value, this);\n\t\t}\n\t\treturn this.negated;\n\t}\n}\n\nexport class ContextKeyRegexExpr implements IContextKeyExpression {\n\n\tpublic static create(key: string, regexp: RegExp | null): ContextKeyRegexExpr {\n\t\treturn new ContextKeyRegexExpr(key, regexp);\n\t}\n\n\tpublic readonly type = ContextKeyExprType.Regex;\n\tprivate negated: ContextKeyExpression | null = null;\n\n\tprivate constructor(\n\t\tprivate readonly key: string,\n\t\tprivate readonly regexp: RegExp | null\n\t) {\n\t\t//\n\t}\n\n\tpublic cmp(other: ContextKeyExpression): number {\n\t\tif (other.type !== this.type) {\n\t\t\treturn this.type - other.type;\n\t\t}\n\t\tif (this.key < other.key) {\n\t\t\treturn -1;\n\t\t}\n\t\tif (this.key > other.key) {\n\t\t\treturn 1;\n\t\t}\n\t\tconst thisSource = this.regexp ? this.regexp.source : '';\n\t\tconst otherSource = other.regexp ? other.regexp.source : '';\n\t\tif (thisSource < otherSource) {\n\t\t\treturn -1;\n\t\t}\n\t\tif (thisSource > otherSource) {\n\t\t\treturn 1;\n\t\t}\n\t\treturn 0;\n\t}\n\n\tpublic equals(other: ContextKeyExpression): boolean {\n\t\tif (other.type === this.type) {\n\t\t\tconst thisSource = this.regexp ? this.regexp.source : '';\n\t\t\tconst otherSource = other.regexp ? other.regexp.source : '';\n\t\t\treturn (this.key === other.key && thisSource === otherSource);\n\t\t}\n\t\treturn false;\n\t}\n\n\tpublic substituteConstants(): ContextKeyExpression | undefined {\n\t\treturn this;\n\t}\n\n\tpublic evaluate(context: IContext): boolean {\n\t\tconst value = context.getValue(this.key);\n\t\treturn this.regexp ? this.regexp.test(value) : false;\n\t}\n\n\tpublic serialize(): string {\n\t\tconst value = this.regexp\n\t\t\t? `/${this.regexp.source}/${this.regexp.flags}`\n\t\t\t: '/invalid/';\n\t\treturn `${this.key} =~ ${value}`;\n\t}\n\n\tpublic keys(): string[] {\n\t\treturn [this.key];\n\t}\n\n\tpublic negate(): ContextKeyExpression {\n\t\tif (!this.negated) {\n\t\t\tthis.negated = ContextKeyNotRegexExpr.create(this);\n\t\t}\n\t\treturn this.negated;\n\t}\n}\n\nexport class ContextKeyNotRegexExpr implements IContextKeyExpression {\n\n\tpublic static create(actual: ContextKeyRegexExpr): ContextKeyExpression {\n\t\treturn new ContextKeyNotRegexExpr(actual);\n\t}\n\n\tpublic readonly type = ContextKeyExprType.NotRegex;\n\n\tprivate constructor(private readonly _actual: ContextKeyRegexExpr) {\n\t\t//\n\t}\n\n\tpublic cmp(other: ContextKeyExpression): number {\n\t\tif (other.type !== this.type) {\n\t\t\treturn this.type - other.type;\n\t\t}\n\t\treturn this._actual.cmp(other._actual);\n\t}\n\n\tpublic equals(other: ContextKeyExpression): boolean {\n\t\tif (other.type === this.type) {\n\t\t\treturn this._actual.equals(other._actual);\n\t\t}\n\t\treturn false;\n\t}\n\n\tpublic substituteConstants(): ContextKeyExpression | undefined {\n\t\treturn this;\n\t}\n\n\tpublic evaluate(context: IContext): boolean {\n\t\treturn !this._actual.evaluate(context);\n\t}\n\n\tpublic serialize(): string {\n\t\treturn `!(${this._actual.serialize()})`;\n\t}\n\n\tpublic keys(): string[] {\n\t\treturn this._actual.keys();\n\t}\n\n\tpublic negate(): ContextKeyExpression {\n\t\treturn this._actual;\n\t}\n}\n\n/**\n * @returns the same instance if nothing changed.\n */\nfunction eliminateConstantsInArray(arr: ContextKeyExpression[]): (ContextKeyExpression | undefined)[] {\n\t// Allocate array only if there is a difference\n\tlet newArr: (ContextKeyExpression | undefined)[] | null = null;\n\tfor (let i = 0, len = arr.length; i < len; i++) {\n\t\tconst newExpr = arr[i].substituteConstants();\n\n\t\tif (arr[i] !== newExpr) {\n\t\t\t// something has changed!\n\n\t\t\t// allocate array on first difference\n\t\t\tif (newArr === null) {\n\t\t\t\tnewArr = [];\n\t\t\t\tfor (let j = 0; j < i; j++) {\n\t\t\t\t\tnewArr[j] = arr[j];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (newArr !== null) {\n\t\t\tnewArr[i] = newExpr;\n\t\t}\n\t}\n\n\tif (newArr === null) {\n\t\treturn arr;\n\t}\n\treturn newArr;\n}\n\nexport class ContextKeyAndExpr implements IContextKeyExpression {\n\n\tpublic static create(_expr: ReadonlyArray, negated: ContextKeyExpression | null, extraRedundantCheck: boolean): ContextKeyExpression | undefined {\n\t\treturn ContextKeyAndExpr._normalizeArr(_expr, negated, extraRedundantCheck);\n\t}\n\n\tpublic readonly type = ContextKeyExprType.And;\n\n\tprivate constructor(\n\t\tpublic readonly expr: ContextKeyExpression[],\n\t\tprivate negated: ContextKeyExpression | null\n\t) {\n\t}\n\n\tpublic cmp(other: ContextKeyExpression): number {\n\t\tif (other.type !== this.type) {\n\t\t\treturn this.type - other.type;\n\t\t}\n\t\tif (this.expr.length < other.expr.length) {\n\t\t\treturn -1;\n\t\t}\n\t\tif (this.expr.length > other.expr.length) {\n\t\t\treturn 1;\n\t\t}\n\t\tfor (let i = 0, len = this.expr.length; i < len; i++) {\n\t\t\tconst r = cmp(this.expr[i], other.expr[i]);\n\t\t\tif (r !== 0) {\n\t\t\t\treturn r;\n\t\t\t}\n\t\t}\n\t\treturn 0;\n\t}\n\n\tpublic equals(other: ContextKeyExpression): boolean {\n\t\tif (other.type === this.type) {\n\t\t\tif (this.expr.length !== other.expr.length) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tfor (let i = 0, len = this.expr.length; i < len; i++) {\n\t\t\t\tif (!this.expr[i].equals(other.expr[i])) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tpublic substituteConstants(): ContextKeyExpression | undefined {\n\t\tconst exprArr = eliminateConstantsInArray(this.expr);\n\t\tif (exprArr === this.expr) {\n\t\t\t// no change\n\t\t\treturn this;\n\t\t}\n\t\treturn ContextKeyAndExpr.create(exprArr, this.negated, false);\n\t}\n\n\tpublic evaluate(context: IContext): boolean {\n\t\tfor (let i = 0, len = this.expr.length; i < len; i++) {\n\t\t\tif (!this.expr[i].evaluate(context)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\tprivate static _normalizeArr(arr: ReadonlyArray, negated: ContextKeyExpression | null, extraRedundantCheck: boolean): ContextKeyExpression | undefined {\n\t\tconst expr: ContextKeyExpression[] = [];\n\t\tlet hasTrue = false;\n\n\t\tfor (const e of arr) {\n\t\t\tif (!e) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (e.type === ContextKeyExprType.True) {\n\t\t\t\t// anything && true ==> anything\n\t\t\t\thasTrue = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (e.type === ContextKeyExprType.False) {\n\t\t\t\t// anything && false ==> false\n\t\t\t\treturn ContextKeyFalseExpr.INSTANCE;\n\t\t\t}\n\n\t\t\tif (e.type === ContextKeyExprType.And) {\n\t\t\t\texpr.push(...e.expr);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\texpr.push(e);\n\t\t}\n\n\t\tif (expr.length === 0 && hasTrue) {\n\t\t\treturn ContextKeyTrueExpr.INSTANCE;\n\t\t}\n\n\t\tif (expr.length === 0) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (expr.length === 1) {\n\t\t\treturn expr[0];\n\t\t}\n\n\t\texpr.sort(cmp);\n\n\t\t// eliminate duplicate terms\n\t\tfor (let i = 1; i < expr.length; i++) {\n\t\t\tif (expr[i - 1].equals(expr[i])) {\n\t\t\t\texpr.splice(i, 1);\n\t\t\t\ti--;\n\t\t\t}\n\t\t}\n\n\t\tif (expr.length === 1) {\n\t\t\treturn expr[0];\n\t\t}\n\n\t\t// We must distribute any OR expression because we don't support parens\n\t\t// OR extensions will be at the end (due to sorting rules)\n\t\twhile (expr.length > 1) {\n\t\t\tconst lastElement = expr[expr.length - 1];\n\t\t\tif (lastElement.type !== ContextKeyExprType.Or) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t// pop the last element\n\t\t\texpr.pop();\n\n\t\t\t// pop the second to last element\n\t\t\tconst secondToLastElement = expr.pop()!;\n\n\t\t\tconst isFinished = (expr.length === 0);\n\n\t\t\t// distribute `lastElement` over `secondToLastElement`\n\t\t\tconst resultElement = ContextKeyOrExpr.create(\n\t\t\t\tlastElement.expr.map(el => ContextKeyAndExpr.create([el, secondToLastElement], null, extraRedundantCheck)),\n\t\t\t\tnull,\n\t\t\t\tisFinished\n\t\t\t);\n\n\t\t\tif (resultElement) {\n\t\t\t\texpr.push(resultElement);\n\t\t\t\texpr.sort(cmp);\n\t\t\t}\n\t\t}\n\n\t\tif (expr.length === 1) {\n\t\t\treturn expr[0];\n\t\t}\n\n\t\t// resolve false AND expressions\n\t\tif (extraRedundantCheck) {\n\t\t\tfor (let i = 0; i < expr.length; i++) {\n\t\t\t\tfor (let j = i + 1; j < expr.length; j++) {\n\t\t\t\t\tif (expr[i].negate().equals(expr[j])) {\n\t\t\t\t\t\t// A && !A case\n\t\t\t\t\t\treturn ContextKeyFalseExpr.INSTANCE;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (expr.length === 1) {\n\t\t\t\treturn expr[0];\n\t\t\t}\n\t\t}\n\n\t\treturn new ContextKeyAndExpr(expr, negated);\n\t}\n\n\tpublic serialize(): string {\n\t\treturn this.expr.map(e => e.serialize()).join(' && ');\n\t}\n\n\tpublic keys(): string[] {\n\t\tconst result: string[] = [];\n\t\tfor (const expr of this.expr) {\n\t\t\tresult.push(...expr.keys());\n\t\t}\n\t\treturn result;\n\t}\n\n\tpublic negate(): ContextKeyExpression {\n\t\tif (!this.negated) {\n\t\t\tconst result: ContextKeyExpression[] = [];\n\t\t\tfor (const expr of this.expr) {\n\t\t\t\tresult.push(expr.negate());\n\t\t\t}\n\t\t\tthis.negated = ContextKeyOrExpr.create(result, this, true)!;\n\t\t}\n\t\treturn this.negated;\n\t}\n}\n\nexport class ContextKeyOrExpr implements IContextKeyExpression {\n\n\tpublic static create(_expr: ReadonlyArray, negated: ContextKeyExpression | null, extraRedundantCheck: boolean): ContextKeyExpression | undefined {\n\t\treturn ContextKeyOrExpr._normalizeArr(_expr, negated, extraRedundantCheck);\n\t}\n\n\tpublic readonly type = ContextKeyExprType.Or;\n\n\tprivate constructor(\n\t\tpublic readonly expr: ContextKeyExpression[],\n\t\tprivate negated: ContextKeyExpression | null\n\t) {\n\t}\n\n\tpublic cmp(other: ContextKeyExpression): number {\n\t\tif (other.type !== this.type) {\n\t\t\treturn this.type - other.type;\n\t\t}\n\t\tif (this.expr.length < other.expr.length) {\n\t\t\treturn -1;\n\t\t}\n\t\tif (this.expr.length > other.expr.length) {\n\t\t\treturn 1;\n\t\t}\n\t\tfor (let i = 0, len = this.expr.length; i < len; i++) {\n\t\t\tconst r = cmp(this.expr[i], other.expr[i]);\n\t\t\tif (r !== 0) {\n\t\t\t\treturn r;\n\t\t\t}\n\t\t}\n\t\treturn 0;\n\t}\n\n\tpublic equals(other: ContextKeyExpression): boolean {\n\t\tif (other.type === this.type) {\n\t\t\tif (this.expr.length !== other.expr.length) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tfor (let i = 0, len = this.expr.length; i < len; i++) {\n\t\t\t\tif (!this.expr[i].equals(other.expr[i])) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tpublic substituteConstants(): ContextKeyExpression | undefined {\n\t\tconst exprArr = eliminateConstantsInArray(this.expr);\n\t\tif (exprArr === this.expr) {\n\t\t\t// no change\n\t\t\treturn this;\n\t\t}\n\t\treturn ContextKeyOrExpr.create(exprArr, this.negated, false);\n\t}\n\n\tpublic evaluate(context: IContext): boolean {\n\t\tfor (let i = 0, len = this.expr.length; i < len; i++) {\n\t\t\tif (this.expr[i].evaluate(context)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate static _normalizeArr(arr: ReadonlyArray, negated: ContextKeyExpression | null, extraRedundantCheck: boolean): ContextKeyExpression | undefined {\n\t\tlet expr: ContextKeyExpression[] = [];\n\t\tlet hasFalse = false;\n\n\t\tif (arr) {\n\t\t\tfor (let i = 0, len = arr.length; i < len; i++) {\n\t\t\t\tconst e = arr[i];\n\t\t\t\tif (!e) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (e.type === ContextKeyExprType.False) {\n\t\t\t\t\t// anything || false ==> anything\n\t\t\t\t\thasFalse = true;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (e.type === ContextKeyExprType.True) {\n\t\t\t\t\t// anything || true ==> true\n\t\t\t\t\treturn ContextKeyTrueExpr.INSTANCE;\n\t\t\t\t}\n\n\t\t\t\tif (e.type === ContextKeyExprType.Or) {\n\t\t\t\t\texpr = expr.concat(e.expr);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\texpr.push(e);\n\t\t\t}\n\n\t\t\tif (expr.length === 0 && hasFalse) {\n\t\t\t\treturn ContextKeyFalseExpr.INSTANCE;\n\t\t\t}\n\n\t\t\texpr.sort(cmp);\n\t\t}\n\n\t\tif (expr.length === 0) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (expr.length === 1) {\n\t\t\treturn expr[0];\n\t\t}\n\n\t\t// eliminate duplicate terms\n\t\tfor (let i = 1; i < expr.length; i++) {\n\t\t\tif (expr[i - 1].equals(expr[i])) {\n\t\t\t\texpr.splice(i, 1);\n\t\t\t\ti--;\n\t\t\t}\n\t\t}\n\n\t\tif (expr.length === 1) {\n\t\t\treturn expr[0];\n\t\t}\n\n\t\t// resolve true OR expressions\n\t\tif (extraRedundantCheck) {\n\t\t\tfor (let i = 0; i < expr.length; i++) {\n\t\t\t\tfor (let j = i + 1; j < expr.length; j++) {\n\t\t\t\t\tif (expr[i].negate().equals(expr[j])) {\n\t\t\t\t\t\t// A || !A case\n\t\t\t\t\t\treturn ContextKeyTrueExpr.INSTANCE;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (expr.length === 1) {\n\t\t\t\treturn expr[0];\n\t\t\t}\n\t\t}\n\n\t\treturn new ContextKeyOrExpr(expr, negated);\n\t}\n\n\tpublic serialize(): string {\n\t\treturn this.expr.map(e => e.serialize()).join(' || ');\n\t}\n\n\tpublic keys(): string[] {\n\t\tconst result: string[] = [];\n\t\tfor (const expr of this.expr) {\n\t\t\tresult.push(...expr.keys());\n\t\t}\n\t\treturn result;\n\t}\n\n\tpublic negate(): ContextKeyExpression {\n\t\tif (!this.negated) {\n\t\t\tconst result: ContextKeyExpression[] = [];\n\t\t\tfor (const expr of this.expr) {\n\t\t\t\tresult.push(expr.negate());\n\t\t\t}\n\n\t\t\t// We don't support parens, so here we distribute the AND over the OR terminals\n\t\t\t// We always take the first 2 AND pairs and distribute them\n\t\t\twhile (result.length > 1) {\n\t\t\t\tconst LEFT = result.shift()!;\n\t\t\t\tconst RIGHT = result.shift()!;\n\n\t\t\t\tconst all: ContextKeyExpression[] = [];\n\t\t\t\tfor (const left of getTerminals(LEFT)) {\n\t\t\t\t\tfor (const right of getTerminals(RIGHT)) {\n\t\t\t\t\t\tall.push(ContextKeyAndExpr.create([left, right], null, false)!);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tresult.unshift(ContextKeyOrExpr.create(all, null, false)!);\n\t\t\t}\n\n\t\t\tthis.negated = ContextKeyOrExpr.create(result, this, true)!;\n\t\t}\n\t\treturn this.negated;\n\t}\n}\n\nexport interface ContextKeyInfo {\n\treadonly key: string;\n\treadonly type?: string;\n\treadonly description?: string;\n}\n\nexport class RawContextKey extends ContextKeyDefinedExpr {\n\n\tprivate static _info: ContextKeyInfo[] = [];\n\n\tstatic all(): IterableIterator {\n\t\treturn RawContextKey._info.values();\n\t}\n\n\tprivate readonly _defaultValue: T | undefined;\n\n\tconstructor(key: string, defaultValue: T | undefined, metaOrHide?: string | true | { type: string; description: string }) {\n\t\tsuper(key, null);\n\t\tthis._defaultValue = defaultValue;\n\n\t\t// collect all context keys into a central place\n\t\tif (typeof metaOrHide === 'object') {\n\t\t\tRawContextKey._info.push({ ...metaOrHide, key });\n\t\t} else if (metaOrHide !== true) {\n\t\t\tRawContextKey._info.push({ key, description: metaOrHide, type: defaultValue !== null && defaultValue !== undefined ? typeof defaultValue : undefined });\n\t\t}\n\t}\n\n\tpublic bindTo(target: IContextKeyService): IContextKey {\n\t\treturn target.createKey(this.key, this._defaultValue);\n\t}\n\n\tpublic getValue(target: IContextKeyService): T | undefined {\n\t\treturn target.getContextKeyValue(this.key);\n\t}\n\n\tpublic toNegated(): ContextKeyExpression {\n\t\treturn this.negate();\n\t}\n\n\tpublic isEqualTo(value: any): ContextKeyExpression {\n\t\treturn ContextKeyEqualsExpr.create(this.key, value);\n\t}\n}\n\nexport type ContextKeyValue = null | undefined | boolean | number | string\n\t| Array\n\t| Record;\n\nexport interface IContext {\n\tgetValue(key: string): T | undefined;\n}\n\nexport interface IContextKey {\n\tset(value: T): void;\n\treset(): void;\n\tget(): T | undefined;\n}\n\nexport interface IContextKeyServiceTarget {\n\tparentElement: IContextKeyServiceTarget | null;\n\tsetAttribute(attr: string, value: string): void;\n\tremoveAttribute(attr: string): void;\n\thasAttribute(attr: string): boolean;\n\tgetAttribute(attr: string): string | null;\n}\n\nexport const IContextKeyService = createDecorator('contextKeyService');\n\nexport interface IReadableSet {\n\thas(value: T): boolean;\n}\n\nexport interface IContextKeyChangeEvent {\n\taffectsSome(keys: IReadableSet): boolean;\n\tallKeysContainedIn(keys: IReadableSet): boolean;\n}\n\nexport type IScopedContextKeyService = IContextKeyService & IDisposable;\n\nexport interface IContextKeyService {\n\treadonly _serviceBrand: undefined;\n\n\tonDidChangeContext: Event;\n\tbufferChangeEvents(callback: Function): void;\n\n\tcreateKey(key: string, defaultValue: T | undefined): IContextKey;\n\tcontextMatchesRules(rules: ContextKeyExpression | undefined): boolean;\n\tgetContextKeyValue(key: string): T | undefined;\n\n\tcreateScoped(target: IContextKeyServiceTarget): IScopedContextKeyService;\n\tgetContext(target: IContextKeyServiceTarget | null): IContext;\n}\n\nfunction cmp1(key1: string, key2: string): number {\n\tif (key1 < key2) {\n\t\treturn -1;\n\t}\n\tif (key1 > key2) {\n\t\treturn 1;\n\t}\n\treturn 0;\n}\n\nfunction cmp2(key1: string, value1: any, key2: string, value2: any): number {\n\tif (key1 < key2) {\n\t\treturn -1;\n\t}\n\tif (key1 > key2) {\n\t\treturn 1;\n\t}\n\tif (value1 < value2) {\n\t\treturn -1;\n\t}\n\tif (value1 > value2) {\n\t\treturn 1;\n\t}\n\treturn 0;\n}\n\n/**\n * Returns true if it is provable `p` implies `q`.\n */\nexport function implies(p: ContextKeyExpression, q: ContextKeyExpression): boolean {\n\n\tif (p.type === ContextKeyExprType.False || q.type === ContextKeyExprType.True) {\n\t\t// false implies anything\n\t\t// anything implies true\n\t\treturn true;\n\t}\n\n\tif (p.type === ContextKeyExprType.Or) {\n\t\tif (q.type === ContextKeyExprType.Or) {\n\t\t\t// `a || b || c` can only imply something like `a || b || c || d`\n\t\t\treturn allElementsIncluded(p.expr, q.expr);\n\t\t}\n\t\treturn false;\n\t}\n\n\tif (q.type === ContextKeyExprType.Or) {\n\t\tfor (const element of q.expr) {\n\t\t\tif (implies(p, element)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tif (p.type === ContextKeyExprType.And) {\n\t\tif (q.type === ContextKeyExprType.And) {\n\t\t\t// `a && b && c` implies `a && c`\n\t\t\treturn allElementsIncluded(q.expr, p.expr);\n\t\t}\n\t\tfor (const element of p.expr) {\n\t\t\tif (implies(element, q)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\treturn p.equals(q);\n}\n\n/**\n * Returns true if all elements in `p` are also present in `q`.\n * The two arrays are assumed to be sorted\n */\nfunction allElementsIncluded(p: ContextKeyExpression[], q: ContextKeyExpression[]): boolean {\n\tlet pIndex = 0;\n\tlet qIndex = 0;\n\twhile (pIndex < p.length && qIndex < q.length) {\n\t\tconst cmp = p[pIndex].cmp(q[qIndex]);\n\n\t\tif (cmp < 0) {\n\t\t\t// an element from `p` is missing from `q`\n\t\t\treturn false;\n\t\t} else if (cmp === 0) {\n\t\t\tpIndex++;\n\t\t\tqIndex++;\n\t\t} else {\n\t\t\tqIndex++;\n\t\t}\n\t}\n\treturn (pIndex === p.length);\n}\n\nfunction getTerminals(node: ContextKeyExpression) {\n\tif (node.type === ContextKeyExprType.Or) {\n\t\treturn node.expr;\n\t}\n\treturn [node];\n}\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\nimport * as nls from 'vs/nls';\nimport { RawContextKey } from 'vs/platform/contextkey/common/contextkey';\n\nexport namespace EditorContextKeys {\n\n\texport const editorSimpleInput = new RawContextKey('editorSimpleInput', false, true);\n\t/**\n\t * A context key that is set when the editor's text has focus (cursor is blinking).\n\t * Is false when focus is in simple editor widgets (repl input, scm commit input).\n\t */\n\texport const editorTextFocus = new RawContextKey('editorTextFocus', false, nls.localize('editorTextFocus', \"Whether the editor text has focus (cursor is blinking)\"));\n\t/**\n\t * A context key that is set when the editor's text or an editor's widget has focus.\n\t */\n\texport const focus = new RawContextKey('editorFocus', false, nls.localize('editorFocus', \"Whether the editor or an editor widget has focus (e.g. focus is in the find widget)\"));\n\n\t/**\n\t * A context key that is set when any editor input has focus (regular editor, repl input...).\n\t */\n\texport const textInputFocus = new RawContextKey('textInputFocus', false, nls.localize('textInputFocus', \"Whether an editor or a rich text input has focus (cursor is blinking)\"));\n\n\texport const readOnly = new RawContextKey('editorReadonly', false, nls.localize('editorReadonly', \"Whether the editor is read-only\"));\n\texport const inDiffEditor = new RawContextKey('inDiffEditor', false, nls.localize('inDiffEditor', \"Whether the context is a diff editor\"));\n\texport const isEmbeddedDiffEditor = new RawContextKey('isEmbeddedDiffEditor', false, nls.localize('isEmbeddedDiffEditor', \"Whether the context is an embedded diff editor\"));\n\texport const inMultiDiffEditor = new RawContextKey('inMultiDiffEditor', false, nls.localize('inMultiDiffEditor', \"Whether the context is a multi diff editor\"));\n\texport const multiDiffEditorAllCollapsed = new RawContextKey('multiDiffEditorAllCollapsed', undefined, nls.localize('multiDiffEditorAllCollapsed', \"Whether all files in multi diff editor are collapsed\"));\n\texport const hasChanges = new RawContextKey('diffEditorHasChanges', false, nls.localize('diffEditorHasChanges', \"Whether the diff editor has changes\"));\n\texport const comparingMovedCode = new RawContextKey('comparingMovedCode', false, nls.localize('comparingMovedCode', \"Whether a moved code block is selected for comparison\"));\n\texport const accessibleDiffViewerVisible = new RawContextKey('accessibleDiffViewerVisible', false, nls.localize('accessibleDiffViewerVisible', \"Whether the accessible diff viewer is visible\"));\n\texport const diffEditorRenderSideBySideInlineBreakpointReached = new RawContextKey('diffEditorRenderSideBySideInlineBreakpointReached', false, nls.localize('diffEditorRenderSideBySideInlineBreakpointReached', \"Whether the diff editor render side by side inline breakpoint is reached\"));\n\texport const diffEditorInlineMode = new RawContextKey('diffEditorInlineMode', false, nls.localize('diffEditorInlineMode', \"Whether inline mode is active\"));\n\n\texport const diffEditorOriginalWritable = new RawContextKey('diffEditorOriginalWritable', false, nls.localize('diffEditorOriginalWritable', \"Whether modified is writable in the diff editor\"));\n\texport const diffEditorModifiedWritable = new RawContextKey('diffEditorModifiedWritable', false, nls.localize('diffEditorModifiedWritable', \"Whether modified is writable in the diff editor\"));\n\texport const diffEditorOriginalUri = new RawContextKey('diffEditorOriginalUri', '', nls.localize('diffEditorOriginalUri', \"The uri of the original document\"));\n\texport const diffEditorModifiedUri = new RawContextKey('diffEditorModifiedUri', '', nls.localize('diffEditorModifiedUri', \"The uri of the modified document\"));\n\n\texport const columnSelection = new RawContextKey('editorColumnSelection', false, nls.localize('editorColumnSelection', \"Whether `editor.columnSelection` is enabled\"));\n\texport const writable = readOnly.toNegated();\n\texport const hasNonEmptySelection = new RawContextKey('editorHasSelection', false, nls.localize('editorHasSelection', \"Whether the editor has text selected\"));\n\texport const hasOnlyEmptySelection = hasNonEmptySelection.toNegated();\n\texport const hasMultipleSelections = new RawContextKey('editorHasMultipleSelections', false, nls.localize('editorHasMultipleSelections', \"Whether the editor has multiple selections\"));\n\texport const hasSingleSelection = hasMultipleSelections.toNegated();\n\texport const tabMovesFocus = new RawContextKey('editorTabMovesFocus', false, nls.localize('editorTabMovesFocus', \"Whether `Tab` will move focus out of the editor\"));\n\texport const tabDoesNotMoveFocus = tabMovesFocus.toNegated();\n\texport const isInEmbeddedEditor = new RawContextKey('isInEmbeddedEditor', false, true);\n\texport const canUndo = new RawContextKey('canUndo', false, true);\n\texport const canRedo = new RawContextKey('canRedo', false, true);\n\n\texport const hoverVisible = new RawContextKey('editorHoverVisible', false, nls.localize('editorHoverVisible', \"Whether the editor hover is visible\"));\n\texport const hoverFocused = new RawContextKey('editorHoverFocused', false, nls.localize('editorHoverFocused', \"Whether the editor hover is focused\"));\n\n\texport const stickyScrollFocused = new RawContextKey('stickyScrollFocused', false, nls.localize('stickyScrollFocused', \"Whether the sticky scroll is focused\"));\n\texport const stickyScrollVisible = new RawContextKey('stickyScrollVisible', false, nls.localize('stickyScrollVisible', \"Whether the sticky scroll is visible\"));\n\n\texport const standaloneColorPickerVisible = new RawContextKey('standaloneColorPickerVisible', false, nls.localize('standaloneColorPickerVisible', \"Whether the standalone color picker is visible\"));\n\texport const standaloneColorPickerFocused = new RawContextKey('standaloneColorPickerFocused', false, nls.localize('standaloneColorPickerFocused', \"Whether the standalone color picker is focused\"));\n\t/**\n\t * A context key that is set when an editor is part of a larger editor, like notebooks or\n\t * (future) a diff editor\n\t */\n\texport const inCompositeEditor = new RawContextKey('inCompositeEditor', undefined, nls.localize('inCompositeEditor', \"Whether the editor is part of a larger editor (e.g. notebooks)\"));\n\texport const notInCompositeEditor = inCompositeEditor.toNegated();\n\n\t// -- mode context keys\n\texport const languageId = new RawContextKey('editorLangId', '', nls.localize('editorLangId', \"The language identifier of the editor\"));\n\texport const hasCompletionItemProvider = new RawContextKey('editorHasCompletionItemProvider', false, nls.localize('editorHasCompletionItemProvider', \"Whether the editor has a completion item provider\"));\n\texport const hasCodeActionsProvider = new RawContextKey('editorHasCodeActionsProvider', false, nls.localize('editorHasCodeActionsProvider', \"Whether the editor has a code actions provider\"));\n\texport const hasCodeLensProvider = new RawContextKey('editorHasCodeLensProvider', false, nls.localize('editorHasCodeLensProvider', \"Whether the editor has a code lens provider\"));\n\texport const hasDefinitionProvider = new RawContextKey('editorHasDefinitionProvider', false, nls.localize('editorHasDefinitionProvider', \"Whether the editor has a definition provider\"));\n\texport const hasDeclarationProvider = new RawContextKey('editorHasDeclarationProvider', false, nls.localize('editorHasDeclarationProvider', \"Whether the editor has a declaration provider\"));\n\texport const hasImplementationProvider = new RawContextKey('editorHasImplementationProvider', false, nls.localize('editorHasImplementationProvider', \"Whether the editor has an implementation provider\"));\n\texport const hasTypeDefinitionProvider = new RawContextKey('editorHasTypeDefinitionProvider', false, nls.localize('editorHasTypeDefinitionProvider', \"Whether the editor has a type definition provider\"));\n\texport const hasHoverProvider = new RawContextKey('editorHasHoverProvider', false, nls.localize('editorHasHoverProvider', \"Whether the editor has a hover provider\"));\n\texport const hasDocumentHighlightProvider = new RawContextKey('editorHasDocumentHighlightProvider', false, nls.localize('editorHasDocumentHighlightProvider', \"Whether the editor has a document highlight provider\"));\n\texport const hasDocumentSymbolProvider = new RawContextKey('editorHasDocumentSymbolProvider', false, nls.localize('editorHasDocumentSymbolProvider', \"Whether the editor has a document symbol provider\"));\n\texport const hasReferenceProvider = new RawContextKey('editorHasReferenceProvider', false, nls.localize('editorHasReferenceProvider', \"Whether the editor has a reference provider\"));\n\texport const hasRenameProvider = new RawContextKey('editorHasRenameProvider', false, nls.localize('editorHasRenameProvider', \"Whether the editor has a rename provider\"));\n\texport const hasSignatureHelpProvider = new RawContextKey('editorHasSignatureHelpProvider', false, nls.localize('editorHasSignatureHelpProvider', \"Whether the editor has a signature help provider\"));\n\texport const hasInlayHintsProvider = new RawContextKey('editorHasInlayHintsProvider', false, nls.localize('editorHasInlayHintsProvider', \"Whether the editor has an inline hints provider\"));\n\n\t// -- mode context keys: formatting\n\texport const hasDocumentFormattingProvider = new RawContextKey('editorHasDocumentFormattingProvider', false, nls.localize('editorHasDocumentFormattingProvider', \"Whether the editor has a document formatting provider\"));\n\texport const hasDocumentSelectionFormattingProvider = new RawContextKey('editorHasDocumentSelectionFormattingProvider', false, nls.localize('editorHasDocumentSelectionFormattingProvider', \"Whether the editor has a document selection formatting provider\"));\n\texport const hasMultipleDocumentFormattingProvider = new RawContextKey('editorHasMultipleDocumentFormattingProvider', false, nls.localize('editorHasMultipleDocumentFormattingProvider', \"Whether the editor has multiple document formatting providers\"));\n\texport const hasMultipleDocumentSelectionFormattingProvider = new RawContextKey('editorHasMultipleDocumentSelectionFormattingProvider', false, nls.localize('editorHasMultipleDocumentSelectionFormattingProvider', \"Whether the editor has multiple document selection formatting providers\"));\n\n}\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\nimport { IObservable, autorun } from 'vs/base/common/observable';\nimport { firstNonWhitespaceIndex } from 'vs/base/common/strings';\nimport { CursorColumns } from 'vs/editor/common/core/cursorColumns';\nimport { InlineCompletionsModel } from 'vs/editor/contrib/inlineCompletions/browser/inlineCompletionsModel';\nimport { RawContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport { localize } from 'vs/nls';\n\nexport class InlineCompletionContextKeys extends Disposable {\n\tpublic static readonly inlineSuggestionVisible = new RawContextKey('inlineSuggestionVisible', false, localize('inlineSuggestionVisible', \"Whether an inline suggestion is visible\"));\n\tpublic static readonly inlineSuggestionHasIndentation = new RawContextKey('inlineSuggestionHasIndentation', false, localize('inlineSuggestionHasIndentation', \"Whether the inline suggestion starts with whitespace\"));\n\tpublic static readonly inlineSuggestionHasIndentationLessThanTabSize = new RawContextKey('inlineSuggestionHasIndentationLessThanTabSize', true, localize('inlineSuggestionHasIndentationLessThanTabSize', \"Whether the inline suggestion starts with whitespace that is less than what would be inserted by tab\"));\n\tpublic static readonly suppressSuggestions = new RawContextKey('inlineSuggestionSuppressSuggestions', undefined, localize('suppressSuggestions', \"Whether suggestions should be suppressed for the current suggestion\"));\n\n\tpublic readonly inlineCompletionVisible = InlineCompletionContextKeys.inlineSuggestionVisible.bindTo(this.contextKeyService);\n\tpublic readonly inlineCompletionSuggestsIndentation = InlineCompletionContextKeys.inlineSuggestionHasIndentation.bindTo(this.contextKeyService);\n\tpublic readonly inlineCompletionSuggestsIndentationLessThanTabSize = InlineCompletionContextKeys.inlineSuggestionHasIndentationLessThanTabSize.bindTo(this.contextKeyService);\n\tpublic readonly suppressSuggestions = InlineCompletionContextKeys.suppressSuggestions.bindTo(this.contextKeyService);\n\n\tconstructor(\n\t\tprivate readonly contextKeyService: IContextKeyService,\n\t\tprivate readonly model: IObservable,\n\t) {\n\t\tsuper();\n\n\t\tthis._register(autorun(reader => {\n\t\t\t/** @description update context key: inlineCompletionVisible, suppressSuggestions */\n\t\t\tconst model = this.model.read(reader);\n\t\t\tconst state = model?.state.read(reader);\n\n\t\t\tconst isInlineCompletionVisible = !!state?.inlineCompletion && state?.primaryGhostText !== undefined && !state?.primaryGhostText.isEmpty();\n\t\t\tthis.inlineCompletionVisible.set(isInlineCompletionVisible);\n\n\t\t\tif (state?.primaryGhostText && state?.inlineCompletion) {\n\t\t\t\tthis.suppressSuggestions.set(state.inlineCompletion.inlineCompletion.source.inlineCompletions.suppressSuggestions);\n\t\t\t}\n\t\t}));\n\n\t\tthis._register(autorun(reader => {\n\t\t\t/** @description update context key: inlineCompletionSuggestsIndentation, inlineCompletionSuggestsIndentationLessThanTabSize */\n\t\t\tconst model = this.model.read(reader);\n\n\t\t\tlet startsWithIndentation = false;\n\t\t\tlet startsWithIndentationLessThanTabSize = true;\n\n\t\t\tconst ghostText = model?.primaryGhostText.read(reader);\n\t\t\tif (!!model?.selectedSuggestItem && ghostText && ghostText.parts.length > 0) {\n\t\t\t\tconst { column, lines } = ghostText.parts[0];\n\n\t\t\t\tconst firstLine = lines[0];\n\n\t\t\t\tconst indentationEndColumn = model.textModel.getLineIndentColumn(ghostText.lineNumber);\n\t\t\t\tconst inIndentation = column <= indentationEndColumn;\n\n\t\t\t\tif (inIndentation) {\n\t\t\t\t\tlet firstNonWsIdx = firstNonWhitespaceIndex(firstLine);\n\t\t\t\t\tif (firstNonWsIdx === -1) {\n\t\t\t\t\t\tfirstNonWsIdx = firstLine.length - 1;\n\t\t\t\t\t}\n\t\t\t\t\tstartsWithIndentation = firstNonWsIdx > 0;\n\n\t\t\t\t\tconst tabSize = model.textModel.getOptions().tabSize;\n\t\t\t\t\tconst visibleColumnIndentation = CursorColumns.visibleColumnFromColumn(firstLine, firstNonWsIdx + 1, tabSize);\n\t\t\t\t\tstartsWithIndentationLessThanTabSize = visibleColumnIndentation < tabSize;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.inlineCompletionSuggestsIndentation.set(startsWithIndentation);\n\t\t\tthis.inlineCompletionSuggestsIndentationLessThanTabSize.set(startsWithIndentationLessThanTabSize);\n\t\t}));\n\t}\n}\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\nimport { CancellationToken } from 'vs/base/common/cancellation';\nimport { onUnexpectedExternalError } from 'vs/base/common/errors';\nimport { assertType } from 'vs/base/common/types';\nimport { URI } from 'vs/base/common/uri';\nimport { IPosition, Position } from 'vs/editor/common/core/position';\nimport { LanguageFeatureRegistry } from 'vs/editor/common/languageFeatureRegistry';\nimport * as languages from 'vs/editor/common/languages';\nimport { ITextModel } from 'vs/editor/common/model';\nimport { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';\nimport { ITextModelService } from 'vs/editor/common/services/resolverService';\nimport { CommandsRegistry } from 'vs/platform/commands/common/commands';\nimport { RawContextKey } from 'vs/platform/contextkey/common/contextkey';\n\nexport const Context = {\n\tVisible: new RawContextKey('parameterHintsVisible', false),\n\tMultipleSignatures: new RawContextKey('parameterHintsMultipleSignatures', false),\n};\n\nexport async function provideSignatureHelp(\n\tregistry: LanguageFeatureRegistry,\n\tmodel: ITextModel,\n\tposition: Position,\n\tcontext: languages.SignatureHelpContext,\n\ttoken: CancellationToken\n): Promise {\n\n\tconst supports = registry.ordered(model);\n\n\tfor (const support of supports) {\n\t\ttry {\n\t\t\tconst result = await support.provideSignatureHelp(model, position, token, context);\n\t\t\tif (result) {\n\t\t\t\treturn result;\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tonUnexpectedExternalError(err);\n\t\t}\n\t}\n\treturn undefined;\n}\n\nCommandsRegistry.registerCommand('_executeSignatureHelpProvider', async (accessor, ...args: [URI, IPosition, string?]) => {\n\tconst [uri, position, triggerCharacter] = args;\n\tassertType(URI.isUri(uri));\n\tassertType(Position.isIPosition(position));\n\tassertType(typeof triggerCharacter === 'string' || !triggerCharacter);\n\n\tconst languageFeaturesService = accessor.get(ILanguageFeaturesService);\n\n\tconst ref = await accessor.get(ITextModelService).createModelReference(uri);\n\ttry {\n\n\t\tconst result = await provideSignatureHelp(languageFeaturesService.signatureHelpProvider, ref.object.textEditorModel, Position.lift(position), {\n\t\t\ttriggerKind: languages.SignatureHelpTriggerKind.Invoke,\n\t\t\tisRetrigger: false,\n\t\t\ttriggerCharacter,\n\t\t}, CancellationToken.None);\n\n\t\tif (!result) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tsetTimeout(() => result.dispose(), 0);\n\t\treturn result.value;\n\n\t} finally {\n\t\tref.dispose();\n\t}\n});\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\nimport { CancelablePromise, createCancelablePromise, Delayer } from 'vs/base/common/async';\nimport { onUnexpectedError } from 'vs/base/common/errors';\nimport { Emitter } from 'vs/base/common/event';\nimport { Disposable, MutableDisposable } from 'vs/base/common/lifecycle';\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\nimport { CharacterSet } from 'vs/editor/common/core/characterClassifier';\nimport { ICursorSelectionChangedEvent } from 'vs/editor/common/cursorEvents';\nimport { LanguageFeatureRegistry } from 'vs/editor/common/languageFeatureRegistry';\nimport * as languages from 'vs/editor/common/languages';\nimport { provideSignatureHelp } from 'vs/editor/contrib/parameterHints/browser/provideSignatureHelp';\n\nexport interface TriggerContext {\n\treadonly triggerKind: languages.SignatureHelpTriggerKind;\n\treadonly triggerCharacter?: string;\n}\n\nnamespace ParameterHintState {\n\texport const enum Type {\n\t\tDefault,\n\t\tActive,\n\t\tPending,\n\t}\n\n\texport const Default = { type: Type.Default } as const;\n\n\texport class Pending {\n\t\treadonly type = Type.Pending;\n\t\tconstructor(\n\t\t\treadonly request: CancelablePromise,\n\t\t\treadonly previouslyActiveHints: languages.SignatureHelp | undefined,\n\t\t) { }\n\t}\n\n\texport class Active {\n\t\treadonly type = Type.Active;\n\t\tconstructor(\n\t\t\treadonly hints: languages.SignatureHelp\n\t\t) { }\n\t}\n\n\texport type State = typeof Default | Pending | Active;\n}\n\nexport class ParameterHintsModel extends Disposable {\n\n\tprivate static readonly DEFAULT_DELAY = 120; // ms\n\n\tprivate readonly _onChangedHints = this._register(new Emitter());\n\tpublic readonly onChangedHints = this._onChangedHints.event;\n\n\tprivate readonly editor: ICodeEditor;\n\tprivate readonly providers: LanguageFeatureRegistry;\n\n\tprivate triggerOnType = false;\n\tprivate _state: ParameterHintState.State = ParameterHintState.Default;\n\tprivate _pendingTriggers: TriggerContext[] = [];\n\n\tprivate readonly _lastSignatureHelpResult = this._register(new MutableDisposable());\n\tprivate readonly triggerChars = new CharacterSet();\n\tprivate readonly retriggerChars = new CharacterSet();\n\n\tprivate readonly throttledDelayer: Delayer;\n\tprivate triggerId = 0;\n\n\tconstructor(\n\t\teditor: ICodeEditor,\n\t\tproviders: LanguageFeatureRegistry,\n\t\tdelay: number = ParameterHintsModel.DEFAULT_DELAY\n\t) {\n\t\tsuper();\n\n\t\tthis.editor = editor;\n\t\tthis.providers = providers;\n\n\t\tthis.throttledDelayer = new Delayer(delay);\n\n\t\tthis._register(this.editor.onDidBlurEditorWidget(() => this.cancel()));\n\t\tthis._register(this.editor.onDidChangeConfiguration(() => this.onEditorConfigurationChange()));\n\t\tthis._register(this.editor.onDidChangeModel(e => this.onModelChanged()));\n\t\tthis._register(this.editor.onDidChangeModelLanguage(_ => this.onModelChanged()));\n\t\tthis._register(this.editor.onDidChangeCursorSelection(e => this.onCursorChange(e)));\n\t\tthis._register(this.editor.onDidChangeModelContent(e => this.onModelContentChange()));\n\t\tthis._register(this.providers.onDidChange(this.onModelChanged, this));\n\t\tthis._register(this.editor.onDidType(text => this.onDidType(text)));\n\n\t\tthis.onEditorConfigurationChange();\n\t\tthis.onModelChanged();\n\t}\n\n\tprivate get state() { return this._state; }\n\tprivate set state(value: ParameterHintState.State) {\n\t\tif (this._state.type === ParameterHintState.Type.Pending) {\n\t\t\tthis._state.request.cancel();\n\t\t}\n\t\tthis._state = value;\n\t}\n\n\tcancel(silent: boolean = false): void {\n\t\tthis.state = ParameterHintState.Default;\n\n\t\tthis.throttledDelayer.cancel();\n\n\t\tif (!silent) {\n\t\t\tthis._onChangedHints.fire(undefined);\n\t\t}\n\t}\n\n\ttrigger(context: TriggerContext, delay?: number): void {\n\t\tconst model = this.editor.getModel();\n\t\tif (!model || !this.providers.has(model)) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst triggerId = ++this.triggerId;\n\n\t\tthis._pendingTriggers.push(context);\n\t\tthis.throttledDelayer.trigger(() => {\n\t\t\treturn this.doTrigger(triggerId);\n\t\t}, delay)\n\t\t\t.catch(onUnexpectedError);\n\t}\n\n\tpublic next(): void {\n\t\tif (this.state.type !== ParameterHintState.Type.Active) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst length = this.state.hints.signatures.length;\n\t\tconst activeSignature = this.state.hints.activeSignature;\n\t\tconst last = (activeSignature % length) === (length - 1);\n\t\tconst cycle = this.editor.getOption(EditorOption.parameterHints).cycle;\n\n\t\t// If there is only one signature, or we're on last signature of list\n\t\tif ((length < 2 || last) && !cycle) {\n\t\t\tthis.cancel();\n\t\t\treturn;\n\t\t}\n\n\t\tthis.updateActiveSignature(last && cycle ? 0 : activeSignature + 1);\n\t}\n\n\tpublic previous(): void {\n\t\tif (this.state.type !== ParameterHintState.Type.Active) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst length = this.state.hints.signatures.length;\n\t\tconst activeSignature = this.state.hints.activeSignature;\n\t\tconst first = activeSignature === 0;\n\t\tconst cycle = this.editor.getOption(EditorOption.parameterHints).cycle;\n\n\t\t// If there is only one signature, or we're on first signature of list\n\t\tif ((length < 2 || first) && !cycle) {\n\t\t\tthis.cancel();\n\t\t\treturn;\n\t\t}\n\n\t\tthis.updateActiveSignature(first && cycle ? length - 1 : activeSignature - 1);\n\t}\n\n\tprivate updateActiveSignature(activeSignature: number) {\n\t\tif (this.state.type !== ParameterHintState.Type.Active) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.state = new ParameterHintState.Active({ ...this.state.hints, activeSignature });\n\t\tthis._onChangedHints.fire(this.state.hints);\n\t}\n\n\tprivate async doTrigger(triggerId: number): Promise {\n\t\tconst isRetrigger = this.state.type === ParameterHintState.Type.Active || this.state.type === ParameterHintState.Type.Pending;\n\t\tconst activeSignatureHelp = this.getLastActiveHints();\n\t\tthis.cancel(true);\n\n\t\tif (this._pendingTriggers.length === 0) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst context: TriggerContext = this._pendingTriggers.reduce(mergeTriggerContexts);\n\t\tthis._pendingTriggers = [];\n\n\t\tconst triggerContext = {\n\t\t\ttriggerKind: context.triggerKind,\n\t\t\ttriggerCharacter: context.triggerCharacter,\n\t\t\tisRetrigger: isRetrigger,\n\t\t\tactiveSignatureHelp: activeSignatureHelp\n\t\t};\n\n\t\tif (!this.editor.hasModel()) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst model = this.editor.getModel();\n\t\tconst position = this.editor.getPosition();\n\n\t\tthis.state = new ParameterHintState.Pending(\n\t\t\tcreateCancelablePromise(token => provideSignatureHelp(this.providers, model, position, triggerContext, token)),\n\t\t\tactiveSignatureHelp);\n\n\t\ttry {\n\t\t\tconst result = await this.state.request;\n\n\t\t\t// Check that we are still resolving the correct signature help\n\t\t\tif (triggerId !== this.triggerId) {\n\t\t\t\tresult?.dispose();\n\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (!result || !result.value.signatures || result.value.signatures.length === 0) {\n\t\t\t\tresult?.dispose();\n\t\t\t\tthis._lastSignatureHelpResult.clear();\n\t\t\t\tthis.cancel();\n\t\t\t\treturn false;\n\t\t\t} else {\n\t\t\t\tthis.state = new ParameterHintState.Active(result.value);\n\t\t\t\tthis._lastSignatureHelpResult.value = result;\n\t\t\t\tthis._onChangedHints.fire(this.state.hints);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tif (triggerId === this.triggerId) {\n\t\t\t\tthis.state = ParameterHintState.Default;\n\t\t\t}\n\t\t\tonUnexpectedError(error);\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tprivate getLastActiveHints(): languages.SignatureHelp | undefined {\n\t\tswitch (this.state.type) {\n\t\t\tcase ParameterHintState.Type.Active: return this.state.hints;\n\t\t\tcase ParameterHintState.Type.Pending: return this.state.previouslyActiveHints;\n\t\t\tdefault: return undefined;\n\t\t}\n\t}\n\n\tprivate get isTriggered(): boolean {\n\t\treturn this.state.type === ParameterHintState.Type.Active\n\t\t\t|| this.state.type === ParameterHintState.Type.Pending\n\t\t\t|| this.throttledDelayer.isTriggered();\n\t}\n\n\tprivate onModelChanged(): void {\n\t\tthis.cancel();\n\n\t\tthis.triggerChars.clear();\n\t\tthis.retriggerChars.clear();\n\n\t\tconst model = this.editor.getModel();\n\t\tif (!model) {\n\t\t\treturn;\n\t\t}\n\n\t\tfor (const support of this.providers.ordered(model)) {\n\t\t\tfor (const ch of support.signatureHelpTriggerCharacters || []) {\n\t\t\t\tif (ch.length) {\n\t\t\t\t\tconst charCode = ch.charCodeAt(0);\n\t\t\t\t\tthis.triggerChars.add(charCode);\n\n\t\t\t\t\t// All trigger characters are also considered retrigger characters\n\t\t\t\t\tthis.retriggerChars.add(charCode);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (const ch of support.signatureHelpRetriggerCharacters || []) {\n\t\t\t\tif (ch.length) {\n\t\t\t\t\tthis.retriggerChars.add(ch.charCodeAt(0));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate onDidType(text: string) {\n\t\tif (!this.triggerOnType) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst lastCharIndex = text.length - 1;\n\t\tconst triggerCharCode = text.charCodeAt(lastCharIndex);\n\n\t\tif (this.triggerChars.has(triggerCharCode) || this.isTriggered && this.retriggerChars.has(triggerCharCode)) {\n\t\t\tthis.trigger({\n\t\t\t\ttriggerKind: languages.SignatureHelpTriggerKind.TriggerCharacter,\n\t\t\t\ttriggerCharacter: text.charAt(lastCharIndex),\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate onCursorChange(e: ICursorSelectionChangedEvent): void {\n\t\tif (e.source === 'mouse') {\n\t\t\tthis.cancel();\n\t\t} else if (this.isTriggered) {\n\t\t\tthis.trigger({ triggerKind: languages.SignatureHelpTriggerKind.ContentChange });\n\t\t}\n\t}\n\n\tprivate onModelContentChange(): void {\n\t\tif (this.isTriggered) {\n\t\t\tthis.trigger({ triggerKind: languages.SignatureHelpTriggerKind.ContentChange });\n\t\t}\n\t}\n\n\tprivate onEditorConfigurationChange(): void {\n\t\tthis.triggerOnType = this.editor.getOption(EditorOption.parameterHints).enabled;\n\n\t\tif (!this.triggerOnType) {\n\t\t\tthis.cancel();\n\t\t}\n\t}\n\n\toverride dispose(): void {\n\t\tthis.cancel(true);\n\t\tsuper.dispose();\n\t}\n}\n\nfunction mergeTriggerContexts(previous: TriggerContext, current: TriggerContext) {\n\tswitch (current.triggerKind) {\n\t\tcase languages.SignatureHelpTriggerKind.Invoke:\n\t\t\t// Invoke overrides previous triggers.\n\t\t\treturn current;\n\n\t\tcase languages.SignatureHelpTriggerKind.ContentChange:\n\t\t\t// Ignore content changes triggers\n\t\t\treturn previous;\n\n\t\tcase languages.SignatureHelpTriggerKind.TriggerCharacter:\n\t\tdefault:\n\t\t\treturn current;\n\t}\n}\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\nimport { IDisposable } from 'vs/base/common/lifecycle';\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\nimport { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';\nimport { CompletionModel } from './completionModel';\nimport { ISelectedSuggestion } from './suggestWidget';\n\nexport class SuggestAlternatives {\n\n\tstatic readonly OtherSuggestions = new RawContextKey('hasOtherSuggestions', false);\n\n\tprivate readonly _ckOtherSuggestions: IContextKey;\n\n\tprivate _index: number = 0;\n\tprivate _model: CompletionModel | undefined;\n\tprivate _acceptNext: ((selected: ISelectedSuggestion) => any) | undefined;\n\tprivate _listener: IDisposable | undefined;\n\tprivate _ignore: boolean | undefined;\n\n\tconstructor(\n\t\tprivate readonly _editor: ICodeEditor,\n\t\t@IContextKeyService contextKeyService: IContextKeyService\n\t) {\n\t\tthis._ckOtherSuggestions = SuggestAlternatives.OtherSuggestions.bindTo(contextKeyService);\n\t}\n\n\tdispose(): void {\n\t\tthis.reset();\n\t}\n\n\treset(): void {\n\t\tthis._ckOtherSuggestions.reset();\n\t\tthis._listener?.dispose();\n\t\tthis._model = undefined;\n\t\tthis._acceptNext = undefined;\n\t\tthis._ignore = false;\n\t}\n\n\tset({ model, index }: ISelectedSuggestion, acceptNext: (selected: ISelectedSuggestion) => any): void {\n\n\t\t// no suggestions -> nothing to do\n\t\tif (model.items.length === 0) {\n\t\t\tthis.reset();\n\t\t\treturn;\n\t\t}\n\n\t\t// no alternative suggestions -> nothing to do\n\t\tconst nextIndex = SuggestAlternatives._moveIndex(true, model, index);\n\t\tif (nextIndex === index) {\n\t\t\tthis.reset();\n\t\t\treturn;\n\t\t}\n\n\t\tthis._acceptNext = acceptNext;\n\t\tthis._model = model;\n\t\tthis._index = index;\n\t\tthis._listener = this._editor.onDidChangeCursorPosition(() => {\n\t\t\tif (!this._ignore) {\n\t\t\t\tthis.reset();\n\t\t\t}\n\t\t});\n\t\tthis._ckOtherSuggestions.set(true);\n\t}\n\n\tprivate static _moveIndex(fwd: boolean, model: CompletionModel, index: number): number {\n\t\tlet newIndex = index;\n\t\tfor (let rounds = model.items.length; rounds > 0; rounds--) {\n\t\t\tnewIndex = (newIndex + model.items.length + (fwd ? +1 : -1)) % model.items.length;\n\t\t\tif (newIndex === index) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (!model.items[newIndex].completion.additionalTextEdits) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\treturn newIndex;\n\t}\n\n\tnext(): void {\n\t\tthis._move(true);\n\t}\n\n\tprev(): void {\n\t\tthis._move(false);\n\t}\n\n\tprivate _move(fwd: boolean): void {\n\t\tif (!this._model) {\n\t\t\t// nothing to reason about\n\t\t\treturn;\n\t\t}\n\t\ttry {\n\t\t\tthis._ignore = true;\n\t\t\tthis._index = SuggestAlternatives._moveIndex(fwd, this._model, this._index);\n\t\t\tthis._acceptNext!({ index: this._index, item: this._model.items[this._index], model: this._model });\n\t\t} finally {\n\t\t\tthis._ignore = false;\n\t\t}\n\t}\n}\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\nimport { IDisposable } from 'vs/base/common/lifecycle';\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\nimport { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';\n\nexport class WordContextKey {\n\n\tstatic readonly AtEnd = new RawContextKey('atEndOfWord', false);\n\n\tprivate readonly _ckAtEnd: IContextKey;\n\tprivate readonly _configListener: IDisposable;\n\n\tprivate _enabled: boolean = false;\n\tprivate _selectionListener?: IDisposable;\n\n\tconstructor(\n\t\tprivate readonly _editor: ICodeEditor,\n\t\t@IContextKeyService contextKeyService: IContextKeyService,\n\t) {\n\n\t\tthis._ckAtEnd = WordContextKey.AtEnd.bindTo(contextKeyService);\n\t\tthis._configListener = this._editor.onDidChangeConfiguration(e => e.hasChanged(EditorOption.tabCompletion) && this._update());\n\t\tthis._update();\n\t}\n\n\tdispose(): void {\n\t\tthis._configListener.dispose();\n\t\tthis._selectionListener?.dispose();\n\t\tthis._ckAtEnd.reset();\n\t}\n\n\tprivate _update(): void {\n\t\t// only update this when tab completions are enabled\n\t\tconst enabled = this._editor.getOption(EditorOption.tabCompletion) === 'on';\n\t\tif (this._enabled === enabled) {\n\t\t\treturn;\n\t\t}\n\t\tthis._enabled = enabled;\n\n\t\tif (this._enabled) {\n\t\t\tconst checkForWordEnd = () => {\n\t\t\t\tif (!this._editor.hasModel()) {\n\t\t\t\t\tthis._ckAtEnd.set(false);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst model = this._editor.getModel();\n\t\t\t\tconst selection = this._editor.getSelection();\n\t\t\t\tconst word = model.getWordAtPosition(selection.getStartPosition());\n\t\t\t\tif (!word) {\n\t\t\t\t\tthis._ckAtEnd.set(false);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tthis._ckAtEnd.set(word.endColumn === selection.getStartPosition().column);\n\t\t\t};\n\t\t\tthis._selectionListener = this._editor.onDidChangeCursorSelection(checkForWordEnd);\n\t\t\tcheckForWordEnd();\n\n\t\t} else if (this._selectionListener) {\n\t\t\tthis._ckAtEnd.reset();\n\t\t\tthis._selectionListener.dispose();\n\t\t\tthis._selectionListener = undefined;\n\t\t}\n\t}\n}\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\nimport { Event } from 'vs/base/common/event';\nimport { RawContextKey } from 'vs/platform/contextkey/common/contextkey';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\n\nexport const IAccessibilityService = createDecorator('accessibilityService');\n\nexport interface IAccessibilityService {\n\treadonly _serviceBrand: undefined;\n\n\treadonly onDidChangeScreenReaderOptimized: Event;\n\tisScreenReaderOptimized(): boolean;\n\tisMotionReduced(): boolean;\n\tgetAccessibilitySupport(): AccessibilitySupport;\n}\n\nexport const 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\n\tDisabled = 1,\n\n\tEnabled = 2\n}\n\nexport const CONTEXT_ACCESSIBILITY_MODE_ENABLED = new RawContextKey('accessibilityModeEnabled', false);\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\nimport * as browser from 'vs/base/browser/browser';\nimport * as arrays from 'vs/base/common/arrays';\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport * as objects from 'vs/base/common/objects';\nimport * as platform from 'vs/base/common/platform';\nimport { ElementSizeObserver } from 'vs/editor/browser/config/elementSizeObserver';\nimport { FontMeasurements } from 'vs/editor/browser/config/fontMeasurements';\nimport { migrateOptions } from 'vs/editor/browser/config/migrateOptions';\nimport { TabFocus } from 'vs/editor/browser/config/tabFocus';\nimport { ComputeOptionsMemory, ConfigurationChangedEvent, EditorOption, editorOptionsRegistry, FindComputedEditorOptionValueById, IComputedEditorOptions, IEditorOptions, IEnvironmentalOptions } from 'vs/editor/common/config/editorOptions';\nimport { EditorZoom } from 'vs/editor/common/config/editorZoom';\nimport { BareFontInfo, FontInfo, IValidatedEditorOptions } from 'vs/editor/common/config/fontInfo';\nimport { IDimension } from 'vs/editor/common/core/dimension';\nimport { IEditorConfiguration } from 'vs/editor/common/config/editorConfiguration';\nimport { AccessibilitySupport, IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';\nimport { getWindow, getWindowById } from 'vs/base/browser/dom';\nimport { PixelRatio } from 'vs/base/browser/pixelRatio';\nimport { MenuId } from 'vs/platform/actions/common/actions';\n\nexport interface IEditorConstructionOptions extends IEditorOptions {\n\t/**\n\t * The initial editor dimension (to avoid measuring the container).\n\t */\n\tdimension?: IDimension;\n\t/**\n\t * Place overflow widgets inside an external DOM node.\n\t * Defaults to an internal DOM node.\n\t */\n\toverflowWidgetsDomNode?: HTMLElement;\n}\n\nexport class EditorConfiguration extends Disposable implements IEditorConfiguration {\n\n\tprivate _onDidChange = this._register(new Emitter());\n\tpublic readonly onDidChange: Event = this._onDidChange.event;\n\n\tprivate _onDidChangeFast = this._register(new Emitter());\n\tpublic readonly onDidChangeFast: Event = this._onDidChangeFast.event;\n\n\tpublic readonly isSimpleWidget: boolean;\n\tpublic readonly contextMenuId: MenuId;\n\tprivate readonly _containerObserver: ElementSizeObserver;\n\n\tprivate _isDominatedByLongLines: boolean = false;\n\tprivate _viewLineCount: number = 1;\n\tprivate _lineNumbersDigitCount: number = 1;\n\tprivate _reservedHeight: number = 0;\n\tprivate _glyphMarginDecorationLaneCount: number = 1;\n\tprivate _targetWindowId: number;\n\n\tprivate readonly _computeOptionsMemory: ComputeOptionsMemory = new ComputeOptionsMemory();\n\t/**\n\t * Raw options as they were passed in and merged with all calls to `updateOptions`.\n\t */\n\tprivate readonly _rawOptions: IEditorOptions;\n\t/**\n\t * Validated version of `_rawOptions`.\n\t */\n\tprivate _validatedOptions: ValidatedEditorOptions;\n\t/**\n\t * Complete options which are a combination of passed in options and env values.\n\t */\n\tpublic options: ComputedEditorOptions;\n\n\tconstructor(\n\t\tisSimpleWidget: boolean,\n\t\tcontextMenuId: MenuId,\n\t\toptions: Readonly,\n\t\tcontainer: HTMLElement | null,\n\t\t@IAccessibilityService private readonly _accessibilityService: IAccessibilityService\n\t) {\n\t\tsuper();\n\t\tthis.isSimpleWidget = isSimpleWidget;\n\t\tthis.contextMenuId = contextMenuId;\n\t\tthis._containerObserver = this._register(new ElementSizeObserver(container, options.dimension));\n\t\tthis._targetWindowId = getWindow(container).vscodeWindowId;\n\n\t\tthis._rawOptions = deepCloneAndMigrateOptions(options);\n\t\tthis._validatedOptions = EditorOptionsUtil.validateOptions(this._rawOptions);\n\t\tthis.options = this._computeOptions();\n\n\t\tif (this.options.get(EditorOption.automaticLayout)) {\n\t\t\tthis._containerObserver.startObserving();\n\t\t}\n\n\t\tthis._register(EditorZoom.onDidChangeZoomLevel(() => this._recomputeOptions()));\n\t\tthis._register(TabFocus.onDidChangeTabFocus(() => this._recomputeOptions()));\n\t\tthis._register(this._containerObserver.onDidChange(() => this._recomputeOptions()));\n\t\tthis._register(FontMeasurements.onDidChange(() => this._recomputeOptions()));\n\t\tthis._register(PixelRatio.getInstance(getWindow(container)).onDidChange(() => this._recomputeOptions()));\n\t\tthis._register(this._accessibilityService.onDidChangeScreenReaderOptimized(() => this._recomputeOptions()));\n\t}\n\n\tprivate _recomputeOptions(): void {\n\t\tconst newOptions = this._computeOptions();\n\t\tconst changeEvent = EditorOptionsUtil.checkEquals(this.options, newOptions);\n\t\tif (changeEvent === null) {\n\t\t\t// nothing changed!\n\t\t\treturn;\n\t\t}\n\n\t\tthis.options = newOptions;\n\t\tthis._onDidChangeFast.fire(changeEvent);\n\t\tthis._onDidChange.fire(changeEvent);\n\t}\n\n\tprivate _computeOptions(): ComputedEditorOptions {\n\t\tconst partialEnv = this._readEnvConfiguration();\n\t\tconst bareFontInfo = BareFontInfo.createFromValidatedSettings(this._validatedOptions, partialEnv.pixelRatio, this.isSimpleWidget);\n\t\tconst fontInfo = this._readFontInfo(bareFontInfo);\n\t\tconst env: IEnvironmentalOptions = {\n\t\t\tmemory: this._computeOptionsMemory,\n\t\t\touterWidth: partialEnv.outerWidth,\n\t\t\touterHeight: partialEnv.outerHeight - this._reservedHeight,\n\t\t\tfontInfo: fontInfo,\n\t\t\textraEditorClassName: partialEnv.extraEditorClassName,\n\t\t\tisDominatedByLongLines: this._isDominatedByLongLines,\n\t\t\tviewLineCount: this._viewLineCount,\n\t\t\tlineNumbersDigitCount: this._lineNumbersDigitCount,\n\t\t\temptySelectionClipboard: partialEnv.emptySelectionClipboard,\n\t\t\tpixelRatio: partialEnv.pixelRatio,\n\t\t\ttabFocusMode: TabFocus.getTabFocusMode(),\n\t\t\taccessibilitySupport: partialEnv.accessibilitySupport,\n\t\t\tglyphMarginDecorationLaneCount: this._glyphMarginDecorationLaneCount\n\t\t};\n\t\treturn EditorOptionsUtil.computeOptions(this._validatedOptions, env);\n\t}\n\n\tprotected _readEnvConfiguration(): IEnvConfiguration {\n\t\treturn {\n\t\t\textraEditorClassName: getExtraEditorClassName(),\n\t\t\touterWidth: this._containerObserver.getWidth(),\n\t\t\touterHeight: this._containerObserver.getHeight(),\n\t\t\temptySelectionClipboard: browser.isWebKit || browser.isFirefox,\n\t\t\tpixelRatio: PixelRatio.getInstance(getWindowById(this._targetWindowId, true).window).value,\n\t\t\taccessibilitySupport: (\n\t\t\t\tthis._accessibilityService.isScreenReaderOptimized()\n\t\t\t\t\t? AccessibilitySupport.Enabled\n\t\t\t\t\t: this._accessibilityService.getAccessibilitySupport()\n\t\t\t)\n\t\t};\n\t}\n\n\tprotected _readFontInfo(bareFontInfo: BareFontInfo): FontInfo {\n\t\treturn FontMeasurements.readFontInfo(getWindowById(this._targetWindowId, true).window, bareFontInfo);\n\t}\n\n\tpublic getRawOptions(): IEditorOptions {\n\t\treturn this._rawOptions;\n\t}\n\n\tpublic updateOptions(_newOptions: Readonly): void {\n\t\tconst newOptions = deepCloneAndMigrateOptions(_newOptions);\n\n\t\tconst didChange = EditorOptionsUtil.applyUpdate(this._rawOptions, newOptions);\n\t\tif (!didChange) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._validatedOptions = EditorOptionsUtil.validateOptions(this._rawOptions);\n\t\tthis._recomputeOptions();\n\t}\n\n\tpublic observeContainer(dimension?: IDimension): void {\n\t\tthis._containerObserver.observe(dimension);\n\t}\n\n\tpublic setIsDominatedByLongLines(isDominatedByLongLines: boolean): void {\n\t\tif (this._isDominatedByLongLines === isDominatedByLongLines) {\n\t\t\treturn;\n\t\t}\n\t\tthis._isDominatedByLongLines = isDominatedByLongLines;\n\t\tthis._recomputeOptions();\n\t}\n\n\tpublic setModelLineCount(modelLineCount: number): void {\n\t\tconst lineNumbersDigitCount = digitCount(modelLineCount);\n\t\tif (this._lineNumbersDigitCount === lineNumbersDigitCount) {\n\t\t\treturn;\n\t\t}\n\t\tthis._lineNumbersDigitCount = lineNumbersDigitCount;\n\t\tthis._recomputeOptions();\n\t}\n\n\tpublic setViewLineCount(viewLineCount: number): void {\n\t\tif (this._viewLineCount === viewLineCount) {\n\t\t\treturn;\n\t\t}\n\t\tthis._viewLineCount = viewLineCount;\n\t\tthis._recomputeOptions();\n\t}\n\n\tpublic setReservedHeight(reservedHeight: number) {\n\t\tif (this._reservedHeight === reservedHeight) {\n\t\t\treturn;\n\t\t}\n\t\tthis._reservedHeight = reservedHeight;\n\t\tthis._recomputeOptions();\n\t}\n\n\tpublic setGlyphMarginDecorationLaneCount(decorationLaneCount: number): void {\n\t\tif (this._glyphMarginDecorationLaneCount === decorationLaneCount) {\n\t\t\treturn;\n\t\t}\n\t\tthis._glyphMarginDecorationLaneCount = decorationLaneCount;\n\t\tthis._recomputeOptions();\n\t}\n}\n\nfunction digitCount(n: number): number {\n\tlet r = 0;\n\twhile (n) {\n\t\tn = Math.floor(n / 10);\n\t\tr++;\n\t}\n\treturn r ? r : 1;\n}\n\nfunction getExtraEditorClassName(): string {\n\tlet extra = '';\n\tif (!browser.isSafari && !browser.isWebkitWebView) {\n\t\t// Use user-select: none in all browsers except Safari and native macOS WebView\n\t\textra += 'no-user-select ';\n\t}\n\tif (browser.isSafari) {\n\t\t// See https://github.com/microsoft/vscode/issues/108822\n\t\textra += 'no-minimap-shadow ';\n\t\textra += 'enable-user-select ';\n\t}\n\tif (platform.isMacintosh) {\n\t\textra += 'mac ';\n\t}\n\treturn extra;\n}\n\nexport interface IEnvConfiguration {\n\textraEditorClassName: string;\n\touterWidth: number;\n\touterHeight: number;\n\temptySelectionClipboard: boolean;\n\tpixelRatio: number;\n\taccessibilitySupport: AccessibilitySupport;\n}\n\nclass ValidatedEditorOptions implements IValidatedEditorOptions {\n\tprivate readonly _values: any[] = [];\n\tpublic _read(option: EditorOption): T {\n\t\treturn this._values[option];\n\t}\n\tpublic get(id: T): FindComputedEditorOptionValueById {\n\t\treturn this._values[id];\n\t}\n\tpublic _write(option: EditorOption, value: T): void {\n\t\tthis._values[option] = value;\n\t}\n}\n\nexport class ComputedEditorOptions implements IComputedEditorOptions {\n\tprivate readonly _values: any[] = [];\n\tpublic _read(id: EditorOption): T {\n\t\tif (id >= this._values.length) {\n\t\t\tthrow new Error('Cannot read uninitialized value');\n\t\t}\n\t\treturn this._values[id];\n\t}\n\tpublic get(id: T): FindComputedEditorOptionValueById {\n\t\treturn this._read(id);\n\t}\n\tpublic _write(id: EditorOption, value: T): void {\n\t\tthis._values[id] = value;\n\t}\n}\n\nclass EditorOptionsUtil {\n\n\tpublic static validateOptions(options: IEditorOptions): ValidatedEditorOptions {\n\t\tconst result = new ValidatedEditorOptions();\n\t\tfor (const editorOption of editorOptionsRegistry) {\n\t\t\tconst value = (editorOption.name === '_never_' ? undefined : (options as any)[editorOption.name]);\n\t\t\tresult._write(editorOption.id, editorOption.validate(value));\n\t\t}\n\t\treturn result;\n\t}\n\n\tpublic static computeOptions(options: ValidatedEditorOptions, env: IEnvironmentalOptions): ComputedEditorOptions {\n\t\tconst result = new ComputedEditorOptions();\n\t\tfor (const editorOption of editorOptionsRegistry) {\n\t\t\tresult._write(editorOption.id, editorOption.compute(env, result, options._read(editorOption.id)));\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate static _deepEquals(a: T, b: T): boolean {\n\t\tif (typeof a !== 'object' || typeof b !== 'object' || !a || !b) {\n\t\t\treturn a === b;\n\t\t}\n\t\tif (Array.isArray(a) || Array.isArray(b)) {\n\t\t\treturn (Array.isArray(a) && Array.isArray(b) ? arrays.equals(a, b) : false);\n\t\t}\n\t\tif (Object.keys(a as unknown as object).length !== Object.keys(b as unknown as object).length) {\n\t\t\treturn false;\n\t\t}\n\t\tfor (const key in a) {\n\t\t\tif (!EditorOptionsUtil._deepEquals(a[key], b[key])) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\tpublic static checkEquals(a: ComputedEditorOptions, b: ComputedEditorOptions): ConfigurationChangedEvent | null {\n\t\tconst result: boolean[] = [];\n\t\tlet somethingChanged = false;\n\t\tfor (const editorOption of editorOptionsRegistry) {\n\t\t\tconst changed = !EditorOptionsUtil._deepEquals(a._read(editorOption.id), b._read(editorOption.id));\n\t\t\tresult[editorOption.id] = changed;\n\t\t\tif (changed) {\n\t\t\t\tsomethingChanged = true;\n\t\t\t}\n\t\t}\n\t\treturn (somethingChanged ? new ConfigurationChangedEvent(result) : null);\n\t}\n\n\t/**\n\t * Returns true if something changed.\n\t * Modifies `options`.\n\t*/\n\tpublic static applyUpdate(options: IEditorOptions, update: Readonly): boolean {\n\t\tlet changed = false;\n\t\tfor (const editorOption of editorOptionsRegistry) {\n\t\t\tif (update.hasOwnProperty(editorOption.name)) {\n\t\t\t\tconst result = editorOption.applyUpdate((options as any)[editorOption.name], (update as any)[editorOption.name]);\n\t\t\t\t(options as any)[editorOption.name] = result.newValue;\n\t\t\t\tchanged = changed || result.didChange;\n\t\t\t}\n\t\t}\n\t\treturn changed;\n\t}\n}\n\nfunction deepCloneAndMigrateOptions(_options: Readonly): IEditorOptions {\n\tconst options = objects.deepClone(_options);\n\tmigrateOptions(options);\n\treturn options;\n}\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\nimport { IObservable, ISettableObservable, derived, observableFromEvent, observableValue } from 'vs/base/common/observable';\nimport { Constants } from 'vs/base/common/uint';\nimport { diffEditorDefaultOptions } from 'vs/editor/common/config/diffEditor';\nimport { IDiffEditorBaseOptions, IDiffEditorOptions, IEditorOptions, ValidDiffEditorBaseOptions, clampedFloat, clampedInt, boolean as validateBooleanOption, stringSet as validateStringSetOption } from 'vs/editor/common/config/editorOptions';\nimport { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';\n\nexport class DiffEditorOptions {\n\tprivate readonly _options: ISettableObservable, { changedOptions: IDiffEditorOptions }>;\n\n\tpublic get editorOptions(): IObservable { return this._options; }\n\n\tprivate readonly _diffEditorWidth = observableValue(this, 0);\n\n\tprivate readonly _screenReaderMode = observableFromEvent(this._accessibilityService.onDidChangeScreenReaderOptimized, () => this._accessibilityService.isScreenReaderOptimized());\n\n\tconstructor(\n\t\toptions: Readonly,\n\t\t@IAccessibilityService private readonly _accessibilityService: IAccessibilityService,\n\t) {\n\t\tconst optionsCopy = { ...options, ...validateDiffEditorOptions(options, diffEditorDefaultOptions) };\n\t\tthis._options = observableValue(this, optionsCopy);\n\t}\n\n\tpublic readonly couldShowInlineViewBecauseOfSize = derived(this, reader =>\n\t\tthis._options.read(reader).renderSideBySide && this._diffEditorWidth.read(reader) <= this._options.read(reader).renderSideBySideInlineBreakpoint\n\t);\n\n\tpublic readonly renderOverviewRuler = derived(this, reader => this._options.read(reader).renderOverviewRuler);\n\tpublic readonly renderSideBySide = derived(this, reader => this._options.read(reader).renderSideBySide\n\t\t&& !(this._options.read(reader).useInlineViewWhenSpaceIsLimited && this.couldShowInlineViewBecauseOfSize.read(reader) && !this._screenReaderMode.read(reader))\n\t);\n\tpublic readonly readOnly = derived(this, reader => this._options.read(reader).readOnly);\n\n\tpublic readonly shouldRenderOldRevertArrows = derived(this, reader => {\n\t\tif (!this._options.read(reader).renderMarginRevertIcon) { return false; }\n\t\tif (!this.renderSideBySide.read(reader)) { return false; }\n\t\tif (this.readOnly.read(reader)) { return false; }\n\t\tif (this.shouldRenderGutterMenu.read(reader)) { return false; }\n\t\treturn true;\n\t});\n\n\tpublic readonly shouldRenderGutterMenu = derived(this, reader => this._options.read(reader).renderGutterMenu);\n\tpublic readonly renderIndicators = derived(this, reader => this._options.read(reader).renderIndicators);\n\tpublic readonly enableSplitViewResizing = derived(this, reader => this._options.read(reader).enableSplitViewResizing);\n\tpublic readonly splitViewDefaultRatio = derived(this, reader => this._options.read(reader).splitViewDefaultRatio);\n\tpublic readonly ignoreTrimWhitespace = derived(this, reader => this._options.read(reader).ignoreTrimWhitespace);\n\tpublic readonly maxComputationTimeMs = derived(this, reader => this._options.read(reader).maxComputationTime);\n\tpublic readonly showMoves = derived(this, reader => this._options.read(reader).experimental.showMoves! && this.renderSideBySide.read(reader));\n\tpublic readonly isInEmbeddedEditor = derived(this, reader => this._options.read(reader).isInEmbeddedEditor);\n\tpublic readonly diffWordWrap = derived(this, reader => this._options.read(reader).diffWordWrap);\n\tpublic readonly originalEditable = derived(this, reader => this._options.read(reader).originalEditable);\n\tpublic readonly diffCodeLens = derived(this, reader => this._options.read(reader).diffCodeLens);\n\tpublic readonly accessibilityVerbose = derived(this, reader => this._options.read(reader).accessibilityVerbose);\n\tpublic readonly diffAlgorithm = derived(this, reader => this._options.read(reader).diffAlgorithm);\n\tpublic readonly showEmptyDecorations = derived(this, reader => this._options.read(reader).experimental.showEmptyDecorations!);\n\tpublic readonly onlyShowAccessibleDiffViewer = derived(this, reader => this._options.read(reader).onlyShowAccessibleDiffViewer);\n\n\tpublic readonly hideUnchangedRegions = derived(this, reader => this._options.read(reader).hideUnchangedRegions.enabled!);\n\tpublic readonly hideUnchangedRegionsRevealLineCount = derived(this, reader => this._options.read(reader).hideUnchangedRegions.revealLineCount!);\n\tpublic readonly hideUnchangedRegionsContextLineCount = derived(this, reader => this._options.read(reader).hideUnchangedRegions.contextLineCount!);\n\tpublic readonly hideUnchangedRegionsMinimumLineCount = derived(this, reader => this._options.read(reader).hideUnchangedRegions.minimumLineCount!);\n\n\tpublic updateOptions(changedOptions: IDiffEditorOptions): void {\n\t\tconst newDiffEditorOptions = validateDiffEditorOptions(changedOptions, this._options.get());\n\t\tconst newOptions = { ...this._options.get(), ...changedOptions, ...newDiffEditorOptions };\n\t\tthis._options.set(newOptions, undefined, { changedOptions: changedOptions });\n\t}\n\n\tpublic setWidth(width: number): void {\n\t\tthis._diffEditorWidth.set(width, undefined);\n\t}\n}\n\nfunction validateDiffEditorOptions(options: Readonly, defaults: ValidDiffEditorBaseOptions): ValidDiffEditorBaseOptions {\n\treturn {\n\t\tenableSplitViewResizing: validateBooleanOption(options.enableSplitViewResizing, defaults.enableSplitViewResizing),\n\t\tsplitViewDefaultRatio: clampedFloat(options.splitViewDefaultRatio, 0.5, 0.1, 0.9),\n\t\trenderSideBySide: validateBooleanOption(options.renderSideBySide, defaults.renderSideBySide),\n\t\trenderMarginRevertIcon: validateBooleanOption(options.renderMarginRevertIcon, defaults.renderMarginRevertIcon),\n\t\tmaxComputationTime: clampedInt(options.maxComputationTime, defaults.maxComputationTime, 0, Constants.MAX_SAFE_SMALL_INTEGER),\n\t\tmaxFileSize: clampedInt(options.maxFileSize, defaults.maxFileSize, 0, Constants.MAX_SAFE_SMALL_INTEGER),\n\t\tignoreTrimWhitespace: validateBooleanOption(options.ignoreTrimWhitespace, defaults.ignoreTrimWhitespace),\n\t\trenderIndicators: validateBooleanOption(options.renderIndicators, defaults.renderIndicators),\n\t\toriginalEditable: validateBooleanOption(options.originalEditable, defaults.originalEditable),\n\t\tdiffCodeLens: validateBooleanOption(options.diffCodeLens, defaults.diffCodeLens),\n\t\trenderOverviewRuler: validateBooleanOption(options.renderOverviewRuler, defaults.renderOverviewRuler),\n\t\tdiffWordWrap: validateStringSetOption<'off' | 'on' | 'inherit'>(options.diffWordWrap, defaults.diffWordWrap, ['off', 'on', 'inherit']),\n\t\tdiffAlgorithm: validateStringSetOption(options.diffAlgorithm, defaults.diffAlgorithm, ['legacy', 'advanced'], { 'smart': 'legacy', 'experimental': 'advanced' }),\n\t\taccessibilityVerbose: validateBooleanOption(options.accessibilityVerbose, defaults.accessibilityVerbose),\n\t\texperimental: {\n\t\t\tshowMoves: validateBooleanOption(options.experimental?.showMoves, defaults.experimental.showMoves!),\n\t\t\tshowEmptyDecorations: validateBooleanOption(options.experimental?.showEmptyDecorations, defaults.experimental.showEmptyDecorations!),\n\t\t},\n\t\thideUnchangedRegions: {\n\t\t\tenabled: validateBooleanOption(options.hideUnchangedRegions?.enabled ?? (options.experimental as any)?.collapseUnchangedRegions, defaults.hideUnchangedRegions.enabled!),\n\t\t\tcontextLineCount: clampedInt(options.hideUnchangedRegions?.contextLineCount, defaults.hideUnchangedRegions.contextLineCount!, 0, Constants.MAX_SAFE_SMALL_INTEGER),\n\t\t\tminimumLineCount: clampedInt(options.hideUnchangedRegions?.minimumLineCount, defaults.hideUnchangedRegions.minimumLineCount!, 0, Constants.MAX_SAFE_SMALL_INTEGER),\n\t\t\trevealLineCount: clampedInt(options.hideUnchangedRegions?.revealLineCount, defaults.hideUnchangedRegions.revealLineCount!, 0, Constants.MAX_SAFE_SMALL_INTEGER),\n\t\t},\n\t\tisInEmbeddedEditor: validateBooleanOption(options.isInEmbeddedEditor, defaults.isInEmbeddedEditor),\n\t\tonlyShowAccessibleDiffViewer: validateBooleanOption(options.onlyShowAccessibleDiffViewer, defaults.onlyShowAccessibleDiffViewer),\n\t\trenderSideBySideInlineBreakpoint: clampedInt(options.renderSideBySideInlineBreakpoint, defaults.renderSideBySideInlineBreakpoint, 0, Constants.MAX_SAFE_SMALL_INTEGER),\n\t\tuseInlineViewWhenSpaceIsLimited: validateBooleanOption(options.useInlineViewWhenSpaceIsLimited, defaults.useInlineViewWhenSpaceIsLimited),\n\t\trenderGutterMenu: validateBooleanOption(options.renderGutterMenu, defaults.renderGutterMenu),\n\t};\n}\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\nimport { Emitter, PauseableEmitter } from 'vs/base/common/event';\nimport { Iterable } from 'vs/base/common/iterator';\nimport { Disposable, IDisposable, MutableDisposable } from 'vs/base/common/lifecycle';\nimport { MarshalledObject } from 'vs/base/common/marshalling';\nimport { MarshalledId } from 'vs/base/common/marshallingIds';\nimport { cloneAndChange } from 'vs/base/common/objects';\nimport { TernarySearchTree } from 'vs/base/common/ternarySearchTree';\nimport { URI } from 'vs/base/common/uri';\nimport { localize } from 'vs/nls';\nimport { CommandsRegistry } from 'vs/platform/commands/common/commands';\nimport { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration';\nimport { ContextKeyExpression, ContextKeyInfo, ContextKeyValue, IContext, IContextKey, IContextKeyChangeEvent, IContextKeyService, IContextKeyServiceTarget, IReadableSet, IScopedContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';\nimport { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';\n\nconst KEYBINDING_CONTEXT_ATTR = 'data-keybinding-context';\n\nexport class Context implements IContext {\n\n\tprotected _parent: Context | null;\n\tprotected _value: Record;\n\tprotected _id: number;\n\n\tconstructor(id: number, parent: Context | null) {\n\t\tthis._id = id;\n\t\tthis._parent = parent;\n\t\tthis._value = Object.create(null);\n\t\tthis._value['_contextId'] = id;\n\t}\n\n\tpublic get value(): Record {\n\t\treturn { ...this._value };\n\t}\n\n\tpublic setValue(key: string, value: any): boolean {\n\t\t// console.log('SET ' + key + ' = ' + value + ' ON ' + this._id);\n\t\tif (this._value[key] !== value) {\n\t\t\tthis._value[key] = value;\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tpublic removeValue(key: string): boolean {\n\t\t// console.log('REMOVE ' + key + ' FROM ' + this._id);\n\t\tif (key in this._value) {\n\t\t\tdelete this._value[key];\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tpublic getValue(key: string): T | undefined {\n\t\tconst ret = this._value[key];\n\t\tif (typeof ret === 'undefined' && this._parent) {\n\t\t\treturn this._parent.getValue(key);\n\t\t}\n\t\treturn ret;\n\t}\n}\n\nclass NullContext extends Context {\n\n\tstatic readonly INSTANCE = new NullContext();\n\n\tconstructor() {\n\t\tsuper(-1, null);\n\t}\n\n\tpublic override setValue(key: string, value: any): boolean {\n\t\treturn false;\n\t}\n\n\tpublic override removeValue(key: string): boolean {\n\t\treturn false;\n\t}\n\n\tpublic override getValue(key: string): T | undefined {\n\t\treturn undefined;\n\t}\n}\n\nclass ConfigAwareContextValuesContainer extends Context {\n\tprivate static readonly _keyPrefix = 'config.';\n\n\tprivate readonly _values = TernarySearchTree.forConfigKeys();\n\tprivate readonly _listener: IDisposable;\n\n\tconstructor(\n\t\tid: number,\n\t\tprivate readonly _configurationService: IConfigurationService,\n\t\temitter: Emitter\n\t) {\n\t\tsuper(id, null);\n\n\t\tthis._listener = this._configurationService.onDidChangeConfiguration(event => {\n\t\t\tif (event.source === ConfigurationTarget.DEFAULT) {\n\t\t\t\t// new setting, reset everything\n\t\t\t\tconst allKeys = Array.from(this._values, ([k]) => k);\n\t\t\t\tthis._values.clear();\n\t\t\t\temitter.fire(new ArrayContextKeyChangeEvent(allKeys));\n\t\t\t} else {\n\t\t\t\tconst changedKeys: string[] = [];\n\t\t\t\tfor (const configKey of event.affectedKeys) {\n\t\t\t\t\tconst contextKey = `config.${configKey}`;\n\n\t\t\t\t\tconst cachedItems = this._values.findSuperstr(contextKey);\n\t\t\t\t\tif (cachedItems !== undefined) {\n\t\t\t\t\t\tchangedKeys.push(...Iterable.map(cachedItems, ([key]) => key));\n\t\t\t\t\t\tthis._values.deleteSuperstr(contextKey);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (this._values.has(contextKey)) {\n\t\t\t\t\t\tchangedKeys.push(contextKey);\n\t\t\t\t\t\tthis._values.delete(contextKey);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\temitter.fire(new ArrayContextKeyChangeEvent(changedKeys));\n\t\t\t}\n\t\t});\n\t}\n\n\tdispose(): void {\n\t\tthis._listener.dispose();\n\t}\n\n\toverride getValue(key: string): any {\n\n\t\tif (key.indexOf(ConfigAwareContextValuesContainer._keyPrefix) !== 0) {\n\t\t\treturn super.getValue(key);\n\t\t}\n\n\t\tif (this._values.has(key)) {\n\t\t\treturn this._values.get(key);\n\t\t}\n\n\t\tconst configKey = key.substr(ConfigAwareContextValuesContainer._keyPrefix.length);\n\t\tconst configValue = this._configurationService.getValue(configKey);\n\t\tlet value: any = undefined;\n\t\tswitch (typeof configValue) {\n\t\t\tcase 'number':\n\t\t\tcase 'boolean':\n\t\t\tcase 'string':\n\t\t\t\tvalue = configValue;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tif (Array.isArray(configValue)) {\n\t\t\t\t\tvalue = JSON.stringify(configValue);\n\t\t\t\t} else {\n\t\t\t\t\tvalue = configValue;\n\t\t\t\t}\n\t\t}\n\n\t\tthis._values.set(key, value);\n\t\treturn value;\n\t}\n\n\toverride setValue(key: string, value: any): boolean {\n\t\treturn super.setValue(key, value);\n\t}\n\n\toverride removeValue(key: string): boolean {\n\t\treturn super.removeValue(key);\n\t}\n}\n\nclass ContextKey implements IContextKey {\n\n\tprivate _service: AbstractContextKeyService;\n\tprivate _key: string;\n\tprivate _defaultValue: T | undefined;\n\n\tconstructor(service: AbstractContextKeyService, key: string, defaultValue: T | undefined) {\n\t\tthis._service = service;\n\t\tthis._key = key;\n\t\tthis._defaultValue = defaultValue;\n\t\tthis.reset();\n\t}\n\n\tpublic set(value: T): void {\n\t\tthis._service.setContext(this._key, value);\n\t}\n\n\tpublic reset(): void {\n\t\tif (typeof this._defaultValue === 'undefined') {\n\t\t\tthis._service.removeContext(this._key);\n\t\t} else {\n\t\t\tthis._service.setContext(this._key, this._defaultValue);\n\t\t}\n\t}\n\n\tpublic get(): T | undefined {\n\t\treturn this._service.getContextKeyValue(this._key);\n\t}\n}\n\nclass SimpleContextKeyChangeEvent implements IContextKeyChangeEvent {\n\tconstructor(readonly key: string) { }\n\taffectsSome(keys: IReadableSet): boolean {\n\t\treturn keys.has(this.key);\n\t}\n\tallKeysContainedIn(keys: IReadableSet): boolean {\n\t\treturn this.affectsSome(keys);\n\t}\n}\n\nclass ArrayContextKeyChangeEvent implements IContextKeyChangeEvent {\n\tconstructor(readonly keys: string[]) { }\n\taffectsSome(keys: IReadableSet): boolean {\n\t\tfor (const key of this.keys) {\n\t\t\tif (keys.has(key)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\tallKeysContainedIn(keys: IReadableSet): boolean {\n\t\treturn this.keys.every(key => keys.has(key));\n\t}\n}\n\nclass CompositeContextKeyChangeEvent implements IContextKeyChangeEvent {\n\tconstructor(readonly events: IContextKeyChangeEvent[]) { }\n\taffectsSome(keys: IReadableSet): boolean {\n\t\tfor (const e of this.events) {\n\t\t\tif (e.affectsSome(keys)) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\tallKeysContainedIn(keys: IReadableSet): boolean {\n\t\treturn this.events.every(evt => evt.allKeysContainedIn(keys));\n\t}\n}\n\nfunction allEventKeysInContext(event: IContextKeyChangeEvent, context: Record): boolean {\n\treturn event.allKeysContainedIn(new Set(Object.keys(context)));\n}\n\nexport abstract class AbstractContextKeyService extends Disposable implements IContextKeyService {\n\tdeclare _serviceBrand: undefined;\n\n\tprotected _isDisposed: boolean;\n\tprotected _myContextId: number;\n\n\tprotected _onDidChangeContext = this._register(new PauseableEmitter({ merge: input => new CompositeContextKeyChangeEvent(input) }));\n\treadonly onDidChangeContext = this._onDidChangeContext.event;\n\n\tconstructor(myContextId: number) {\n\t\tsuper();\n\t\tthis._isDisposed = false;\n\t\tthis._myContextId = myContextId;\n\t}\n\n\tpublic createKey(key: string, defaultValue: T | undefined): IContextKey {\n\t\tif (this._isDisposed) {\n\t\t\tthrow new Error(`AbstractContextKeyService has been disposed`);\n\t\t}\n\t\treturn new ContextKey(this, key, defaultValue);\n\t}\n\n\n\tbufferChangeEvents(callback: Function): void {\n\t\tthis._onDidChangeContext.pause();\n\t\ttry {\n\t\t\tcallback();\n\t\t} finally {\n\t\t\tthis._onDidChangeContext.resume();\n\t\t}\n\t}\n\n\tpublic createScoped(domNode: IContextKeyServiceTarget): IScopedContextKeyService {\n\t\tif (this._isDisposed) {\n\t\t\tthrow new Error(`AbstractContextKeyService has been disposed`);\n\t\t}\n\t\treturn new ScopedContextKeyService(this, domNode);\n\t}\n\n\tpublic contextMatchesRules(rules: ContextKeyExpression | undefined): boolean {\n\t\tif (this._isDisposed) {\n\t\t\tthrow new Error(`AbstractContextKeyService has been disposed`);\n\t\t}\n\t\tconst context = this.getContextValuesContainer(this._myContextId);\n\t\tconst result = (rules ? rules.evaluate(context) : true);\n\t\t// console.group(rules.serialize() + ' -> ' + result);\n\t\t// rules.keys().forEach(key => { console.log(key, ctx[key]); });\n\t\t// console.groupEnd();\n\t\treturn result;\n\t}\n\n\tpublic getContextKeyValue(key: string): T | undefined {\n\t\tif (this._isDisposed) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn this.getContextValuesContainer(this._myContextId).getValue(key);\n\t}\n\n\tpublic setContext(key: string, value: any): void {\n\t\tif (this._isDisposed) {\n\t\t\treturn;\n\t\t}\n\t\tconst myContext = this.getContextValuesContainer(this._myContextId);\n\t\tif (!myContext) {\n\t\t\treturn;\n\t\t}\n\t\tif (myContext.setValue(key, value)) {\n\t\t\tthis._onDidChangeContext.fire(new SimpleContextKeyChangeEvent(key));\n\t\t}\n\t}\n\n\tpublic removeContext(key: string): void {\n\t\tif (this._isDisposed) {\n\t\t\treturn;\n\t\t}\n\t\tif (this.getContextValuesContainer(this._myContextId).removeValue(key)) {\n\t\t\tthis._onDidChangeContext.fire(new SimpleContextKeyChangeEvent(key));\n\t\t}\n\t}\n\n\tpublic getContext(target: IContextKeyServiceTarget | null): IContext {\n\t\tif (this._isDisposed) {\n\t\t\treturn NullContext.INSTANCE;\n\t\t}\n\t\treturn this.getContextValuesContainer(findContextAttr(target));\n\t}\n\n\tpublic abstract getContextValuesContainer(contextId: number): Context;\n\tpublic abstract createChildContext(parentContextId?: number): number;\n\tpublic abstract disposeContext(contextId: number): void;\n\n\tpublic override dispose(): void {\n\t\tsuper.dispose();\n\t\tthis._isDisposed = true;\n\t}\n}\n\nexport class ContextKeyService extends AbstractContextKeyService implements IContextKeyService {\n\n\tprivate _lastContextId: number;\n\tprivate readonly _contexts = new Map();\n\n\tconstructor(@IConfigurationService configurationService: IConfigurationService) {\n\t\tsuper(0);\n\t\tthis._lastContextId = 0;\n\n\t\tconst myContext = this._register(new ConfigAwareContextValuesContainer(this._myContextId, configurationService, this._onDidChangeContext));\n\t\tthis._contexts.set(this._myContextId, myContext);\n\n\t\t// Uncomment this to see the contexts continuously logged\n\t\t// let lastLoggedValue: string | null = null;\n\t\t// setInterval(() => {\n\t\t// \tlet values = Object.keys(this._contexts).map((key) => this._contexts[key]);\n\t\t// \tlet logValue = values.map(v => JSON.stringify(v._value, null, '\\t')).join('\\n');\n\t\t// \tif (lastLoggedValue !== logValue) {\n\t\t// \t\tlastLoggedValue = logValue;\n\t\t// \t\tconsole.log(lastLoggedValue);\n\t\t// \t}\n\t\t// }, 2000);\n\t}\n\n\tpublic getContextValuesContainer(contextId: number): Context {\n\t\tif (this._isDisposed) {\n\t\t\treturn NullContext.INSTANCE;\n\t\t}\n\t\treturn this._contexts.get(contextId) || NullContext.INSTANCE;\n\t}\n\n\tpublic createChildContext(parentContextId: number = this._myContextId): number {\n\t\tif (this._isDisposed) {\n\t\t\tthrow new Error(`ContextKeyService has been disposed`);\n\t\t}\n\t\tconst id = (++this._lastContextId);\n\t\tthis._contexts.set(id, new Context(id, this.getContextValuesContainer(parentContextId)));\n\t\treturn id;\n\t}\n\n\tpublic disposeContext(contextId: number): void {\n\t\tif (!this._isDisposed) {\n\t\t\tthis._contexts.delete(contextId);\n\t\t}\n\t}\n}\n\nclass ScopedContextKeyService extends AbstractContextKeyService {\n\n\tprivate _parent: AbstractContextKeyService;\n\tprivate _domNode: IContextKeyServiceTarget;\n\n\tprivate readonly _parentChangeListener = this._register(new MutableDisposable());\n\n\tconstructor(parent: AbstractContextKeyService, domNode: IContextKeyServiceTarget) {\n\t\tsuper(parent.createChildContext());\n\t\tthis._parent = parent;\n\t\tthis._updateParentChangeListener();\n\n\t\tthis._domNode = domNode;\n\t\tif (this._domNode.hasAttribute(KEYBINDING_CONTEXT_ATTR)) {\n\t\t\tlet extraInfo = '';\n\t\t\tif ((this._domNode as HTMLElement).classList) {\n\t\t\t\textraInfo = Array.from((this._domNode as HTMLElement).classList.values()).join(', ');\n\t\t\t}\n\n\t\t\tconsole.error(`Element already has context attribute${extraInfo ? ': ' + extraInfo : ''}`);\n\t\t}\n\t\tthis._domNode.setAttribute(KEYBINDING_CONTEXT_ATTR, String(this._myContextId));\n\t}\n\n\tprivate _updateParentChangeListener(): void {\n\t\t// Forward parent events to this listener. Parent will change.\n\t\tthis._parentChangeListener.value = this._parent.onDidChangeContext(e => {\n\t\t\tconst thisContainer = this._parent.getContextValuesContainer(this._myContextId);\n\t\t\tconst thisContextValues = thisContainer.value;\n\n\t\t\tif (!allEventKeysInContext(e, thisContextValues)) {\n\t\t\t\tthis._onDidChangeContext.fire(e);\n\t\t\t}\n\t\t});\n\t}\n\n\tpublic override dispose(): void {\n\t\tif (this._isDisposed) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._parent.disposeContext(this._myContextId);\n\t\tthis._domNode.removeAttribute(KEYBINDING_CONTEXT_ATTR);\n\t\tsuper.dispose();\n\t}\n\n\tpublic getContextValuesContainer(contextId: number): Context {\n\t\tif (this._isDisposed) {\n\t\t\treturn NullContext.INSTANCE;\n\t\t}\n\t\treturn this._parent.getContextValuesContainer(contextId);\n\t}\n\n\tpublic createChildContext(parentContextId: number = this._myContextId): number {\n\t\tif (this._isDisposed) {\n\t\t\tthrow new Error(`ScopedContextKeyService has been disposed`);\n\t\t}\n\t\treturn this._parent.createChildContext(parentContextId);\n\t}\n\n\tpublic disposeContext(contextId: number): void {\n\t\tif (this._isDisposed) {\n\t\t\treturn;\n\t\t}\n\t\tthis._parent.disposeContext(contextId);\n\t}\n}\n\nfunction findContextAttr(domNode: IContextKeyServiceTarget | null): number {\n\twhile (domNode) {\n\t\tif (domNode.hasAttribute(KEYBINDING_CONTEXT_ATTR)) {\n\t\t\tconst attr = domNode.getAttribute(KEYBINDING_CONTEXT_ATTR);\n\t\t\tif (attr) {\n\t\t\t\treturn parseInt(attr, 10);\n\t\t\t}\n\t\t\treturn NaN;\n\t\t}\n\t\tdomNode = domNode.parentElement;\n\t}\n\treturn 0;\n}\n\nexport function setContext(accessor: ServicesAccessor, contextKey: any, contextValue: any) {\n\tconst contextKeyService = accessor.get(IContextKeyService);\n\tcontextKeyService.createKey(String(contextKey), stringifyURIs(contextValue));\n}\n\nfunction stringifyURIs(contextValue: any): any {\n\treturn cloneAndChange(contextValue, (obj) => {\n\t\tif (typeof obj === 'object' && (obj).$mid === MarshalledId.Uri) {\n\t\t\treturn URI.revive(obj).toString();\n\t\t}\n\t\tif (obj instanceof URI) {\n\t\t\treturn obj.toString();\n\t\t}\n\t\treturn undefined;\n\t});\n}\n\nCommandsRegistry.registerCommand('_setContext', setContext);\n\nCommandsRegistry.registerCommand({\n\tid: 'getContextKeyInfo',\n\thandler() {\n\t\treturn [...RawContextKey.all()].sort((a, b) => a.key.localeCompare(b.key));\n\t},\n\tmetadata: {\n\t\tdescription: localize('getContextKeyInfo', \"A command that returns information about context keys\"),\n\t\targs: []\n\t}\n});\n\nCommandsRegistry.registerCommand('_generateContextKeyInfo', function () {\n\tconst result: ContextKeyInfo[] = [];\n\tconst seen = new Set();\n\tfor (const info of RawContextKey.all()) {\n\t\tif (!seen.has(info.key)) {\n\t\t\tseen.add(info.key);\n\t\t\tresult.push(info);\n\t\t}\n\t}\n\tresult.sort((a, b) => a.key.localeCompare(b.key));\n\tconsole.log(JSON.stringify(result, undefined, 2));\n});\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\nimport { isIOS, isLinux, isMacintosh, isMobile, isWeb, isWindows } from 'vs/base/common/platform';\nimport { localize } from 'vs/nls';\nimport { RawContextKey } from 'vs/platform/contextkey/common/contextkey';\n\nexport const IsMacContext = new RawContextKey('isMac', isMacintosh, localize('isMac', \"Whether the operating system is macOS\"));\nexport const IsLinuxContext = new RawContextKey('isLinux', isLinux, localize('isLinux', \"Whether the operating system is Linux\"));\nexport const IsWindowsContext = new RawContextKey('isWindows', isWindows, localize('isWindows', \"Whether the operating system is Windows\"));\n\nexport const IsWebContext = new RawContextKey('isWeb', isWeb, localize('isWeb', \"Whether the platform is a web browser\"));\nexport const IsMacNativeContext = new RawContextKey('isMacNative', isMacintosh && !isWeb, localize('isMacNative', \"Whether the operating system is macOS on a non-browser platform\"));\nexport const IsIOSContext = new RawContextKey('isIOS', isIOS, localize('isIOS', \"Whether the operating system is iOS\"));\nexport const IsMobileContext = new RawContextKey('isMobile', isMobile, localize('isMobile', \"Whether the platform is a mobile web browser\"));\n\nexport const IsDevelopmentContext = new RawContextKey('isDevelopment', false, true);\nexport const ProductQualityContext = new RawContextKey('productQualityType', '', localize('productQualityType', \"Quality type of VS Code\"));\n\nexport const InputFocusedContextKey = 'inputFocus';\nexport const InputFocusedContext = new RawContextKey(InputFocusedContextKey, false, localize('inputFocus', \"Whether keyboard focus is inside an input box\"));\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\nimport { IContextMenuDelegate } from 'vs/base/browser/contextmenu';\nimport { StandardMouseEvent } from 'vs/base/browser/mouseEvent';\nimport { AnchorAlignment, AnchorAxisAlignment, IAnchor, IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview';\nimport { IAction } from 'vs/base/common/actions';\nimport { Event } from 'vs/base/common/event';\nimport { IDisposable } from 'vs/base/common/lifecycle';\nimport { IMenuActionOptions, MenuId } from 'vs/platform/actions/common/actions';\nimport { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\n\nexport const IContextViewService = createDecorator('contextViewService');\n\nexport interface IContextViewService extends IContextViewProvider {\n\n\treadonly _serviceBrand: undefined;\n\n\tshowContextView(delegate: IContextViewDelegate, container?: HTMLElement, shadowRoot?: boolean): IOpenContextView;\n\thideContextView(data?: any): void;\n\tgetContextViewElement(): HTMLElement;\n}\n\nexport interface IContextViewDelegate {\n\n\tcanRelayout?: boolean; // Default: true\n\n\t/**\n\t * The anchor where to position the context view.\n\t * Use a `HTMLElement` to position the view at the element,\n\t * a `StandardMouseEvent` to position it at the mouse position\n\t * or an `IAnchor` to position it at a specific location.\n\t */\n\tgetAnchor(): HTMLElement | StandardMouseEvent | IAnchor;\n\trender(container: HTMLElement): IDisposable;\n\tonHide?(data?: any): void;\n\tfocus?(): void;\n\tanchorAlignment?: AnchorAlignment;\n\tanchorAxisAlignment?: AnchorAxisAlignment; // Default: 0\n}\n\nexport interface IOpenContextView {\n\tclose: () => void;\n}\n\nexport const IContextMenuService = createDecorator('contextMenuService');\n\nexport interface IContextMenuService {\n\n\treadonly _serviceBrand: undefined;\n\n\treadonly onDidShowContextMenu: Event;\n\n\tshowContextMenu(delegate: IContextMenuDelegate | IContextMenuMenuDelegate): void;\n}\n\nexport type IContextMenuMenuDelegate = {\n\t/**\n\t * The MenuId that should be used to populate the context menu.\n\t */\n\tmenuId?: MenuId;\n\t/**\n\t * Optional options how menu actions are invoked\n\t */\n\tmenuActionOptions?: IMenuActionOptions;\n\t/**\n\t * Optional context key service which drives the given menu\n\t */\n\tcontextKeyService?: IContextKeyService;\n\n\t/**\n\t * Optional getter for extra actions. They will be prepended to the menu actions.\n\t */\n\tgetActions?(): IAction[];\n} & Omit;\n","\nimport Severity from 'vs/base/common/severity';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\n\nexport interface IBaseDialogOptions {\n\treadonly type?: Severity | DialogType;\n\n\treadonly title?: string;\n\treadonly message: string;\n\treadonly detail?: string;\n}\n\nexport interface IConfirmation extends IBaseDialogOptions {\n\n\t/**\n\t * If not provided, defaults to `Yes`.\n\t */\n\treadonly primaryButton?: string;\n\n\t/**\n\t * If not provided, defaults to `Cancel`.\n\t */\n\treadonly cancelButton?: string;\n}\n\nexport interface IConfirmationResult extends ICheckboxResult {\n\n\t/**\n\t * Will be true if the dialog was confirmed with the primary button pressed.\n\t */\n\treadonly confirmed: boolean;\n}\n\nexport interface IPromptBaseButton {\n\n\t/**\n\t * @returns the result of the prompt button will be returned\n\t * as result from the `prompt()` call.\n\t */\n\trun(checkbox: ICheckboxResult): T | Promise;\n}\n\nexport interface IPromptButton extends IPromptBaseButton {\n\treadonly label: string;\n}\n\nexport interface IPromptCancelButton extends IPromptBaseButton {\n}\n\nexport interface IPrompt extends IBaseDialogOptions {\n\n\t/**\n\t * The buttons to show in the prompt. Defaults to `OK`\n\t * if no buttons or cancel button is provided.\n\t */\n\treadonly buttons?: IPromptButton[];\n\n\t/**\n\t * The cancel button to show in the prompt. Defaults to\n\t * `Cancel` if set to `true`.\n\t */\n\treadonly cancelButton?: IPromptCancelButton | true | string;\n}\n\nexport interface IPromptWithCustomCancel extends IPrompt {\n\treadonly cancelButton: IPromptCancelButton;\n}\n\nexport interface IPromptWithDefaultCancel extends IPrompt {\n}\n\nexport interface IPromptResult extends ICheckboxResult {\n\n\t/**\n\t * The result of the `IPromptButton` that was pressed or `undefined` if none.\n\t */\n\treadonly result?: T;\n}\n\nexport interface IPromptResultWithCancel extends IPromptResult {\n\treadonly result: T;\n}\n\nexport type DialogType = 'none' | 'info' | 'error' | 'question' | 'warning';\n\nexport interface ICheckboxResult {\n\n\t/**\n\t * This will only be defined if the confirmation was created\n\t * with the checkbox option defined.\n\t */\n\treadonly checkboxChecked?: boolean;\n}\n\nexport const IDialogService = createDecorator('dialogService');\n\n/**\n * A service to bring up modal dialogs.\n *\n * Note: use the `INotificationService.prompt()` method for a non-modal way to ask\n * the user for input.\n */\nexport interface IDialogService {\n\n\treadonly _serviceBrand: undefined;\n\n\t/**\n\t * Ask the user for confirmation with a modal dialog.\n\t */\n\tconfirm(confirmation: IConfirmation): Promise;\n\n\t/**\n\t * Prompt the user with a modal dialog. Provides a bit\n\t * more control over the dialog compared to the simpler\n\t * `confirm` method. Specifically, allows to show more\n\t * than 2 buttons and makes it easier to just show a\n\t * message to the user.\n\t *\n\t * @returns a promise that resolves to the `T` result\n\t * from the provided `IPromptButton` or `undefined`.\n\t */\n\tprompt(prompt: IPromptWithCustomCancel): Promise>;\n\tprompt(prompt: IPromptWithDefaultCancel): Promise>;\n\tprompt(prompt: IPrompt): Promise>;\n\n\t/**\n\t * Show a modal error dialog.\n\t */\n\terror(message: string, detail?: string): Promise;\n}\n","\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\n\nexport const IEnvironmentService = createDecorator('environmentService');\n\n/**\n * A basic environment service that can be used in various processes,\n * such as main, renderer and shared process. Use subclasses of this\n * service for specific environment.\n */\nexport interface IEnvironmentService {\n\n\treadonly _serviceBrand: undefined;\n\tisExtensionDevelopment: boolean;\n\tisBuilt: boolean;\n\n\t// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\t//\n\t// NOTE: KEEP THIS INTERFACE AS SMALL AS POSSIBLE.\n\t//\n\t// AS SUCH:\n\t// - PUT NON-WEB PROPERTIES INTO NATIVE ENVIRONMENT SERVICE\n\t// - PUT WORKBENCH ONLY PROPERTIES INTO WORKBENCH ENVIRONMENT SERVICE\n\t// - PUT ELECTRON-MAIN ONLY PROPERTIES INTO MAIN ENVIRONMENT SERVICE\n\t//\n\t// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n}\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\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\nimport { Disposable, DisposableStore } from 'vs/base/common/lifecycle';\nimport { IHoverDelegate, IHoverDelegateOptions } from 'vs/base/browser/ui/hover/hoverDelegate';\nimport { IConfigurationService } from 'vs/platform/configuration/common/configuration';\nimport { addStandardDisposableListener } from 'vs/base/browser/dom';\nimport { KeyCode } from 'vs/base/common/keyCodes';\nimport { IHoverDelegate2, IHoverOptions, IHoverWidget } from 'vs/base/browser/ui/hover/hover';\n\nexport const IHoverService = createDecorator('hoverService');\n\nexport interface IHoverService extends IHoverDelegate2 {\n\treadonly _serviceBrand: undefined;\n}\n\nexport class WorkbenchHoverDelegate extends Disposable implements IHoverDelegate {\n\n\tprivate lastHoverHideTime = 0;\n\tprivate timeLimit = 200;\n\n\tprivate _delay: number;\n\tget delay(): number {\n\t\tif (this.isInstantlyHovering()) {\n\t\t\treturn 0; // show instantly when a hover was recently shown\n\t\t}\n\t\treturn this._delay;\n\t}\n\n\tprivate readonly hoverDisposables = this._register(new DisposableStore());\n\n\tconstructor(\n\t\tpublic readonly placement: 'mouse' | 'element',\n\t\tprivate readonly instantHover: boolean,\n\t\tprivate overrideOptions: Partial | ((options: IHoverDelegateOptions, focus?: boolean) => Partial) = {},\n\t\t@IConfigurationService private readonly configurationService: IConfigurationService,\n\t\t@IHoverService private readonly hoverService: IHoverService,\n\t) {\n\t\tsuper();\n\n\t\tthis._delay = this.configurationService.getValue('workbench.hover.delay');\n\t\tthis._register(this.configurationService.onDidChangeConfiguration(e => {\n\t\t\tif (e.affectsConfiguration('workbench.hover.delay')) {\n\t\t\t\tthis._delay = this.configurationService.getValue('workbench.hover.delay');\n\t\t\t}\n\t\t}));\n\t}\n\n\tshowHover(options: IHoverDelegateOptions, focus?: boolean): IHoverWidget | undefined {\n\t\tconst overrideOptions = typeof this.overrideOptions === 'function' ? this.overrideOptions(options, focus) : this.overrideOptions;\n\n\t\t// close hover on escape\n\t\tthis.hoverDisposables.clear();\n\t\tconst targets = options.target instanceof HTMLElement ? [options.target] : options.target.targetElements;\n\t\tfor (const target of targets) {\n\t\t\tthis.hoverDisposables.add(addStandardDisposableListener(target, 'keydown', (e) => {\n\t\t\t\tif (e.equals(KeyCode.Escape)) {\n\t\t\t\t\tthis.hoverService.hideHover();\n\t\t\t\t}\n\t\t\t}));\n\t\t}\n\n\t\tconst id = options.content instanceof HTMLElement ? undefined : options.content.toString();\n\n\t\treturn this.hoverService.showHover({\n\t\t\t...options,\n\t\t\t...overrideOptions,\n\t\t\tpersistence: {\n\t\t\t\thideOnKeyDown: true,\n\t\t\t\t...overrideOptions.persistence\n\t\t\t},\n\t\t\tid,\n\t\t\tappearance: {\n\t\t\t\t...options.appearance,\n\t\t\t\tcompact: true,\n\t\t\t\tskipFadeInAnimation: this.isInstantlyHovering(),\n\t\t\t\t...overrideOptions.appearance\n\t\t\t}\n\t\t}, focus);\n\t}\n\n\tprivate isInstantlyHovering(): boolean {\n\t\treturn this.instantHover && Date.now() - this.lastHoverHideTime < this.timeLimit;\n\t}\n\n\tonDidHideHover(): void {\n\t\tthis.hoverDisposables.clear();\n\t\tif (this.instantHover) {\n\t\t\tthis.lastHoverHideTime = Date.now();\n\t\t}\n\t}\n}\n\n// TODO@benibenj remove this, only temp fix for contextviews\nexport const nativeHoverDelegate: IHoverDelegate = {\n\tshowHover: function (): IHoverWidget | undefined {\n\t\tthrow new Error('Native hover function not implemented.');\n\t},\n\tdelay: 0,\n\tshowNativeHover: true\n};\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\nimport { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';\nimport { SyncDescriptor } from './descriptors';\n\nexport class ServiceCollection {\n\n\tprivate _entries = new Map, any>();\n\n\tconstructor(...entries: [ServiceIdentifier, any][]) {\n\t\tfor (const [id, service] of entries) {\n\t\t\tthis.set(id, service);\n\t\t}\n\t}\n\n\tset(id: ServiceIdentifier, instanceOrDescriptor: T | SyncDescriptor): T | SyncDescriptor {\n\t\tconst result = this._entries.get(id);\n\t\tthis._entries.set(id, instanceOrDescriptor);\n\t\treturn result;\n\t}\n\n\tget(id: ServiceIdentifier): T | SyncDescriptor {\n\t\treturn this._entries.get(id);\n\t}\n}\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\nimport { GlobalIdleValue } from 'vs/base/common/async';\nimport { Event } from 'vs/base/common/event';\nimport { illegalState } from 'vs/base/common/errors';\nimport { DisposableStore, dispose, IDisposable, isDisposable, toDisposable } from 'vs/base/common/lifecycle';\nimport { SyncDescriptor, SyncDescriptor0 } from 'vs/platform/instantiation/common/descriptors';\nimport { Graph } from 'vs/platform/instantiation/common/graph';\nimport { GetLeadingNonServiceArgs, IInstantiationService, ServiceIdentifier, ServicesAccessor, _util } from 'vs/platform/instantiation/common/instantiation';\nimport { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';\nimport { LinkedList } from 'vs/base/common/linkedList';\n\n// TRACING\nconst _enableAllTracing = false\n\t// || \"TRUE\" // DO NOT CHECK IN!\n\t;\n\nclass CyclicDependencyError extends Error {\n\tconstructor(graph: Graph) {\n\t\tsuper('cyclic dependency between services');\n\t\tthis.message = graph.findCycleSlow() ?? `UNABLE to detect cycle, dumping graph: \\n${graph.toString()}`;\n\t}\n}\n\nexport class InstantiationService implements IInstantiationService {\n\n\tdeclare readonly _serviceBrand: undefined;\n\n\treadonly _globalGraph?: Graph;\n\tprivate _globalGraphImplicitDependency?: string;\n\n\tprivate _isDisposed = false;\n\tprivate readonly _servicesToMaybeDispose = new Set();\n\tprivate readonly _children = new Set();\n\n\tconstructor(\n\t\tprivate readonly _services: ServiceCollection = new ServiceCollection(),\n\t\tprivate readonly _strict: boolean = false,\n\t\tprivate readonly _parent?: InstantiationService,\n\t\tprivate readonly _enableTracing: boolean = _enableAllTracing\n\t) {\n\n\t\tthis._services.set(IInstantiationService, this);\n\t\tthis._globalGraph = _enableTracing ? _parent?._globalGraph ?? new Graph(e => e) : undefined;\n\t}\n\n\tdispose(): void {\n\t\tif (!this._isDisposed) {\n\t\t\tthis._isDisposed = true;\n\t\t\t// dispose all child services\n\t\t\tdispose(this._children);\n\t\t\tthis._children.clear();\n\n\t\t\t// dispose all services created by this service\n\t\t\tfor (const candidate of this._servicesToMaybeDispose) {\n\t\t\t\tif (isDisposable(candidate)) {\n\t\t\t\t\tcandidate.dispose();\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis._servicesToMaybeDispose.clear();\n\t\t}\n\t}\n\n\tprivate _throwIfDisposed(): void {\n\t\tif (this._isDisposed) {\n\t\t\tthrow new Error('InstantiationService has been disposed');\n\t\t}\n\t}\n\n\tcreateChild(services: ServiceCollection, store?: DisposableStore): IInstantiationService {\n\t\tthis._throwIfDisposed();\n\n\t\tconst that = this;\n\t\tconst result = new class extends InstantiationService {\n\t\t\toverride dispose(): void {\n\t\t\t\tthat._children.delete(result);\n\t\t\t\tsuper.dispose();\n\t\t\t}\n\t\t}(services, this._strict, this, this._enableTracing);\n\t\tthis._children.add(result);\n\n\t\tstore?.add(result);\n\t\treturn result;\n\t}\n\n\tinvokeFunction(fn: (accessor: ServicesAccessor, ...args: TS) => R, ...args: TS): R {\n\t\tthis._throwIfDisposed();\n\n\t\tconst _trace = Trace.traceInvocation(this._enableTracing, fn);\n\t\tlet _done = false;\n\t\ttry {\n\t\t\tconst accessor: ServicesAccessor = {\n\t\t\t\tget: (id: ServiceIdentifier) => {\n\n\t\t\t\t\tif (_done) {\n\t\t\t\t\t\tthrow illegalState('service accessor is only valid during the invocation of its target method');\n\t\t\t\t\t}\n\n\t\t\t\t\tconst result = this._getOrCreateServiceInstance(id, _trace);\n\t\t\t\t\tif (!result) {\n\t\t\t\t\t\tthrow new Error(`[invokeFunction] unknown service '${id}'`);\n\t\t\t\t\t}\n\t\t\t\t\treturn result;\n\t\t\t\t}\n\t\t\t};\n\t\t\treturn fn(accessor, ...args);\n\t\t} finally {\n\t\t\t_done = true;\n\t\t\t_trace.stop();\n\t\t}\n\t}\n\n\tcreateInstance(descriptor: SyncDescriptor0): T;\n\tcreateInstance any, R extends InstanceType>(ctor: Ctor, ...args: GetLeadingNonServiceArgs>): R;\n\tcreateInstance(ctorOrDescriptor: any | SyncDescriptor, ...rest: any[]): any {\n\t\tthis._throwIfDisposed();\n\n\t\tlet _trace: Trace;\n\t\tlet result: any;\n\t\tif (ctorOrDescriptor instanceof SyncDescriptor) {\n\t\t\t_trace = Trace.traceCreation(this._enableTracing, ctorOrDescriptor.ctor);\n\t\t\tresult = this._createInstance(ctorOrDescriptor.ctor, ctorOrDescriptor.staticArguments.concat(rest), _trace);\n\t\t} else {\n\t\t\t_trace = Trace.traceCreation(this._enableTracing, ctorOrDescriptor);\n\t\t\tresult = this._createInstance(ctorOrDescriptor, rest, _trace);\n\t\t}\n\t\t_trace.stop();\n\t\treturn result;\n\t}\n\n\tprivate _createInstance(ctor: any, args: any[] = [], _trace: Trace): T {\n\n\t\t// arguments defined by service decorators\n\t\tconst serviceDependencies = _util.getServiceDependencies(ctor).sort((a, b) => a.index - b.index);\n\t\tconst serviceArgs: any[] = [];\n\t\tfor (const dependency of serviceDependencies) {\n\t\t\tconst service = this._getOrCreateServiceInstance(dependency.id, _trace);\n\t\t\tif (!service) {\n\t\t\t\tthis._throwIfStrict(`[createInstance] ${ctor.name} depends on UNKNOWN service ${dependency.id}.`, false);\n\t\t\t}\n\t\t\tserviceArgs.push(service);\n\t\t}\n\n\t\tconst firstServiceArgPos = serviceDependencies.length > 0 ? serviceDependencies[0].index : args.length;\n\n\t\t// check for argument mismatches, adjust static args if needed\n\t\tif (args.length !== firstServiceArgPos) {\n\t\t\tconsole.trace(`[createInstance] First service dependency of ${ctor.name} at position ${firstServiceArgPos + 1} conflicts with ${args.length} static arguments`);\n\n\t\t\tconst delta = firstServiceArgPos - args.length;\n\t\t\tif (delta > 0) {\n\t\t\t\targs = args.concat(new Array(delta));\n\t\t\t} else {\n\t\t\t\targs = args.slice(0, firstServiceArgPos);\n\t\t\t}\n\t\t}\n\n\t\t// now create the instance\n\t\treturn Reflect.construct(ctor, args.concat(serviceArgs));\n\t}\n\n\tprivate _setCreatedServiceInstance(id: ServiceIdentifier, instance: T): void {\n\t\tif (this._services.get(id) instanceof SyncDescriptor) {\n\t\t\tthis._services.set(id, instance);\n\t\t} else if (this._parent) {\n\t\t\tthis._parent._setCreatedServiceInstance(id, instance);\n\t\t} else {\n\t\t\tthrow new Error('illegalState - setting UNKNOWN service instance');\n\t\t}\n\t}\n\n\tprivate _getServiceInstanceOrDescriptor(id: ServiceIdentifier): T | SyncDescriptor {\n\t\tconst instanceOrDesc = this._services.get(id);\n\t\tif (!instanceOrDesc && this._parent) {\n\t\t\treturn this._parent._getServiceInstanceOrDescriptor(id);\n\t\t} else {\n\t\t\treturn instanceOrDesc;\n\t\t}\n\t}\n\n\tprotected _getOrCreateServiceInstance(id: ServiceIdentifier, _trace: Trace): T {\n\t\tif (this._globalGraph && this._globalGraphImplicitDependency) {\n\t\t\tthis._globalGraph.insertEdge(this._globalGraphImplicitDependency, String(id));\n\t\t}\n\t\tconst thing = this._getServiceInstanceOrDescriptor(id);\n\t\tif (thing instanceof SyncDescriptor) {\n\t\t\treturn this._safeCreateAndCacheServiceInstance(id, thing, _trace.branch(id, true));\n\t\t} else {\n\t\t\t_trace.branch(id, false);\n\t\t\treturn thing;\n\t\t}\n\t}\n\n\tprivate readonly _activeInstantiations = new Set>();\n\n\n\tprivate _safeCreateAndCacheServiceInstance(id: ServiceIdentifier, desc: SyncDescriptor, _trace: Trace): T {\n\t\tif (this._activeInstantiations.has(id)) {\n\t\t\tthrow new Error(`illegal state - RECURSIVELY instantiating service '${id}'`);\n\t\t}\n\t\tthis._activeInstantiations.add(id);\n\t\ttry {\n\t\t\treturn this._createAndCacheServiceInstance(id, desc, _trace);\n\t\t} finally {\n\t\t\tthis._activeInstantiations.delete(id);\n\t\t}\n\t}\n\n\tprivate _createAndCacheServiceInstance(id: ServiceIdentifier, desc: SyncDescriptor, _trace: Trace): T {\n\n\t\ttype Triple = { id: ServiceIdentifier; desc: SyncDescriptor; _trace: Trace };\n\t\tconst graph = new Graph(data => data.id.toString());\n\n\t\tlet cycleCount = 0;\n\t\tconst stack = [{ id, desc, _trace }];\n\t\twhile (stack.length) {\n\t\t\tconst item = stack.pop()!;\n\t\t\tgraph.lookupOrInsertNode(item);\n\n\t\t\t// a weak but working heuristic for cycle checks\n\t\t\tif (cycleCount++ > 1000) {\n\t\t\t\tthrow new CyclicDependencyError(graph);\n\t\t\t}\n\n\t\t\t// check all dependencies for existence and if they need to be created first\n\t\t\tfor (const dependency of _util.getServiceDependencies(item.desc.ctor)) {\n\n\t\t\t\tconst instanceOrDesc = this._getServiceInstanceOrDescriptor(dependency.id);\n\t\t\t\tif (!instanceOrDesc) {\n\t\t\t\t\tthis._throwIfStrict(`[createInstance] ${id} depends on ${dependency.id} which is NOT registered.`, true);\n\t\t\t\t}\n\n\t\t\t\t// take note of all service dependencies\n\t\t\t\tthis._globalGraph?.insertEdge(String(item.id), String(dependency.id));\n\n\t\t\t\tif (instanceOrDesc instanceof SyncDescriptor) {\n\t\t\t\t\tconst d = { id: dependency.id, desc: instanceOrDesc, _trace: item._trace.branch(dependency.id, true) };\n\t\t\t\t\tgraph.insertEdge(item, d);\n\t\t\t\t\tstack.push(d);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\twhile (true) {\n\t\t\tconst roots = graph.roots();\n\n\t\t\t// if there is no more roots but still\n\t\t\t// nodes in the graph we have a cycle\n\t\t\tif (roots.length === 0) {\n\t\t\t\tif (!graph.isEmpty()) {\n\t\t\t\t\tthrow new CyclicDependencyError(graph);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tfor (const { data } of roots) {\n\t\t\t\t// Repeat the check for this still being a service sync descriptor. That's because\n\t\t\t\t// instantiating a dependency might have side-effect and recursively trigger instantiation\n\t\t\t\t// so that some dependencies are now fullfilled already.\n\t\t\t\tconst instanceOrDesc = this._getServiceInstanceOrDescriptor(data.id);\n\t\t\t\tif (instanceOrDesc instanceof SyncDescriptor) {\n\t\t\t\t\t// create instance and overwrite the service collections\n\t\t\t\t\tconst instance = this._createServiceInstanceWithOwner(data.id, data.desc.ctor, data.desc.staticArguments, data.desc.supportsDelayedInstantiation, data._trace);\n\t\t\t\t\tthis._setCreatedServiceInstance(data.id, instance);\n\t\t\t\t}\n\t\t\t\tgraph.removeNode(data);\n\t\t\t}\n\t\t}\n\t\treturn this._getServiceInstanceOrDescriptor(id);\n\t}\n\n\tprivate _createServiceInstanceWithOwner(id: ServiceIdentifier, ctor: any, args: any[] = [], supportsDelayedInstantiation: boolean, _trace: Trace): T {\n\t\tif (this._services.get(id) instanceof SyncDescriptor) {\n\t\t\treturn this._createServiceInstance(id, ctor, args, supportsDelayedInstantiation, _trace, this._servicesToMaybeDispose);\n\t\t} else if (this._parent) {\n\t\t\treturn this._parent._createServiceInstanceWithOwner(id, ctor, args, supportsDelayedInstantiation, _trace);\n\t\t} else {\n\t\t\tthrow new Error(`illegalState - creating UNKNOWN service instance ${ctor.name}`);\n\t\t}\n\t}\n\n\tprivate _createServiceInstance(id: ServiceIdentifier, ctor: any, args: any[] = [], supportsDelayedInstantiation: boolean, _trace: Trace, disposeBucket: Set): T {\n\t\tif (!supportsDelayedInstantiation) {\n\t\t\t// eager instantiation\n\t\t\tconst result = this._createInstance(ctor, args, _trace);\n\t\t\tdisposeBucket.add(result);\n\t\t\treturn result;\n\n\t\t} else {\n\t\t\tconst child = new InstantiationService(undefined, this._strict, this, this._enableTracing);\n\t\t\tchild._globalGraphImplicitDependency = String(id);\n\n\t\t\ttype EaryListenerData = {\n\t\t\t\tlistener: Parameters>;\n\t\t\t\tdisposable?: IDisposable;\n\t\t\t};\n\n\t\t\t// Return a proxy object that's backed by an idle value. That\n\t\t\t// strategy is to instantiate services in our idle time or when actually\n\t\t\t// needed but not when injected into a consumer\n\n\t\t\t// return \"empty events\" when the service isn't instantiated yet\n\t\t\tconst earlyListeners = new Map>();\n\n\t\t\tconst idle = new GlobalIdleValue(() => {\n\t\t\t\tconst result = child._createInstance(ctor, args, _trace);\n\n\t\t\t\t// early listeners that we kept are now being subscribed to\n\t\t\t\t// the real service\n\t\t\t\tfor (const [key, values] of earlyListeners) {\n\t\t\t\t\tconst candidate = >(result)[key];\n\t\t\t\t\tif (typeof candidate === 'function') {\n\t\t\t\t\t\tfor (const value of values) {\n\t\t\t\t\t\t\tvalue.disposable = candidate.apply(result, value.listener);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tearlyListeners.clear();\n\t\t\t\tdisposeBucket.add(result);\n\t\t\t\treturn result;\n\t\t\t});\n\t\t\treturn new Proxy(Object.create(null), {\n\t\t\t\tget(target: any, key: PropertyKey): any {\n\n\t\t\t\t\tif (!idle.isInitialized) {\n\t\t\t\t\t\t// looks like an event\n\t\t\t\t\t\tif (typeof key === 'string' && (key.startsWith('onDid') || key.startsWith('onWill'))) {\n\t\t\t\t\t\t\tlet list = earlyListeners.get(key);\n\t\t\t\t\t\t\tif (!list) {\n\t\t\t\t\t\t\t\tlist = new LinkedList();\n\t\t\t\t\t\t\t\tearlyListeners.set(key, list);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst event: Event = (callback, thisArg, disposables) => {\n\t\t\t\t\t\t\t\tif (idle.isInitialized) {\n\t\t\t\t\t\t\t\t\treturn idle.value[key](callback, thisArg, disposables);\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tconst entry: EaryListenerData = { listener: [callback, thisArg, disposables], disposable: undefined };\n\t\t\t\t\t\t\t\t\tconst rm = list.push(entry);\n\t\t\t\t\t\t\t\t\tconst result = toDisposable(() => {\n\t\t\t\t\t\t\t\t\t\trm();\n\t\t\t\t\t\t\t\t\t\tentry.disposable?.dispose();\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\treturn result;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\treturn event;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// value already exists\n\t\t\t\t\tif (key in target) {\n\t\t\t\t\t\treturn target[key];\n\t\t\t\t\t}\n\n\t\t\t\t\t// create value\n\t\t\t\t\tconst obj = idle.value;\n\t\t\t\t\tlet prop = obj[key];\n\t\t\t\t\tif (typeof prop !== 'function') {\n\t\t\t\t\t\treturn prop;\n\t\t\t\t\t}\n\t\t\t\t\tprop = prop.bind(obj);\n\t\t\t\t\ttarget[key] = prop;\n\t\t\t\t\treturn prop;\n\t\t\t\t},\n\t\t\t\tset(_target: T, p: PropertyKey, value: any): boolean {\n\t\t\t\t\tidle.value[p] = value;\n\t\t\t\t\treturn true;\n\t\t\t\t},\n\t\t\t\tgetPrototypeOf(_target: T) {\n\t\t\t\t\treturn ctor.prototype;\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\n\tprivate _throwIfStrict(msg: string, printWarning: boolean): void {\n\t\tif (printWarning) {\n\t\t\tconsole.warn(msg);\n\t\t}\n\t\tif (this._strict) {\n\t\t\tthrow new Error(msg);\n\t\t}\n\t}\n}\n\n//#region -- tracing ---\n\nconst enum TraceType {\n\tNone = 0,\n\tCreation = 1,\n\tInvocation = 2,\n\tBranch = 3,\n}\n\nexport class Trace {\n\n\tstatic all = new Set();\n\n\tprivate static readonly _None = new class extends Trace {\n\t\tconstructor() { super(TraceType.None, null); }\n\t\toverride stop() { }\n\t\toverride branch() { return this; }\n\t};\n\n\tstatic traceInvocation(_enableTracing: boolean, ctor: any): Trace {\n\t\treturn !_enableTracing ? Trace._None : new Trace(TraceType.Invocation, ctor.name || new Error().stack!.split('\\n').slice(3, 4).join('\\n'));\n\t}\n\n\tstatic traceCreation(_enableTracing: boolean, ctor: any): Trace {\n\t\treturn !_enableTracing ? Trace._None : new Trace(TraceType.Creation, ctor.name);\n\t}\n\n\tprivate static _totals: number = 0;\n\tprivate readonly _start: number = Date.now();\n\tprivate readonly _dep: [ServiceIdentifier, boolean, Trace?][] = [];\n\n\tprivate constructor(\n\t\treadonly type: TraceType,\n\t\treadonly name: string | null\n\t) { }\n\n\tbranch(id: ServiceIdentifier, first: boolean): Trace {\n\t\tconst child = new Trace(TraceType.Branch, id.toString());\n\t\tthis._dep.push([id, first, child]);\n\t\treturn child;\n\t}\n\n\tstop() {\n\t\tconst dur = Date.now() - this._start;\n\t\tTrace._totals += dur;\n\n\t\tlet causedCreation = false;\n\n\t\tfunction printChild(n: number, trace: Trace) {\n\t\t\tconst res: string[] = [];\n\t\t\tconst prefix = new Array(n + 1).join('\\t');\n\t\t\tfor (const [id, first, child] of trace._dep) {\n\t\t\t\tif (first && child) {\n\t\t\t\t\tcausedCreation = true;\n\t\t\t\t\tres.push(`${prefix}CREATES -> ${id}`);\n\t\t\t\t\tconst nested = printChild(n + 1, child);\n\t\t\t\t\tif (nested) {\n\t\t\t\t\t\tres.push(nested);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tres.push(`${prefix}uses -> ${id}`);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn res.join('\\n');\n\t\t}\n\n\t\tconst lines = [\n\t\t\t`${this.type === TraceType.Creation ? 'CREATE' : 'CALL'} ${this.name}`,\n\t\t\t`${printChild(1, this)}`,\n\t\t\t`DONE, took ${dur.toFixed(2)}ms (grand total ${Trace._totals.toFixed(2)}ms)`\n\t\t];\n\n\t\tif (dur > 2 || causedCreation) {\n\t\t\tTrace.all.add(lines.join('\\n'));\n\t\t}\n\t}\n}\n\n//#endregion\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\nimport { illegalArgument } from 'vs/base/common/errors';\nimport { AriaLabelProvider, ElectronAcceleratorLabelProvider, UILabelProvider, UserSettingsLabelProvider } from 'vs/base/common/keybindingLabels';\nimport { Chord, SingleModifierChord, ResolvedKeybinding, ResolvedChord } from 'vs/base/common/keybindings';\nimport { OperatingSystem } from 'vs/base/common/platform';\n\nexport abstract class BaseResolvedKeybinding extends ResolvedKeybinding {\n\n\tprotected readonly _os: OperatingSystem;\n\tprotected readonly _chords: readonly T[];\n\n\tconstructor(os: OperatingSystem, chords: readonly T[]) {\n\t\tsuper();\n\t\tif (chords.length === 0) {\n\t\t\tthrow illegalArgument(`chords`);\n\t\t}\n\t\tthis._os = os;\n\t\tthis._chords = chords;\n\t}\n\n\tpublic getLabel(): string | null {\n\t\treturn UILabelProvider.toLabel(this._os, this._chords, (keybinding) => this._getLabel(keybinding));\n\t}\n\n\tpublic getAriaLabel(): string | null {\n\t\treturn AriaLabelProvider.toLabel(this._os, this._chords, (keybinding) => this._getAriaLabel(keybinding));\n\t}\n\n\tpublic getElectronAccelerator(): string | null {\n\t\tif (this._chords.length > 1) {\n\t\t\t// [Electron Accelerators] Electron cannot handle chords\n\t\t\treturn null;\n\t\t}\n\t\tif (this._chords[0].isDuplicateModifierCase()) {\n\t\t\t// [Electron Accelerators] Electron cannot handle modifier only keybindings\n\t\t\t// e.g. \"shift shift\"\n\t\t\treturn null;\n\t\t}\n\t\treturn ElectronAcceleratorLabelProvider.toLabel(this._os, this._chords, (keybinding) => this._getElectronAccelerator(keybinding));\n\t}\n\n\tpublic getUserSettingsLabel(): string | null {\n\t\treturn UserSettingsLabelProvider.toLabel(this._os, this._chords, (keybinding) => this._getUserSettingsLabel(keybinding));\n\t}\n\n\tpublic hasMultipleChords(): boolean {\n\t\treturn (this._chords.length > 1);\n\t}\n\n\tpublic getChords(): ResolvedChord[] {\n\t\treturn this._chords.map((keybinding) => this._getChord(keybinding));\n\t}\n\n\tprivate _getChord(keybinding: T): ResolvedChord {\n\t\treturn new ResolvedChord(\n\t\t\tkeybinding.ctrlKey,\n\t\t\tkeybinding.shiftKey,\n\t\t\tkeybinding.altKey,\n\t\t\tkeybinding.metaKey,\n\t\t\tthis._getLabel(keybinding),\n\t\t\tthis._getAriaLabel(keybinding)\n\t\t);\n\t}\n\n\tpublic getDispatchChords(): (string | null)[] {\n\t\treturn this._chords.map((keybinding) => this._getChordDispatch(keybinding));\n\t}\n\n\tpublic getSingleModifierDispatchChords(): (SingleModifierChord | null)[] {\n\t\treturn this._chords.map((keybinding) => this._getSingleModifierChordDispatch(keybinding));\n\t}\n\n\tprotected abstract _getLabel(keybinding: T): string | null;\n\tprotected abstract _getAriaLabel(keybinding: T): string | null;\n\tprotected abstract _getElectronAccelerator(keybinding: T): string | null;\n\tprotected abstract _getUserSettingsLabel(keybinding: T): string | null;\n\tprotected abstract _getChordDispatch(keybinding: T): string | null;\n\tprotected abstract _getSingleModifierChordDispatch(keybinding: T): SingleModifierChord | null;\n}\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\nimport { Event } from 'vs/base/common/event';\nimport { KeyCode } from 'vs/base/common/keyCodes';\nimport { ResolvedKeybinding } from 'vs/base/common/keybindings';\nimport { IContextKeyService, IContextKeyServiceTarget } from 'vs/platform/contextkey/common/contextkey';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\nimport { ResolutionResult } from 'vs/platform/keybinding/common/keybindingResolver';\nimport { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem';\n\nexport interface IKeyboardEvent {\n\treadonly _standardKeyboardEventBrand: true;\n\n\treadonly ctrlKey: boolean;\n\treadonly shiftKey: boolean;\n\treadonly altKey: boolean;\n\treadonly metaKey: boolean;\n\treadonly keyCode: KeyCode;\n}\n\nexport const IKeybindingService = createDecorator('keybindingService');\n\nexport interface IKeybindingService {\n\treadonly _serviceBrand: undefined;\n\n\tonDidUpdateKeybindings: Event;\n\n\tresolveKeyboardEvent(keyboardEvent: IKeyboardEvent): ResolvedKeybinding;\n\n\t/**\n\t * Resolve and dispatch `keyboardEvent` and invoke the command.\n\t */\n\tdispatchEvent(e: IKeyboardEvent, target: IContextKeyServiceTarget): boolean;\n\n\t/**\n\t * Resolve and dispatch `keyboardEvent`, but do not invoke the command or change inner state.\n\t */\n\tsoftDispatch(keyboardEvent: IKeyboardEvent, target: IContextKeyServiceTarget): ResolutionResult;\n\n\t/**\n\t * Look up the preferred (last defined) keybinding for a command.\n\t * @returns The preferred keybinding or null if the command is not bound.\n\t */\n\tlookupKeybinding(commandId: string, context?: IContextKeyService): ResolvedKeybinding | undefined;\n\n\tgetKeybindings(): readonly ResolvedKeybindingItem[];\n\n\t/**\n\t * Will the given key event produce a character that's rendered on screen, e.g. in a\n\t * text box. *Note* that the results of this function can be incorrect.\n\t */\n\tmightProducePrintableCharacter(event: IKeyboardEvent): boolean;\n}\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 *--------------------------------------------------------------------------------------------*/\nimport * as dom from 'vs/base/browser/dom';\nimport { HoverAction } from 'vs/base/browser/ui/hover/hoverWidget';\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport { IEditorHoverAction, IEditorHoverStatusBar } from 'vs/editor/contrib/hover/browser/hoverTypes';\nimport { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';\n\nconst $ = dom.$;\n\nexport class EditorHoverStatusBar extends Disposable implements IEditorHoverStatusBar {\n\n\tpublic readonly hoverElement: HTMLElement;\n\tprivate readonly actionsElement: HTMLElement;\n\tprivate _hasContent: boolean = false;\n\n\tpublic get hasContent() {\n\t\treturn this._hasContent;\n\t}\n\n\tconstructor(\n\t\t@IKeybindingService private readonly _keybindingService: IKeybindingService,\n\t) {\n\t\tsuper();\n\t\tthis.hoverElement = $('div.hover-row.status-bar');\n\t\tthis.hoverElement.tabIndex = 0;\n\t\tthis.actionsElement = dom.append(this.hoverElement, $('div.actions'));\n\t}\n\n\tpublic addAction(\n\t\tactionOptions: {\n\t\t\tlabel: string;\n\t\t\ticonClass?: string; run: (target: HTMLElement) => void;\n\t\t\tcommandId: string;\n\t\t}): IEditorHoverAction {\n\n\t\tconst keybinding = this._keybindingService.lookupKeybinding(actionOptions.commandId);\n\t\tconst keybindingLabel = keybinding ? keybinding.getLabel() : null;\n\t\tthis._hasContent = true;\n\t\treturn this._register(HoverAction.render(this.actionsElement, actionOptions, keybindingLabel));\n\t}\n\n\tpublic append(element: HTMLElement): HTMLElement {\n\t\tconst result = dom.append(this.actionsElement, element);\n\t\tthis._hasContent = true;\n\t\treturn result;\n\t}\n}\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\nimport * as dom from 'vs/base/browser/dom';\nimport { ContentWidgetPositionPreference, ICodeEditor, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser';\nimport { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions';\nimport { HoverStartSource } from 'vs/editor/contrib/hover/browser/hoverOperation';\nimport { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';\nimport { ResizableContentWidget } from 'vs/editor/contrib/hover/browser/resizableContentWidget';\nimport { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';\nimport { IConfigurationService } from 'vs/platform/configuration/common/configuration';\nimport { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';\nimport { EditorContextKeys } from 'vs/editor/common/editorContextKeys';\nimport { getHoverAccessibleViewHint, HoverWidget } from 'vs/base/browser/ui/hover/hoverWidget';\nimport { PositionAffinity } from 'vs/editor/common/model';\nimport { ContentHoverVisibleData } from 'vs/editor/contrib/hover/browser/contentHoverTypes';\n\nconst HORIZONTAL_SCROLLING_BY = 30;\nconst CONTAINER_HEIGHT_PADDING = 6;\n\nexport class ContentHoverWidget extends ResizableContentWidget {\n\n\tpublic static ID = 'editor.contrib.resizableContentHoverWidget';\n\tprivate static _lastDimensions: dom.Dimension = new dom.Dimension(0, 0);\n\n\tprivate _visibleData: ContentHoverVisibleData | undefined;\n\tprivate _positionPreference: ContentWidgetPositionPreference | undefined;\n\tprivate _minimumSize: dom.Dimension;\n\tprivate _contentWidth: number | undefined;\n\n\tprivate readonly _hover: HoverWidget = this._register(new HoverWidget());\n\tprivate readonly _hoverVisibleKey: IContextKey;\n\tprivate readonly _hoverFocusedKey: IContextKey;\n\n\tpublic get isColorPickerVisible(): boolean {\n\t\treturn Boolean(this._visibleData?.colorPicker);\n\t}\n\n\tpublic get isVisibleFromKeyboard(): boolean {\n\t\treturn (this._visibleData?.source === HoverStartSource.Keyboard);\n\t}\n\n\tpublic get isVisible(): boolean {\n\t\treturn this._hoverVisibleKey.get() ?? false;\n\t}\n\n\tpublic get isFocused(): boolean {\n\t\treturn this._hoverFocusedKey.get() ?? false;\n\t}\n\n\tconstructor(\n\t\teditor: ICodeEditor,\n\t\t@IContextKeyService contextKeyService: IContextKeyService,\n\t\t@IConfigurationService private readonly _configurationService: IConfigurationService,\n\t\t@IAccessibilityService private readonly _accessibilityService: IAccessibilityService,\n\t\t@IKeybindingService private readonly _keybindingService: IKeybindingService\n\t) {\n\t\tconst minimumHeight = editor.getOption(EditorOption.lineHeight) + 8;\n\t\tconst minimumWidth = 150;\n\t\tconst minimumSize = new dom.Dimension(minimumWidth, minimumHeight);\n\t\tsuper(editor, minimumSize);\n\n\t\tthis._minimumSize = minimumSize;\n\t\tthis._hoverVisibleKey = EditorContextKeys.hoverVisible.bindTo(contextKeyService);\n\t\tthis._hoverFocusedKey = EditorContextKeys.hoverFocused.bindTo(contextKeyService);\n\n\t\tdom.append(this._resizableNode.domNode, this._hover.containerDomNode);\n\t\tthis._resizableNode.domNode.style.zIndex = '50';\n\n\t\tthis._register(this._editor.onDidLayoutChange(() => {\n\t\t\tif (this.isVisible) {\n\t\t\t\tthis._updateMaxDimensions();\n\t\t\t}\n\t\t}));\n\t\tthis._register(this._editor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => {\n\t\t\tif (e.hasChanged(EditorOption.fontInfo)) {\n\t\t\t\tthis._updateFont();\n\t\t\t}\n\t\t}));\n\t\tconst focusTracker = this._register(dom.trackFocus(this._resizableNode.domNode));\n\t\tthis._register(focusTracker.onDidFocus(() => {\n\t\t\tthis._hoverFocusedKey.set(true);\n\t\t}));\n\t\tthis._register(focusTracker.onDidBlur(() => {\n\t\t\tthis._hoverFocusedKey.set(false);\n\t\t}));\n\t\tthis._setHoverData(undefined);\n\t\tthis._editor.addContentWidget(this);\n\t}\n\n\tpublic override dispose(): void {\n\t\tsuper.dispose();\n\t\tthis._visibleData?.disposables.dispose();\n\t\tthis._editor.removeContentWidget(this);\n\t}\n\n\tpublic getId(): string {\n\t\treturn ContentHoverWidget.ID;\n\t}\n\n\tprivate static _applyDimensions(container: HTMLElement, width: number | string, height: number | string): void {\n\t\tconst transformedWidth = typeof width === 'number' ? `${width}px` : width;\n\t\tconst transformedHeight = typeof height === 'number' ? `${height}px` : height;\n\t\tcontainer.style.width = transformedWidth;\n\t\tcontainer.style.height = transformedHeight;\n\t}\n\n\tprivate _setContentsDomNodeDimensions(width: number | string, height: number | string): void {\n\t\tconst contentsDomNode = this._hover.contentsDomNode;\n\t\treturn ContentHoverWidget._applyDimensions(contentsDomNode, width, height);\n\t}\n\n\tprivate _setContainerDomNodeDimensions(width: number | string, height: number | string): void {\n\t\tconst containerDomNode = this._hover.containerDomNode;\n\t\treturn ContentHoverWidget._applyDimensions(containerDomNode, width, height);\n\t}\n\n\tprivate _setHoverWidgetDimensions(width: number | string, height: number | string): void {\n\t\tthis._setContentsDomNodeDimensions(width, height);\n\t\tthis._setContainerDomNodeDimensions(width, height);\n\t\tthis._layoutContentWidget();\n\t}\n\n\tprivate static _applyMaxDimensions(container: HTMLElement, width: number | string, height: number | string) {\n\t\tconst transformedWidth = typeof width === 'number' ? `${width}px` : width;\n\t\tconst transformedHeight = typeof height === 'number' ? `${height}px` : height;\n\t\tcontainer.style.maxWidth = transformedWidth;\n\t\tcontainer.style.maxHeight = transformedHeight;\n\t}\n\n\tprivate _setHoverWidgetMaxDimensions(width: number | string, height: number | string): void {\n\t\tContentHoverWidget._applyMaxDimensions(this._hover.contentsDomNode, width, height);\n\t\tContentHoverWidget._applyMaxDimensions(this._hover.containerDomNode, width, height);\n\t\tthis._hover.containerDomNode.style.setProperty('--vscode-hover-maxWidth', typeof width === 'number' ? `${width}px` : width);\n\t\tthis._layoutContentWidget();\n\t}\n\n\tprivate _setAdjustedHoverWidgetDimensions(size: dom.Dimension): void {\n\t\tthis._setHoverWidgetMaxDimensions('none', 'none');\n\t\tconst width = size.width;\n\t\tconst height = size.height;\n\t\tthis._setHoverWidgetDimensions(width, height);\n\t}\n\n\tprivate _updateResizableNodeMaxDimensions(): void {\n\t\tconst maxRenderingWidth = this._findMaximumRenderingWidth() ?? Infinity;\n\t\tconst maxRenderingHeight = this._findMaximumRenderingHeight() ?? Infinity;\n\t\tthis._resizableNode.maxSize = new dom.Dimension(maxRenderingWidth, maxRenderingHeight);\n\t\tthis._setHoverWidgetMaxDimensions(maxRenderingWidth, maxRenderingHeight);\n\t}\n\n\tprotected override _resize(size: dom.Dimension): void {\n\t\tContentHoverWidget._lastDimensions = new dom.Dimension(size.width, size.height);\n\t\tthis._setAdjustedHoverWidgetDimensions(size);\n\t\tthis._resizableNode.layout(size.height, size.width);\n\t\tthis._updateResizableNodeMaxDimensions();\n\t\tthis._hover.scrollbar.scanDomNode();\n\t\tthis._editor.layoutContentWidget(this);\n\t\tthis._visibleData?.colorPicker?.layout();\n\t}\n\n\tprivate _findAvailableSpaceVertically(): number | undefined {\n\t\tconst position = this._visibleData?.showAtPosition;\n\t\tif (!position) {\n\t\t\treturn;\n\t\t}\n\t\treturn this._positionPreference === ContentWidgetPositionPreference.ABOVE ?\n\t\t\tthis._availableVerticalSpaceAbove(position)\n\t\t\t: this._availableVerticalSpaceBelow(position);\n\t}\n\n\tprivate _findMaximumRenderingHeight(): number | undefined {\n\t\tconst availableSpace = this._findAvailableSpaceVertically();\n\t\tif (!availableSpace) {\n\t\t\treturn;\n\t\t}\n\t\t// Padding needed in order to stop the resizing down to a smaller height\n\t\tlet maximumHeight = CONTAINER_HEIGHT_PADDING;\n\t\tArray.from(this._hover.contentsDomNode.children).forEach((hoverPart) => {\n\t\t\tmaximumHeight += hoverPart.clientHeight;\n\t\t});\n\n\t\treturn Math.min(availableSpace, maximumHeight);\n\t}\n\n\tprivate _isHoverTextOverflowing(): boolean {\n\t\t// To find out if the text is overflowing, we will disable wrapping, check the widths, and then re-enable wrapping\n\t\tthis._hover.containerDomNode.style.setProperty('--vscode-hover-whiteSpace', 'nowrap');\n\t\tthis._hover.containerDomNode.style.setProperty('--vscode-hover-sourceWhiteSpace', 'nowrap');\n\n\t\tconst overflowing = Array.from(this._hover.contentsDomNode.children).some((hoverElement) => {\n\t\t\treturn hoverElement.scrollWidth > hoverElement.clientWidth;\n\t\t});\n\n\t\tthis._hover.containerDomNode.style.removeProperty('--vscode-hover-whiteSpace');\n\t\tthis._hover.containerDomNode.style.removeProperty('--vscode-hover-sourceWhiteSpace');\n\n\t\treturn overflowing;\n\t}\n\n\tprivate _findMaximumRenderingWidth(): number | undefined {\n\t\tif (!this._editor || !this._editor.hasModel()) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst overflowing = this._isHoverTextOverflowing();\n\t\tconst initialWidth = (\n\t\t\ttypeof this._contentWidth === 'undefined'\n\t\t\t\t? 0\n\t\t\t\t: this._contentWidth - 2 // - 2 for the borders\n\t\t);\n\n\t\tif (overflowing || this._hover.containerDomNode.clientWidth < initialWidth) {\n\t\t\tconst bodyBoxWidth = dom.getClientArea(this._hover.containerDomNode.ownerDocument.body).width;\n\t\t\tconst horizontalPadding = 14;\n\t\t\treturn bodyBoxWidth - horizontalPadding;\n\t\t} else {\n\t\t\treturn this._hover.containerDomNode.clientWidth + 2;\n\t\t}\n\t}\n\n\tpublic isMouseGettingCloser(posx: number, posy: number): boolean {\n\n\t\tif (!this._visibleData) {\n\t\t\treturn false;\n\t\t}\n\t\tif (\n\t\t\ttypeof this._visibleData.initialMousePosX === 'undefined'\n\t\t\t|| typeof this._visibleData.initialMousePosY === 'undefined'\n\t\t) {\n\t\t\tthis._visibleData.initialMousePosX = posx;\n\t\t\tthis._visibleData.initialMousePosY = posy;\n\t\t\treturn false;\n\t\t}\n\n\t\tconst widgetRect = dom.getDomNodePagePosition(this.getDomNode());\n\t\tif (typeof this._visibleData.closestMouseDistance === 'undefined') {\n\t\t\tthis._visibleData.closestMouseDistance = computeDistanceFromPointToRectangle(\n\t\t\t\tthis._visibleData.initialMousePosX,\n\t\t\t\tthis._visibleData.initialMousePosY,\n\t\t\t\twidgetRect.left,\n\t\t\t\twidgetRect.top,\n\t\t\t\twidgetRect.width,\n\t\t\t\twidgetRect.height\n\t\t\t);\n\t\t}\n\n\t\tconst distance = computeDistanceFromPointToRectangle(\n\t\t\tposx,\n\t\t\tposy,\n\t\t\twidgetRect.left,\n\t\t\twidgetRect.top,\n\t\t\twidgetRect.width,\n\t\t\twidgetRect.height\n\t\t);\n\t\tif (distance > this._visibleData.closestMouseDistance + 4 /* tolerance of 4 pixels */) {\n\t\t\t// The mouse is getting farther away\n\t\t\treturn false;\n\t\t}\n\n\t\tthis._visibleData.closestMouseDistance = Math.min(this._visibleData.closestMouseDistance, distance);\n\t\treturn true;\n\t}\n\n\tprivate _setHoverData(hoverData: ContentHoverVisibleData | undefined): void {\n\t\tthis._visibleData?.disposables.dispose();\n\t\tthis._visibleData = hoverData;\n\t\tthis._hoverVisibleKey.set(!!hoverData);\n\t\tthis._hover.containerDomNode.classList.toggle('hidden', !hoverData);\n\t}\n\n\tprivate _updateFont(): void {\n\t\tconst { fontSize, lineHeight } = this._editor.getOption(EditorOption.fontInfo);\n\t\tconst contentsDomNode = this._hover.contentsDomNode;\n\t\tcontentsDomNode.style.fontSize = `${fontSize}px`;\n\t\tcontentsDomNode.style.lineHeight = `${lineHeight / fontSize}`;\n\t\tconst codeClasses: HTMLElement[] = Array.prototype.slice.call(this._hover.contentsDomNode.getElementsByClassName('code'));\n\t\tcodeClasses.forEach(node => this._editor.applyFontInfo(node));\n\t}\n\n\tprivate _updateContent(node: DocumentFragment): void {\n\t\tconst contentsDomNode = this._hover.contentsDomNode;\n\t\tcontentsDomNode.style.paddingBottom = '';\n\t\tcontentsDomNode.textContent = '';\n\t\tcontentsDomNode.appendChild(node);\n\t}\n\n\tprivate _layoutContentWidget(): void {\n\t\tthis._editor.layoutContentWidget(this);\n\t\tthis._hover.onContentsChanged();\n\t}\n\n\tprivate _updateMaxDimensions() {\n\t\tconst height = Math.max(this._editor.getLayoutInfo().height / 4, 250, ContentHoverWidget._lastDimensions.height);\n\t\tconst width = Math.max(this._editor.getLayoutInfo().width * 0.66, 500, ContentHoverWidget._lastDimensions.width);\n\t\tthis._setHoverWidgetMaxDimensions(width, height);\n\t}\n\n\tprivate _render(node: DocumentFragment, hoverData: ContentHoverVisibleData) {\n\t\tthis._setHoverData(hoverData);\n\t\tthis._updateFont();\n\t\tthis._updateContent(node);\n\t\tthis._updateMaxDimensions();\n\t\tthis.onContentsChanged();\n\t\t// Simply force a synchronous render on the editor\n\t\t// such that the widget does not really render with left = '0px'\n\t\tthis._editor.render();\n\t}\n\n\toverride getPosition(): IContentWidgetPosition | null {\n\t\tif (!this._visibleData) {\n\t\t\treturn null;\n\t\t}\n\t\treturn {\n\t\t\tposition: this._visibleData.showAtPosition,\n\t\t\tsecondaryPosition: this._visibleData.showAtSecondaryPosition,\n\t\t\tpositionAffinity: this._visibleData.isBeforeContent ? PositionAffinity.LeftOfInjectedText : undefined,\n\t\t\tpreference: [this._positionPreference ?? ContentWidgetPositionPreference.ABOVE]\n\t\t};\n\t}\n\n\tpublic showAt(node: DocumentFragment, hoverData: ContentHoverVisibleData): void {\n\t\tif (!this._editor || !this._editor.hasModel()) {\n\t\t\treturn;\n\t\t}\n\t\tthis._render(node, hoverData);\n\t\tconst widgetHeight = dom.getTotalHeight(this._hover.containerDomNode);\n\t\tconst widgetPosition = hoverData.showAtPosition;\n\t\tthis._positionPreference = this._findPositionPreference(widgetHeight, widgetPosition) ?? ContentWidgetPositionPreference.ABOVE;\n\n\t\t// See https://github.com/microsoft/vscode/issues/140339\n\t\t// TODO: Doing a second layout of the hover after force rendering the editor\n\t\tthis.onContentsChanged();\n\t\tif (hoverData.stoleFocus) {\n\t\t\tthis._hover.containerDomNode.focus();\n\t\t}\n\t\thoverData.colorPicker?.layout();\n\t\t// The aria label overrides the label, so if we add to it, add the contents of the hover\n\t\tconst hoverFocused = this._hover.containerDomNode.ownerDocument.activeElement === this._hover.containerDomNode;\n\t\tconst accessibleViewHint = hoverFocused && getHoverAccessibleViewHint(\n\t\t\tthis._configurationService.getValue('accessibility.verbosity.hover') === true && this._accessibilityService.isScreenReaderOptimized(),\n\t\t\tthis._keybindingService.lookupKeybinding('editor.action.accessibleView')?.getAriaLabel() ?? ''\n\t\t);\n\n\t\tif (accessibleViewHint) {\n\t\t\tthis._hover.contentsDomNode.ariaLabel = this._hover.contentsDomNode.textContent + ', ' + accessibleViewHint;\n\t\t}\n\t}\n\n\tpublic hide(): void {\n\t\tif (!this._visibleData) {\n\t\t\treturn;\n\t\t}\n\t\tconst stoleFocus = this._visibleData.stoleFocus || this._hoverFocusedKey.get();\n\t\tthis._setHoverData(undefined);\n\t\tthis._resizableNode.maxSize = new dom.Dimension(Infinity, Infinity);\n\t\tthis._resizableNode.clearSashHoverState();\n\t\tthis._hoverFocusedKey.set(false);\n\t\tthis._editor.layoutContentWidget(this);\n\t\tif (stoleFocus) {\n\t\t\tthis._editor.focus();\n\t\t}\n\t}\n\n\tprivate _removeConstraintsRenderNormally(): void {\n\t\t// Added because otherwise the initial size of the hover content is smaller than should be\n\t\tconst layoutInfo = this._editor.getLayoutInfo();\n\t\tthis._resizableNode.layout(layoutInfo.height, layoutInfo.width);\n\t\tthis._setHoverWidgetDimensions('auto', 'auto');\n\t}\n\n\tpublic setMinimumDimensions(dimensions: dom.Dimension): void {\n\t\t// We combine the new minimum dimensions with the previous ones\n\t\tthis._minimumSize = new dom.Dimension(\n\t\t\tMath.max(this._minimumSize.width, dimensions.width),\n\t\t\tMath.max(this._minimumSize.height, dimensions.height)\n\t\t);\n\t\tthis._updateMinimumWidth();\n\t}\n\n\tprivate _updateMinimumWidth(): void {\n\t\tconst width = (\n\t\t\ttypeof this._contentWidth === 'undefined'\n\t\t\t\t? this._minimumSize.width\n\t\t\t\t: Math.min(this._contentWidth, this._minimumSize.width)\n\t\t);\n\t\t// We want to avoid that the hover is artificially large, so we use the content width as minimum width\n\t\tthis._resizableNode.minSize = new dom.Dimension(width, this._minimumSize.height);\n\t}\n\n\tpublic onContentsChanged(): void {\n\t\tthis._removeConstraintsRenderNormally();\n\t\tconst containerDomNode = this._hover.containerDomNode;\n\n\t\tlet height = dom.getTotalHeight(containerDomNode);\n\t\tlet width = dom.getTotalWidth(containerDomNode);\n\t\tthis._resizableNode.layout(height, width);\n\n\t\tthis._setHoverWidgetDimensions(width, height);\n\n\t\theight = dom.getTotalHeight(containerDomNode);\n\t\twidth = dom.getTotalWidth(containerDomNode);\n\t\tthis._contentWidth = width;\n\t\tthis._updateMinimumWidth();\n\t\tthis._resizableNode.layout(height, width);\n\n\t\tif (this._visibleData?.showAtPosition) {\n\t\t\tconst widgetHeight = dom.getTotalHeight(this._hover.containerDomNode);\n\t\t\tthis._positionPreference = this._findPositionPreference(widgetHeight, this._visibleData.showAtPosition);\n\t\t}\n\t\tthis._layoutContentWidget();\n\t}\n\n\tpublic focus(): void {\n\t\tthis._hover.containerDomNode.focus();\n\t}\n\n\tpublic scrollUp(): void {\n\t\tconst scrollTop = this._hover.scrollbar.getScrollPosition().scrollTop;\n\t\tconst fontInfo = this._editor.getOption(EditorOption.fontInfo);\n\t\tthis._hover.scrollbar.setScrollPosition({ scrollTop: scrollTop - fontInfo.lineHeight });\n\t}\n\n\tpublic scrollDown(): void {\n\t\tconst scrollTop = this._hover.scrollbar.getScrollPosition().scrollTop;\n\t\tconst fontInfo = this._editor.getOption(EditorOption.fontInfo);\n\t\tthis._hover.scrollbar.setScrollPosition({ scrollTop: scrollTop + fontInfo.lineHeight });\n\t}\n\n\tpublic scrollLeft(): void {\n\t\tconst scrollLeft = this._hover.scrollbar.getScrollPosition().scrollLeft;\n\t\tthis._hover.scrollbar.setScrollPosition({ scrollLeft: scrollLeft - HORIZONTAL_SCROLLING_BY });\n\t}\n\n\tpublic scrollRight(): void {\n\t\tconst scrollLeft = this._hover.scrollbar.getScrollPosition().scrollLeft;\n\t\tthis._hover.scrollbar.setScrollPosition({ scrollLeft: scrollLeft + HORIZONTAL_SCROLLING_BY });\n\t}\n\n\tpublic pageUp(): void {\n\t\tconst scrollTop = this._hover.scrollbar.getScrollPosition().scrollTop;\n\t\tconst scrollHeight = this._hover.scrollbar.getScrollDimensions().height;\n\t\tthis._hover.scrollbar.setScrollPosition({ scrollTop: scrollTop - scrollHeight });\n\t}\n\n\tpublic pageDown(): void {\n\t\tconst scrollTop = this._hover.scrollbar.getScrollPosition().scrollTop;\n\t\tconst scrollHeight = this._hover.scrollbar.getScrollDimensions().height;\n\t\tthis._hover.scrollbar.setScrollPosition({ scrollTop: scrollTop + scrollHeight });\n\t}\n\n\tpublic goToTop(): void {\n\t\tthis._hover.scrollbar.setScrollPosition({ scrollTop: 0 });\n\t}\n\n\tpublic goToBottom(): void {\n\t\tthis._hover.scrollbar.setScrollPosition({ scrollTop: this._hover.scrollbar.getScrollDimensions().scrollHeight });\n\t}\n}\n\nfunction computeDistanceFromPointToRectangle(pointX: number, pointY: number, left: number, top: number, width: number, height: number): number {\n\tconst x = (left + width / 2); // x center of rectangle\n\tconst y = (top + height / 2); // y center of rectangle\n\tconst dx = Math.max(Math.abs(pointX - x) - width / 2, 0);\n\tconst dy = Math.max(Math.abs(pointY - y) - height / 2, 0);\n\treturn Math.sqrt(dx * dx + dy * dy);\n}\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\nimport { implies, ContextKeyExpression, ContextKeyExprType, IContext, IContextKeyService, expressionsAreEqualWithConstantSubstitution } from 'vs/platform/contextkey/common/contextkey';\nimport { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem';\n\n//#region resolution-result\n\nexport const enum ResultKind {\n\t/** No keybinding found this sequence of chords */\n\tNoMatchingKb,\n\n\t/** There're several keybindings that have the given sequence of chords as a prefix */\n\tMoreChordsNeeded,\n\n\t/** A single keybinding found to be dispatched/invoked */\n\tKbFound\n}\n\nexport type ResolutionResult =\n\t| { kind: ResultKind.NoMatchingKb }\n\t| { kind: ResultKind.MoreChordsNeeded }\n\t| { kind: ResultKind.KbFound; commandId: string | null; commandArgs: any; isBubble: boolean };\n\n\n// util definitions to make working with the above types easier within this module:\n\nexport const NoMatchingKb: ResolutionResult = { kind: ResultKind.NoMatchingKb };\nconst MoreChordsNeeded: ResolutionResult = { kind: ResultKind.MoreChordsNeeded };\nfunction KbFound(commandId: string | null, commandArgs: any, isBubble: boolean): ResolutionResult {\n\treturn { kind: ResultKind.KbFound, commandId, commandArgs, isBubble };\n}\n\n//#endregion\n\n/**\n * Stores mappings from keybindings to commands and from commands to keybindings.\n * Given a sequence of chords, `resolve`s which keybinding it matches\n */\nexport class KeybindingResolver {\n\tprivate readonly _log: (str: string) => void;\n\tprivate readonly _defaultKeybindings: ResolvedKeybindingItem[];\n\tprivate readonly _keybindings: ResolvedKeybindingItem[];\n\tprivate readonly _defaultBoundCommands: Map;\n\tprivate readonly _map: Map;\n\tprivate readonly _lookupMap: Map;\n\n\tconstructor(\n\t\t/** built-in and extension-provided keybindings */\n\t\tdefaultKeybindings: ResolvedKeybindingItem[],\n\t\t/** user's keybindings */\n\t\toverrides: ResolvedKeybindingItem[],\n\t\tlog: (str: string) => void\n\t) {\n\t\tthis._log = log;\n\t\tthis._defaultKeybindings = defaultKeybindings;\n\n\t\tthis._defaultBoundCommands = new Map();\n\t\tfor (const defaultKeybinding of defaultKeybindings) {\n\t\t\tconst command = defaultKeybinding.command;\n\t\t\tif (command && command.charAt(0) !== '-') {\n\t\t\t\tthis._defaultBoundCommands.set(command, true);\n\t\t\t}\n\t\t}\n\n\t\tthis._map = new Map();\n\t\tthis._lookupMap = new Map();\n\n\t\tthis._keybindings = KeybindingResolver.handleRemovals(([] as ResolvedKeybindingItem[]).concat(defaultKeybindings).concat(overrides));\n\t\tfor (let i = 0, len = this._keybindings.length; i < len; i++) {\n\t\t\tconst k = this._keybindings[i];\n\t\t\tif (k.chords.length === 0) {\n\t\t\t\t// unbound\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// substitute with constants that are registered after startup - https://github.com/microsoft/vscode/issues/174218#issuecomment-1437972127\n\t\t\tconst when = k.when?.substituteConstants();\n\n\t\t\tif (when && when.type === ContextKeyExprType.False) {\n\t\t\t\t// when condition is false\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tthis._addKeyPress(k.chords[0], k);\n\t\t}\n\t}\n\n\tprivate static _isTargetedForRemoval(defaultKb: ResolvedKeybindingItem, keypress: string[] | null, when: ContextKeyExpression | undefined): boolean {\n\t\tif (keypress) {\n\t\t\tfor (let i = 0; i < keypress.length; i++) {\n\t\t\t\tif (keypress[i] !== defaultKb.chords[i]) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// `true` means always, as does `undefined`\n\t\t// so we will treat `true` === `undefined`\n\t\tif (when && when.type !== ContextKeyExprType.True) {\n\t\t\tif (!defaultKb.when) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (!expressionsAreEqualWithConstantSubstitution(when, defaultKb.when)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\n\t}\n\n\t/**\n\t * Looks for rules containing \"-commandId\" and removes them.\n\t */\n\tpublic static handleRemovals(rules: ResolvedKeybindingItem[]): ResolvedKeybindingItem[] {\n\t\t// Do a first pass and construct a hash-map for removals\n\t\tconst removals = new Map();\n\t\tfor (let i = 0, len = rules.length; i < len; i++) {\n\t\t\tconst rule = rules[i];\n\t\t\tif (rule.command && rule.command.charAt(0) === '-') {\n\t\t\t\tconst command = rule.command.substring(1);\n\t\t\t\tif (!removals.has(command)) {\n\t\t\t\t\tremovals.set(command, [rule]);\n\t\t\t\t} else {\n\t\t\t\t\tremovals.get(command)!.push(rule);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (removals.size === 0) {\n\t\t\t// There are no removals\n\t\t\treturn rules;\n\t\t}\n\n\t\t// Do a second pass and keep only non-removed keybindings\n\t\tconst result: ResolvedKeybindingItem[] = [];\n\t\tfor (let i = 0, len = rules.length; i < len; i++) {\n\t\t\tconst rule = rules[i];\n\n\t\t\tif (!rule.command || rule.command.length === 0) {\n\t\t\t\tresult.push(rule);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (rule.command.charAt(0) === '-') {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst commandRemovals = removals.get(rule.command);\n\t\t\tif (!commandRemovals || !rule.isDefault) {\n\t\t\t\tresult.push(rule);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tlet isRemoved = false;\n\t\t\tfor (const commandRemoval of commandRemovals) {\n\t\t\t\tconst when = commandRemoval.when;\n\t\t\t\tif (this._isTargetedForRemoval(rule, commandRemoval.chords, when)) {\n\t\t\t\t\tisRemoved = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!isRemoved) {\n\t\t\t\tresult.push(rule);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate _addKeyPress(keypress: string, item: ResolvedKeybindingItem): void {\n\n\t\tconst conflicts = this._map.get(keypress);\n\n\t\tif (typeof conflicts === 'undefined') {\n\t\t\t// There is no conflict so far\n\t\t\tthis._map.set(keypress, [item]);\n\t\t\tthis._addToLookupMap(item);\n\t\t\treturn;\n\t\t}\n\n\t\tfor (let i = conflicts.length - 1; i >= 0; i--) {\n\t\t\tconst conflict = conflicts[i];\n\n\t\t\tif (conflict.command === item.command) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Test if the shorter keybinding is a prefix of the longer one.\n\t\t\t// If the shorter keybinding is a prefix, it effectively will shadow the longer one and is considered a conflict.\n\t\t\tlet isShorterKbPrefix = true;\n\t\t\tfor (let i = 1; i < conflict.chords.length && i < item.chords.length; i++) {\n\t\t\t\tif (conflict.chords[i] !== item.chords[i]) {\n\t\t\t\t\t// The ith step does not conflict\n\t\t\t\t\tisShorterKbPrefix = false;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!isShorterKbPrefix) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (KeybindingResolver.whenIsEntirelyIncluded(conflict.when, item.when)) {\n\t\t\t\t// `item` completely overwrites `conflict`\n\t\t\t\t// Remove conflict from the lookupMap\n\t\t\t\tthis._removeFromLookupMap(conflict);\n\t\t\t}\n\t\t}\n\n\t\tconflicts.push(item);\n\t\tthis._addToLookupMap(item);\n\t}\n\n\tprivate _addToLookupMap(item: ResolvedKeybindingItem): void {\n\t\tif (!item.command) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet arr = this._lookupMap.get(item.command);\n\t\tif (typeof arr === 'undefined') {\n\t\t\tarr = [item];\n\t\t\tthis._lookupMap.set(item.command, arr);\n\t\t} else {\n\t\t\tarr.push(item);\n\t\t}\n\t}\n\n\tprivate _removeFromLookupMap(item: ResolvedKeybindingItem): void {\n\t\tif (!item.command) {\n\t\t\treturn;\n\t\t}\n\t\tconst arr = this._lookupMap.get(item.command);\n\t\tif (typeof arr === 'undefined') {\n\t\t\treturn;\n\t\t}\n\t\tfor (let i = 0, len = arr.length; i < len; i++) {\n\t\t\tif (arr[i] === item) {\n\t\t\t\tarr.splice(i, 1);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Returns true if it is provable `a` implies `b`.\n\t */\n\tpublic static whenIsEntirelyIncluded(a: ContextKeyExpression | null | undefined, b: ContextKeyExpression | null | undefined): boolean {\n\t\tif (!b || b.type === ContextKeyExprType.True) {\n\t\t\treturn true;\n\t\t}\n\t\tif (!a || a.type === ContextKeyExprType.True) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn implies(a, b);\n\t}\n\n\tpublic getKeybindings(): readonly ResolvedKeybindingItem[] {\n\t\treturn this._keybindings;\n\t}\n\n\tpublic lookupPrimaryKeybinding(commandId: string, context: IContextKeyService): ResolvedKeybindingItem | null {\n\t\tconst items = this._lookupMap.get(commandId);\n\t\tif (typeof items === 'undefined' || items.length === 0) {\n\t\t\treturn null;\n\t\t}\n\t\tif (items.length === 1) {\n\t\t\treturn items[0];\n\t\t}\n\n\t\tfor (let i = items.length - 1; i >= 0; i--) {\n\t\t\tconst item = items[i];\n\t\t\tif (context.contextMatchesRules(item.when)) {\n\t\t\t\treturn item;\n\t\t\t}\n\t\t}\n\n\t\treturn items[items.length - 1];\n\t}\n\n\t/**\n\t * Looks up a keybinding trigged as a result of pressing a sequence of chords - `[...currentChords, keypress]`\n\t *\n\t * Example: resolving 3 chords pressed sequentially - `cmd+k cmd+p cmd+i`:\n\t * \t`currentChords = [ 'cmd+k' , 'cmd+p' ]` and `keypress = `cmd+i` - last pressed chord\n\t */\n\tpublic resolve(context: IContext, currentChords: string[], keypress: string): ResolutionResult {\n\n\t\tconst pressedChords = [...currentChords, keypress];\n\n\t\tthis._log(`| Resolving ${pressedChords}`);\n\n\t\tconst kbCandidates = this._map.get(pressedChords[0]);\n\t\tif (kbCandidates === undefined) {\n\t\t\t// No bindings with such 0-th chord\n\t\t\tthis._log(`\\\\ No keybinding entries.`);\n\t\t\treturn NoMatchingKb;\n\t\t}\n\n\t\tlet lookupMap: ResolvedKeybindingItem[] | null = null;\n\n\t\tif (pressedChords.length < 2) {\n\t\t\tlookupMap = kbCandidates;\n\t\t} else {\n\t\t\t// Fetch all chord bindings for `currentChords`\n\t\t\tlookupMap = [];\n\t\t\tfor (let i = 0, len = kbCandidates.length; i < len; i++) {\n\n\t\t\t\tconst candidate = kbCandidates[i];\n\n\t\t\t\tif (pressedChords.length > candidate.chords.length) { // # of pressed chords can't be less than # of chords in a keybinding to invoke\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tlet prefixMatches = true;\n\t\t\t\tfor (let i = 1; i < pressedChords.length; i++) {\n\t\t\t\t\tif (candidate.chords[i] !== pressedChords[i]) {\n\t\t\t\t\t\tprefixMatches = false;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (prefixMatches) {\n\t\t\t\t\tlookupMap.push(candidate);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// check there's a keybinding with a matching when clause\n\t\tconst result = this._findCommand(context, lookupMap);\n\t\tif (!result) {\n\t\t\tthis._log(`\\\\ From ${lookupMap.length} keybinding entries, no when clauses matched the context.`);\n\t\t\treturn NoMatchingKb;\n\t\t}\n\n\t\t// check we got all chords necessary to be sure a particular keybinding needs to be invoked\n\t\tif (pressedChords.length < result.chords.length) {\n\t\t\t// The chord sequence is not complete\n\t\t\tthis._log(`\\\\ From ${lookupMap.length} keybinding entries, awaiting ${result.chords.length - pressedChords.length} more chord(s), when: ${printWhenExplanation(result.when)}, source: ${printSourceExplanation(result)}.`);\n\t\t\treturn MoreChordsNeeded;\n\t\t}\n\n\t\tthis._log(`\\\\ From ${lookupMap.length} keybinding entries, matched ${result.command}, when: ${printWhenExplanation(result.when)}, source: ${printSourceExplanation(result)}.`);\n\n\t\treturn KbFound(result.command, result.commandArgs, result.bubble);\n\t}\n\n\tprivate _findCommand(context: IContext, matches: ResolvedKeybindingItem[]): ResolvedKeybindingItem | null {\n\t\tfor (let i = matches.length - 1; i >= 0; i--) {\n\t\t\tconst k = matches[i];\n\n\t\t\tif (!KeybindingResolver._contextMatchesRules(context, k.when)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\treturn k;\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tprivate static _contextMatchesRules(context: IContext, rules: ContextKeyExpression | null | undefined): boolean {\n\t\tif (!rules) {\n\t\t\treturn true;\n\t\t}\n\t\treturn rules.evaluate(context);\n\t}\n}\n\nfunction printWhenExplanation(when: ContextKeyExpression | undefined): string {\n\tif (!when) {\n\t\treturn `no when condition`;\n\t}\n\treturn `${when.serialize()}`;\n}\n\nfunction printSourceExplanation(kb: ResolvedKeybindingItem): string {\n\treturn (\n\t\tkb.extensionId\n\t\t\t? (kb.isBuiltinExtension ? `built-in extension ${kb.extensionId}` : `user extension ${kb.extensionId}`)\n\t\t\t: (kb.isDefault ? `built-in` : `user`)\n\t);\n}\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\nimport { WorkbenchActionExecutedClassification, WorkbenchActionExecutedEvent } from 'vs/base/common/actions';\nimport { IntervalTimer, TimeoutTimer } from 'vs/base/common/async';\nimport { illegalState } from 'vs/base/common/errors';\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { IME } from 'vs/base/common/ime';\nimport { KeyCode } from 'vs/base/common/keyCodes';\nimport { ResolvedChord, ResolvedKeybinding, SingleModifierChord } from 'vs/base/common/keybindings';\nimport { Disposable, IDisposable } from 'vs/base/common/lifecycle';\nimport * as nls from 'vs/nls';\n\nimport { ICommandService } from 'vs/platform/commands/common/commands';\nimport { IContextKeyService, IContextKeyServiceTarget } from 'vs/platform/contextkey/common/contextkey';\nimport { IKeybindingService, IKeyboardEvent } from 'vs/platform/keybinding/common/keybinding';\nimport { ResolutionResult, KeybindingResolver, ResultKind, NoMatchingKb } from 'vs/platform/keybinding/common/keybindingResolver';\nimport { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem';\nimport { ILogService } from 'vs/platform/log/common/log';\nimport { INotificationService } from 'vs/platform/notification/common/notification';\nimport { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';\n\ninterface CurrentChord {\n\tkeypress: string;\n\tlabel: string | null;\n}\n\nconst HIGH_FREQ_COMMANDS = /^(cursor|delete|undo|redo|tab|editor\\.action\\.clipboard)/;\n\nexport abstract class AbstractKeybindingService extends Disposable implements IKeybindingService {\n\n\tpublic _serviceBrand: undefined;\n\n\tprotected readonly _onDidUpdateKeybindings: Emitter = this._register(new Emitter());\n\tget onDidUpdateKeybindings(): Event {\n\t\treturn this._onDidUpdateKeybindings ? this._onDidUpdateKeybindings.event : Event.None; // Sinon stubbing walks properties on prototype\n\t}\n\n\t/** recently recorded keypresses that can trigger a keybinding;\n\t *\n\t * example: say, there's \"cmd+k cmd+i\" keybinding;\n\t * the user pressed \"cmd+k\" (before they press \"cmd+i\")\n\t * \"cmd+k\" would be stored in this array, when on pressing \"cmd+i\", the service\n\t * would invoke the command bound by the keybinding\n\t */\n\tprivate _currentChords: CurrentChord[];\n\n\tprivate _currentChordChecker: IntervalTimer;\n\tprivate _currentChordStatusMessage: IDisposable | null;\n\tprivate _ignoreSingleModifiers: KeybindingModifierSet;\n\tprivate _currentSingleModifier: SingleModifierChord | null;\n\tprivate _currentSingleModifierClearTimeout: TimeoutTimer;\n\tprotected _currentlyDispatchingCommandId: string | null;\n\n\tprotected _logging: boolean;\n\n\tpublic get inChordMode(): boolean {\n\t\treturn this._currentChords.length > 0;\n\t}\n\n\tconstructor(\n\t\tprivate _contextKeyService: IContextKeyService,\n\t\tprotected _commandService: ICommandService,\n\t\tprotected _telemetryService: ITelemetryService,\n\t\tprivate _notificationService: INotificationService,\n\t\tprotected _logService: ILogService,\n\t) {\n\t\tsuper();\n\n\t\tthis._currentChords = [];\n\t\tthis._currentChordChecker = new IntervalTimer();\n\t\tthis._currentChordStatusMessage = null;\n\t\tthis._ignoreSingleModifiers = KeybindingModifierSet.EMPTY;\n\t\tthis._currentSingleModifier = null;\n\t\tthis._currentSingleModifierClearTimeout = new TimeoutTimer();\n\t\tthis._currentlyDispatchingCommandId = null;\n\t\tthis._logging = false;\n\t}\n\n\tpublic override dispose(): void {\n\t\tsuper.dispose();\n\t}\n\n\tprotected abstract _getResolver(): KeybindingResolver;\n\tprotected abstract _documentHasFocus(): boolean;\n\tpublic abstract resolveKeyboardEvent(keyboardEvent: IKeyboardEvent): ResolvedKeybinding;\n\n\tprotected _log(str: string): void {\n\t\tif (this._logging) {\n\t\t\tthis._logService.info(`[KeybindingService]: ${str}`);\n\t\t}\n\t}\n\n\tpublic getKeybindings(): readonly ResolvedKeybindingItem[] {\n\t\treturn this._getResolver().getKeybindings();\n\t}\n\n\tpublic lookupKeybinding(commandId: string, context?: IContextKeyService): ResolvedKeybinding | undefined {\n\t\tconst result = this._getResolver().lookupPrimaryKeybinding(commandId, context || this._contextKeyService);\n\t\tif (!result) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn result.resolvedKeybinding;\n\t}\n\n\tpublic dispatchEvent(e: IKeyboardEvent, target: IContextKeyServiceTarget): boolean {\n\t\treturn this._dispatch(e, target);\n\t}\n\n\t// TODO@ulugbekna: update namings to align with `_doDispatch`\n\t// TODO@ulugbekna: this fn doesn't seem to take into account single-modifier keybindings, eg `shift shift`\n\tpublic softDispatch(e: IKeyboardEvent, target: IContextKeyServiceTarget): ResolutionResult {\n\t\tthis._log(`/ Soft dispatching keyboard event`);\n\t\tconst keybinding = this.resolveKeyboardEvent(e);\n\t\tif (keybinding.hasMultipleChords()) {\n\t\t\tconsole.warn('keyboard event should not be mapped to multiple chords');\n\t\t\treturn NoMatchingKb;\n\t\t}\n\t\tconst [firstChord,] = keybinding.getDispatchChords();\n\t\tif (firstChord === null) {\n\t\t\t// cannot be dispatched, probably only modifier keys\n\t\t\tthis._log(`\\\\ Keyboard event cannot be dispatched`);\n\t\t\treturn NoMatchingKb;\n\t\t}\n\n\t\tconst contextValue = this._contextKeyService.getContext(target);\n\t\tconst currentChords = this._currentChords.map((({ keypress }) => keypress));\n\t\treturn this._getResolver().resolve(contextValue, currentChords, firstChord);\n\t}\n\n\tprivate _scheduleLeaveChordMode(): void {\n\t\tconst chordLastInteractedTime = Date.now();\n\t\tthis._currentChordChecker.cancelAndSet(() => {\n\n\t\t\tif (!this._documentHasFocus()) {\n\t\t\t\t// Focus has been lost => leave chord mode\n\t\t\t\tthis._leaveChordMode();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (Date.now() - chordLastInteractedTime > 5000) {\n\t\t\t\t// 5 seconds elapsed => leave chord mode\n\t\t\t\tthis._leaveChordMode();\n\t\t\t}\n\n\t\t}, 500);\n\t}\n\n\tprivate _expectAnotherChord(firstChord: string, keypressLabel: string | null): void {\n\n\t\tthis._currentChords.push({ keypress: firstChord, label: keypressLabel });\n\n\t\tswitch (this._currentChords.length) {\n\t\t\tcase 0:\n\t\t\t\tthrow illegalState('impossible');\n\t\t\tcase 1:\n\t\t\t\t// TODO@ulugbekna: revise this message and the one below (at least, fix terminology)\n\t\t\t\tthis._currentChordStatusMessage = this._notificationService.status(nls.localize('first.chord', \"({0}) was pressed. Waiting for second key of chord...\", keypressLabel));\n\t\t\t\tbreak;\n\t\t\tdefault: {\n\t\t\t\tconst fullKeypressLabel = this._currentChords.map(({ label }) => label).join(', ');\n\t\t\t\tthis._currentChordStatusMessage = this._notificationService.status(nls.localize('next.chord', \"({0}) was pressed. Waiting for next key of chord...\", fullKeypressLabel));\n\t\t\t}\n\t\t}\n\n\t\tthis._scheduleLeaveChordMode();\n\n\t\tif (IME.enabled) {\n\t\t\tIME.disable();\n\t\t}\n\t}\n\n\tprivate _leaveChordMode(): void {\n\t\tif (this._currentChordStatusMessage) {\n\t\t\tthis._currentChordStatusMessage.dispose();\n\t\t\tthis._currentChordStatusMessage = null;\n\t\t}\n\t\tthis._currentChordChecker.cancel();\n\t\tthis._currentChords = [];\n\t\tIME.enable();\n\t}\n\n\tprotected _dispatch(e: IKeyboardEvent, target: IContextKeyServiceTarget): boolean {\n\t\treturn this._doDispatch(this.resolveKeyboardEvent(e), target, /*isSingleModiferChord*/false);\n\t}\n\n\tprotected _singleModifierDispatch(e: IKeyboardEvent, target: IContextKeyServiceTarget): boolean {\n\t\tconst keybinding = this.resolveKeyboardEvent(e);\n\t\tconst [singleModifier,] = keybinding.getSingleModifierDispatchChords();\n\n\t\tif (singleModifier) {\n\n\t\t\tif (this._ignoreSingleModifiers.has(singleModifier)) {\n\t\t\t\tthis._log(`+ Ignoring single modifier ${singleModifier} due to it being pressed together with other keys.`);\n\t\t\t\tthis._ignoreSingleModifiers = KeybindingModifierSet.EMPTY;\n\t\t\t\tthis._currentSingleModifierClearTimeout.cancel();\n\t\t\t\tthis._currentSingleModifier = null;\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tthis._ignoreSingleModifiers = KeybindingModifierSet.EMPTY;\n\n\t\t\tif (this._currentSingleModifier === null) {\n\t\t\t\t// we have a valid `singleModifier`, store it for the next keyup, but clear it in 300ms\n\t\t\t\tthis._log(`+ Storing single modifier for possible chord ${singleModifier}.`);\n\t\t\t\tthis._currentSingleModifier = singleModifier;\n\t\t\t\tthis._currentSingleModifierClearTimeout.cancelAndSet(() => {\n\t\t\t\t\tthis._log(`+ Clearing single modifier due to 300ms elapsed.`);\n\t\t\t\t\tthis._currentSingleModifier = null;\n\t\t\t\t}, 300);\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (singleModifier === this._currentSingleModifier) {\n\t\t\t\t// bingo!\n\t\t\t\tthis._log(`/ Dispatching single modifier chord ${singleModifier} ${singleModifier}`);\n\t\t\t\tthis._currentSingleModifierClearTimeout.cancel();\n\t\t\t\tthis._currentSingleModifier = null;\n\t\t\t\treturn this._doDispatch(keybinding, target, /*isSingleModiferChord*/true);\n\t\t\t}\n\n\t\t\tthis._log(`+ Clearing single modifier due to modifier mismatch: ${this._currentSingleModifier} ${singleModifier}`);\n\t\t\tthis._currentSingleModifierClearTimeout.cancel();\n\t\t\tthis._currentSingleModifier = null;\n\t\t\treturn false;\n\t\t}\n\n\t\t// When pressing a modifier and holding it pressed with any other modifier or key combination,\n\t\t// the pressed modifiers should no longer be considered for single modifier dispatch.\n\t\tconst [firstChord,] = keybinding.getChords();\n\t\tthis._ignoreSingleModifiers = new KeybindingModifierSet(firstChord);\n\n\t\tif (this._currentSingleModifier !== null) {\n\t\t\tthis._log(`+ Clearing single modifier due to other key up.`);\n\t\t}\n\t\tthis._currentSingleModifierClearTimeout.cancel();\n\t\tthis._currentSingleModifier = null;\n\t\treturn false;\n\t}\n\n\tprivate _doDispatch(userKeypress: ResolvedKeybinding, target: IContextKeyServiceTarget, isSingleModiferChord = false): boolean {\n\t\tlet shouldPreventDefault = false;\n\n\t\tif (userKeypress.hasMultipleChords()) { // warn - because user can press a single chord at a time\n\t\t\tconsole.warn('Unexpected keyboard event mapped to multiple chords');\n\t\t\treturn false;\n\t\t}\n\n\t\tlet userPressedChord: string | null = null;\n\t\tlet currentChords: string[] | null = null;\n\n\t\tif (isSingleModiferChord) {\n\t\t\t// The keybinding is the second keypress of a single modifier chord, e.g. \"shift shift\".\n\t\t\t// A single modifier can only occur when the same modifier is pressed in short sequence,\n\t\t\t// hence we disregard `_currentChord` and use the same modifier instead.\n\t\t\tconst [dispatchKeyname,] = userKeypress.getSingleModifierDispatchChords();\n\t\t\tuserPressedChord = dispatchKeyname;\n\t\t\tcurrentChords = dispatchKeyname ? [dispatchKeyname] : []; // TODO@ulugbekna: in the `else` case we assign an empty array - make sure `resolve` can handle an empty array well\n\t\t} else {\n\t\t\t[userPressedChord,] = userKeypress.getDispatchChords();\n\t\t\tcurrentChords = this._currentChords.map(({ keypress }) => keypress);\n\t\t}\n\n\t\tif (userPressedChord === null) {\n\t\t\tthis._log(`\\\\ Keyboard event cannot be dispatched in keydown phase.`);\n\t\t\t// cannot be dispatched, probably only modifier keys\n\t\t\treturn shouldPreventDefault;\n\t\t}\n\n\t\tconst contextValue = this._contextKeyService.getContext(target);\n\t\tconst keypressLabel = userKeypress.getLabel();\n\n\t\tconst resolveResult = this._getResolver().resolve(contextValue, currentChords, userPressedChord);\n\n\t\tswitch (resolveResult.kind) {\n\n\t\t\tcase ResultKind.NoMatchingKb: {\n\n\t\t\t\tthis._logService.trace('KeybindingService#dispatch', keypressLabel, `[ No matching keybinding ]`);\n\n\t\t\t\tif (this.inChordMode) {\n\t\t\t\t\tconst currentChordsLabel = this._currentChords.map(({ label }) => label).join(', ');\n\t\t\t\t\tthis._log(`+ Leaving multi-chord mode: Nothing bound to \"${currentChordsLabel}, ${keypressLabel}\".`);\n\t\t\t\t\tthis._notificationService.status(nls.localize('missing.chord', \"The key combination ({0}, {1}) is not a command.\", currentChordsLabel, keypressLabel), { hideAfter: 10 * 1000 /* 10s */ });\n\t\t\t\t\tthis._leaveChordMode();\n\n\t\t\t\t\tshouldPreventDefault = true;\n\t\t\t\t}\n\t\t\t\treturn shouldPreventDefault;\n\t\t\t}\n\n\t\t\tcase ResultKind.MoreChordsNeeded: {\n\n\t\t\t\tthis._logService.trace('KeybindingService#dispatch', keypressLabel, `[ Several keybindings match - more chords needed ]`);\n\n\t\t\t\tshouldPreventDefault = true;\n\t\t\t\tthis._expectAnotherChord(userPressedChord, keypressLabel);\n\t\t\t\tthis._log(this._currentChords.length === 1 ? `+ Entering multi-chord mode...` : `+ Continuing multi-chord mode...`);\n\t\t\t\treturn shouldPreventDefault;\n\t\t\t}\n\n\t\t\tcase ResultKind.KbFound: {\n\n\t\t\t\tthis._logService.trace('KeybindingService#dispatch', keypressLabel, `[ Will dispatch command ${resolveResult.commandId} ]`);\n\n\t\t\t\tif (resolveResult.commandId === null || resolveResult.commandId === '') {\n\n\t\t\t\t\tif (this.inChordMode) {\n\t\t\t\t\t\tconst currentChordsLabel = this._currentChords.map(({ label }) => label).join(', ');\n\t\t\t\t\t\tthis._log(`+ Leaving chord mode: Nothing bound to \"${currentChordsLabel}, ${keypressLabel}\".`);\n\t\t\t\t\t\tthis._notificationService.status(nls.localize('missing.chord', \"The key combination ({0}, {1}) is not a command.\", currentChordsLabel, keypressLabel), { hideAfter: 10 * 1000 /* 10s */ });\n\t\t\t\t\t\tthis._leaveChordMode();\n\t\t\t\t\t\tshouldPreventDefault = true;\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\t\t\t\t\tif (this.inChordMode) {\n\t\t\t\t\t\tthis._leaveChordMode();\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!resolveResult.isBubble) {\n\t\t\t\t\t\tshouldPreventDefault = true;\n\t\t\t\t\t}\n\n\t\t\t\t\tthis._log(`+ Invoking command ${resolveResult.commandId}.`);\n\t\t\t\t\tthis._currentlyDispatchingCommandId = resolveResult.commandId;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tif (typeof resolveResult.commandArgs === 'undefined') {\n\t\t\t\t\t\t\tthis._commandService.executeCommand(resolveResult.commandId).then(undefined, err => this._notificationService.warn(err));\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tthis._commandService.executeCommand(resolveResult.commandId, resolveResult.commandArgs).then(undefined, err => this._notificationService.warn(err));\n\t\t\t\t\t\t}\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tthis._currentlyDispatchingCommandId = null;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!HIGH_FREQ_COMMANDS.test(resolveResult.commandId)) {\n\t\t\t\t\t\tthis._telemetryService.publicLog2('workbenchActionExecuted', { id: resolveResult.commandId, from: 'keybinding', detail: userKeypress.getUserSettingsLabel() ?? undefined });\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn shouldPreventDefault;\n\t\t\t}\n\t\t}\n\t}\n\n\tmightProducePrintableCharacter(event: IKeyboardEvent): boolean {\n\t\tif (event.ctrlKey || event.metaKey) {\n\t\t\t// ignore ctrl/cmd-combination but not shift/alt-combinatios\n\t\t\treturn false;\n\t\t}\n\t\t// weak check for certain ranges. this is properly implemented in a subclass\n\t\t// with access to the KeyboardMapperFactory.\n\t\tif ((event.keyCode >= KeyCode.KeyA && event.keyCode <= KeyCode.KeyZ)\n\t\t\t|| (event.keyCode >= KeyCode.Digit0 && event.keyCode <= KeyCode.Digit9)) {\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n}\n\nclass KeybindingModifierSet {\n\n\tpublic static EMPTY = new KeybindingModifierSet(null);\n\n\tprivate readonly _ctrlKey: boolean;\n\tprivate readonly _shiftKey: boolean;\n\tprivate readonly _altKey: boolean;\n\tprivate readonly _metaKey: boolean;\n\n\tconstructor(source: ResolvedChord | null) {\n\t\tthis._ctrlKey = source ? source.ctrlKey : false;\n\t\tthis._shiftKey = source ? source.shiftKey : false;\n\t\tthis._altKey = source ? source.altKey : false;\n\t\tthis._metaKey = source ? source.metaKey : false;\n\t}\n\n\thas(modifier: SingleModifierChord) {\n\t\tswitch (modifier) {\n\t\t\tcase 'ctrl': return this._ctrlKey;\n\t\t\tcase 'shift': return this._shiftKey;\n\t\t\tcase 'alt': return this._altKey;\n\t\t\tcase 'meta': return this._metaKey;\n\t\t}\n\t}\n}\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\nimport { CharCode } from 'vs/base/common/charCode';\nimport { ResolvedKeybinding } from 'vs/base/common/keybindings';\nimport { ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey';\n\nexport class ResolvedKeybindingItem {\n\t_resolvedKeybindingItemBrand: void = undefined;\n\n\tpublic readonly resolvedKeybinding: ResolvedKeybinding | undefined;\n\tpublic readonly chords: string[];\n\tpublic readonly bubble: boolean;\n\tpublic readonly command: string | null;\n\tpublic readonly commandArgs: any;\n\tpublic readonly when: ContextKeyExpression | undefined;\n\tpublic readonly isDefault: boolean;\n\tpublic readonly extensionId: string | null;\n\tpublic readonly isBuiltinExtension: boolean;\n\n\tconstructor(resolvedKeybinding: ResolvedKeybinding | undefined, command: string | null, commandArgs: any, when: ContextKeyExpression | undefined, isDefault: boolean, extensionId: string | null, isBuiltinExtension: boolean) {\n\t\tthis.resolvedKeybinding = resolvedKeybinding;\n\t\tthis.chords = resolvedKeybinding ? toEmptyArrayIfContainsNull(resolvedKeybinding.getDispatchChords()) : [];\n\t\tif (resolvedKeybinding && this.chords.length === 0) {\n\t\t\t// handle possible single modifier chord keybindings\n\t\t\tthis.chords = toEmptyArrayIfContainsNull(resolvedKeybinding.getSingleModifierDispatchChords());\n\t\t}\n\t\tthis.bubble = (command ? command.charCodeAt(0) === CharCode.Caret : false);\n\t\tthis.command = this.bubble ? command!.substr(1) : command;\n\t\tthis.commandArgs = commandArgs;\n\t\tthis.when = when;\n\t\tthis.isDefault = isDefault;\n\t\tthis.extensionId = extensionId;\n\t\tthis.isBuiltinExtension = isBuiltinExtension;\n\t}\n}\n\nexport function toEmptyArrayIfContainsNull(arr: (T | null)[]): T[] {\n\tconst result: T[] = [];\n\tfor (let i = 0, len = arr.length; i < len; i++) {\n\t\tconst element = arr[i];\n\t\tif (!element) {\n\t\t\treturn [];\n\t\t}\n\t\tresult.push(element);\n\t}\n\treturn result;\n}\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\nimport { KeyCode, KeyCodeUtils, IMMUTABLE_CODE_TO_KEY_CODE, ScanCode } from 'vs/base/common/keyCodes';\nimport { SingleModifierChord, Chord, KeyCodeChord, Keybinding } from 'vs/base/common/keybindings';\nimport { OperatingSystem } from 'vs/base/common/platform';\nimport { BaseResolvedKeybinding } from 'vs/platform/keybinding/common/baseResolvedKeybinding';\nimport { toEmptyArrayIfContainsNull } from 'vs/platform/keybinding/common/resolvedKeybindingItem';\n\n/**\n * Do not instantiate. Use KeybindingService to get a ResolvedKeybinding seeded with information about the current kb layout.\n */\nexport class USLayoutResolvedKeybinding extends BaseResolvedKeybinding {\n\n\tconstructor(chords: KeyCodeChord[], os: OperatingSystem) {\n\t\tsuper(os, chords);\n\t}\n\n\tprivate _keyCodeToUILabel(keyCode: KeyCode): string {\n\t\tif (this._os === OperatingSystem.Macintosh) {\n\t\t\tswitch (keyCode) {\n\t\t\t\tcase KeyCode.LeftArrow:\n\t\t\t\t\treturn '←';\n\t\t\t\tcase KeyCode.UpArrow:\n\t\t\t\t\treturn '↑';\n\t\t\t\tcase KeyCode.RightArrow:\n\t\t\t\t\treturn '→';\n\t\t\t\tcase KeyCode.DownArrow:\n\t\t\t\t\treturn '↓';\n\t\t\t}\n\t\t}\n\t\treturn KeyCodeUtils.toString(keyCode);\n\t}\n\n\tprotected _getLabel(chord: KeyCodeChord): string | null {\n\t\tif (chord.isDuplicateModifierCase()) {\n\t\t\treturn '';\n\t\t}\n\t\treturn this._keyCodeToUILabel(chord.keyCode);\n\t}\n\n\tprotected _getAriaLabel(chord: KeyCodeChord): string | null {\n\t\tif (chord.isDuplicateModifierCase()) {\n\t\t\treturn '';\n\t\t}\n\t\treturn KeyCodeUtils.toString(chord.keyCode);\n\t}\n\n\tprotected _getElectronAccelerator(chord: KeyCodeChord): string | null {\n\t\treturn KeyCodeUtils.toElectronAccelerator(chord.keyCode);\n\t}\n\n\tprotected _getUserSettingsLabel(chord: KeyCodeChord): string | null {\n\t\tif (chord.isDuplicateModifierCase()) {\n\t\t\treturn '';\n\t\t}\n\t\tconst result = KeyCodeUtils.toUserSettingsUS(chord.keyCode);\n\t\treturn (result ? result.toLowerCase() : result);\n\t}\n\n\tprotected _getChordDispatch(chord: KeyCodeChord): string | null {\n\t\treturn USLayoutResolvedKeybinding.getDispatchStr(chord);\n\t}\n\n\tpublic static getDispatchStr(chord: KeyCodeChord): string | null {\n\t\tif (chord.isModifierKey()) {\n\t\t\treturn null;\n\t\t}\n\t\tlet result = '';\n\n\t\tif (chord.ctrlKey) {\n\t\t\tresult += 'ctrl+';\n\t\t}\n\t\tif (chord.shiftKey) {\n\t\t\tresult += 'shift+';\n\t\t}\n\t\tif (chord.altKey) {\n\t\t\tresult += 'alt+';\n\t\t}\n\t\tif (chord.metaKey) {\n\t\t\tresult += 'meta+';\n\t\t}\n\t\tresult += KeyCodeUtils.toString(chord.keyCode);\n\n\t\treturn result;\n\t}\n\n\tprotected _getSingleModifierChordDispatch(keybinding: KeyCodeChord): SingleModifierChord | null {\n\t\tif (keybinding.keyCode === KeyCode.Ctrl && !keybinding.shiftKey && !keybinding.altKey && !keybinding.metaKey) {\n\t\t\treturn 'ctrl';\n\t\t}\n\t\tif (keybinding.keyCode === KeyCode.Shift && !keybinding.ctrlKey && !keybinding.altKey && !keybinding.metaKey) {\n\t\t\treturn 'shift';\n\t\t}\n\t\tif (keybinding.keyCode === KeyCode.Alt && !keybinding.ctrlKey && !keybinding.shiftKey && !keybinding.metaKey) {\n\t\t\treturn 'alt';\n\t\t}\n\t\tif (keybinding.keyCode === KeyCode.Meta && !keybinding.ctrlKey && !keybinding.shiftKey && !keybinding.altKey) {\n\t\t\treturn 'meta';\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * *NOTE*: Check return value for `KeyCode.Unknown`.\n\t */\n\tprivate static _scanCodeToKeyCode(scanCode: ScanCode): KeyCode {\n\t\tconst immutableKeyCode = IMMUTABLE_CODE_TO_KEY_CODE[scanCode];\n\t\tif (immutableKeyCode !== KeyCode.DependsOnKbLayout) {\n\t\t\treturn immutableKeyCode;\n\t\t}\n\n\t\tswitch (scanCode) {\n\t\t\tcase ScanCode.KeyA: return KeyCode.KeyA;\n\t\t\tcase ScanCode.KeyB: return KeyCode.KeyB;\n\t\t\tcase ScanCode.KeyC: return KeyCode.KeyC;\n\t\t\tcase ScanCode.KeyD: return KeyCode.KeyD;\n\t\t\tcase ScanCode.KeyE: return KeyCode.KeyE;\n\t\t\tcase ScanCode.KeyF: return KeyCode.KeyF;\n\t\t\tcase ScanCode.KeyG: return KeyCode.KeyG;\n\t\t\tcase ScanCode.KeyH: return KeyCode.KeyH;\n\t\t\tcase ScanCode.KeyI: return KeyCode.KeyI;\n\t\t\tcase ScanCode.KeyJ: return KeyCode.KeyJ;\n\t\t\tcase ScanCode.KeyK: return KeyCode.KeyK;\n\t\t\tcase ScanCode.KeyL: return KeyCode.KeyL;\n\t\t\tcase ScanCode.KeyM: return KeyCode.KeyM;\n\t\t\tcase ScanCode.KeyN: return KeyCode.KeyN;\n\t\t\tcase ScanCode.KeyO: return KeyCode.KeyO;\n\t\t\tcase ScanCode.KeyP: return KeyCode.KeyP;\n\t\t\tcase ScanCode.KeyQ: return KeyCode.KeyQ;\n\t\t\tcase ScanCode.KeyR: return KeyCode.KeyR;\n\t\t\tcase ScanCode.KeyS: return KeyCode.KeyS;\n\t\t\tcase ScanCode.KeyT: return KeyCode.KeyT;\n\t\t\tcase ScanCode.KeyU: return KeyCode.KeyU;\n\t\t\tcase ScanCode.KeyV: return KeyCode.KeyV;\n\t\t\tcase ScanCode.KeyW: return KeyCode.KeyW;\n\t\t\tcase ScanCode.KeyX: return KeyCode.KeyX;\n\t\t\tcase ScanCode.KeyY: return KeyCode.KeyY;\n\t\t\tcase ScanCode.KeyZ: return KeyCode.KeyZ;\n\t\t\tcase ScanCode.Digit1: return KeyCode.Digit1;\n\t\t\tcase ScanCode.Digit2: return KeyCode.Digit2;\n\t\t\tcase ScanCode.Digit3: return KeyCode.Digit3;\n\t\t\tcase ScanCode.Digit4: return KeyCode.Digit4;\n\t\t\tcase ScanCode.Digit5: return KeyCode.Digit5;\n\t\t\tcase ScanCode.Digit6: return KeyCode.Digit6;\n\t\t\tcase ScanCode.Digit7: return KeyCode.Digit7;\n\t\t\tcase ScanCode.Digit8: return KeyCode.Digit8;\n\t\t\tcase ScanCode.Digit9: return KeyCode.Digit9;\n\t\t\tcase ScanCode.Digit0: return KeyCode.Digit0;\n\t\t\tcase ScanCode.Minus: return KeyCode.Minus;\n\t\t\tcase ScanCode.Equal: return KeyCode.Equal;\n\t\t\tcase ScanCode.BracketLeft: return KeyCode.BracketLeft;\n\t\t\tcase ScanCode.BracketRight: return KeyCode.BracketRight;\n\t\t\tcase ScanCode.Backslash: return KeyCode.Backslash;\n\t\t\tcase ScanCode.IntlHash: return KeyCode.Unknown; // missing\n\t\t\tcase ScanCode.Semicolon: return KeyCode.Semicolon;\n\t\t\tcase ScanCode.Quote: return KeyCode.Quote;\n\t\t\tcase ScanCode.Backquote: return KeyCode.Backquote;\n\t\t\tcase ScanCode.Comma: return KeyCode.Comma;\n\t\t\tcase ScanCode.Period: return KeyCode.Period;\n\t\t\tcase ScanCode.Slash: return KeyCode.Slash;\n\t\t\tcase ScanCode.IntlBackslash: return KeyCode.IntlBackslash;\n\t\t}\n\t\treturn KeyCode.Unknown;\n\t}\n\n\tprivate static _toKeyCodeChord(chord: Chord | null): KeyCodeChord | null {\n\t\tif (!chord) {\n\t\t\treturn null;\n\t\t}\n\t\tif (chord instanceof KeyCodeChord) {\n\t\t\treturn chord;\n\t\t}\n\t\tconst keyCode = this._scanCodeToKeyCode(chord.scanCode);\n\t\tif (keyCode === KeyCode.Unknown) {\n\t\t\treturn null;\n\t\t}\n\t\treturn new KeyCodeChord(chord.ctrlKey, chord.shiftKey, chord.altKey, chord.metaKey, keyCode);\n\t}\n\n\tpublic static resolveKeybinding(keybinding: Keybinding, os: OperatingSystem): USLayoutResolvedKeybinding[] {\n\t\tconst chords: KeyCodeChord[] = toEmptyArrayIfContainsNull(keybinding.chords.map(chord => this._toKeyCodeChord(chord)));\n\t\tif (chords.length > 0) {\n\t\t\treturn [new USLayoutResolvedKeybinding(chords, os)];\n\t\t}\n\t\treturn [];\n\t}\n}\n","\nimport { URI } from 'vs/base/common/uri';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\n\nexport const ILabelService = createDecorator('labelService');\n\nexport interface ILabelService {\n\n\treadonly _serviceBrand: undefined;\n\n\t/**\n\t * Gets the human readable label for a uri.\n\t * If `relative` is passed returns a label relative to the workspace root that the uri belongs to.\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.\n\t * If `separator` is passed, will use that over the defined path separator of the formatter.\n\t */\n\tgetUriLabel(resource: URI, options?: { relative?: boolean; noPrefix?: boolean; separator?: '/' | '\\\\' }): string;\n\tgetUriBasenameLabel(resource: URI): string;\n}\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\nimport { IDimension } from 'vs/base/browser/dom';\nimport { Event } from 'vs/base/common/event';\nimport { DisposableStore } from 'vs/base/common/lifecycle';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\n\nexport const ILayoutService = createDecorator('layoutService');\n\nexport interface ILayoutOffsetInfo {\n\n\t/**\n\t * Generic top offset\n\t */\n\treadonly top: number;\n\n\t/**\n\t * Quick pick specific top offset.\n\t */\n\treadonly quickPickTop: number;\n}\n\nexport interface ILayoutService {\n\n\treadonly _serviceBrand: undefined;\n\n\t/**\n\t * An event that is emitted when the main container is layed out.\n\t */\n\treadonly onDidLayoutMainContainer: Event;\n\n\t/**\n\t * An event that is emitted when any container is layed out.\n\t */\n\treadonly onDidLayoutContainer: Event<{ readonly container: HTMLElement; readonly dimension: IDimension }>;\n\n\t/**\n\t * An event that is emitted when the active container is layed out.\n\t */\n\treadonly onDidLayoutActiveContainer: Event;\n\n\t/**\n\t * An event that is emitted when a new container is added. This\n\t * can happen in multi-window environments.\n\t */\n\treadonly onDidAddContainer: Event<{ readonly container: HTMLElement; readonly disposables: DisposableStore }>;\n\n\t/**\n\t * An event that is emitted when the active container changes.\n\t */\n\treadonly onDidChangeActiveContainer: Event;\n\n\t/**\n\t * The dimensions of the main container.\n\t */\n\treadonly mainContainerDimension: IDimension;\n\n\t/**\n\t * The dimensions of the active container.\n\t */\n\treadonly activeContainerDimension: IDimension;\n\n\t/**\n\t * Main container of the application.\n\t */\n\treadonly mainContainer: HTMLElement;\n\n\t/**\n\t * Active container of the application. When multiple windows are opened, will return\n\t * the container of the active, focused window.\n\t */\n\treadonly activeContainer: HTMLElement;\n\n\t/**\n\t * All the containers of the application. There can be one container per window.\n\t */\n\treadonly containers: Iterable;\n\n\t/**\n\t * Get the container for the given window.\n\t */\n\tgetContainer(window: Window): HTMLElement;\n\n\t/**\n\t * Ensures that the styles for the container associated\n\t * to the window have loaded. For the main window, this\n\t * will resolve instantly, but for floating windows, this\n\t * will resolve once the styles have been loaded and helps\n\t * for when certain layout assumptions are made.\n\t */\n\twhenContainerStylesLoaded(window: Window): Promise | undefined;\n\n\t/**\n\t * An offset to use for positioning elements inside the main container.\n\t */\n\treadonly mainContainerOffset: ILayoutOffsetInfo;\n\n\t/**\n\t * An offset to use for positioning elements inside the container.\n\t */\n\treadonly activeContainerOffset: ILayoutOffsetInfo;\n\n\t/**\n\t * Focus the primary component of the active container.\n\t */\n\tfocus(): void;\n}\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\nimport * as dom from 'vs/base/browser/dom';\nimport { mainWindow } from 'vs/base/browser/window';\nimport { coalesce, firstOrDefault } from 'vs/base/common/arrays';\nimport { Event } from 'vs/base/common/event';\nimport { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';\nimport { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions';\nimport { ILayoutOffsetInfo, ILayoutService } from 'vs/platform/layout/browser/layoutService';\n\nclass StandaloneLayoutService implements ILayoutService {\n\tdeclare readonly _serviceBrand: undefined;\n\n\treadonly onDidLayoutMainContainer = Event.None;\n\treadonly onDidLayoutActiveContainer = Event.None;\n\treadonly onDidLayoutContainer = Event.None;\n\treadonly onDidChangeActiveContainer = Event.None;\n\treadonly onDidAddContainer = Event.None;\n\n\tget mainContainer(): HTMLElement {\n\t\treturn firstOrDefault(this._codeEditorService.listCodeEditors())?.getContainerDomNode() ?? mainWindow.document.body;\n\t}\n\n\tget activeContainer(): HTMLElement {\n\t\tconst activeCodeEditor = this._codeEditorService.getFocusedCodeEditor() ?? this._codeEditorService.getActiveCodeEditor();\n\n\t\treturn activeCodeEditor?.getContainerDomNode() ?? this.mainContainer;\n\t}\n\n\tget mainContainerDimension(): dom.IDimension {\n\t\treturn dom.getClientArea(this.mainContainer);\n\t}\n\n\tget activeContainerDimension() {\n\t\treturn dom.getClientArea(this.activeContainer);\n\t}\n\n\treadonly mainContainerOffset: ILayoutOffsetInfo = { top: 0, quickPickTop: 0 };\n\treadonly activeContainerOffset: ILayoutOffsetInfo = { top: 0, quickPickTop: 0 };\n\n\tget containers(): Iterable {\n\t\treturn coalesce(this._codeEditorService.listCodeEditors().map(codeEditor => codeEditor.getContainerDomNode()));\n\t}\n\n\tgetContainer() {\n\t\treturn this.activeContainer;\n\t}\n\n\twhenContainerStylesLoaded() { return undefined; }\n\n\tfocus(): void {\n\t\tthis._codeEditorService.getFocusedCodeEditor()?.focus();\n\t}\n\n\tconstructor(\n\t\t@ICodeEditorService private _codeEditorService: ICodeEditorService\n\t) { }\n\n}\n\nexport class EditorScopedLayoutService extends StandaloneLayoutService {\n\toverride get mainContainer(): HTMLElement {\n\t\treturn this._container;\n\t}\n\tconstructor(\n\t\tprivate _container: HTMLElement,\n\t\t@ICodeEditorService codeEditorService: ICodeEditorService,\n\t) {\n\t\tsuper(codeEditorService);\n\t}\n}\n\nregisterSingleton(ILayoutService, StandaloneLayoutService, InstantiationType.Delayed);\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\nimport { addDisposableListener } from 'vs/base/browser/dom';\nimport { mainWindow } from 'vs/base/browser/window';\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport { AccessibilitySupport, CONTEXT_ACCESSIBILITY_MODE_ENABLED, IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';\nimport { IConfigurationService } from 'vs/platform/configuration/common/configuration';\nimport { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';\nimport { ILayoutService } from 'vs/platform/layout/browser/layoutService';\n\nexport class AccessibilityService extends Disposable implements IAccessibilityService {\n\tdeclare readonly _serviceBrand: undefined;\n\n\tprivate _accessibilityModeEnabledContext: IContextKey;\n\tprotected _accessibilitySupport = AccessibilitySupport.Unknown;\n\tprotected readonly _onDidChangeScreenReaderOptimized = new Emitter();\n\n\tprotected _configMotionReduced: 'auto' | 'on' | 'off';\n\tprotected _systemMotionReduced: boolean;\n\tprotected readonly _onDidChangeReducedMotion = new Emitter();\n\n\tconstructor(\n\t\t@IContextKeyService private readonly _contextKeyService: IContextKeyService,\n\t\t@ILayoutService private readonly _layoutService: ILayoutService,\n\t\t@IConfigurationService protected readonly _configurationService: IConfigurationService\n\t) {\n\t\tsuper();\n\t\tthis._accessibilityModeEnabledContext = CONTEXT_ACCESSIBILITY_MODE_ENABLED.bindTo(this._contextKeyService);\n\n\t\tconst updateContextKey = () => this._accessibilityModeEnabledContext.set(this.isScreenReaderOptimized());\n\t\tthis._register(this._configurationService.onDidChangeConfiguration(e => {\n\t\t\tif (e.affectsConfiguration('editor.accessibilitySupport')) {\n\t\t\t\tupdateContextKey();\n\t\t\t\tthis._onDidChangeScreenReaderOptimized.fire();\n\t\t\t}\n\t\t\tif (e.affectsConfiguration('workbench.reduceMotion')) {\n\t\t\t\tthis._configMotionReduced = this._configurationService.getValue('workbench.reduceMotion');\n\t\t\t\tthis._onDidChangeReducedMotion.fire();\n\t\t\t}\n\t\t}));\n\t\tupdateContextKey();\n\t\tthis._register(this.onDidChangeScreenReaderOptimized(() => updateContextKey()));\n\n\t\tconst reduceMotionMatcher = mainWindow.matchMedia(`(prefers-reduced-motion: reduce)`);\n\t\tthis._systemMotionReduced = reduceMotionMatcher.matches;\n\t\tthis._configMotionReduced = this._configurationService.getValue<'auto' | 'on' | 'off'>('workbench.reduceMotion');\n\n\t\tthis.initReducedMotionListeners(reduceMotionMatcher);\n\t}\n\n\tprivate initReducedMotionListeners(reduceMotionMatcher: MediaQueryList) {\n\n\t\tthis._register(addDisposableListener(reduceMotionMatcher, 'change', () => {\n\t\t\tthis._systemMotionReduced = reduceMotionMatcher.matches;\n\t\t\tif (this._configMotionReduced === 'auto') {\n\t\t\t\tthis._onDidChangeReducedMotion.fire();\n\t\t\t}\n\t\t}));\n\n\t\tconst updateRootClasses = () => {\n\t\t\tconst reduce = this.isMotionReduced();\n\t\t\tthis._layoutService.mainContainer.classList.toggle('reduce-motion', reduce);\n\t\t\tthis._layoutService.mainContainer.classList.toggle('enable-motion', !reduce);\n\t\t};\n\n\t\tupdateRootClasses();\n\t\tthis._register(this.onDidChangeReducedMotion(() => updateRootClasses()));\n\t}\n\n\tget onDidChangeScreenReaderOptimized(): Event {\n\t\treturn this._onDidChangeScreenReaderOptimized.event;\n\t}\n\n\tisScreenReaderOptimized(): boolean {\n\t\tconst config = this._configurationService.getValue('editor.accessibilitySupport');\n\t\treturn config === 'on' || (config === 'auto' && this._accessibilitySupport === AccessibilitySupport.Enabled);\n\t}\n\n\tget onDidChangeReducedMotion(): Event {\n\t\treturn this._onDidChangeReducedMotion.event;\n\t}\n\n\tisMotionReduced(): boolean {\n\t\tconst config = this._configMotionReduced;\n\t\treturn config === 'on' || (config === 'auto' && this._systemMotionReduced);\n\t}\n\n\tgetAccessibilitySupport(): AccessibilitySupport {\n\t\treturn this._accessibilitySupport;\n\t}\n}\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\nimport { ContextView, ContextViewDOMPosition, IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview';\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport { ILayoutService } from 'vs/platform/layout/browser/layoutService';\nimport { IContextViewDelegate, IContextViewService, IOpenContextView } from './contextView';\nimport { getWindow } from 'vs/base/browser/dom';\n\nexport class ContextViewHandler extends Disposable implements IContextViewProvider {\n\n\tprivate openContextView: IOpenContextView | undefined;\n\tprotected readonly contextView = this._register(new ContextView(this.layoutService.mainContainer, ContextViewDOMPosition.ABSOLUTE));\n\n\tconstructor(\n\t\t@ILayoutService private readonly layoutService: ILayoutService\n\t) {\n\t\tsuper();\n\n\t\tthis.layout();\n\t\tthis._register(layoutService.onDidLayoutContainer(() => this.layout()));\n\t}\n\n\t// ContextView\n\n\tshowContextView(delegate: IContextViewDelegate, container?: HTMLElement, shadowRoot?: boolean): IOpenContextView {\n\t\tlet domPosition: ContextViewDOMPosition;\n\t\tif (container) {\n\t\t\tif (container === this.layoutService.getContainer(getWindow(container))) {\n\t\t\t\tdomPosition = ContextViewDOMPosition.ABSOLUTE;\n\t\t\t} else if (shadowRoot) {\n\t\t\t\tdomPosition = ContextViewDOMPosition.FIXED_SHADOW;\n\t\t\t} else {\n\t\t\t\tdomPosition = ContextViewDOMPosition.FIXED;\n\t\t\t}\n\t\t} else {\n\t\t\tdomPosition = ContextViewDOMPosition.ABSOLUTE;\n\t\t}\n\n\t\tthis.contextView.setContainer(container ?? this.layoutService.activeContainer, domPosition);\n\n\t\tthis.contextView.show(delegate);\n\n\t\tconst openContextView: IOpenContextView = {\n\t\t\tclose: () => {\n\t\t\t\tif (this.openContextView === openContextView) {\n\t\t\t\t\tthis.hideContextView();\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\tthis.openContextView = openContextView;\n\t\treturn openContextView;\n\t}\n\n\tlayout(): void {\n\t\tthis.contextView.layout();\n\t}\n\n\thideContextView(data?: any): void {\n\t\tthis.contextView.hide(data);\n\t\tthis.openContextView = undefined;\n\t}\n}\n\nexport class ContextViewService extends ContextViewHandler implements IContextViewService {\n\n\tdeclare readonly _serviceBrand: undefined;\n\n\tgetContextViewElement(): HTMLElement {\n\t\treturn this.contextView.getViewElement();\n\t}\n}\n","\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { Disposable, IDisposable } from 'vs/base/common/lifecycle';\nimport { RawContextKey } from 'vs/platform/contextkey/common/contextkey';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\n\nexport const ILogService = createDecorator('logService');\n\nexport enum LogLevel {\n\tOff,\n\tTrace,\n\tDebug,\n\tInfo,\n\tWarning,\n\tError\n}\n\nexport const DEFAULT_LOG_LEVEL: LogLevel = LogLevel.Info;\n\nexport interface ILogger extends IDisposable {\n\tonDidChangeLogLevel: Event;\n\tgetLevel(): LogLevel;\n\tsetLevel(level: LogLevel): void;\n\n\ttrace(message: string, ...args: any[]): void;\n\tdebug(message: string, ...args: any[]): void;\n\tinfo(message: string, ...args: any[]): void;\n\twarn(message: string, ...args: any[]): void;\n\terror(message: string | Error, ...args: any[]): void;\n}\n\nexport interface ILogService extends ILogger {\n\treadonly _serviceBrand: undefined;\n}\n\nexport abstract class AbstractLogger extends Disposable implements ILogger {\n\n\tprivate level: LogLevel = DEFAULT_LOG_LEVEL;\n\tprivate readonly _onDidChangeLogLevel: Emitter = this._register(new Emitter());\n\treadonly onDidChangeLogLevel: Event = this._onDidChangeLogLevel.event;\n\n\tsetLevel(level: LogLevel): void {\n\t\tif (this.level !== level) {\n\t\t\tthis.level = level;\n\t\t\tthis._onDidChangeLogLevel.fire(this.level);\n\t\t}\n\t}\n\n\tgetLevel(): LogLevel {\n\t\treturn this.level;\n\t}\n\n\tprotected checkLogLevel(level: LogLevel): boolean {\n\t\treturn this.level !== LogLevel.Off && this.level <= level;\n\t}\n\n\tabstract trace(message: string, ...args: any[]): void;\n\tabstract debug(message: string, ...args: any[]): void;\n\tabstract info(message: string, ...args: any[]): void;\n\tabstract warn(message: string, ...args: any[]): void;\n\tabstract error(message: string | Error, ...args: any[]): void;\n}\n\nexport class ConsoleLogger extends AbstractLogger implements ILogger {\n\n\tconstructor(logLevel: LogLevel = DEFAULT_LOG_LEVEL, private readonly useColors: boolean = true) {\n\t\tsuper();\n\t\tthis.setLevel(logLevel);\n\t}\n\n\ttrace(message: string, ...args: any[]): void {\n\t\tif (this.checkLogLevel(LogLevel.Trace)) {\n\t\t\tif (this.useColors) {\n\t\t\t\tconsole.log('%cTRACE', 'color: #888', message, ...args);\n\t\t\t} else {\n\t\t\t\tconsole.log(message, ...args);\n\t\t\t}\n\t\t}\n\t}\n\n\tdebug(message: string, ...args: any[]): void {\n\t\tif (this.checkLogLevel(LogLevel.Debug)) {\n\t\t\tif (this.useColors) {\n\t\t\t\tconsole.log('%cDEBUG', 'background: #eee; color: #888', message, ...args);\n\t\t\t} else {\n\t\t\t\tconsole.log(message, ...args);\n\t\t\t}\n\t\t}\n\t}\n\n\tinfo(message: string, ...args: any[]): void {\n\t\tif (this.checkLogLevel(LogLevel.Info)) {\n\t\t\tif (this.useColors) {\n\t\t\t\tconsole.log('%c INFO', 'color: #33f', message, ...args);\n\t\t\t} else {\n\t\t\t\tconsole.log(message, ...args);\n\t\t\t}\n\t\t}\n\t}\n\n\twarn(message: string | Error, ...args: any[]): void {\n\t\tif (this.checkLogLevel(LogLevel.Warning)) {\n\t\t\tif (this.useColors) {\n\t\t\t\tconsole.log('%c WARN', 'color: #993', message, ...args);\n\t\t\t} else {\n\t\t\t\tconsole.log(message, ...args);\n\t\t\t}\n\t\t}\n\t}\n\n\terror(message: string, ...args: any[]): void {\n\t\tif (this.checkLogLevel(LogLevel.Error)) {\n\t\t\tif (this.useColors) {\n\t\t\t\tconsole.log('%c ERR', 'color: #f33', message, ...args);\n\t\t\t} else {\n\t\t\t\tconsole.error(message, ...args);\n\t\t\t}\n\t\t}\n\t}\n}\n\nexport class MultiplexLogger extends AbstractLogger implements ILogger {\n\n\tconstructor(private readonly loggers: ReadonlyArray) {\n\t\tsuper();\n\t\tif (loggers.length) {\n\t\t\tthis.setLevel(loggers[0].getLevel());\n\t\t}\n\t}\n\n\toverride setLevel(level: LogLevel): void {\n\t\tfor (const logger of this.loggers) {\n\t\t\tlogger.setLevel(level);\n\t\t}\n\t\tsuper.setLevel(level);\n\t}\n\n\ttrace(message: string, ...args: any[]): void {\n\t\tfor (const logger of this.loggers) {\n\t\t\tlogger.trace(message, ...args);\n\t\t}\n\t}\n\n\tdebug(message: string, ...args: any[]): void {\n\t\tfor (const logger of this.loggers) {\n\t\t\tlogger.debug(message, ...args);\n\t\t}\n\t}\n\n\tinfo(message: string, ...args: any[]): void {\n\t\tfor (const logger of this.loggers) {\n\t\t\tlogger.info(message, ...args);\n\t\t}\n\t}\n\n\twarn(message: string, ...args: any[]): void {\n\t\tfor (const logger of this.loggers) {\n\t\t\tlogger.warn(message, ...args);\n\t\t}\n\t}\n\n\terror(message: string | Error, ...args: any[]): void {\n\t\tfor (const logger of this.loggers) {\n\t\t\tlogger.error(message, ...args);\n\t\t}\n\t}\n\n\toverride dispose(): void {\n\t\tfor (const logger of this.loggers) {\n\t\t\tlogger.dispose();\n\t\t}\n\t\tsuper.dispose();\n\t}\n}\n\nexport function LogLevelToString(logLevel: LogLevel): string {\n\tswitch (logLevel) {\n\t\tcase LogLevel.Trace: return 'trace';\n\t\tcase LogLevel.Debug: return 'debug';\n\t\tcase LogLevel.Info: return 'info';\n\t\tcase LogLevel.Warning: return 'warn';\n\t\tcase LogLevel.Error: return 'error';\n\t\tcase LogLevel.Off: return 'off';\n\t}\n}\n\n// Contexts\nexport const CONTEXT_LOG_LEVEL = new RawContextKey('logLevel', LogLevelToString(LogLevel.Info));\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\nimport * as browser from 'vs/base/browser/browser';\nimport * as dom from 'vs/base/browser/dom';\nimport { DomEmitter } from 'vs/base/browser/event';\nimport { IKeyboardEvent, StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';\nimport { inputLatency } from 'vs/base/browser/performance';\nimport { RunOnceScheduler } from 'vs/base/common/async';\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { KeyCode } from 'vs/base/common/keyCodes';\nimport { Disposable, IDisposable, MutableDisposable } from 'vs/base/common/lifecycle';\nimport { Mimes } from 'vs/base/common/mime';\nimport { OperatingSystem } from 'vs/base/common/platform';\nimport * as strings from 'vs/base/common/strings';\nimport { ITextAreaWrapper, ITypeData, TextAreaState, _debugComposition } from 'vs/editor/browser/controller/textAreaState';\nimport { Position } from 'vs/editor/common/core/position';\nimport { Selection } from 'vs/editor/common/core/selection';\nimport { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';\nimport { ILogService } from 'vs/platform/log/common/log';\n\nexport namespace TextAreaSyntethicEvents {\n\texport const Tap = '-monaco-textarea-synthetic-tap';\n}\n\nexport interface ICompositionData {\n}\n\nexport const CopyOptions = {\n\tforceCopyWithSyntaxHighlighting: false\n};\n\nexport interface IPasteData {\n\ttext: string;\n\tmetadata: ClipboardStoredMetadata | null;\n}\n\nexport interface ClipboardDataToCopy {\n\tisFromEmptySelection: boolean;\n\tmulticursorText: string[] | null | undefined;\n\ttext: string;\n\thtml: string | null | undefined;\n\tmode: string | null;\n}\n\nexport interface ClipboardStoredMetadata {\n\tversion: 1;\n\tisFromEmptySelection: boolean | undefined;\n\tmulticursorText: string[] | null | undefined;\n\tmode: string | null;\n}\n\nexport interface ITextAreaInputHost {\n\tgetDataToCopy(): ClipboardDataToCopy;\n\tgetScreenReaderContent(): TextAreaState;\n\tdeduceModelPosition(viewAnchorPosition: Position, deltaOffset: number, lineFeedCnt: number): Position;\n}\n\ninterface InMemoryClipboardMetadata {\n\tlastCopiedValue: string;\n\tdata: ClipboardStoredMetadata;\n}\n\n/**\n * Every time we write to the clipboard, we record a bit of extra metadata here.\n * Every time we read from the cipboard, if the text matches our last written text,\n * we can fetch the previous metadata.\n */\nexport class InMemoryClipboardMetadataManager {\n\tpublic static readonly INSTANCE = new InMemoryClipboardMetadataManager();\n\n\tprivate _lastState: InMemoryClipboardMetadata | null;\n\n\tconstructor() {\n\t\tthis._lastState = null;\n\t}\n\n\tpublic set(lastCopiedValue: string, data: ClipboardStoredMetadata): void {\n\t\tthis._lastState = { lastCopiedValue, data };\n\t}\n\n\tpublic get(pastedText: string): ClipboardStoredMetadata | null {\n\t\tif (this._lastState && this._lastState.lastCopiedValue === pastedText) {\n\t\t\t// match!\n\t\t\treturn this._lastState.data;\n\t\t}\n\t\tthis._lastState = null;\n\t\treturn null;\n\t}\n}\n\nexport interface ICompositionStartEvent {\n\tdata: string;\n}\n\nexport interface ICompleteTextAreaWrapper extends ITextAreaWrapper {\n\treadonly onKeyDown: Event;\n\treadonly onKeyUp: Event;\n\treadonly onCompositionStart: Event;\n\treadonly onCompositionUpdate: Event;\n\treadonly onCompositionEnd: Event;\n\treadonly onInput: Event;\n\treadonly onCut: Event;\n\treadonly onCopy: Event;\n\treadonly onPaste: Event;\n\treadonly onFocus: Event;\n\treadonly onBlur: Event;\n\treadonly onSyntheticTap: Event;\n\n\treadonly ownerDocument: Document;\n\n\tsetIgnoreSelectionChangeTime(reason: string): void;\n\tgetIgnoreSelectionChangeTime(): number;\n\tresetSelectionChangeTime(): void;\n\n\thasFocus(): boolean;\n}\n\nexport interface IBrowser {\n\tisAndroid: boolean;\n\tisFirefox: boolean;\n\tisChrome: boolean;\n\tisSafari: boolean;\n}\n\nclass CompositionContext {\n\n\tprivate _lastTypeTextLength: number;\n\n\tconstructor() {\n\t\tthis._lastTypeTextLength = 0;\n\t}\n\n\tpublic handleCompositionUpdate(text: string | null | undefined): ITypeData {\n\t\ttext = text || '';\n\t\tconst typeInput: ITypeData = {\n\t\t\ttext: text,\n\t\t\treplacePrevCharCnt: this._lastTypeTextLength,\n\t\t\treplaceNextCharCnt: 0,\n\t\t\tpositionDelta: 0\n\t\t};\n\t\tthis._lastTypeTextLength = text.length;\n\t\treturn typeInput;\n\t}\n}\n\n/**\n * Writes screen reader content to the textarea and is able to analyze its input events to generate:\n * - onCut\n * - onPaste\n * - onType\n *\n * Composition events are generated for presentation purposes (composition input is reflected in onType).\n */\nexport class TextAreaInput extends Disposable {\n\n\tprivate _onFocus = this._register(new Emitter());\n\tpublic readonly onFocus: Event = this._onFocus.event;\n\n\tprivate _onBlur = this._register(new Emitter());\n\tpublic readonly onBlur: Event = this._onBlur.event;\n\n\tprivate _onKeyDown = this._register(new Emitter());\n\tpublic readonly onKeyDown: Event = this._onKeyDown.event;\n\n\tprivate _onKeyUp = this._register(new Emitter());\n\tpublic readonly onKeyUp: Event = this._onKeyUp.event;\n\n\tprivate _onCut = this._register(new Emitter());\n\tpublic readonly onCut: Event = this._onCut.event;\n\n\tprivate _onPaste = this._register(new Emitter());\n\tpublic readonly onPaste: Event = this._onPaste.event;\n\n\tprivate _onType = this._register(new Emitter());\n\tpublic readonly onType: Event = this._onType.event;\n\n\tprivate _onCompositionStart = this._register(new Emitter());\n\tpublic readonly onCompositionStart: Event = this._onCompositionStart.event;\n\n\tprivate _onCompositionUpdate = this._register(new Emitter());\n\tpublic readonly onCompositionUpdate: Event = this._onCompositionUpdate.event;\n\n\tprivate _onCompositionEnd = this._register(new Emitter());\n\tpublic readonly onCompositionEnd: Event = this._onCompositionEnd.event;\n\n\tprivate _onSelectionChangeRequest = this._register(new Emitter());\n\tpublic readonly onSelectionChangeRequest: Event = this._onSelectionChangeRequest.event;\n\n\t// ---\n\n\tprivate readonly _asyncTriggerCut: RunOnceScheduler;\n\n\tprivate readonly _asyncFocusGainWriteScreenReaderContent: MutableDisposable = this._register(new MutableDisposable());\n\n\tprivate _textAreaState: TextAreaState;\n\n\tpublic get textAreaState(): TextAreaState {\n\t\treturn this._textAreaState;\n\t}\n\n\tprivate _selectionChangeListener: IDisposable | null;\n\n\tprivate _hasFocus: boolean;\n\tprivate _currentComposition: CompositionContext | null;\n\n\tconstructor(\n\t\tprivate readonly _host: ITextAreaInputHost,\n\t\tprivate readonly _textArea: ICompleteTextAreaWrapper,\n\t\tprivate readonly _OS: OperatingSystem,\n\t\tprivate readonly _browser: IBrowser,\n\t\t@IAccessibilityService private readonly _accessibilityService: IAccessibilityService,\n\t\t@ILogService private readonly _logService: ILogService\n\t) {\n\t\tsuper();\n\t\tthis._asyncTriggerCut = this._register(new RunOnceScheduler(() => this._onCut.fire(), 0));\n\t\tthis._textAreaState = TextAreaState.EMPTY;\n\t\tthis._selectionChangeListener = null;\n\t\tif (this._accessibilityService.isScreenReaderOptimized()) {\n\t\t\tthis.writeNativeTextAreaContent('ctor');\n\t\t}\n\t\tthis._register(Event.runAndSubscribe(this._accessibilityService.onDidChangeScreenReaderOptimized, () => {\n\t\t\tif (this._accessibilityService.isScreenReaderOptimized() && !this._asyncFocusGainWriteScreenReaderContent.value) {\n\t\t\t\tthis._asyncFocusGainWriteScreenReaderContent.value = this._register(new RunOnceScheduler(() => this.writeNativeTextAreaContent('asyncFocusGain'), 0));\n\t\t\t} else {\n\t\t\t\tthis._asyncFocusGainWriteScreenReaderContent.clear();\n\t\t\t}\n\t\t}));\n\t\tthis._hasFocus = false;\n\t\tthis._currentComposition = null;\n\n\t\tlet lastKeyDown: IKeyboardEvent | null = null;\n\n\t\tthis._register(this._textArea.onKeyDown((_e) => {\n\t\t\tconst e = new StandardKeyboardEvent(_e);\n\t\t\tif (e.keyCode === KeyCode.KEY_IN_COMPOSITION\n\t\t\t\t|| (this._currentComposition && e.keyCode === KeyCode.Backspace)) {\n\t\t\t\t// Stop propagation for keyDown events if the IME is processing key input\n\t\t\t\te.stopPropagation();\n\t\t\t}\n\n\t\t\tif (e.equals(KeyCode.Escape)) {\n\t\t\t\t// Prevent default always for `Esc`, otherwise it will generate a keypress\n\t\t\t\t// See https://msdn.microsoft.com/en-us/library/ie/ms536939(v=vs.85).aspx\n\t\t\t\te.preventDefault();\n\t\t\t}\n\n\t\t\tlastKeyDown = e;\n\t\t\tthis._onKeyDown.fire(e);\n\t\t}));\n\n\t\tthis._register(this._textArea.onKeyUp((_e) => {\n\t\t\tconst e = new StandardKeyboardEvent(_e);\n\t\t\tthis._onKeyUp.fire(e);\n\t\t}));\n\n\t\tthis._register(this._textArea.onCompositionStart((e) => {\n\t\t\tif (_debugComposition) {\n\t\t\t\tconsole.log(`[compositionstart]`, e);\n\t\t\t}\n\n\t\t\tconst currentComposition = new CompositionContext();\n\t\t\tif (this._currentComposition) {\n\t\t\t\t// simply reset the composition context\n\t\t\t\tthis._currentComposition = currentComposition;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis._currentComposition = currentComposition;\n\n\t\t\tif (\n\t\t\t\tthis._OS === OperatingSystem.Macintosh\n\t\t\t\t&& lastKeyDown\n\t\t\t\t&& lastKeyDown.equals(KeyCode.KEY_IN_COMPOSITION)\n\t\t\t\t&& this._textAreaState.selectionStart === this._textAreaState.selectionEnd\n\t\t\t\t&& this._textAreaState.selectionStart > 0\n\t\t\t\t&& this._textAreaState.value.substr(this._textAreaState.selectionStart - 1, 1) === e.data\n\t\t\t\t&& (lastKeyDown.code === 'ArrowRight' || lastKeyDown.code === 'ArrowLeft')\n\t\t\t) {\n\t\t\t\t// Handling long press case on Chromium/Safari macOS + arrow key => pretend the character was selected\n\t\t\t\tif (_debugComposition) {\n\t\t\t\t\tconsole.log(`[compositionstart] Handling long press case on macOS + arrow key`, e);\n\t\t\t\t}\n\t\t\t\t// Pretend the previous character was composed (in order to get it removed by subsequent compositionupdate events)\n\t\t\t\tcurrentComposition.handleCompositionUpdate('x');\n\t\t\t\tthis._onCompositionStart.fire({ data: e.data });\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (this._browser.isAndroid) {\n\t\t\t\t// when tapping on the editor, Android enters composition mode to edit the current word\n\t\t\t\t// so we cannot clear the textarea on Android and we must pretend the current word was selected\n\t\t\t\tthis._onCompositionStart.fire({ data: e.data });\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis._onCompositionStart.fire({ data: e.data });\n\t\t}));\n\n\t\tthis._register(this._textArea.onCompositionUpdate((e) => {\n\t\t\tif (_debugComposition) {\n\t\t\t\tconsole.log(`[compositionupdate]`, e);\n\t\t\t}\n\t\t\tconst currentComposition = this._currentComposition;\n\t\t\tif (!currentComposition) {\n\t\t\t\t// should not be possible to receive a 'compositionupdate' without a 'compositionstart'\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (this._browser.isAndroid) {\n\t\t\t\t// On Android, the data sent with the composition update event is unusable.\n\t\t\t\t// For example, if the cursor is in the middle of a word like Mic|osoft\n\t\t\t\t// and Microsoft is chosen from the keyboard's suggestions, the e.data will contain \"Microsoft\".\n\t\t\t\t// This is not really usable because it doesn't tell us where the edit began and where it ended.\n\t\t\t\tconst newState = TextAreaState.readFromTextArea(this._textArea, this._textAreaState);\n\t\t\t\tconst typeInput = TextAreaState.deduceAndroidCompositionInput(this._textAreaState, newState);\n\t\t\t\tthis._textAreaState = newState;\n\t\t\t\tthis._onType.fire(typeInput);\n\t\t\t\tthis._onCompositionUpdate.fire(e);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst typeInput = currentComposition.handleCompositionUpdate(e.data);\n\t\t\tthis._textAreaState = TextAreaState.readFromTextArea(this._textArea, this._textAreaState);\n\t\t\tthis._onType.fire(typeInput);\n\t\t\tthis._onCompositionUpdate.fire(e);\n\t\t}));\n\n\t\tthis._register(this._textArea.onCompositionEnd((e) => {\n\t\t\tif (_debugComposition) {\n\t\t\t\tconsole.log(`[compositionend]`, e);\n\t\t\t}\n\t\t\tconst currentComposition = this._currentComposition;\n\t\t\tif (!currentComposition) {\n\t\t\t\t// https://github.com/microsoft/monaco-editor/issues/1663\n\t\t\t\t// On iOS 13.2, Chinese system IME randomly trigger an additional compositionend event with empty data\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis._currentComposition = null;\n\n\t\t\tif (this._browser.isAndroid) {\n\t\t\t\t// On Android, the data sent with the composition update event is unusable.\n\t\t\t\t// For example, if the cursor is in the middle of a word like Mic|osoft\n\t\t\t\t// and Microsoft is chosen from the keyboard's suggestions, the e.data will contain \"Microsoft\".\n\t\t\t\t// This is not really usable because it doesn't tell us where the edit began and where it ended.\n\t\t\t\tconst newState = TextAreaState.readFromTextArea(this._textArea, this._textAreaState);\n\t\t\t\tconst typeInput = TextAreaState.deduceAndroidCompositionInput(this._textAreaState, newState);\n\t\t\t\tthis._textAreaState = newState;\n\t\t\t\tthis._onType.fire(typeInput);\n\t\t\t\tthis._onCompositionEnd.fire();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst typeInput = currentComposition.handleCompositionUpdate(e.data);\n\t\t\tthis._textAreaState = TextAreaState.readFromTextArea(this._textArea, this._textAreaState);\n\t\t\tthis._onType.fire(typeInput);\n\t\t\tthis._onCompositionEnd.fire();\n\t\t}));\n\n\t\tthis._register(this._textArea.onInput((e) => {\n\t\t\tif (_debugComposition) {\n\t\t\t\tconsole.log(`[input]`, e);\n\t\t\t}\n\n\t\t\t// Pretend here we touched the text area, as the `input` event will most likely\n\t\t\t// result in a `selectionchange` event which we want to ignore\n\t\t\tthis._textArea.setIgnoreSelectionChangeTime('received input event');\n\n\t\t\tif (this._currentComposition) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst newState = TextAreaState.readFromTextArea(this._textArea, this._textAreaState);\n\t\t\tconst typeInput = TextAreaState.deduceInput(this._textAreaState, newState, /*couldBeEmojiInput*/this._OS === OperatingSystem.Macintosh);\n\n\t\t\tif (typeInput.replacePrevCharCnt === 0 && typeInput.text.length === 1) {\n\t\t\t\t// one character was typed\n\t\t\t\tif (\n\t\t\t\t\tstrings.isHighSurrogate(typeInput.text.charCodeAt(0))\n\t\t\t\t\t|| typeInput.text.charCodeAt(0) === 0x7f /* Delete */\n\t\t\t\t) {\n\t\t\t\t\t// Ignore invalid input but keep it around for next time\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis._textAreaState = newState;\n\t\t\tif (\n\t\t\t\ttypeInput.text !== ''\n\t\t\t\t|| typeInput.replacePrevCharCnt !== 0\n\t\t\t\t|| typeInput.replaceNextCharCnt !== 0\n\t\t\t\t|| typeInput.positionDelta !== 0\n\t\t\t) {\n\t\t\t\tthis._onType.fire(typeInput);\n\t\t\t}\n\t\t}));\n\n\t\t// --- Clipboard operations\n\n\t\tthis._register(this._textArea.onCut((e) => {\n\t\t\t// Pretend here we touched the text area, as the `cut` event will most likely\n\t\t\t// result in a `selectionchange` event which we want to ignore\n\t\t\tthis._textArea.setIgnoreSelectionChangeTime('received cut event');\n\n\t\t\tthis._ensureClipboardGetsEditorSelection(e);\n\t\t\tthis._asyncTriggerCut.schedule();\n\t\t}));\n\n\t\tthis._register(this._textArea.onCopy((e) => {\n\t\t\tthis._ensureClipboardGetsEditorSelection(e);\n\t\t}));\n\n\t\tthis._register(this._textArea.onPaste((e) => {\n\t\t\t// Pretend here we touched the text area, as the `paste` event will most likely\n\t\t\t// result in a `selectionchange` event which we want to ignore\n\t\t\tthis._textArea.setIgnoreSelectionChangeTime('received paste event');\n\n\t\t\te.preventDefault();\n\n\t\t\tif (!e.clipboardData) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlet [text, metadata] = ClipboardEventUtils.getTextData(e.clipboardData);\n\t\t\tif (!text) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// try the in-memory store\n\t\t\tmetadata = metadata || InMemoryClipboardMetadataManager.INSTANCE.get(text);\n\n\t\t\tthis._onPaste.fire({\n\t\t\t\ttext: text,\n\t\t\t\tmetadata: metadata\n\t\t\t});\n\t\t}));\n\n\t\tthis._register(this._textArea.onFocus(() => {\n\t\t\tconst hadFocus = this._hasFocus;\n\n\t\t\tthis._setHasFocus(true);\n\n\t\t\tif (this._accessibilityService.isScreenReaderOptimized() && this._browser.isSafari && !hadFocus && this._hasFocus) {\n\t\t\t\t// When \"tabbing into\" the textarea, immediately after dispatching the 'focus' event,\n\t\t\t\t// Safari will always move the selection at offset 0 in the textarea\n\t\t\t\tif (!this._asyncFocusGainWriteScreenReaderContent.value) {\n\t\t\t\t\tthis._asyncFocusGainWriteScreenReaderContent.value = new RunOnceScheduler(() => this.writeNativeTextAreaContent('asyncFocusGain'), 0);\n\t\t\t\t}\n\t\t\t\tthis._asyncFocusGainWriteScreenReaderContent.value.schedule();\n\t\t\t}\n\t\t}));\n\t\tthis._register(this._textArea.onBlur(() => {\n\t\t\tif (this._currentComposition) {\n\t\t\t\t// See https://github.com/microsoft/vscode/issues/112621\n\t\t\t\t// where compositionend is not triggered when the editor\n\t\t\t\t// is taken off-dom during a composition\n\n\t\t\t\t// Clear the flag to be able to write to the textarea\n\t\t\t\tthis._currentComposition = null;\n\n\t\t\t\t// Clear the textarea to avoid an unwanted cursor type\n\t\t\t\tthis.writeNativeTextAreaContent('blurWithoutCompositionEnd');\n\n\t\t\t\t// Fire artificial composition end\n\t\t\t\tthis._onCompositionEnd.fire();\n\t\t\t}\n\t\t\tthis._setHasFocus(false);\n\t\t}));\n\t\tthis._register(this._textArea.onSyntheticTap(() => {\n\t\t\tif (this._browser.isAndroid && this._currentComposition) {\n\t\t\t\t// on Android, tapping does not cancel the current composition, so the\n\t\t\t\t// textarea is stuck showing the old composition\n\n\t\t\t\t// Clear the flag to be able to write to the textarea\n\t\t\t\tthis._currentComposition = null;\n\n\t\t\t\t// Clear the textarea to avoid an unwanted cursor type\n\t\t\t\tthis.writeNativeTextAreaContent('tapWithoutCompositionEnd');\n\n\t\t\t\t// Fire artificial composition end\n\t\t\t\tthis._onCompositionEnd.fire();\n\t\t\t}\n\t\t}));\n\t}\n\n\tprivate _installSelectionChangeListener(): IDisposable {\n\t\t// See https://github.com/microsoft/vscode/issues/27216 and https://github.com/microsoft/vscode/issues/98256\n\t\t// When using a Braille display, it is possible for users to reposition the\n\t\t// system caret. This is reflected in Chrome as a `selectionchange` event.\n\t\t//\n\t\t// The `selectionchange` event appears to be emitted under numerous other circumstances,\n\t\t// so it is quite a challenge to distinguish a `selectionchange` coming in from a user\n\t\t// using a Braille display from all the other cases.\n\t\t//\n\t\t// The problems with the `selectionchange` event are:\n\t\t// * the event is emitted when the textarea is focused programmatically -- textarea.focus()\n\t\t// * the event is emitted when the selection is changed in the textarea programmatically -- textarea.setSelectionRange(...)\n\t\t// * the event is emitted when the value of the textarea is changed programmatically -- textarea.value = '...'\n\t\t// * the event is emitted when tabbing into the textarea\n\t\t// * the event is emitted asynchronously (sometimes with a delay as high as a few tens of ms)\n\t\t// * the event sometimes comes in bursts for a single logical textarea operation\n\n\t\t// `selectionchange` events often come multiple times for a single logical change\n\t\t// so throttle multiple `selectionchange` events that burst in a short period of time.\n\t\tlet previousSelectionChangeEventTime = 0;\n\t\treturn dom.addDisposableListener(this._textArea.ownerDocument, 'selectionchange', (e) => {//todo\n\t\t\tinputLatency.onSelectionChange();\n\n\t\t\tif (!this._hasFocus) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (this._currentComposition) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (!this._browser.isChrome) {\n\t\t\t\t// Support only for Chrome until testing happens on other browsers\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst now = Date.now();\n\n\t\t\tconst delta1 = now - previousSelectionChangeEventTime;\n\t\t\tpreviousSelectionChangeEventTime = now;\n\t\t\tif (delta1 < 5) {\n\t\t\t\t// received another `selectionchange` event within 5ms of the previous `selectionchange` event\n\t\t\t\t// => ignore it\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst delta2 = now - this._textArea.getIgnoreSelectionChangeTime();\n\t\t\tthis._textArea.resetSelectionChangeTime();\n\t\t\tif (delta2 < 100) {\n\t\t\t\t// received a `selectionchange` event within 100ms since we touched the textarea\n\t\t\t\t// => ignore it, since we caused it\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (!this._textAreaState.selection) {\n\t\t\t\t// Cannot correlate a position in the textarea with a position in the editor...\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst newValue = this._textArea.getValue();\n\t\t\tif (this._textAreaState.value !== newValue) {\n\t\t\t\t// Cannot correlate a position in the textarea with a position in the editor...\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst newSelectionStart = this._textArea.getSelectionStart();\n\t\t\tconst newSelectionEnd = this._textArea.getSelectionEnd();\n\t\t\tif (this._textAreaState.selectionStart === newSelectionStart && this._textAreaState.selectionEnd === newSelectionEnd) {\n\t\t\t\t// Nothing to do...\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst _newSelectionStartPosition = this._textAreaState.deduceEditorPosition(newSelectionStart);\n\t\t\tconst newSelectionStartPosition = this._host.deduceModelPosition(_newSelectionStartPosition[0]!, _newSelectionStartPosition[1], _newSelectionStartPosition[2]);\n\n\t\t\tconst _newSelectionEndPosition = this._textAreaState.deduceEditorPosition(newSelectionEnd);\n\t\t\tconst newSelectionEndPosition = this._host.deduceModelPosition(_newSelectionEndPosition[0]!, _newSelectionEndPosition[1], _newSelectionEndPosition[2]);\n\n\t\t\tconst newSelection = new Selection(\n\t\t\t\tnewSelectionStartPosition.lineNumber, newSelectionStartPosition.column,\n\t\t\t\tnewSelectionEndPosition.lineNumber, newSelectionEndPosition.column\n\t\t\t);\n\n\t\t\tthis._onSelectionChangeRequest.fire(newSelection);\n\t\t});\n\t}\n\n\tpublic override dispose(): void {\n\t\tsuper.dispose();\n\t\tif (this._selectionChangeListener) {\n\t\t\tthis._selectionChangeListener.dispose();\n\t\t\tthis._selectionChangeListener = null;\n\t\t}\n\t}\n\n\tpublic focusTextArea(): void {\n\t\t// Setting this._hasFocus and writing the screen reader content\n\t\t// will result in a focus() and setSelectionRange() in the textarea\n\t\tthis._setHasFocus(true);\n\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\n\t\tthis.refreshFocusState();\n\t}\n\n\tpublic isFocused(): boolean {\n\t\treturn this._hasFocus;\n\t}\n\n\tpublic refreshFocusState(): void {\n\t\tthis._setHasFocus(this._textArea.hasFocus());\n\t}\n\n\tprivate _setHasFocus(newHasFocus: boolean): void {\n\t\tif (this._hasFocus === newHasFocus) {\n\t\t\t// no change\n\t\t\treturn;\n\t\t}\n\t\tthis._hasFocus = newHasFocus;\n\n\t\tif (this._selectionChangeListener) {\n\t\t\tthis._selectionChangeListener.dispose();\n\t\t\tthis._selectionChangeListener = null;\n\t\t}\n\t\tif (this._hasFocus) {\n\t\t\tthis._selectionChangeListener = this._installSelectionChangeListener();\n\t\t}\n\n\t\tif (this._hasFocus) {\n\t\t\tthis.writeNativeTextAreaContent('focusgain');\n\t\t}\n\n\t\tif (this._hasFocus) {\n\t\t\tthis._onFocus.fire();\n\t\t} else {\n\t\t\tthis._onBlur.fire();\n\t\t}\n\t}\n\n\tprivate _setAndWriteTextAreaState(reason: string, textAreaState: TextAreaState): void {\n\t\tif (!this._hasFocus) {\n\t\t\ttextAreaState = textAreaState.collapseSelection();\n\t\t}\n\n\t\ttextAreaState.writeToTextArea(reason, this._textArea, this._hasFocus);\n\t\tthis._textAreaState = textAreaState;\n\t}\n\n\tpublic writeNativeTextAreaContent(reason: string): void {\n\t\tif ((!this._accessibilityService.isScreenReaderOptimized() && reason === 'render') || this._currentComposition) {\n\t\t\t// Do not write to the text on render unless a screen reader is being used #192278\n\t\t\t// Do not write to the text area when doing composition\n\t\t\treturn;\n\t\t}\n\t\tthis._logService.trace(`writeTextAreaState(reason: ${reason})`);\n\t\tthis._setAndWriteTextAreaState(reason, this._host.getScreenReaderContent());\n\t}\n\n\tprivate _ensureClipboardGetsEditorSelection(e: ClipboardEvent): void {\n\t\tconst dataToCopy = this._host.getDataToCopy();\n\t\tconst storedMetadata: ClipboardStoredMetadata = {\n\t\t\tversion: 1,\n\t\t\tisFromEmptySelection: dataToCopy.isFromEmptySelection,\n\t\t\tmulticursorText: dataToCopy.multicursorText,\n\t\t\tmode: dataToCopy.mode\n\t\t};\n\t\tInMemoryClipboardMetadataManager.INSTANCE.set(\n\t\t\t// When writing \"LINE\\r\\n\" to the clipboard and then pasting,\n\t\t\t// Firefox pastes \"LINE\\n\", so let's work around this quirk\n\t\t\t(this._browser.isFirefox ? dataToCopy.text.replace(/\\r\\n/g, '\\n') : dataToCopy.text),\n\t\t\tstoredMetadata\n\t\t);\n\n\t\te.preventDefault();\n\t\tif (e.clipboardData) {\n\t\t\tClipboardEventUtils.setTextData(e.clipboardData, dataToCopy.text, dataToCopy.html, storedMetadata);\n\t\t}\n\t}\n}\n\nexport const ClipboardEventUtils = {\n\n\tgetTextData(clipboardData: DataTransfer): [string, ClipboardStoredMetadata | null] {\n\t\tconst text = clipboardData.getData(Mimes.text);\n\t\tlet metadata: ClipboardStoredMetadata | null = null;\n\t\tconst rawmetadata = clipboardData.getData('vscode-editor-data');\n\t\tif (typeof rawmetadata === 'string') {\n\t\t\ttry {\n\t\t\t\tmetadata = JSON.parse(rawmetadata);\n\t\t\t\tif (metadata.version !== 1) {\n\t\t\t\t\tmetadata = null;\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// no problem!\n\t\t\t}\n\t\t}\n\n\t\tif (text.length === 0 && metadata === null && clipboardData.files.length > 0) {\n\t\t\t// no textual data pasted, generate text from file names\n\t\t\tconst files: File[] = Array.prototype.slice.call(clipboardData.files, 0);\n\t\t\treturn [files.map(file => file.name).join('\\n'), null];\n\t\t}\n\n\t\treturn [text, metadata];\n\t},\n\n\tsetTextData(clipboardData: DataTransfer, text: string, html: string | null | undefined, metadata: ClipboardStoredMetadata): void {\n\t\tclipboardData.setData(Mimes.text, text);\n\t\tif (typeof html === 'string') {\n\t\t\tclipboardData.setData('text/html', html);\n\t\t}\n\t\tclipboardData.setData('vscode-editor-data', JSON.stringify(metadata));\n\t}\n};\n\nexport class TextAreaWrapper extends Disposable implements ICompleteTextAreaWrapper {\n\n\tpublic readonly onKeyDown = this._register(new DomEmitter(this._actual, 'keydown')).event;\n\tpublic readonly onKeyUp = this._register(new DomEmitter(this._actual, 'keyup')).event;\n\tpublic readonly onCompositionStart = this._register(new DomEmitter(this._actual, 'compositionstart')).event;\n\tpublic readonly onCompositionUpdate = this._register(new DomEmitter(this._actual, 'compositionupdate')).event;\n\tpublic readonly onCompositionEnd = this._register(new DomEmitter(this._actual, 'compositionend')).event;\n\tpublic readonly onBeforeInput = this._register(new DomEmitter(this._actual, 'beforeinput')).event;\n\tpublic readonly onInput = >this._register(new DomEmitter(this._actual, 'input')).event;\n\tpublic readonly onCut = this._register(new DomEmitter(this._actual, 'cut')).event;\n\tpublic readonly onCopy = this._register(new DomEmitter(this._actual, 'copy')).event;\n\tpublic readonly onPaste = this._register(new DomEmitter(this._actual, 'paste')).event;\n\tpublic readonly onFocus = this._register(new DomEmitter(this._actual, 'focus')).event;\n\tpublic readonly onBlur = this._register(new DomEmitter(this._actual, 'blur')).event;\n\n\tpublic get ownerDocument(): Document {\n\t\treturn this._actual.ownerDocument;\n\t}\n\n\tprivate _onSyntheticTap = this._register(new Emitter());\n\tpublic readonly onSyntheticTap: Event = this._onSyntheticTap.event;\n\n\tprivate _ignoreSelectionChangeTime: number;\n\n\tconstructor(\n\t\tprivate readonly _actual: HTMLTextAreaElement\n\t) {\n\t\tsuper();\n\t\tthis._ignoreSelectionChangeTime = 0;\n\n\t\tthis._register(this.onKeyDown(() => inputLatency.onKeyDown()));\n\t\tthis._register(this.onBeforeInput(() => inputLatency.onBeforeInput()));\n\t\tthis._register(this.onInput(() => inputLatency.onInput()));\n\t\tthis._register(this.onKeyUp(() => inputLatency.onKeyUp()));\n\n\t\tthis._register(dom.addDisposableListener(this._actual, TextAreaSyntethicEvents.Tap, () => this._onSyntheticTap.fire()));\n\t}\n\n\tpublic hasFocus(): boolean {\n\t\tconst shadowRoot = dom.getShadowRoot(this._actual);\n\t\tif (shadowRoot) {\n\t\t\treturn shadowRoot.activeElement === this._actual;\n\t\t} else if (this._actual.isConnected) {\n\t\t\treturn dom.getActiveElement() === this._actual;\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tpublic setIgnoreSelectionChangeTime(reason: string): void {\n\t\tthis._ignoreSelectionChangeTime = Date.now();\n\t}\n\n\tpublic getIgnoreSelectionChangeTime(): number {\n\t\treturn this._ignoreSelectionChangeTime;\n\t}\n\n\tpublic resetSelectionChangeTime(): void {\n\t\tthis._ignoreSelectionChangeTime = 0;\n\t}\n\n\tpublic getValue(): string {\n\t\t// console.log('current value: ' + this._textArea.value);\n\t\treturn this._actual.value;\n\t}\n\n\tpublic setValue(reason: string, value: string): void {\n\t\tconst textArea = this._actual;\n\t\tif (textArea.value === value) {\n\t\t\t// No change\n\t\t\treturn;\n\t\t}\n\t\t// console.log('reason: ' + reason + ', current value: ' + textArea.value + ' => new value: ' + value);\n\t\tthis.setIgnoreSelectionChangeTime('setValue');\n\t\ttextArea.value = value;\n\t}\n\n\tpublic getSelectionStart(): number {\n\t\treturn this._actual.selectionDirection === 'backward' ? this._actual.selectionEnd : this._actual.selectionStart;\n\t}\n\n\tpublic getSelectionEnd(): number {\n\t\treturn this._actual.selectionDirection === 'backward' ? this._actual.selectionStart : this._actual.selectionEnd;\n\t}\n\n\tpublic setSelectionRange(reason: string, selectionStart: number, selectionEnd: number): void {\n\t\tconst textArea = this._actual;\n\n\t\tlet activeElement: Element | null = null;\n\t\tconst shadowRoot = dom.getShadowRoot(textArea);\n\t\tif (shadowRoot) {\n\t\t\tactiveElement = shadowRoot.activeElement;\n\t\t} else {\n\t\t\tactiveElement = dom.getActiveElement();\n\t\t}\n\t\tconst activeWindow = dom.getWindow(activeElement);\n\n\t\tconst currentIsFocused = (activeElement === textArea);\n\t\tconst currentSelectionStart = textArea.selectionStart;\n\t\tconst currentSelectionEnd = textArea.selectionEnd;\n\n\t\tif (currentIsFocused && currentSelectionStart === selectionStart && currentSelectionEnd === selectionEnd) {\n\t\t\t// No change\n\t\t\t// Firefox iframe bug https://github.com/microsoft/monaco-editor/issues/643#issuecomment-367871377\n\t\t\tif (browser.isFirefox && activeWindow.parent !== activeWindow) {\n\t\t\t\ttextArea.focus();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// console.log('reason: ' + reason + ', setSelectionRange: ' + selectionStart + ' -> ' + selectionEnd);\n\n\t\tif (currentIsFocused) {\n\t\t\t// No need to focus, only need to change the selection range\n\t\t\tthis.setIgnoreSelectionChangeTime('setSelectionRange');\n\t\t\ttextArea.setSelectionRange(selectionStart, selectionEnd);\n\t\t\tif (browser.isFirefox && activeWindow.parent !== activeWindow) {\n\t\t\t\ttextArea.focus();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// If the focus is outside the textarea, browsers will try really hard to reveal the textarea.\n\t\t// Here, we try to undo the browser's desperate reveal.\n\t\ttry {\n\t\t\tconst scrollState = dom.saveParentsScrollTop(textArea);\n\t\t\tthis.setIgnoreSelectionChangeTime('setSelectionRange');\n\t\t\ttextArea.focus();\n\t\t\ttextArea.setSelectionRange(selectionStart, selectionEnd);\n\t\t\tdom.restoreParentsScrollTop(textArea, scrollState);\n\t\t} catch (e) {\n\t\t\t// Sometimes IE throws when setting selection (e.g. textarea is off-DOM)\n\t\t}\n\t}\n}\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\nimport { doHash } from 'vs/base/common/hash';\nimport { LRUCache } from 'vs/base/common/map';\nimport { clamp, MovingAverage, SlidingWindowAverage } from 'vs/base/common/numbers';\nimport { LanguageFeatureRegistry } from 'vs/editor/common/languageFeatureRegistry';\nimport { ITextModel } from 'vs/editor/common/model';\nimport { IEnvironmentService } from 'vs/platform/environment/common/environment';\nimport { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\nimport { ILogService } from 'vs/platform/log/common/log';\nimport { matchesScheme } from 'vs/base/common/network';\n\n\nexport const ILanguageFeatureDebounceService = createDecorator('ILanguageFeatureDebounceService');\n\nexport interface ILanguageFeatureDebounceService {\n\n\treadonly _serviceBrand: undefined;\n\n\tfor(feature: LanguageFeatureRegistry, debugName: string, config?: { min?: number; max?: number; salt?: string }): IFeatureDebounceInformation;\n}\n\nexport interface IFeatureDebounceInformation {\n\tget(model: ITextModel): number;\n\tupdate(model: ITextModel, value: number): number;\n\tdefault(): number;\n}\n\nnamespace IdentityHash {\n\tconst _hashes = new WeakMap();\n\tlet pool = 0;\n\texport function of(obj: object): number {\n\t\tlet value = _hashes.get(obj);\n\t\tif (value === undefined) {\n\t\t\tvalue = ++pool;\n\t\t\t_hashes.set(obj, value);\n\t\t}\n\t\treturn value;\n\t}\n}\n\nclass NullDebounceInformation implements IFeatureDebounceInformation {\n\n\tconstructor(private readonly _default: number) { }\n\n\tget(_model: ITextModel): number {\n\t\treturn this._default;\n\t}\n\tupdate(_model: ITextModel, _value: number): number {\n\t\treturn this._default;\n\t}\n\tdefault(): number {\n\t\treturn this._default;\n\t}\n}\n\nclass FeatureDebounceInformation implements IFeatureDebounceInformation {\n\n\tprivate readonly _cache = new LRUCache(50, 0.7);\n\n\tconstructor(\n\t\tprivate readonly _logService: ILogService,\n\t\tprivate readonly _name: string,\n\t\tprivate readonly _registry: LanguageFeatureRegistry,\n\t\tprivate readonly _default: number,\n\t\tprivate readonly _min: number,\n\t\tprivate readonly _max: number,\n\t) { }\n\n\tprivate _key(model: ITextModel): string {\n\t\treturn model.id + this._registry.all(model).reduce((hashVal, obj) => doHash(IdentityHash.of(obj), hashVal), 0);\n\t}\n\n\tget(model: ITextModel): number {\n\t\tconst key = this._key(model);\n\t\tconst avg = this._cache.get(key);\n\t\treturn avg\n\t\t\t? clamp(avg.value, this._min, this._max)\n\t\t\t: this.default();\n\t}\n\n\tupdate(model: ITextModel, value: number): number {\n\t\tconst key = this._key(model);\n\t\tlet avg = this._cache.get(key);\n\t\tif (!avg) {\n\t\t\tavg = new SlidingWindowAverage(6);\n\t\t\tthis._cache.set(key, avg);\n\t\t}\n\t\tconst newValue = clamp(avg.update(value), this._min, this._max);\n\t\tif (!matchesScheme(model.uri, 'output')) {\n\t\t\tthis._logService.trace(`[DEBOUNCE: ${this._name}] for ${model.uri.toString()} is ${newValue}ms`);\n\t\t}\n\t\treturn newValue;\n\t}\n\n\tprivate _overall(): number {\n\t\tconst result = new MovingAverage();\n\t\tfor (const [, avg] of this._cache) {\n\t\t\tresult.update(avg.value);\n\t\t}\n\t\treturn result.value;\n\t}\n\n\tdefault() {\n\t\tconst value = (this._overall() | 0) || this._default;\n\t\treturn clamp(value, this._min, this._max);\n\t}\n}\n\n\nexport class LanguageFeatureDebounceService implements ILanguageFeatureDebounceService {\n\n\tdeclare _serviceBrand: undefined;\n\n\tprivate readonly _data = new Map();\n\tprivate readonly _isDev: boolean;\n\n\tconstructor(\n\t\t@ILogService private readonly _logService: ILogService,\n\t\t@IEnvironmentService envService: IEnvironmentService,\n\t) {\n\n\t\tthis._isDev = envService.isExtensionDevelopment || !envService.isBuilt;\n\t}\n\n\tfor(feature: LanguageFeatureRegistry, name: string, config?: { min?: number; max?: number; key?: string }): IFeatureDebounceInformation {\n\t\tconst min = config?.min ?? 50;\n\t\tconst max = config?.max ?? min ** 2;\n\t\tconst extra = config?.key ?? undefined;\n\t\tconst key = `${IdentityHash.of(feature)},${min}${extra ? ',' + extra : ''}`;\n\t\tlet info = this._data.get(key);\n\t\tif (!info) {\n\t\t\tif (this._isDev) {\n\t\t\t\tthis._logService.debug(`[DEBOUNCE: ${name}] is disabled in developed mode`);\n\t\t\t\tinfo = new NullDebounceInformation(min * 1.5);\n\t\t\t} else {\n\t\t\t\tinfo = new FeatureDebounceInformation(\n\t\t\t\t\tthis._logService,\n\t\t\t\t\tname,\n\t\t\t\t\tfeature,\n\t\t\t\t\t(this._overallAverage() | 0) || (min * 1.5), // default is overall default or derived from min-value\n\t\t\t\t\tmin,\n\t\t\t\t\tmax\n\t\t\t\t);\n\t\t\t}\n\t\t\tthis._data.set(key, info);\n\t\t}\n\t\treturn info;\n\t}\n\n\tprivate _overallAverage(): number {\n\t\t// Average of all language features. Not a great value but an approximation\n\t\tconst result = new MovingAverage();\n\t\tfor (const info of this._data.values()) {\n\t\t\tresult.update(info.default());\n\t\t}\n\t\treturn result.value;\n\t}\n}\n\nregisterSingleton(ILanguageFeatureDebounceService, LanguageFeatureDebounceService, InstantiationType.Delayed);\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\nimport { equals } from 'vs/base/common/arrays';\nimport { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';\nimport { onUnexpectedExternalError } from 'vs/base/common/errors';\nimport { Iterable } from 'vs/base/common/iterator';\nimport { LRUCache } from 'vs/base/common/map';\nimport { URI } from 'vs/base/common/uri';\nimport { Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\nimport { ITextModel } from 'vs/editor/common/model';\nimport { DocumentSymbol, DocumentSymbolProvider } from 'vs/editor/common/languages';\nimport { IFeatureDebounceInformation, ILanguageFeatureDebounceService } from 'vs/editor/common/services/languageFeatureDebounce';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\nimport { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions';\nimport { IModelService } from 'vs/editor/common/services/model';\nimport { DisposableStore } from 'vs/base/common/lifecycle';\nimport { LanguageFeatureRegistry } from 'vs/editor/common/languageFeatureRegistry';\nimport { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';\n\nexport abstract class TreeElement {\n\n\tabstract id: string;\n\tabstract children: Map;\n\tabstract parent: TreeElement | undefined;\n\n\tremove(): void {\n\t\tthis.parent?.children.delete(this.id);\n\t}\n\n\tstatic findId(candidate: DocumentSymbol | string, container: TreeElement): string {\n\t\t// complex id-computation which contains the origin/extension,\n\t\t// the parent path, and some dedupe logic when names collide\n\t\tlet candidateId: string;\n\t\tif (typeof candidate === 'string') {\n\t\t\tcandidateId = `${container.id}/${candidate}`;\n\t\t} else {\n\t\t\tcandidateId = `${container.id}/${candidate.name}`;\n\t\t\tif (container.children.get(candidateId) !== undefined) {\n\t\t\t\tcandidateId = `${container.id}/${candidate.name}_${candidate.range.startLineNumber}_${candidate.range.startColumn}`;\n\t\t\t}\n\t\t}\n\n\t\tlet id = candidateId;\n\t\tfor (let i = 0; container.children.get(id) !== undefined; i++) {\n\t\t\tid = `${candidateId}_${i}`;\n\t\t}\n\n\t\treturn id;\n\t}\n\n\tstatic empty(element: TreeElement): boolean {\n\t\treturn element.children.size === 0;\n\t}\n}\n\nexport class OutlineElement extends TreeElement {\n\n\tchildren = new Map();\n\n\tconstructor(\n\t\treadonly id: string,\n\t\tpublic parent: TreeElement | undefined,\n\t\treadonly symbol: DocumentSymbol\n\t) {\n\t\tsuper();\n\t}\n}\n\nexport class OutlineGroup extends TreeElement {\n\n\tchildren = new Map();\n\n\tconstructor(\n\t\treadonly id: string,\n\t\tpublic parent: TreeElement | undefined,\n\t\treadonly label: string,\n\t\treadonly order: number,\n\t) {\n\t\tsuper();\n\t}\n}\n\nexport class OutlineModel extends TreeElement {\n\n\tstatic create(registry: LanguageFeatureRegistry, textModel: ITextModel, token: CancellationToken): Promise {\n\n\t\tconst cts = new CancellationTokenSource(token);\n\t\tconst result = new OutlineModel(textModel.uri);\n\t\tconst provider = registry.ordered(textModel);\n\t\tconst promises = provider.map((provider, index) => {\n\n\t\t\tconst id = TreeElement.findId(`provider_${index}`, result);\n\t\t\tconst group = new OutlineGroup(id, result, provider.displayName ?? 'Unknown Outline Provider', index);\n\n\n\t\t\treturn Promise.resolve(provider.provideDocumentSymbols(textModel, cts.token)).then(result => {\n\t\t\t\tfor (const info of result || []) {\n\t\t\t\t\tOutlineModel._makeOutlineElement(info, group);\n\t\t\t\t}\n\t\t\t\treturn group;\n\t\t\t}, err => {\n\t\t\t\tonUnexpectedExternalError(err);\n\t\t\t\treturn group;\n\t\t\t}).then(group => {\n\t\t\t\tif (!TreeElement.empty(group)) {\n\t\t\t\t\tresult._groups.set(id, group);\n\t\t\t\t} else {\n\t\t\t\t\tgroup.remove();\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\n\t\tconst listener = registry.onDidChange(() => {\n\t\t\tconst newProvider = registry.ordered(textModel);\n\t\t\tif (!equals(newProvider, provider)) {\n\t\t\t\tcts.cancel();\n\t\t\t}\n\t\t});\n\n\t\treturn Promise.all(promises).then(() => {\n\t\t\tif (cts.token.isCancellationRequested && !token.isCancellationRequested) {\n\t\t\t\treturn OutlineModel.create(registry, textModel, token);\n\t\t\t} else {\n\t\t\t\treturn result._compact();\n\t\t\t}\n\t\t}).finally(() => {\n\t\t\tcts.dispose();\n\t\t\tlistener.dispose();\n\t\t\tcts.dispose();\n\t\t});\n\t}\n\n\tprivate static _makeOutlineElement(info: DocumentSymbol, container: OutlineGroup | OutlineElement): void {\n\t\tconst id = TreeElement.findId(info, container);\n\t\tconst res = new OutlineElement(id, container, info);\n\t\tif (info.children) {\n\t\t\tfor (const childInfo of info.children) {\n\t\t\t\tOutlineModel._makeOutlineElement(childInfo, res);\n\t\t\t}\n\t\t}\n\t\tcontainer.children.set(res.id, res);\n\t}\n\n\treadonly id = 'root';\n\treadonly parent = undefined;\n\n\tprotected _groups = new Map();\n\tchildren = new Map();\n\n\tprotected constructor(readonly uri: URI) {\n\t\tsuper();\n\n\t\tthis.id = 'root';\n\t\tthis.parent = undefined;\n\t}\n\n\tprivate _compact(): this {\n\t\tlet count = 0;\n\t\tfor (const [key, group] of this._groups) {\n\t\t\tif (group.children.size === 0) { // empty\n\t\t\t\tthis._groups.delete(key);\n\t\t\t} else {\n\t\t\t\tcount += 1;\n\t\t\t}\n\t\t}\n\t\tif (count !== 1) {\n\t\t\t//\n\t\t\tthis.children = this._groups;\n\t\t} else {\n\t\t\t// adopt all elements of the first group\n\t\t\tconst group = Iterable.first(this._groups.values())!;\n\t\t\tfor (const [, child] of group.children) {\n\t\t\t\tchild.parent = this;\n\t\t\t\tthis.children.set(child.id, child);\n\t\t\t}\n\t\t}\n\t\treturn this;\n\t}\n\n\tgetTopLevelSymbols(): DocumentSymbol[] {\n\t\tconst roots: DocumentSymbol[] = [];\n\t\tfor (const child of this.children.values()) {\n\t\t\tif (child instanceof OutlineElement) {\n\t\t\t\troots.push(child.symbol);\n\t\t\t} else {\n\t\t\t\troots.push(...Iterable.map(child.children.values(), child => child.symbol));\n\t\t\t}\n\t\t}\n\t\treturn roots.sort((a, b) => Range.compareRangesUsingStarts(a.range, b.range));\n\t}\n\n\tasListOfDocumentSymbols(): DocumentSymbol[] {\n\t\tconst roots = this.getTopLevelSymbols();\n\t\tconst bucket: DocumentSymbol[] = [];\n\t\tOutlineModel._flattenDocumentSymbols(bucket, roots, '');\n\t\treturn bucket.sort((a, b) =>\n\t\t\tPosition.compare(Range.getStartPosition(a.range), Range.getStartPosition(b.range)) || Position.compare(Range.getEndPosition(b.range), Range.getEndPosition(a.range))\n\t\t);\n\t}\n\n\tprivate static _flattenDocumentSymbols(bucket: DocumentSymbol[], entries: DocumentSymbol[], overrideContainerLabel: string): void {\n\t\tfor (const entry of entries) {\n\t\t\tbucket.push({\n\t\t\t\tkind: entry.kind,\n\t\t\t\ttags: entry.tags,\n\t\t\t\tname: entry.name,\n\t\t\t\tdetail: entry.detail,\n\t\t\t\tcontainerName: entry.containerName || overrideContainerLabel,\n\t\t\t\trange: entry.range,\n\t\t\t\tselectionRange: entry.selectionRange,\n\t\t\t\tchildren: undefined, // we flatten it...\n\t\t\t});\n\n\t\t\t// Recurse over children\n\t\t\tif (entry.children) {\n\t\t\t\tOutlineModel._flattenDocumentSymbols(bucket, entry.children, entry.name);\n\t\t\t}\n\t\t}\n\t}\n}\n\n\nexport const IOutlineModelService = createDecorator('IOutlineModelService');\n\nexport interface IOutlineModelService {\n\t_serviceBrand: undefined;\n\tgetOrCreate(model: ITextModel, token: CancellationToken): Promise;\n}\n\ninterface CacheEntry {\n\tversionId: number;\n\tprovider: DocumentSymbolProvider[];\n\n\tpromiseCnt: number;\n\tsource: CancellationTokenSource;\n\tpromise: Promise;\n\tmodel: OutlineModel | undefined;\n}\n\nexport class OutlineModelService implements IOutlineModelService {\n\n\tdeclare _serviceBrand: undefined;\n\n\tprivate readonly _disposables = new DisposableStore();\n\tprivate readonly _debounceInformation: IFeatureDebounceInformation;\n\tprivate readonly _cache = new LRUCache(10, 0.7);\n\n\tconstructor(\n\t\t@ILanguageFeaturesService private readonly _languageFeaturesService: ILanguageFeaturesService,\n\t\t@ILanguageFeatureDebounceService debounces: ILanguageFeatureDebounceService,\n\t\t@IModelService modelService: IModelService\n\t) {\n\t\tthis._debounceInformation = debounces.for(_languageFeaturesService.documentSymbolProvider, 'DocumentSymbols', { min: 350 });\n\n\t\t// don't cache outline models longer than their text model\n\t\tthis._disposables.add(modelService.onModelRemoved(textModel => {\n\t\t\tthis._cache.delete(textModel.id);\n\t\t}));\n\t}\n\n\tdispose(): void {\n\t\tthis._disposables.dispose();\n\t}\n\n\tasync getOrCreate(textModel: ITextModel, token: CancellationToken): Promise {\n\n\t\tconst registry = this._languageFeaturesService.documentSymbolProvider;\n\t\tconst provider = registry.ordered(textModel);\n\n\t\tlet data = this._cache.get(textModel.id);\n\t\tif (!data || data.versionId !== textModel.getVersionId() || !equals(data.provider, provider)) {\n\t\t\tconst source = new CancellationTokenSource();\n\t\t\tdata = {\n\t\t\t\tversionId: textModel.getVersionId(),\n\t\t\t\tprovider,\n\t\t\t\tpromiseCnt: 0,\n\t\t\t\tsource,\n\t\t\t\tpromise: OutlineModel.create(registry, textModel, source.token),\n\t\t\t\tmodel: undefined,\n\t\t\t};\n\t\t\tthis._cache.set(textModel.id, data);\n\n\t\t\tconst now = Date.now();\n\t\t\tdata.promise.then(outlineModel => {\n\t\t\t\tdata!.model = outlineModel;\n\t\t\t\tthis._debounceInformation.update(textModel, Date.now() - now);\n\t\t\t}).catch(_err => {\n\t\t\t\tthis._cache.delete(textModel.id);\n\t\t\t});\n\t\t}\n\n\t\tif (data.model) {\n\t\t\t// resolved -> return data\n\t\t\treturn data.model;\n\t\t}\n\n\t\t// increase usage counter\n\t\tdata.promiseCnt += 1;\n\n\t\tconst listener = token.onCancellationRequested(() => {\n\t\t\t// last -> cancel provider request, remove cached promise\n\t\t\tif (--data.promiseCnt === 0) {\n\t\t\t\tdata.source.cancel();\n\t\t\t\tthis._cache.delete(textModel.id);\n\t\t\t}\n\t\t});\n\n\t\ttry {\n\t\t\treturn await data.promise;\n\t\t} finally {\n\t\t\tlistener.dispose();\n\t\t}\n\t}\n}\n\nregisterSingleton(IOutlineModelService, OutlineModelService, InstantiationType.Delayed);\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\nimport { reverseOrder, compareBy, numberComparator } from 'vs/base/common/arrays';\nimport { observableValue, observableSignalFromEvent, autorunWithStore, IReader } from 'vs/base/common/observable';\nimport { HideUnchangedRegionsFeature, IDiffEditorBreadcrumbsSource } from 'vs/editor/browser/widget/diffEditor/features/hideUnchangedRegionsFeature';\nimport { DisposableCancellationTokenSource } from 'vs/editor/browser/widget/diffEditor/utils';\nimport { LineRange } from 'vs/editor/common/core/lineRange';\nimport { ITextModel } from 'vs/editor/common/model';\nimport { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';\nimport { IOutlineModelService, OutlineModel } from 'vs/editor/contrib/documentSymbols/browser/outlineModel';\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport { Event } from 'vs/base/common/event';\nimport { SymbolKind } from 'vs/editor/common/languages';\n\nclass DiffEditorBreadcrumbsSource extends Disposable implements IDiffEditorBreadcrumbsSource {\n\tprivate readonly _currentModel = observableValue(this, undefined);\n\n\tconstructor(\n\t\tprivate readonly _textModel: ITextModel,\n\t\t@ILanguageFeaturesService private readonly _languageFeaturesService: ILanguageFeaturesService,\n\t\t@IOutlineModelService private readonly _outlineModelService: IOutlineModelService,\n\t) {\n\t\tsuper();\n\n\t\tconst documentSymbolProviderChanged = observableSignalFromEvent(\n\t\t\t'documentSymbolProvider.onDidChange',\n\t\t\tthis._languageFeaturesService.documentSymbolProvider.onDidChange\n\t\t);\n\n\t\tconst textModelChanged = observableSignalFromEvent(\n\t\t\t'_textModel.onDidChangeContent',\n\t\t\tEvent.debounce(e => this._textModel.onDidChangeContent(e), () => undefined, 100)\n\t\t);\n\n\t\tthis._register(autorunWithStore(async (reader, store) => {\n\t\t\tdocumentSymbolProviderChanged.read(reader);\n\t\t\ttextModelChanged.read(reader);\n\n\t\t\tconst src = store.add(new DisposableCancellationTokenSource());\n\t\t\tconst model = await this._outlineModelService.getOrCreate(this._textModel, src.token);\n\t\t\tif (store.isDisposed) { return; }\n\n\t\t\tthis._currentModel.set(model, undefined);\n\t\t}));\n\t}\n\n\tpublic getBreadcrumbItems(startRange: LineRange, reader: IReader): { name: string; kind: SymbolKind; startLineNumber: number }[] {\n\t\tconst m = this._currentModel.read(reader);\n\t\tif (!m) { return []; }\n\t\tconst symbols = m.asListOfDocumentSymbols()\n\t\t\t.filter(s => startRange.contains(s.range.startLineNumber) && !startRange.contains(s.range.endLineNumber));\n\t\tsymbols.sort(reverseOrder(compareBy(s => s.range.endLineNumber - s.range.startLineNumber, numberComparator)));\n\t\treturn symbols.map(s => ({ name: s.name, kind: s.kind, startLineNumber: s.range.startLineNumber }));\n\t}\n}\n\nHideUnchangedRegionsFeature.setBreadcrumbsSourceFactory((textModel, instantiationService) => {\n\treturn instantiationService.createInstance(DiffEditorBreadcrumbsSource, textModel);\n});\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\nimport { CancellationToken } from 'vs/base/common/cancellation';\nimport { assertType } from 'vs/base/common/types';\nimport { URI } from 'vs/base/common/uri';\nimport { ITextModelService } from 'vs/editor/common/services/resolverService';\nimport { IOutlineModelService } from 'vs/editor/contrib/documentSymbols/browser/outlineModel';\nimport { CommandsRegistry } from 'vs/platform/commands/common/commands';\n\nCommandsRegistry.registerCommand('_executeDocumentSymbolProvider', async function (accessor, ...args) {\n\tconst [resource] = args;\n\tassertType(URI.isUri(resource));\n\n\tconst outlineService = accessor.get(IOutlineModelService);\n\tconst modelService = accessor.get(ITextModelService);\n\n\tconst reference = await modelService.createModelReference(resource);\n\ttry {\n\t\treturn (await outlineService.getOrCreate(reference.object.textEditorModel, CancellationToken.None)).getTopLevelSymbols();\n\t} finally {\n\t\treference.dispose();\n\t}\n});\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\nimport { isSafari, isWebkitWebView } from 'vs/base/browser/browser';\nimport { $, addDisposableListener, getActiveDocument, getActiveWindow, onDidRegisterWindow } from 'vs/base/browser/dom';\nimport { mainWindow } from 'vs/base/browser/window';\nimport { DeferredPromise } from 'vs/base/common/async';\nimport { Event } from 'vs/base/common/event';\nimport { hash } from 'vs/base/common/hash';\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport { URI } from 'vs/base/common/uri';\nimport { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';\nimport { ILayoutService } from 'vs/platform/layout/browser/layoutService';\nimport { ILogService } from 'vs/platform/log/common/log';\n\nexport class BrowserClipboardService extends Disposable implements IClipboardService {\n\n\tdeclare readonly _serviceBrand: undefined;\n\n\tconstructor(\n\t\t@ILayoutService private readonly layoutService: ILayoutService,\n\t\t@ILogService private readonly logService: ILogService\n\t) {\n\t\tsuper();\n\n\t\tif (isSafari || isWebkitWebView) {\n\t\t\tthis.installWebKitWriteTextWorkaround();\n\t\t}\n\n\t\t// Keep track of copy operations to reset our set of\n\t\t// copied resources: since we keep resources in memory\n\t\t// and not in the clipboard, we have to invalidate\n\t\t// that state when the user copies other data.\n\t\tthis._register(Event.runAndSubscribe(onDidRegisterWindow, ({ window, disposables }) => {\n\t\t\tdisposables.add(addDisposableListener(window.document, 'copy', () => this.clearResources()));\n\t\t}, { window: mainWindow, disposables: this._store }));\n\t}\n\n\tprivate webKitPendingClipboardWritePromise: DeferredPromise | undefined;\n\n\t// In Safari, it has the following note:\n\t//\n\t// \"The request to write to the clipboard must be triggered during a user gesture.\n\t// A call to clipboard.write or clipboard.writeText outside the scope of a user\n\t// gesture(such as \"click\" or \"touch\" event handlers) will result in the immediate\n\t// rejection of the promise returned by the API call.\"\n\t// From: https://webkit.org/blog/10855/async-clipboard-api/\n\t//\n\t// Since extensions run in a web worker, and handle gestures in an asynchronous way,\n\t// they are not classified by Safari as \"in response to a user gesture\" and will reject.\n\t//\n\t// This function sets up some handlers to work around that behavior.\n\tprivate installWebKitWriteTextWorkaround(): void {\n\t\tconst handler = () => {\n\t\t\tconst currentWritePromise = new DeferredPromise();\n\n\t\t\t// Cancel the previous promise since we just created a new one in response to this new event\n\t\t\tif (this.webKitPendingClipboardWritePromise && !this.webKitPendingClipboardWritePromise.isSettled) {\n\t\t\t\tthis.webKitPendingClipboardWritePromise.cancel();\n\t\t\t}\n\t\t\tthis.webKitPendingClipboardWritePromise = currentWritePromise;\n\n\t\t\t// The ctor of ClipboardItem allows you to pass in a promise that will resolve to a string.\n\t\t\t// This allows us to pass in a Promise that will either be cancelled by another event or\n\t\t\t// resolved with the contents of the first call to this.writeText.\n\t\t\t// see https://developer.mozilla.org/en-US/docs/Web/API/ClipboardItem/ClipboardItem#parameters\n\t\t\tgetActiveWindow().navigator.clipboard.write([new ClipboardItem({\n\t\t\t\t'text/plain': currentWritePromise.p,\n\t\t\t})]).catch(async err => {\n\t\t\t\tif (!(err instanceof Error) || err.name !== 'NotAllowedError' || !currentWritePromise.isRejected) {\n\t\t\t\t\tthis.logService.error(err);\n\t\t\t\t}\n\t\t\t});\n\t\t};\n\n\t\tthis._register(Event.runAndSubscribe(this.layoutService.onDidAddContainer, ({ container, disposables }) => {\n\t\t\tdisposables.add(addDisposableListener(container, 'click', handler));\n\t\t\tdisposables.add(addDisposableListener(container, 'keydown', handler));\n\t\t}, { container: this.layoutService.mainContainer, disposables: this._store }));\n\t}\n\n\tprivate readonly mapTextToType = new Map(); // unsupported in web (only in-memory)\n\n\tasync writeText(text: string, type?: string): Promise {\n\n\t\t// Clear resources given we are writing text\n\t\tthis.writeResources([]);\n\n\t\t// With type: only in-memory is supported\n\t\tif (type) {\n\t\t\tthis.mapTextToType.set(type, text);\n\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.webKitPendingClipboardWritePromise) {\n\t\t\t// For Safari, we complete this Promise which allows the call to `navigator.clipboard.write()`\n\t\t\t// above to resolve and successfully copy to the clipboard. If we let this continue, Safari\n\t\t\t// would throw an error because this call stack doesn't appear to originate from a user gesture.\n\t\t\treturn this.webKitPendingClipboardWritePromise.complete(text);\n\t\t}\n\n\t\t// Guard access to navigator.clipboard with try/catch\n\t\t// as we have seen DOMExceptions in certain browsers\n\t\t// due to security policies.\n\t\ttry {\n\t\t\treturn await getActiveWindow().navigator.clipboard.writeText(text);\n\t\t} catch (error) {\n\t\t\tconsole.error(error);\n\t\t}\n\n\t\t// Fallback to textarea and execCommand solution\n\t\tthis.fallbackWriteText(text);\n\t}\n\n\tprivate fallbackWriteText(text: string): void {\n\t\tconst activeDocument = getActiveDocument();\n\t\tconst activeElement = activeDocument.activeElement;\n\n\t\tconst textArea: HTMLTextAreaElement = activeDocument.body.appendChild($('textarea', { 'aria-hidden': true }));\n\t\ttextArea.style.height = '1px';\n\t\ttextArea.style.width = '1px';\n\t\ttextArea.style.position = 'absolute';\n\n\t\ttextArea.value = text;\n\t\ttextArea.focus();\n\t\ttextArea.select();\n\n\t\tactiveDocument.execCommand('copy');\n\n\t\tif (activeElement instanceof HTMLElement) {\n\t\t\tactiveElement.focus();\n\t\t}\n\n\t\tactiveDocument.body.removeChild(textArea);\n\t}\n\n\tasync readText(type?: string): Promise {\n\n\t\t// With type: only in-memory is supported\n\t\tif (type) {\n\t\t\treturn this.mapTextToType.get(type) || '';\n\t\t}\n\n\t\t// Guard access to navigator.clipboard with try/catch\n\t\t// as we have seen DOMExceptions in certain browsers\n\t\t// due to security policies.\n\t\ttry {\n\t\t\treturn await getActiveWindow().navigator.clipboard.readText();\n\t\t} catch (error) {\n\t\t\tconsole.error(error);\n\t\t}\n\n\t\treturn '';\n\t}\n\n\tprivate findText = ''; // unsupported in web (only in-memory)\n\n\tasync readFindText(): Promise {\n\t\treturn this.findText;\n\t}\n\n\tasync writeFindText(text: string): Promise {\n\t\tthis.findText = text;\n\t}\n\n\tprivate resources: URI[] = []; // unsupported in web (only in-memory)\n\tprivate resourcesStateHash: number | undefined = undefined;\n\n\tprivate static readonly MAX_RESOURCE_STATE_SOURCE_LENGTH = 1000;\n\n\tasync writeResources(resources: URI[]): Promise {\n\t\tif (resources.length === 0) {\n\t\t\tthis.clearResources();\n\t\t} else {\n\t\t\tthis.resources = resources;\n\t\t\tthis.resourcesStateHash = await this.computeResourcesStateHash();\n\t\t}\n\t}\n\n\tasync readResources(): Promise {\n\t\tconst resourcesStateHash = await this.computeResourcesStateHash();\n\t\tif (this.resourcesStateHash !== resourcesStateHash) {\n\t\t\tthis.clearResources(); // state mismatch, resources no longer valid\n\t\t}\n\n\t\treturn this.resources;\n\t}\n\n\tprivate async computeResourcesStateHash(): Promise {\n\t\tif (this.resources.length === 0) {\n\t\t\treturn undefined; // no resources, no hash needed\n\t\t}\n\n\t\t// Resources clipboard is managed in-memory only and thus\n\t\t// fails to invalidate when clipboard data is changing.\n\t\t// As such, we compute the hash of the current clipboard\n\t\t// and use that to later validate the resources clipboard.\n\n\t\tconst clipboardText = await this.readText();\n\t\treturn hash(clipboardText.substring(0, BrowserClipboardService.MAX_RESOURCE_STATE_SOURCE_LENGTH));\n\t}\n\n\tprivate clearResources(): void {\n\t\tthis.resources = [];\n\t\tthis.resourcesStateHash = undefined;\n\t}\n}\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\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport { Event } from 'vs/base/common/event';\nimport { ILogger, ILogService, LogLevel, MultiplexLogger } from 'vs/platform/log/common/log';\n\nexport class LogService extends Disposable implements ILogService {\n\n\tdeclare readonly _serviceBrand: undefined;\n\n\tprivate readonly logger: ILogger;\n\n\tconstructor(primaryLogger: ILogger, otherLoggers: ILogger[] = []) {\n\t\tsuper();\n\t\tthis.logger = new MultiplexLogger([primaryLogger, ...otherLoggers]);\n\t\tthis._register(primaryLogger.onDidChangeLogLevel(level => this.setLevel(level)));\n\t}\n\n\tget onDidChangeLogLevel(): Event {\n\t\treturn this.logger.onDidChangeLogLevel;\n\t}\n\n\tsetLevel(level: LogLevel): void {\n\t\tthis.logger.setLevel(level);\n\t}\n\n\tgetLevel(): LogLevel {\n\t\treturn this.logger.getLevel();\n\t}\n\n\ttrace(message: string, ...args: any[]): void {\n\t\tthis.logger.trace(message, ...args);\n\t}\n\n\tdebug(message: string, ...args: any[]): void {\n\t\tthis.logger.debug(message, ...args);\n\t}\n\n\tinfo(message: string, ...args: any[]): void {\n\t\tthis.logger.info(message, ...args);\n\t}\n\n\twarn(message: string, ...args: any[]): void {\n\t\tthis.logger.warn(message, ...args);\n\t}\n\n\terror(message: string | Error, ...args: any[]): void {\n\t\tthis.logger.error(message, ...args);\n\t}\n}\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\nimport { Event } from 'vs/base/common/event';\nimport Severity from 'vs/base/common/severity';\nimport { URI } from 'vs/base/common/uri';\nimport { localize } from 'vs/nls';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\n\nexport interface IMarkerService {\n\treadonly _serviceBrand: undefined;\n\n\tchangeOne(owner: string, resource: URI, markers: IMarkerData[]): void;\n\n\tchangeAll(owner: string, data: IResourceMarker[]): void;\n\n\tremove(owner: string, resources: URI[]): void;\n\n\tread(filter?: { owner?: string; resource?: URI; severities?: number; take?: number }): IMarker[];\n\n\treadonly onMarkerChanged: Event;\n}\n\n/**\n *\n */\nexport interface IRelatedInformation {\n\tresource: URI;\n\tmessage: string;\n\tstartLineNumber: number;\n\tstartColumn: number;\n\tendLineNumber: number;\n\tendColumn: number;\n}\n\nexport const enum MarkerTag {\n\tUnnecessary = 1,\n\tDeprecated = 2\n}\n\nexport enum MarkerSeverity {\n\tHint = 1,\n\tInfo = 2,\n\tWarning = 4,\n\tError = 8,\n}\n\nexport namespace MarkerSeverity {\n\n\texport function compare(a: MarkerSeverity, b: MarkerSeverity): number {\n\t\treturn b - a;\n\t}\n\n\tconst _displayStrings: { [value: number]: string } = Object.create(null);\n\t_displayStrings[MarkerSeverity.Error] = localize('sev.error', \"Error\");\n\t_displayStrings[MarkerSeverity.Warning] = localize('sev.warning', \"Warning\");\n\t_displayStrings[MarkerSeverity.Info] = localize('sev.info', \"Info\");\n\n\texport function toString(a: MarkerSeverity): string {\n\t\treturn _displayStrings[a] || '';\n\t}\n\n\texport function fromSeverity(severity: Severity): MarkerSeverity {\n\t\tswitch (severity) {\n\t\t\tcase Severity.Error: return MarkerSeverity.Error;\n\t\t\tcase Severity.Warning: return MarkerSeverity.Warning;\n\t\t\tcase Severity.Info: return MarkerSeverity.Info;\n\t\t\tcase Severity.Ignore: return MarkerSeverity.Hint;\n\t\t}\n\t}\n\n\texport function toSeverity(severity: MarkerSeverity): Severity {\n\t\tswitch (severity) {\n\t\t\tcase MarkerSeverity.Error: return Severity.Error;\n\t\t\tcase MarkerSeverity.Warning: return Severity.Warning;\n\t\t\tcase MarkerSeverity.Info: return Severity.Info;\n\t\t\tcase MarkerSeverity.Hint: return Severity.Ignore;\n\t\t}\n\t}\n}\n\n/**\n * A structure defining a problem/warning/etc.\n */\nexport interface IMarkerData {\n\tcode?: string | { value: string; target: URI };\n\tseverity: MarkerSeverity;\n\tmessage: string;\n\tsource?: string;\n\tstartLineNumber: number;\n\tstartColumn: number;\n\tendLineNumber: number;\n\tendColumn: number;\n\tmodelVersionId?: number;\n\trelatedInformation?: IRelatedInformation[];\n\ttags?: MarkerTag[];\n}\n\nexport interface IResourceMarker {\n\tresource: URI;\n\tmarker: IMarkerData;\n}\n\nexport interface IMarker {\n\towner: string;\n\tresource: URI;\n\tseverity: MarkerSeverity;\n\tcode?: string | { value: string; target: URI };\n\tmessage: string;\n\tsource?: string;\n\tstartLineNumber: number;\n\tstartColumn: number;\n\tendLineNumber: number;\n\tendColumn: number;\n\tmodelVersionId?: number;\n\trelatedInformation?: IRelatedInformation[];\n\ttags?: MarkerTag[];\n}\n\nexport interface MarkerStatistics {\n\terrors: number;\n\twarnings: number;\n\tinfos: number;\n\tunknowns: number;\n}\n\nexport namespace IMarkerData {\n\tconst emptyString = '';\n\texport function makeKey(markerData: IMarkerData): string {\n\t\treturn makeKeyOptionalMessage(markerData, true);\n\t}\n\n\texport function makeKeyOptionalMessage(markerData: IMarkerData, useMessage: boolean): string {\n\t\tconst result: string[] = [emptyString];\n\t\tif (markerData.source) {\n\t\t\tresult.push(markerData.source.replace('¦', '\\\\¦'));\n\t\t} else {\n\t\t\tresult.push(emptyString);\n\t\t}\n\t\tif (markerData.code) {\n\t\t\tif (typeof markerData.code === 'string') {\n\t\t\t\tresult.push(markerData.code.replace('¦', '\\\\¦'));\n\t\t\t} else {\n\t\t\t\tresult.push(markerData.code.value.replace('¦', '\\\\¦'));\n\t\t\t}\n\t\t} else {\n\t\t\tresult.push(emptyString);\n\t\t}\n\t\tif (markerData.severity !== undefined && markerData.severity !== null) {\n\t\t\tresult.push(MarkerSeverity.toString(markerData.severity));\n\t\t} else {\n\t\t\tresult.push(emptyString);\n\t\t}\n\n\t\t// Modifed to not include the message as part of the marker key to work around\n\t\t// https://github.com/microsoft/vscode/issues/77475\n\t\tif (markerData.message && useMessage) {\n\t\t\tresult.push(markerData.message.replace('¦', '\\\\¦'));\n\t\t} else {\n\t\t\tresult.push(emptyString);\n\t\t}\n\t\tif (markerData.startLineNumber !== undefined && markerData.startLineNumber !== null) {\n\t\t\tresult.push(markerData.startLineNumber.toString());\n\t\t} else {\n\t\t\tresult.push(emptyString);\n\t\t}\n\t\tif (markerData.startColumn !== undefined && markerData.startColumn !== null) {\n\t\t\tresult.push(markerData.startColumn.toString());\n\t\t} else {\n\t\t\tresult.push(emptyString);\n\t\t}\n\t\tif (markerData.endLineNumber !== undefined && markerData.endLineNumber !== null) {\n\t\t\tresult.push(markerData.endLineNumber.toString());\n\t\t} else {\n\t\t\tresult.push(emptyString);\n\t\t}\n\t\tif (markerData.endColumn !== undefined && markerData.endColumn !== null) {\n\t\t\tresult.push(markerData.endColumn.toString());\n\t\t} else {\n\t\t\tresult.push(emptyString);\n\t\t}\n\t\tresult.push(emptyString);\n\t\treturn result.join('¦');\n\t}\n}\n\nexport const IMarkerService = createDecorator('markerService');\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\nimport { binarySearch } from 'vs/base/common/arrays';\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { DisposableStore } from 'vs/base/common/lifecycle';\nimport { LinkedList } from 'vs/base/common/linkedList';\nimport { compare } from 'vs/base/common/strings';\nimport { URI } from 'vs/base/common/uri';\nimport { Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\nimport { ITextModel } from 'vs/editor/common/model';\nimport { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\nimport { IMarker, IMarkerService, MarkerSeverity } from 'vs/platform/markers/common/markers';\nimport { IConfigurationService } from 'vs/platform/configuration/common/configuration';\n\nexport class MarkerCoordinate {\n\tconstructor(\n\t\treadonly marker: IMarker,\n\t\treadonly index: number,\n\t\treadonly total: number\n\t) { }\n}\n\nexport class MarkerList {\n\n\tprivate readonly _onDidChange = new Emitter();\n\treadonly onDidChange: Event = this._onDidChange.event;\n\n\tprivate readonly _resourceFilter?: (uri: URI) => boolean;\n\tprivate readonly _dispoables = new DisposableStore();\n\n\tprivate _markers: IMarker[] = [];\n\tprivate _nextIdx: number = -1;\n\n\tconstructor(\n\t\tresourceFilter: URI | ((uri: URI) => boolean) | undefined,\n\t\t@IMarkerService private readonly _markerService: IMarkerService,\n\t\t@IConfigurationService private readonly _configService: IConfigurationService,\n\t) {\n\t\tif (URI.isUri(resourceFilter)) {\n\t\t\tthis._resourceFilter = uri => uri.toString() === resourceFilter.toString();\n\t\t} else if (resourceFilter) {\n\t\t\tthis._resourceFilter = resourceFilter;\n\t\t}\n\n\t\tconst compareOrder = this._configService.getValue('problems.sortOrder');\n\t\tconst compareMarker = (a: IMarker, b: IMarker): number => {\n\t\t\tlet res = compare(a.resource.toString(), b.resource.toString());\n\t\t\tif (res === 0) {\n\t\t\t\tif (compareOrder === 'position') {\n\t\t\t\t\tres = Range.compareRangesUsingStarts(a, b) || MarkerSeverity.compare(a.severity, b.severity);\n\t\t\t\t} else {\n\t\t\t\t\tres = MarkerSeverity.compare(a.severity, b.severity) || Range.compareRangesUsingStarts(a, b);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn res;\n\t\t};\n\n\t\tconst updateMarker = () => {\n\t\t\tthis._markers = this._markerService.read({\n\t\t\t\tresource: URI.isUri(resourceFilter) ? resourceFilter : undefined,\n\t\t\t\tseverities: MarkerSeverity.Error | MarkerSeverity.Warning | MarkerSeverity.Info\n\t\t\t});\n\t\t\tif (typeof resourceFilter === 'function') {\n\t\t\t\tthis._markers = this._markers.filter(m => this._resourceFilter!(m.resource));\n\t\t\t}\n\t\t\tthis._markers.sort(compareMarker);\n\t\t};\n\n\t\tupdateMarker();\n\n\t\tthis._dispoables.add(_markerService.onMarkerChanged(uris => {\n\t\t\tif (!this._resourceFilter || uris.some(uri => this._resourceFilter!(uri))) {\n\t\t\t\tupdateMarker();\n\t\t\t\tthis._nextIdx = -1;\n\t\t\t\tthis._onDidChange.fire();\n\t\t\t}\n\t\t}));\n\t}\n\n\tdispose(): void {\n\t\tthis._dispoables.dispose();\n\t\tthis._onDidChange.dispose();\n\t}\n\n\tmatches(uri: URI | undefined) {\n\t\tif (!this._resourceFilter && !uri) {\n\t\t\treturn true;\n\t\t}\n\t\tif (!this._resourceFilter || !uri) {\n\t\t\treturn false;\n\t\t}\n\t\treturn this._resourceFilter(uri);\n\t}\n\n\tget selected(): MarkerCoordinate | undefined {\n\t\tconst marker = this._markers[this._nextIdx];\n\t\treturn marker && new MarkerCoordinate(marker, this._nextIdx + 1, this._markers.length);\n\t}\n\n\tprivate _initIdx(model: ITextModel, position: Position, fwd: boolean): void {\n\t\tlet found = false;\n\n\t\tlet idx = this._markers.findIndex(marker => marker.resource.toString() === model.uri.toString());\n\t\tif (idx < 0) {\n\t\t\tidx = binarySearch(this._markers, { resource: model.uri }, (a, b) => compare(a.resource.toString(), b.resource.toString()));\n\t\t\tif (idx < 0) {\n\t\t\t\tidx = ~idx;\n\t\t\t}\n\t\t}\n\n\t\tfor (let i = idx; i < this._markers.length; i++) {\n\t\t\tlet range = Range.lift(this._markers[i]);\n\n\t\t\tif (range.isEmpty()) {\n\t\t\t\tconst word = model.getWordAtPosition(range.getStartPosition());\n\t\t\t\tif (word) {\n\t\t\t\t\trange = new Range(range.startLineNumber, word.startColumn, range.startLineNumber, word.endColumn);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (position && (range.containsPosition(position) || position.isBeforeOrEqual(range.getStartPosition()))) {\n\t\t\t\tthis._nextIdx = i;\n\t\t\t\tfound = true;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (this._markers[i].resource.toString() !== model.uri.toString()) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (!found) {\n\t\t\t// after the last change\n\t\t\tthis._nextIdx = fwd ? 0 : this._markers.length - 1;\n\t\t}\n\t\tif (this._nextIdx < 0) {\n\t\t\tthis._nextIdx = this._markers.length - 1;\n\t\t}\n\t}\n\n\tresetIndex() {\n\t\tthis._nextIdx = -1;\n\t}\n\n\tmove(fwd: boolean, model: ITextModel, position: Position): boolean {\n\t\tif (this._markers.length === 0) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst oldIdx = this._nextIdx;\n\t\tif (this._nextIdx === -1) {\n\t\t\tthis._initIdx(model, position, fwd);\n\t\t} else if (fwd) {\n\t\t\tthis._nextIdx = (this._nextIdx + 1) % this._markers.length;\n\t\t} else if (!fwd) {\n\t\t\tthis._nextIdx = (this._nextIdx - 1 + this._markers.length) % this._markers.length;\n\t\t}\n\n\t\tif (oldIdx !== this._nextIdx) {\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tfind(uri: URI, position: Position): MarkerCoordinate | undefined {\n\t\tlet idx = this._markers.findIndex(marker => marker.resource.toString() === uri.toString());\n\t\tif (idx < 0) {\n\t\t\treturn undefined;\n\t\t}\n\t\tfor (; idx < this._markers.length; idx++) {\n\t\t\tif (Range.containsPosition(this._markers[idx], position)) {\n\t\t\t\treturn new MarkerCoordinate(this._markers[idx], idx + 1, this._markers.length);\n\t\t\t}\n\t\t}\n\t\treturn undefined;\n\t}\n}\n\nexport const IMarkerNavigationService = createDecorator('IMarkerNavigationService');\n\nexport interface IMarkerNavigationService {\n\treadonly _serviceBrand: undefined;\n\tgetMarkerList(resource: URI | undefined): MarkerList;\n}\n\nexport interface IMarkerListProvider {\n\tgetMarkerList(resource: URI | undefined): MarkerList | undefined;\n}\n\nclass MarkerNavigationService implements IMarkerNavigationService, IMarkerListProvider {\n\n\treadonly _serviceBrand: undefined;\n\n\tprivate readonly _provider = new LinkedList();\n\n\tconstructor(\n\t\t@IMarkerService private readonly _markerService: IMarkerService,\n\t\t@IConfigurationService private readonly _configService: IConfigurationService,\n\t) { }\n\n\tgetMarkerList(resource: URI | undefined): MarkerList {\n\t\tfor (const provider of this._provider) {\n\t\t\tconst result = provider.getMarkerList(resource);\n\t\t\tif (result) {\n\t\t\t\treturn result;\n\t\t\t}\n\t\t}\n\t\t// default\n\t\treturn new MarkerList(resource, this._markerService, this._configService);\n\t}\n}\n\nregisterSingleton(IMarkerNavigationService, MarkerNavigationService, InstantiationType.Delayed);\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\nimport { isFalsyOrEmpty, isNonEmptyArray } from 'vs/base/common/arrays';\nimport { DebounceEmitter } from 'vs/base/common/event';\nimport { Iterable } from 'vs/base/common/iterator';\nimport { IDisposable } from 'vs/base/common/lifecycle';\nimport { ResourceMap } from 'vs/base/common/map';\nimport { Schemas } from 'vs/base/common/network';\nimport { URI } from 'vs/base/common/uri';\nimport { IMarker, IMarkerData, IMarkerService, IResourceMarker, MarkerSeverity, MarkerStatistics } from './markers';\n\nexport const unsupportedSchemas = new Set([\n\tSchemas.inMemory,\n\tSchemas.vscodeSourceControl,\n\tSchemas.walkThrough,\n\tSchemas.walkThroughSnippet,\n\tSchemas.vscodeChatCodeBlock,\n]);\n\nclass DoubleResourceMap {\n\n\tprivate _byResource = new ResourceMap>();\n\tprivate _byOwner = new Map>();\n\n\tset(resource: URI, owner: string, value: V) {\n\t\tlet ownerMap = this._byResource.get(resource);\n\t\tif (!ownerMap) {\n\t\t\townerMap = new Map();\n\t\t\tthis._byResource.set(resource, ownerMap);\n\t\t}\n\t\townerMap.set(owner, value);\n\n\t\tlet resourceMap = this._byOwner.get(owner);\n\t\tif (!resourceMap) {\n\t\t\tresourceMap = new ResourceMap();\n\t\t\tthis._byOwner.set(owner, resourceMap);\n\t\t}\n\t\tresourceMap.set(resource, value);\n\t}\n\n\tget(resource: URI, owner: string): V | undefined {\n\t\tconst ownerMap = this._byResource.get(resource);\n\t\treturn ownerMap?.get(owner);\n\t}\n\n\tdelete(resource: URI, owner: string): boolean {\n\t\tlet removedA = false;\n\t\tlet removedB = false;\n\t\tconst ownerMap = this._byResource.get(resource);\n\t\tif (ownerMap) {\n\t\t\tremovedA = ownerMap.delete(owner);\n\t\t}\n\t\tconst resourceMap = this._byOwner.get(owner);\n\t\tif (resourceMap) {\n\t\t\tremovedB = resourceMap.delete(resource);\n\t\t}\n\t\tif (removedA !== removedB) {\n\t\t\tthrow new Error('illegal state');\n\t\t}\n\t\treturn removedA && removedB;\n\t}\n\n\tvalues(key?: URI | string): Iterable {\n\t\tif (typeof key === 'string') {\n\t\t\treturn this._byOwner.get(key)?.values() ?? Iterable.empty();\n\t\t}\n\t\tif (URI.isUri(key)) {\n\t\t\treturn this._byResource.get(key)?.values() ?? Iterable.empty();\n\t\t}\n\n\t\treturn Iterable.map(Iterable.concat(...this._byOwner.values()), map => map[1]);\n\t}\n}\n\nclass MarkerStats implements MarkerStatistics {\n\n\terrors: number = 0;\n\tinfos: number = 0;\n\twarnings: number = 0;\n\tunknowns: number = 0;\n\n\tprivate readonly _data = new ResourceMap();\n\tprivate readonly _service: IMarkerService;\n\tprivate readonly _subscription: IDisposable;\n\n\tconstructor(service: IMarkerService) {\n\t\tthis._service = service;\n\t\tthis._subscription = service.onMarkerChanged(this._update, this);\n\t}\n\n\tdispose(): void {\n\t\tthis._subscription.dispose();\n\t}\n\n\tprivate _update(resources: readonly URI[]): void {\n\t\tfor (const resource of resources) {\n\t\t\tconst oldStats = this._data.get(resource);\n\t\t\tif (oldStats) {\n\t\t\t\tthis._substract(oldStats);\n\t\t\t}\n\t\t\tconst newStats = this._resourceStats(resource);\n\t\t\tthis._add(newStats);\n\t\t\tthis._data.set(resource, newStats);\n\t\t}\n\t}\n\n\tprivate _resourceStats(resource: URI): MarkerStatistics {\n\t\tconst result: MarkerStatistics = { errors: 0, warnings: 0, infos: 0, unknowns: 0 };\n\n\t\t// TODO this is a hack\n\t\tif (unsupportedSchemas.has(resource.scheme)) {\n\t\t\treturn result;\n\t\t}\n\n\t\tfor (const { severity } of this._service.read({ resource })) {\n\t\t\tif (severity === MarkerSeverity.Error) {\n\t\t\t\tresult.errors += 1;\n\t\t\t} else if (severity === MarkerSeverity.Warning) {\n\t\t\t\tresult.warnings += 1;\n\t\t\t} else if (severity === MarkerSeverity.Info) {\n\t\t\t\tresult.infos += 1;\n\t\t\t} else {\n\t\t\t\tresult.unknowns += 1;\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tprivate _substract(op: MarkerStatistics) {\n\t\tthis.errors -= op.errors;\n\t\tthis.warnings -= op.warnings;\n\t\tthis.infos -= op.infos;\n\t\tthis.unknowns -= op.unknowns;\n\t}\n\n\tprivate _add(op: MarkerStatistics) {\n\t\tthis.errors += op.errors;\n\t\tthis.warnings += op.warnings;\n\t\tthis.infos += op.infos;\n\t\tthis.unknowns += op.unknowns;\n\t}\n}\n\nexport class MarkerService implements IMarkerService {\n\n\tdeclare readonly _serviceBrand: undefined;\n\n\tprivate readonly _onMarkerChanged = new DebounceEmitter({\n\t\tdelay: 0,\n\t\tmerge: MarkerService._merge\n\t});\n\n\treadonly onMarkerChanged = this._onMarkerChanged.event;\n\n\tprivate readonly _data = new DoubleResourceMap();\n\tprivate readonly _stats = new MarkerStats(this);\n\n\tdispose(): void {\n\t\tthis._stats.dispose();\n\t\tthis._onMarkerChanged.dispose();\n\t}\n\n\tremove(owner: string, resources: URI[]): void {\n\t\tfor (const resource of resources || []) {\n\t\t\tthis.changeOne(owner, resource, []);\n\t\t}\n\t}\n\n\tchangeOne(owner: string, resource: URI, markerData: IMarkerData[]): void {\n\n\t\tif (isFalsyOrEmpty(markerData)) {\n\t\t\t// remove marker for this (owner,resource)-tuple\n\t\t\tconst removed = this._data.delete(resource, owner);\n\t\t\tif (removed) {\n\t\t\t\tthis._onMarkerChanged.fire([resource]);\n\t\t\t}\n\n\t\t} else {\n\t\t\t// insert marker for this (owner,resource)-tuple\n\t\t\tconst markers: IMarker[] = [];\n\t\t\tfor (const data of markerData) {\n\t\t\t\tconst marker = MarkerService._toMarker(owner, resource, data);\n\t\t\t\tif (marker) {\n\t\t\t\t\tmarkers.push(marker);\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis._data.set(resource, owner, markers);\n\t\t\tthis._onMarkerChanged.fire([resource]);\n\t\t}\n\t}\n\n\tprivate static _toMarker(owner: string, resource: URI, data: IMarkerData): IMarker | undefined {\n\t\tlet {\n\t\t\tcode, severity,\n\t\t\tmessage, source,\n\t\t\tstartLineNumber, startColumn, endLineNumber, endColumn,\n\t\t\trelatedInformation,\n\t\t\ttags,\n\t\t} = data;\n\n\t\tif (!message) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\t// santize data\n\t\tstartLineNumber = startLineNumber > 0 ? startLineNumber : 1;\n\t\tstartColumn = startColumn > 0 ? startColumn : 1;\n\t\tendLineNumber = endLineNumber >= startLineNumber ? endLineNumber : startLineNumber;\n\t\tendColumn = endColumn > 0 ? endColumn : startColumn;\n\n\t\treturn {\n\t\t\tresource,\n\t\t\towner,\n\t\t\tcode,\n\t\t\tseverity,\n\t\t\tmessage,\n\t\t\tsource,\n\t\t\tstartLineNumber,\n\t\t\tstartColumn,\n\t\t\tendLineNumber,\n\t\t\tendColumn,\n\t\t\trelatedInformation,\n\t\t\ttags,\n\t\t};\n\t}\n\n\tchangeAll(owner: string, data: IResourceMarker[]): void {\n\t\tconst changes: URI[] = [];\n\n\t\t// remove old marker\n\t\tconst existing = this._data.values(owner);\n\t\tif (existing) {\n\t\t\tfor (const data of existing) {\n\t\t\t\tconst first = Iterable.first(data);\n\t\t\t\tif (first) {\n\t\t\t\t\tchanges.push(first.resource);\n\t\t\t\t\tthis._data.delete(first.resource, owner);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// add new markers\n\t\tif (isNonEmptyArray(data)) {\n\n\t\t\t// group by resource\n\t\t\tconst groups = new ResourceMap();\n\t\t\tfor (const { resource, marker: markerData } of data) {\n\t\t\t\tconst marker = MarkerService._toMarker(owner, resource, markerData);\n\t\t\t\tif (!marker) {\n\t\t\t\t\t// filter bad markers\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst array = groups.get(resource);\n\t\t\t\tif (!array) {\n\t\t\t\t\tgroups.set(resource, [marker]);\n\t\t\t\t\tchanges.push(resource);\n\t\t\t\t} else {\n\t\t\t\t\tarray.push(marker);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// insert all\n\t\t\tfor (const [resource, value] of groups) {\n\t\t\t\tthis._data.set(resource, owner, value);\n\t\t\t}\n\t\t}\n\n\t\tif (changes.length > 0) {\n\t\t\tthis._onMarkerChanged.fire(changes);\n\t\t}\n\t}\n\n\tread(filter: { owner?: string; resource?: URI; severities?: number; take?: number } = Object.create(null)): IMarker[] {\n\n\t\tlet { owner, resource, severities, take } = filter;\n\n\t\tif (!take || take < 0) {\n\t\t\ttake = -1;\n\t\t}\n\n\t\tif (owner && resource) {\n\t\t\t// exactly one owner AND resource\n\t\t\tconst data = this._data.get(resource, owner);\n\t\t\tif (!data) {\n\t\t\t\treturn [];\n\t\t\t} else {\n\t\t\t\tconst result: IMarker[] = [];\n\t\t\t\tfor (const marker of data) {\n\t\t\t\t\tif (MarkerService._accept(marker, severities)) {\n\t\t\t\t\t\tconst newLen = result.push(marker);\n\t\t\t\t\t\tif (take > 0 && newLen === take) {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t} else if (!owner && !resource) {\n\t\t\t// all\n\t\t\tconst result: IMarker[] = [];\n\t\t\tfor (const markers of this._data.values()) {\n\t\t\t\tfor (const data of markers) {\n\t\t\t\t\tif (MarkerService._accept(data, severities)) {\n\t\t\t\t\t\tconst newLen = result.push(data);\n\t\t\t\t\t\tif (take > 0 && newLen === take) {\n\t\t\t\t\t\t\treturn result;\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\n\t\t} else {\n\t\t\t// of one resource OR owner\n\t\t\tconst iterable = this._data.values(resource ?? owner!);\n\t\t\tconst result: IMarker[] = [];\n\t\t\tfor (const markers of iterable) {\n\t\t\t\tfor (const data of markers) {\n\t\t\t\t\tif (MarkerService._accept(data, severities)) {\n\t\t\t\t\t\tconst newLen = result.push(data);\n\t\t\t\t\t\tif (take > 0 && newLen === take) {\n\t\t\t\t\t\t\treturn result;\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\t}\n\n\tprivate static _accept(marker: IMarker, severities?: number): boolean {\n\t\treturn severities === undefined || (severities & marker.severity) === marker.severity;\n\t}\n\n\t// --- event debounce logic\n\n\tprivate static _merge(all: (readonly URI[])[]): URI[] {\n\t\tconst set = new ResourceMap();\n\t\tfor (const array of all) {\n\t\t\tfor (const item of array) {\n\t\t\t\tset.set(item, true);\n\t\t\t}\n\t\t}\n\t\treturn Array.from(set.keys());\n\t}\n}\n","\nimport { IDisposable } from 'vs/base/common/lifecycle';\nimport BaseSeverity from 'vs/base/common/severity';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\n\nexport import Severity = BaseSeverity;\n\nexport const INotificationService = createDecorator('notificationService');\n\nexport type NotificationMessage = string | Error;\n\nexport interface INotificationProperties {\n}\n\nexport interface INotificationSource {\n}\n\nexport interface INotification extends INotificationProperties {\n\n\t/**\n\t * The severity of the notification. Either `Info`, `Warning` or `Error`.\n\t */\n\treadonly severity: Severity;\n\n\t/**\n\t * The message of the notification. This can either be a `string` or `Error`. Messages\n\t * can optionally include links in the format: `[text](link)`\n\t */\n\treadonly message: NotificationMessage;\n\n\t/**\n\t * The source of the notification appears as additional information.\n\t */\n\treadonly source?: string | INotificationSource;\n}\n\nexport interface INotificationHandle {\n}\n\ninterface IBasePromptChoice {\n\n\t/**\n\t * Label to show for the choice to the user.\n\t */\n\treadonly label: string;\n\n\t/**\n\t * Triggered when the user selects the choice.\n\t */\n\trun: () => void;\n}\n\nexport interface IPromptChoice extends IBasePromptChoice {\n}\n\nexport interface IPromptChoiceWithMenu extends IPromptChoice {\n}\n\nexport interface IPromptOptions extends INotificationProperties {\n}\n\nexport interface IStatusMessageOptions {\n\n\t/**\n\t * An optional timeout after which the status message is to be hidden. By default\n\t * the status message will not hide until another status message is displayed.\n\t */\n\treadonly hideAfter?: number;\n}\n\n/**\n * A service to bring up notifications and non-modal prompts.\n *\n * Note: use the `IDialogService` for a modal way to ask the user for input.\n */\nexport interface INotificationService {\n\n\treadonly _serviceBrand: undefined;\n\n\t/**\n\t * Show the provided notification to the user. The returned `INotificationHandle`\n\t * can be used to control the notification afterwards.\n\t *\n\t * **Note:** If your intent is to show a message with actions to the user, consider\n\t * the `INotificationService.prompt()` method instead which are optimized for\n\t * this usecase and much easier to use!\n\t *\n\t * @returns a handle on the notification to e.g. hide it or update message, buttons, etc.\n\t */\n\tnotify(notification: INotification): INotificationHandle;\n\n\t/**\n\t * A convenient way of reporting infos. Use the `INotificationService.notify`\n\t * method if you need more control over the notification.\n\t */\n\tinfo(message: NotificationMessage | NotificationMessage[]): void;\n\n\t/**\n\t * A convenient way of reporting warnings. Use the `INotificationService.notify`\n\t * method if you need more control over the notification.\n\t */\n\twarn(message: NotificationMessage | NotificationMessage[]): void;\n\n\t/**\n\t * A convenient way of reporting errors. Use the `INotificationService.notify`\n\t * method if you need more control over the notification.\n\t */\n\terror(message: NotificationMessage | NotificationMessage[]): void;\n\n\t/**\n\t * Shows a prompt in the notification area with the provided choices. The prompt\n\t * is non-modal. If you want to show a modal dialog instead, use `IDialogService`.\n\t *\n\t * @param severity the severity of the notification. Either `Info`, `Warning` or `Error`.\n\t * @param message the message to show as status.\n\t * @param choices options to be chosen from.\n\t * @param options provides some optional configuration options.\n\t *\n\t * @returns a handle on the notification to e.g. hide it or update message, buttons, etc.\n\t */\n\tprompt(severity: Severity, message: string, choices: (IPromptChoice | IPromptChoiceWithMenu)[], options?: IPromptOptions): INotificationHandle;\n\n\t/**\n\t * Shows a status message in the status area with the provided text.\n\t *\n\t * @param message the message to show as status\n\t * @param options provides some optional configuration options\n\t *\n\t * @returns a disposable to hide the status message\n\t */\n\tstatus(message: NotificationMessage, options?: IStatusMessageOptions): IDisposable;\n}\n\nexport class NoOpNotification implements INotificationHandle {\n}\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\nimport * as dom from 'vs/base/browser/dom';\nimport { Button } from 'vs/base/browser/ui/button/button';\nimport { toAction } from 'vs/base/common/actions';\nimport { CancellationToken } from 'vs/base/common/cancellation';\nimport { toErrorMessage } from 'vs/base/common/errorMessage';\nimport { isCancellationError } from 'vs/base/common/errors';\nimport { Event } from 'vs/base/common/event';\nimport { Disposable, MutableDisposable, toDisposable } from 'vs/base/common/lifecycle';\nimport 'vs/css!./postEditWidget';\nimport { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser';\nimport { IBulkEditResult, IBulkEditService } from 'vs/editor/browser/services/bulkEditService';\nimport { Range } from 'vs/editor/common/core/range';\nimport { DocumentDropEdit, DocumentPasteEdit } from 'vs/editor/common/languages';\nimport { TrackedRangeStickiness } from 'vs/editor/common/model';\nimport { createCombinedWorkspaceEdit } from 'vs/editor/contrib/dropOrPasteInto/browser/edit';\nimport { localize } from 'vs/nls';\nimport { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';\nimport { IContextMenuService } from 'vs/platform/contextview/browser/contextView';\nimport { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';\nimport { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';\nimport { INotificationService } from 'vs/platform/notification/common/notification';\n\n\ninterface EditSet {\n\treadonly activeEditIndex: number;\n\treadonly allEdits: ReadonlyArray;\n}\n\ninterface ShowCommand {\n\treadonly id: string;\n\treadonly label: string;\n}\n\nclass PostEditWidget extends Disposable implements IContentWidget {\n\tprivate static readonly baseId = 'editor.widget.postEditWidget';\n\n\treadonly allowEditorOverflow = true;\n\treadonly suppressMouseDown = true;\n\n\tprivate domNode!: HTMLElement;\n\tprivate button!: Button;\n\n\tprivate readonly visibleContext: IContextKey;\n\n\tconstructor(\n\t\tprivate readonly typeId: string,\n\t\tprivate readonly editor: ICodeEditor,\n\t\tvisibleContext: RawContextKey,\n\t\tprivate readonly showCommand: ShowCommand,\n\t\tprivate readonly range: Range,\n\t\tprivate readonly edits: EditSet,\n\t\tprivate readonly onSelectNewEdit: (editIndex: number) => void,\n\t\t@IContextMenuService private readonly _contextMenuService: IContextMenuService,\n\t\t@IContextKeyService contextKeyService: IContextKeyService,\n\t\t@IKeybindingService private readonly _keybindingService: IKeybindingService,\n\t) {\n\t\tsuper();\n\n\t\tthis.create();\n\n\t\tthis.visibleContext = visibleContext.bindTo(contextKeyService);\n\t\tthis.visibleContext.set(true);\n\t\tthis._register(toDisposable(() => this.visibleContext.reset()));\n\n\t\tthis.editor.addContentWidget(this);\n\t\tthis.editor.layoutContentWidget(this);\n\n\t\tthis._register(toDisposable((() => this.editor.removeContentWidget(this))));\n\n\t\tthis._register(this.editor.onDidChangeCursorPosition(e => {\n\t\t\tif (!range.containsPosition(e.position)) {\n\t\t\t\tthis.dispose();\n\t\t\t}\n\t\t}));\n\n\t\tthis._register(Event.runAndSubscribe(_keybindingService.onDidUpdateKeybindings, () => {\n\t\t\tthis._updateButtonTitle();\n\t\t}));\n\t}\n\n\tprivate _updateButtonTitle() {\n\t\tconst binding = this._keybindingService.lookupKeybinding(this.showCommand.id)?.getLabel();\n\t\tthis.button.element.title = this.showCommand.label + (binding ? ` (${binding})` : '');\n\t}\n\n\tprivate create(): void {\n\t\tthis.domNode = dom.$('.post-edit-widget');\n\n\t\tthis.button = this._register(new Button(this.domNode, {\n\t\t\tsupportIcons: true,\n\t\t}));\n\t\tthis.button.label = '$(insert)';\n\n\t\tthis._register(dom.addDisposableListener(this.domNode, dom.EventType.CLICK, () => this.showSelector()));\n\t}\n\n\tgetId(): string {\n\t\treturn PostEditWidget.baseId + '.' + this.typeId;\n\t}\n\n\tgetDomNode(): HTMLElement {\n\t\treturn this.domNode;\n\t}\n\n\tgetPosition(): IContentWidgetPosition | null {\n\t\treturn {\n\t\t\tposition: this.range.getEndPosition(),\n\t\t\tpreference: [ContentWidgetPositionPreference.BELOW]\n\t\t};\n\t}\n\n\tshowSelector() {\n\t\tthis._contextMenuService.showContextMenu({\n\t\t\tgetAnchor: () => {\n\t\t\t\tconst pos = dom.getDomNodePagePosition(this.button.element);\n\t\t\t\treturn { x: pos.left + pos.width, y: pos.top + pos.height };\n\t\t\t},\n\t\t\tgetActions: () => {\n\t\t\t\treturn this.edits.allEdits.map((edit, i) => toAction({\n\t\t\t\t\tid: '',\n\t\t\t\t\tlabel: edit.title,\n\t\t\t\t\tchecked: i === this.edits.activeEditIndex,\n\t\t\t\t\trun: () => {\n\t\t\t\t\t\tif (i !== this.edits.activeEditIndex) {\n\t\t\t\t\t\t\treturn this.onSelectNewEdit(i);\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});\n\t}\n}\n\nexport class PostEditWidgetManager extends Disposable {\n\n\tprivate readonly _currentWidget = this._register(new MutableDisposable>());\n\n\tconstructor(\n\t\tprivate readonly _id: string,\n\t\tprivate readonly _editor: ICodeEditor,\n\t\tprivate readonly _visibleContext: RawContextKey,\n\t\tprivate readonly _showCommand: ShowCommand,\n\t\t@IInstantiationService private readonly _instantiationService: IInstantiationService,\n\t\t@IBulkEditService private readonly _bulkEditService: IBulkEditService,\n\t\t@INotificationService private readonly _notificationService: INotificationService,\n\t) {\n\t\tsuper();\n\n\t\tthis._register(Event.any(\n\t\t\t_editor.onDidChangeModel,\n\t\t\t_editor.onDidChangeModelContent,\n\t\t)(() => this.clear()));\n\t}\n\n\tpublic async applyEditAndShowIfNeeded(ranges: readonly Range[], edits: EditSet, canShowWidget: boolean, resolve: (edit: T, token: CancellationToken) => Promise, token: CancellationToken) {\n\t\tconst model = this._editor.getModel();\n\t\tif (!model || !ranges.length) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst edit = edits.allEdits.at(edits.activeEditIndex);\n\t\tif (!edit) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst onDidSelectEdit = async (newEditIndex: number) => {\n\t\t\tconst model = this._editor.getModel();\n\t\t\tif (!model) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tawait model.undo();\n\t\t\tthis.applyEditAndShowIfNeeded(ranges, { activeEditIndex: newEditIndex, allEdits: edits.allEdits }, canShowWidget, resolve, token);\n\t\t};\n\n\t\tconst handleError = (e: Error, message: string) => {\n\t\t\tif (isCancellationError(e)) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis._notificationService.error(message);\n\t\t\tif (canShowWidget) {\n\t\t\t\tthis.show(ranges[0], edits, onDidSelectEdit);\n\t\t\t}\n\t\t};\n\n\t\tlet resolvedEdit: T;\n\t\ttry {\n\t\t\tresolvedEdit = await resolve(edit, token);\n\t\t} catch (e) {\n\t\t\treturn handleError(e, localize('resolveError', \"Error resolving edit '{0}':\\n{1}\", edit.title, toErrorMessage(e)));\n\t\t}\n\n\t\tif (token.isCancellationRequested) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst combinedWorkspaceEdit = createCombinedWorkspaceEdit(model.uri, ranges, resolvedEdit);\n\n\t\t// Use a decoration to track edits around the trigger range\n\t\tconst primaryRange = ranges[0];\n\t\tconst editTrackingDecoration = model.deltaDecorations([], [{\n\t\t\trange: primaryRange,\n\t\t\toptions: { description: 'paste-line-suffix', stickiness: TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges }\n\t\t}]);\n\n\t\tthis._editor.focus();\n\t\tlet editResult: IBulkEditResult;\n\t\tlet editRange: Range | null;\n\t\ttry {\n\t\t\teditResult = await this._bulkEditService.apply(combinedWorkspaceEdit, { editor: this._editor, token });\n\t\t\teditRange = model.getDecorationRange(editTrackingDecoration[0]);\n\t\t} catch (e) {\n\t\t\treturn handleError(e, localize('applyError', \"Error applying edit '{0}':\\n{1}\", edit.title, toErrorMessage(e)));\n\t\t} finally {\n\t\t\tmodel.deltaDecorations(editTrackingDecoration, []);\n\t\t}\n\n\t\tif (token.isCancellationRequested) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (canShowWidget && editResult.isApplied && edits.allEdits.length > 1) {\n\t\t\tthis.show(editRange ?? primaryRange, edits, onDidSelectEdit);\n\t\t}\n\t}\n\n\tpublic show(range: Range, edits: EditSet, onDidSelectEdit: (newIndex: number) => void) {\n\t\tthis.clear();\n\n\t\tif (this._editor.hasModel()) {\n\t\t\tthis._currentWidget.value = this._instantiationService.createInstance(PostEditWidget, this._id, this._editor, this._visibleContext, this._showCommand, range, edits, onDidSelectEdit);\n\t\t}\n\t}\n\n\tpublic clear() {\n\t\tthis._currentWidget.clear();\n\t}\n\n\tpublic tryShowSelector() {\n\t\tthis._currentWidget.value?.showSelector();\n\t}\n}\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\nimport { IDisposable } from 'vs/base/common/lifecycle';\nimport { autorunOpts, IReader } from 'vs/base/common/observable';\nimport { ContextKeyValue, RawContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';\n\n/** Update the configuration key with a value derived from observables. */\nexport function bindContextKey(key: RawContextKey, service: IContextKeyService, computeValue: (reader: IReader) => T): IDisposable {\n\tconst boundKey = key.bindTo(service);\n\treturn autorunOpts({ debugName: () => `Set Context Key \"${key.key}\"` }, reader => {\n\t\tboundKey.set(computeValue(reader));\n\t});\n}\n\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\nimport { CancellationToken } from 'vs/base/common/cancellation';\nimport { IDisposable } from 'vs/base/common/lifecycle';\nimport { URI } from 'vs/base/common/uri';\nimport { IEditorOptions, ITextEditorSelection } from 'vs/platform/editor/common/editor';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\n\nexport const IOpenerService = createDecorator('openerService');\n\nexport type OpenInternalOptions = {\n\n\t/**\n\t * Signals that the intent is to open an editor to the side\n\t * of the currently active editor.\n\t */\n\treadonly openToSide?: boolean;\n\n\t/**\n\t * Extra editor options to apply in case an editor is used to open.\n\t */\n\treadonly editorOptions?: IEditorOptions;\n\n\t/**\n\t * Signals that the editor to open was triggered through a user\n\t * action, such as keyboard or mouse usage.\n\t */\n\treadonly fromUserGesture?: boolean;\n\n\t/**\n\t * Allow command links to be handled.\n\t *\n\t * If this is an array, then only the commands included in the array can be run.\n\t */\n\treadonly allowCommands?: boolean | readonly string[];\n};\n\nexport type OpenExternalOptions = {\n\treadonly openExternal?: boolean;\n\treadonly allowTunneling?: boolean;\n\treadonly allowContributedOpeners?: boolean | string;\n\treadonly fromWorkspace?: boolean;\n};\n\nexport type OpenOptions = OpenInternalOptions & OpenExternalOptions;\n\nexport type ResolveExternalUriOptions = { readonly allowTunneling?: boolean };\n\nexport interface IResolvedExternalUri extends IDisposable {\n\tresolved: URI;\n}\n\nexport interface IOpener {\n\topen(resource: URI | string, options?: OpenInternalOptions | OpenExternalOptions): Promise;\n}\n\nexport interface IExternalOpener {\n\topenExternal(href: string, ctx: { sourceUri: URI; preferredOpenerId?: string }, token: CancellationToken): Promise;\n\tdispose?(): void;\n}\n\nexport interface IValidator {\n\tshouldOpen(resource: URI | string, openOptions?: OpenOptions): Promise;\n}\n\nexport interface IExternalUriResolver {\n\tresolveExternalUri(resource: URI, options?: OpenOptions): Promise<{ resolved: URI; dispose(): void } | undefined>;\n}\n\nexport interface IOpenerService {\n\n\treadonly _serviceBrand: undefined;\n\n\t/**\n\t * Register a participant that can handle the open() call.\n\t */\n\tregisterOpener(opener: IOpener): IDisposable;\n\n\t/**\n\t * Opens a resource, like a webaddress, a document uri, or executes command.\n\t *\n\t * @param resource A resource\n\t * @return A promise that resolves when the opening is done.\n\t */\n\topen(resource: URI | string, options?: OpenInternalOptions | OpenExternalOptions): Promise;\n}\n\n/**\n * file:///some/file.js#73\n * file:///some/file.js#L73\n * file:///some/file.js#73,84\n * file:///some/file.js#L73,84\n * file:///some/file.js#73-83\n * file:///some/file.js#L73-L83\n * file:///some/file.js#73,84-83,52\n * file:///some/file.js#L73,84-L83,52\n */\nexport function extractSelection(uri: URI): { selection: ITextEditorSelection | undefined; uri: URI } {\n\tlet selection: ITextEditorSelection | undefined = undefined;\n\tconst match = /^L?(\\d+)(?:,(\\d+))?(-L?(\\d+)(?:,(\\d+))?)?/.exec(uri.fragment);\n\tif (match) {\n\t\tselection = {\n\t\t\tstartLineNumber: parseInt(match[1]),\n\t\t\tstartColumn: match[2] ? parseInt(match[2]) : 1,\n\t\t\tendLineNumber: match[4] ? parseInt(match[4]) : undefined,\n\t\t\tendColumn: match[4] ? (match[5] ? parseInt(match[5]) : 1) : undefined\n\t\t};\n\t\turi = uri.with({ fragment: '' });\n\t}\n\treturn { selection, uri };\n}\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\nimport * as dom from 'vs/base/browser/dom';\nimport { mainWindow } from 'vs/base/browser/window';\nimport { CancellationToken } from 'vs/base/common/cancellation';\nimport { IDisposable } from 'vs/base/common/lifecycle';\nimport { LinkedList } from 'vs/base/common/linkedList';\nimport { ResourceMap } from 'vs/base/common/map';\nimport { parse } from 'vs/base/common/marshalling';\nimport { matchesScheme, matchesSomeScheme, Schemas } from 'vs/base/common/network';\nimport { normalizePath } from 'vs/base/common/resources';\nimport { URI } from 'vs/base/common/uri';\nimport { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';\nimport { ICommandService } from 'vs/platform/commands/common/commands';\nimport { EditorOpenSource } from 'vs/platform/editor/common/editor';\nimport { extractSelection, IExternalOpener, IExternalUriResolver, IOpener, IOpenerService, IResolvedExternalUri, IValidator, OpenOptions, ResolveExternalUriOptions } from 'vs/platform/opener/common/opener';\n\nclass CommandOpener implements IOpener {\n\n\tconstructor(@ICommandService private readonly _commandService: ICommandService) { }\n\n\tasync open(target: URI | string, options?: OpenOptions): Promise {\n\t\tif (!matchesScheme(target, Schemas.command)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (!options?.allowCommands) {\n\t\t\t// silently ignore commands when command-links are disabled, also\n\t\t\t// suppress other openers by returning TRUE\n\t\t\treturn true;\n\t\t}\n\n\t\tif (typeof target === 'string') {\n\t\t\ttarget = URI.parse(target);\n\t\t}\n\n\t\tif (Array.isArray(options.allowCommands)) {\n\t\t\t// Only allow specific commands\n\t\t\tif (!options.allowCommands.includes(target.path)) {\n\t\t\t\t// Suppress other openers by returning TRUE\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\t// execute as command\n\t\tlet args: any = [];\n\t\ttry {\n\t\t\targs = parse(decodeURIComponent(target.query));\n\t\t} catch {\n\t\t\t// ignore and retry\n\t\t\ttry {\n\t\t\t\targs = parse(target.query);\n\t\t\t} catch {\n\t\t\t\t// ignore error\n\t\t\t}\n\t\t}\n\t\tif (!Array.isArray(args)) {\n\t\t\targs = [args];\n\t\t}\n\t\tawait this._commandService.executeCommand(target.path, ...args);\n\t\treturn true;\n\t}\n}\n\nclass EditorOpener implements IOpener {\n\n\tconstructor(@ICodeEditorService private readonly _editorService: ICodeEditorService) { }\n\n\tasync open(target: URI | string, options: OpenOptions) {\n\t\tif (typeof target === 'string') {\n\t\t\ttarget = URI.parse(target);\n\t\t}\n\t\tconst { selection, uri } = extractSelection(target);\n\t\ttarget = uri;\n\n\t\tif (target.scheme === Schemas.file) {\n\t\t\ttarget = normalizePath(target); // workaround for non-normalized paths (https://github.com/microsoft/vscode/issues/12954)\n\t\t}\n\n\t\tawait this._editorService.openCodeEditor(\n\t\t\t{\n\t\t\t\tresource: target,\n\t\t\t\toptions: {\n\t\t\t\t\tselection,\n\t\t\t\t\tsource: options?.fromUserGesture ? EditorOpenSource.USER : EditorOpenSource.API,\n\t\t\t\t\t...options?.editorOptions\n\t\t\t\t}\n\t\t\t},\n\t\t\tthis._editorService.getFocusedCodeEditor(),\n\t\t\toptions?.openToSide\n\t\t);\n\n\t\treturn true;\n\t}\n}\n\nexport class OpenerService implements IOpenerService {\n\n\tdeclare readonly _serviceBrand: undefined;\n\n\tprivate readonly _openers = new LinkedList();\n\tprivate readonly _validators = new LinkedList();\n\tprivate readonly _resolvers = new LinkedList();\n\tprivate readonly _resolvedUriTargets = new ResourceMap(uri => uri.with({ path: null, fragment: null, query: null }).toString());\n\n\tprivate _defaultExternalOpener: IExternalOpener;\n\tprivate readonly _externalOpeners = new LinkedList();\n\n\tconstructor(\n\t\t@ICodeEditorService editorService: ICodeEditorService,\n\t\t@ICommandService commandService: ICommandService\n\t) {\n\t\t// Default external opener is going through window.open()\n\t\tthis._defaultExternalOpener = {\n\t\t\topenExternal: async href => {\n\t\t\t\t// ensure to open HTTP/HTTPS links into new windows\n\t\t\t\t// to not trigger a navigation. Any other link is\n\t\t\t\t// safe to be set as HREF to prevent a blank window\n\t\t\t\t// from opening.\n\t\t\t\tif (matchesSomeScheme(href, Schemas.http, Schemas.https)) {\n\t\t\t\t\tdom.windowOpenNoOpener(href);\n\t\t\t\t} else {\n\t\t\t\t\tmainWindow.location.href = href;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t};\n\n\t\t// Default opener: any external, maito, http(s), command, and catch-all-editors\n\t\tthis._openers.push({\n\t\t\topen: async (target: URI | string, options?: OpenOptions) => {\n\t\t\t\tif (options?.openExternal || matchesSomeScheme(target, Schemas.mailto, Schemas.http, Schemas.https, Schemas.vsls)) {\n\t\t\t\t\t// open externally\n\t\t\t\t\tawait this._doOpenExternal(target, options);\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t}\n\t\t});\n\t\tthis._openers.push(new CommandOpener(commandService));\n\t\tthis._openers.push(new EditorOpener(editorService));\n\t}\n\n\tregisterOpener(opener: IOpener): IDisposable {\n\t\tconst remove = this._openers.unshift(opener);\n\t\treturn { dispose: remove };\n\t}\n\n\tasync open(target: URI | string, options?: OpenOptions): Promise {\n\t\t// check with contributed validators\n\t\tconst targetURI = typeof target === 'string' ? URI.parse(target) : target;\n\t\t// validate against the original URI that this URI resolves to, if one exists\n\t\tconst validationTarget = this._resolvedUriTargets.get(targetURI) ?? target;\n\t\tfor (const validator of this._validators) {\n\t\t\tif (!(await validator.shouldOpen(validationTarget, options))) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\t// check with contributed openers\n\t\tfor (const opener of this._openers) {\n\t\t\tconst handled = await opener.open(target, options);\n\t\t\tif (handled) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tasync resolveExternalUri(resource: URI, options?: ResolveExternalUriOptions): Promise {\n\t\tfor (const resolver of this._resolvers) {\n\t\t\ttry {\n\t\t\t\tconst result = await resolver.resolveExternalUri(resource, options);\n\t\t\t\tif (result) {\n\t\t\t\t\tif (!this._resolvedUriTargets.has(result.resolved)) {\n\t\t\t\t\t\tthis._resolvedUriTargets.set(result.resolved, resource);\n\t\t\t\t\t}\n\t\t\t\t\treturn result;\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// noop\n\t\t\t}\n\t\t}\n\n\t\tthrow new Error('Could not resolve external URI: ' + resource.toString());\n\t}\n\n\tprivate async _doOpenExternal(resource: URI | string, options: OpenOptions | undefined): Promise {\n\n\t\t//todo@jrieken IExternalUriResolver should support `uri: URI | string`\n\t\tconst uri = typeof resource === 'string' ? URI.parse(resource) : resource;\n\t\tlet externalUri: URI;\n\n\t\ttry {\n\t\t\texternalUri = (await this.resolveExternalUri(uri, options)).resolved;\n\t\t} catch {\n\t\t\texternalUri = uri;\n\t\t}\n\n\t\tlet href: string;\n\t\tif (typeof resource === 'string' && uri.toString() === externalUri.toString()) {\n\t\t\t// open the url-string AS IS\n\t\t\thref = resource;\n\t\t} else {\n\t\t\t// open URI using the toString(noEncode)+encodeURI-trick\n\t\t\thref = encodeURI(externalUri.toString(true));\n\t\t}\n\n\t\tif (options?.allowContributedOpeners) {\n\t\t\tconst preferredOpenerId = typeof options?.allowContributedOpeners === 'string' ? options?.allowContributedOpeners : undefined;\n\t\t\tfor (const opener of this._externalOpeners) {\n\t\t\t\tconst didOpen = await opener.openExternal(href, {\n\t\t\t\t\tsourceUri: uri,\n\t\t\t\t\tpreferredOpenerId,\n\t\t\t\t}, CancellationToken.None);\n\t\t\t\tif (didOpen) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this._defaultExternalOpener.openExternal(href, { sourceUri: uri }, CancellationToken.None);\n\t}\n\n\tdispose() {\n\t\tthis._validators.clear();\n\t}\n}\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\nimport { $, append, EventHelper, EventLike } from 'vs/base/browser/dom';\nimport { DomEmitter } from 'vs/base/browser/event';\nimport { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';\nimport { EventType as TouchEventType, Gesture } from 'vs/base/browser/touch';\nimport { Event } from 'vs/base/common/event';\nimport { KeyCode } from 'vs/base/common/keyCodes';\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport { IOpenerService } from 'vs/platform/opener/common/opener';\nimport 'vs/css!./link';\nimport { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegateFactory';\nimport { IHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate';\nimport { IUpdatableHover } from 'vs/base/browser/ui/hover/hover';\nimport { IHoverService } from 'vs/platform/hover/browser/hover';\n\nexport interface ILinkDescriptor {\n\treadonly label: string | HTMLElement;\n\treadonly href: string;\n\treadonly title?: string;\n\treadonly tabIndex?: number;\n}\n\nexport interface ILinkOptions {\n\treadonly opener?: (href: string) => void;\n\treadonly hoverDelegate?: IHoverDelegate;\n}\n\nexport class Link extends Disposable {\n\n\tprivate el: HTMLAnchorElement;\n\tprivate hover?: IUpdatableHover;\n\tprivate hoverDelegate: IHoverDelegate;\n\n\tprivate _enabled: boolean = true;\n\n\tget enabled(): boolean {\n\t\treturn this._enabled;\n\t}\n\n\tset enabled(enabled: boolean) {\n\t\tif (enabled) {\n\t\t\tthis.el.setAttribute('aria-disabled', 'false');\n\t\t\tthis.el.tabIndex = 0;\n\t\t\tthis.el.style.pointerEvents = 'auto';\n\t\t\tthis.el.style.opacity = '1';\n\t\t\tthis.el.style.cursor = 'pointer';\n\t\t\tthis._enabled = false;\n\t\t} else {\n\t\t\tthis.el.setAttribute('aria-disabled', 'true');\n\t\t\tthis.el.tabIndex = -1;\n\t\t\tthis.el.style.pointerEvents = 'none';\n\t\t\tthis.el.style.opacity = '0.4';\n\t\t\tthis.el.style.cursor = 'default';\n\t\t\tthis._enabled = true;\n\t\t}\n\n\t\tthis._enabled = enabled;\n\t}\n\n\tconstructor(\n\t\tcontainer: HTMLElement,\n\t\tprivate _link: ILinkDescriptor,\n\t\toptions: ILinkOptions = {},\n\t\t@IHoverService private readonly _hoverService: IHoverService,\n\t\t@IOpenerService openerService: IOpenerService\n\t) {\n\t\tsuper();\n\n\t\tthis.el = append(container, $('a.monaco-link', {\n\t\t\ttabIndex: _link.tabIndex ?? 0,\n\t\t\thref: _link.href,\n\t\t}, _link.label));\n\n\t\tthis.hoverDelegate = options.hoverDelegate ?? getDefaultHoverDelegate('mouse');\n\t\tthis.setTooltip(_link.title);\n\n\t\tthis.el.setAttribute('role', 'button');\n\n\t\tconst onClickEmitter = this._register(new DomEmitter(this.el, 'click'));\n\t\tconst onKeyPress = this._register(new DomEmitter(this.el, 'keypress'));\n\t\tconst onEnterPress = Event.chain(onKeyPress.event, $ =>\n\t\t\t$.map(e => new StandardKeyboardEvent(e))\n\t\t\t\t.filter(e => e.keyCode === KeyCode.Enter)\n\t\t);\n\t\tconst onTap = this._register(new DomEmitter(this.el, TouchEventType.Tap)).event;\n\t\tthis._register(Gesture.addTarget(this.el));\n\t\tconst onOpen = Event.any(onClickEmitter.event, onEnterPress, onTap);\n\n\t\tthis._register(onOpen(e => {\n\t\t\tif (!this.enabled) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tEventHelper.stop(e, true);\n\n\t\t\tif (options?.opener) {\n\t\t\t\toptions.opener(this._link.href);\n\t\t\t} else {\n\t\t\t\topenerService.open(this._link.href, { allowCommands: true });\n\t\t\t}\n\t\t}));\n\n\t\tthis.enabled = true;\n\t}\n\n\tprivate setTooltip(title: string | undefined): void {\n\t\tif (this.hoverDelegate.showNativeHover) {\n\t\t\tthis.el.title = title ?? '';\n\t\t} else if (!this.hover && title) {\n\t\t\tthis.hover = this._register(this._hoverService.setupUpdatableHover(this.hoverDelegate, this.el, title));\n\t\t} else if (this.hover) {\n\t\t\tthis.hover.update(title);\n\t\t}\n\t}\n}\n","\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\n\nexport const IProgressService = createDecorator('progressService');\n\n/**\n * A progress service that can be used to report progress to various locations of the UI.\n */\nexport interface IProgressService {\n\n\treadonly _serviceBrand: undefined;\n\n\twithProgress(\n\t\toptions: IProgressOptions | IProgressDialogOptions | IProgressNotificationOptions | IProgressWindowOptions | IProgressCompositeOptions,\n\t\ttask: (progress: IProgress) => Promise,\n\t\tonDidCancel?: (choice?: number) => void\n\t): Promise;\n}\n\nexport interface IProgressIndicator {\n\n\t/**\n\t * Show progress customized with the provided flags.\n\t */\n\tshow(infinite: true, delay?: number): IProgressRunner;\n\tshow(total: number, delay?: number): IProgressRunner;\n\n\t/**\n\t * Indicate progress for the duration of the provided promise. Progress will stop in\n\t * any case of promise completion, error or cancellation.\n\t */\n\tshowWhile(promise: Promise, delay?: number): Promise;\n}\n\nexport const enum ProgressLocation {\n\tExplorer = 1,\n\tScm = 3,\n\tExtensions = 5,\n\tWindow = 10,\n\tNotification = 15,\n\tDialog = 20\n}\n\nexport interface IProgressOptions {\n\treadonly location: ProgressLocation | string;\n\treadonly title?: string;\n}\n\nexport interface IProgressNotificationOptions extends IProgressOptions {\n}\n\nexport interface IProgressDialogOptions extends IProgressOptions {\n}\n\nexport interface IProgressWindowOptions extends IProgressOptions {\n}\n\nexport interface IProgressCompositeOptions extends IProgressOptions {\n}\n\nexport interface IProgressStep {\n}\n\nexport interface IProgressRunner {\n\ttotal(value: number): void;\n\tworked(value: number): void;\n\tdone(): void;\n}\n\nexport const emptyProgressRunner = Object.freeze({\n\ttotal() { },\n\tworked() { },\n\tdone() { }\n});\n\nexport interface IProgress {\n\treport(item: T): void;\n}\n\nexport class Progress implements IProgress {\n\n\tstatic readonly None = Object.freeze>({ report() { } });\n\n\tprivate _value?: T;\n\n\tconstructor(private callback: (data: T) => unknown) {\n\t}\n\n\treport(item: T) {\n\t\tthis._value = item;\n\t\tthis.callback(this._value);\n\t}\n}\n\nexport const IEditorProgressService = createDecorator('editorProgressService');\n\n/**\n * A progress service that will report progress local to the editor triggered from.\n */\nexport interface IEditorProgressService extends IProgressIndicator {\n\n\treadonly _serviceBrand: undefined;\n}\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\nimport { timeout } from 'vs/base/common/async';\nimport { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';\nimport { Disposable, DisposableStore, IDisposable, MutableDisposable } from 'vs/base/common/lifecycle';\nimport { IKeyMods, IQuickPickDidAcceptEvent, IQuickPickSeparator, IQuickPick, IQuickPickItem, IQuickInputButton } from 'vs/platform/quickinput/common/quickInput';\nimport { IQuickAccessProvider, IQuickAccessProviderRunOptions } from 'vs/platform/quickinput/common/quickAccess';\nimport { isFunction } from 'vs/base/common/types';\n\nexport enum TriggerAction {\n\n\t/**\n\t * Do nothing after the button was clicked.\n\t */\n\tNO_ACTION,\n\n\t/**\n\t * Close the picker.\n\t */\n\tCLOSE_PICKER,\n\n\t/**\n\t * Update the results of the picker.\n\t */\n\tREFRESH_PICKER,\n\n\t/**\n\t * Remove the item from the picker.\n\t */\n\tREMOVE_ITEM\n}\n\nexport interface IPickerQuickAccessItem extends IQuickPickItem {\n\n\t/**\n\t* A method that will be executed when the pick item is accepted from\n\t* the picker. The picker will close automatically before running this.\n\t*\n\t* @param keyMods the state of modifier keys when the item was accepted.\n\t* @param event the underlying event that caused the accept to trigger.\n\t*/\n\taccept?(keyMods: IKeyMods, event: IQuickPickDidAcceptEvent): void;\n\n\t/**\n\t * A method that will be executed when a button of the pick item was\n\t * clicked on.\n\t *\n\t * @param buttonIndex index of the button of the item that\n\t * was clicked.\n\t *\n\t * @param the state of modifier keys when the button was triggered.\n\t *\n\t * @returns a value that indicates what should happen after the trigger\n\t * which can be a `Promise` for long running operations.\n\t */\n\ttrigger?(buttonIndex: number, keyMods: IKeyMods): TriggerAction | Promise;\n}\n\nexport interface IPickerQuickAccessSeparator extends IQuickPickSeparator {\n\t/**\n\t * A method that will be executed when a button of the pick item was\n\t * clicked on.\n\t *\n\t * @param buttonIndex index of the button of the item that\n\t * was clicked.\n\t *\n\t * @param the state of modifier keys when the button was triggered.\n\t *\n\t * @returns a value that indicates what should happen after the trigger\n\t * which can be a `Promise` for long running operations.\n\t */\n\ttrigger?(buttonIndex: number, keyMods: IKeyMods): TriggerAction | Promise;\n}\n\nexport interface IPickerQuickAccessProviderOptions {\n\n\t/**\n\t * Enables support for opening picks in the background via gesture.\n\t */\n\treadonly canAcceptInBackground?: boolean;\n\n\t/**\n\t * Enables to show a pick entry when no results are returned from a search.\n\t */\n\treadonly noResultsPick?: T | ((filter: string) => T);\n\n\t/** Whether to skip trimming the pick filter string */\n\treadonly shouldSkipTrimPickFilter?: boolean;\n}\n\nexport type Pick = T | IQuickPickSeparator;\nexport type PicksWithActive = { items: readonly Pick[]; active?: T };\nexport type Picks = readonly Pick[] | PicksWithActive;\nexport type FastAndSlowPicks = {\n\n\t/**\n\t * Picks that will show instantly or after a short delay\n\t * based on the `mergeDelay` property to reduce flicker.\n\t */\n\treadonly picks: Picks;\n\n\t/**\n\t * Picks that will show after they have been resolved.\n\t */\n\treadonly additionalPicks: Promise>;\n\n\t/**\n\t * A delay in milliseconds to wait before showing the\n\t * `picks` to give a chance to merge with `additionalPicks`\n\t * for reduced flicker.\n\t */\n\treadonly mergeDelay?: number;\n};\n\nfunction isPicksWithActive(obj: unknown): obj is PicksWithActive {\n\tconst candidate = obj as PicksWithActive;\n\n\treturn Array.isArray(candidate.items);\n}\n\nfunction isFastAndSlowPicks(obj: unknown): obj is FastAndSlowPicks {\n\tconst candidate = obj as FastAndSlowPicks;\n\n\treturn !!candidate.picks && candidate.additionalPicks instanceof Promise;\n}\n\nexport abstract class PickerQuickAccessProvider extends Disposable implements IQuickAccessProvider {\n\n\tconstructor(private prefix: string, protected options?: IPickerQuickAccessProviderOptions) {\n\t\tsuper();\n\t}\n\n\tprovide(picker: IQuickPick, token: CancellationToken, runOptions?: IQuickAccessProviderRunOptions): IDisposable {\n\t\tconst disposables = new DisposableStore();\n\n\t\t// Apply options if any\n\t\tpicker.canAcceptInBackground = !!this.options?.canAcceptInBackground;\n\n\t\t// Disable filtering & sorting, we control the results\n\t\tpicker.matchOnLabel = picker.matchOnDescription = picker.matchOnDetail = picker.sortByLabel = false;\n\n\t\t// Set initial picks and update on type\n\t\tlet picksCts: CancellationTokenSource | undefined = undefined;\n\t\tconst picksDisposable = disposables.add(new MutableDisposable());\n\t\tconst updatePickerItems = async () => {\n\t\t\tconst picksDisposables = picksDisposable.value = new DisposableStore();\n\n\t\t\t// Cancel any previous ask for picks and busy\n\t\t\tpicksCts?.dispose(true);\n\t\t\tpicker.busy = false;\n\n\t\t\t// Create new cancellation source for this run\n\t\t\tpicksCts = new CancellationTokenSource(token);\n\n\t\t\t// Collect picks and support both long running and short or combined\n\t\t\tconst picksToken = picksCts.token;\n\t\t\tlet picksFilter = picker.value.substring(this.prefix.length);\n\n\t\t\tif (!this.options?.shouldSkipTrimPickFilter) {\n\t\t\t\tpicksFilter = picksFilter.trim();\n\t\t\t}\n\n\t\t\tconst providedPicks = this._getPicks(picksFilter, picksDisposables, picksToken, runOptions);\n\n\t\t\tconst applyPicks = (picks: Picks, skipEmpty?: boolean): boolean => {\n\t\t\t\tlet items: readonly Pick[];\n\t\t\t\tlet activeItem: T | undefined = undefined;\n\n\t\t\t\tif (isPicksWithActive(picks)) {\n\t\t\t\t\titems = picks.items;\n\t\t\t\t\tactiveItem = picks.active;\n\t\t\t\t} else {\n\t\t\t\t\titems = picks;\n\t\t\t\t}\n\n\t\t\t\tif (items.length === 0) {\n\t\t\t\t\tif (skipEmpty) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\n\t\t\t\t\t// We show the no results pick if we have no input to prevent completely empty pickers #172613\n\t\t\t\t\tif ((picksFilter.length > 0 || picker.hideInput) && this.options?.noResultsPick) {\n\t\t\t\t\t\tif (isFunction(this.options.noResultsPick)) {\n\t\t\t\t\t\t\titems = [this.options.noResultsPick(picksFilter)];\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\titems = [this.options.noResultsPick];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tpicker.items = items;\n\t\t\t\tif (activeItem) {\n\t\t\t\t\tpicker.activeItems = [activeItem];\n\t\t\t\t}\n\n\t\t\t\treturn true;\n\t\t\t};\n\n\t\t\tconst applyFastAndSlowPicks = async (fastAndSlowPicks: FastAndSlowPicks): Promise => {\n\t\t\t\tlet fastPicksApplied = false;\n\t\t\t\tlet slowPicksApplied = false;\n\n\t\t\t\tawait Promise.all([\n\n\t\t\t\t\t// Fast Picks: if `mergeDelay` is configured, in order to reduce\n\t\t\t\t\t// amount of flicker, we race against the slow picks over some delay\n\t\t\t\t\t// and then set the fast picks.\n\t\t\t\t\t// If the slow picks are faster, we reduce the flicker by only\n\t\t\t\t\t// setting the items once.\n\n\t\t\t\t\t(async () => {\n\t\t\t\t\t\tif (typeof fastAndSlowPicks.mergeDelay === 'number') {\n\t\t\t\t\t\t\tawait timeout(fastAndSlowPicks.mergeDelay);\n\t\t\t\t\t\t\tif (picksToken.isCancellationRequested) {\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (!slowPicksApplied) {\n\t\t\t\t\t\t\tfastPicksApplied = applyPicks(fastAndSlowPicks.picks, true /* skip over empty to reduce flicker */);\n\t\t\t\t\t\t}\n\t\t\t\t\t})(),\n\n\t\t\t\t\t// Slow Picks: we await the slow picks and then set them at\n\t\t\t\t\t// once together with the fast picks, but only if we actually\n\t\t\t\t\t// have additional results.\n\n\t\t\t\t\t(async () => {\n\t\t\t\t\t\tpicker.busy = true;\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst awaitedAdditionalPicks = await fastAndSlowPicks.additionalPicks;\n\t\t\t\t\t\t\tif (picksToken.isCancellationRequested) {\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tlet picks: readonly Pick[];\n\t\t\t\t\t\t\tlet activePick: Pick | undefined = undefined;\n\t\t\t\t\t\t\tif (isPicksWithActive(fastAndSlowPicks.picks)) {\n\t\t\t\t\t\t\t\tpicks = fastAndSlowPicks.picks.items;\n\t\t\t\t\t\t\t\tactivePick = fastAndSlowPicks.picks.active;\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tpicks = fastAndSlowPicks.picks;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tlet additionalPicks: readonly Pick[];\n\t\t\t\t\t\t\tlet additionalActivePick: Pick | undefined = undefined;\n\t\t\t\t\t\t\tif (isPicksWithActive(awaitedAdditionalPicks)) {\n\t\t\t\t\t\t\t\tadditionalPicks = awaitedAdditionalPicks.items;\n\t\t\t\t\t\t\t\tadditionalActivePick = awaitedAdditionalPicks.active;\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tadditionalPicks = awaitedAdditionalPicks;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (additionalPicks.length > 0 || !fastPicksApplied) {\n\t\t\t\t\t\t\t\t// If we do not have any activePick or additionalActivePick\n\t\t\t\t\t\t\t\t// we try to preserve the currently active pick from the\n\t\t\t\t\t\t\t\t// fast results. This fixes an issue where the user might\n\t\t\t\t\t\t\t\t// have made a pick active before the additional results\n\t\t\t\t\t\t\t\t// kick in.\n\t\t\t\t\t\t\t\t// See https://github.com/microsoft/vscode/issues/102480\n\t\t\t\t\t\t\t\tlet fallbackActivePick: Pick | undefined = undefined;\n\t\t\t\t\t\t\t\tif (!activePick && !additionalActivePick) {\n\t\t\t\t\t\t\t\t\tconst fallbackActivePickCandidate = picker.activeItems[0];\n\t\t\t\t\t\t\t\t\tif (fallbackActivePickCandidate && picks.indexOf(fallbackActivePickCandidate) !== -1) {\n\t\t\t\t\t\t\t\t\t\tfallbackActivePick = fallbackActivePickCandidate;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tapplyPicks({\n\t\t\t\t\t\t\t\t\titems: [...picks, ...additionalPicks],\n\t\t\t\t\t\t\t\t\tactive: activePick || additionalActivePick || fallbackActivePick\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} finally {\n\t\t\t\t\t\t\tif (!picksToken.isCancellationRequested) {\n\t\t\t\t\t\t\t\tpicker.busy = false;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tslowPicksApplied = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t})()\n\t\t\t\t]);\n\t\t\t};\n\n\t\t\t// No Picks\n\t\t\tif (providedPicks === null) {\n\t\t\t\t// Ignore\n\t\t\t}\n\n\t\t\t// Fast and Slow Picks\n\t\t\telse if (isFastAndSlowPicks(providedPicks)) {\n\t\t\t\tawait applyFastAndSlowPicks(providedPicks);\n\t\t\t}\n\n\t\t\t// Fast Picks\n\t\t\telse if (!(providedPicks instanceof Promise)) {\n\t\t\t\tapplyPicks(providedPicks);\n\t\t\t}\n\n\t\t\t// Slow Picks\n\t\t\telse {\n\t\t\t\tpicker.busy = true;\n\t\t\t\ttry {\n\t\t\t\t\tconst awaitedPicks = await providedPicks;\n\t\t\t\t\tif (picksToken.isCancellationRequested) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (isFastAndSlowPicks(awaitedPicks)) {\n\t\t\t\t\t\tawait applyFastAndSlowPicks(awaitedPicks);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tapplyPicks(awaitedPicks);\n\t\t\t\t\t}\n\t\t\t\t} finally {\n\t\t\t\t\tif (!picksToken.isCancellationRequested) {\n\t\t\t\t\t\tpicker.busy = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\tdisposables.add(picker.onDidChangeValue(() => updatePickerItems()));\n\t\tupdatePickerItems();\n\n\t\t// Accept the pick on accept and hide picker\n\t\tdisposables.add(picker.onDidAccept(event => {\n\t\t\tif (runOptions?.handleAccept) {\n\t\t\t\tif (!event.inBackground) {\n\t\t\t\t\tpicker.hide(); // hide picker unless we accept in background\n\t\t\t\t}\n\t\t\t\trunOptions.handleAccept?.(picker.activeItems[0]);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst [item] = picker.selectedItems;\n\t\t\tif (typeof item?.accept === 'function') {\n\t\t\t\tif (!event.inBackground) {\n\t\t\t\t\tpicker.hide(); // hide picker unless we accept in background\n\t\t\t\t}\n\n\t\t\t\titem.accept(picker.keyMods, event);\n\t\t\t}\n\t\t}));\n\n\t\tconst buttonTrigger = async (button: IQuickInputButton, item: T | IPickerQuickAccessSeparator) => {\n\t\t\tif (typeof item.trigger !== 'function') {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst buttonIndex = item.buttons?.indexOf(button) ?? -1;\n\t\t\tif (buttonIndex >= 0) {\n\t\t\t\tconst result = item.trigger(buttonIndex, picker.keyMods);\n\t\t\t\tconst action = (typeof result === 'number') ? result : await result;\n\n\t\t\t\tif (token.isCancellationRequested) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tswitch (action) {\n\t\t\t\t\tcase TriggerAction.NO_ACTION:\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase TriggerAction.CLOSE_PICKER:\n\t\t\t\t\t\tpicker.hide();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase TriggerAction.REFRESH_PICKER:\n\t\t\t\t\t\tupdatePickerItems();\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase TriggerAction.REMOVE_ITEM: {\n\t\t\t\t\t\tconst index = picker.items.indexOf(item);\n\t\t\t\t\t\tif (index !== -1) {\n\t\t\t\t\t\t\tconst items = picker.items.slice();\n\t\t\t\t\t\t\tconst removed = items.splice(index, 1);\n\t\t\t\t\t\t\tconst activeItems = picker.activeItems.filter(activeItem => activeItem !== removed[0]);\n\t\t\t\t\t\t\tconst keepScrollPositionBefore = picker.keepScrollPosition;\n\t\t\t\t\t\t\tpicker.keepScrollPosition = true;\n\t\t\t\t\t\t\tpicker.items = items;\n\t\t\t\t\t\t\tif (activeItems) {\n\t\t\t\t\t\t\t\tpicker.activeItems = activeItems;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tpicker.keepScrollPosition = keepScrollPositionBefore;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\t// Trigger the pick with button index if button triggered\n\t\tdisposables.add(picker.onDidTriggerItemButton(({ button, item }) => buttonTrigger(button, item)));\n\t\tdisposables.add(picker.onDidTriggerSeparatorButton(({ button, separator }) => buttonTrigger(button, separator)));\n\n\t\treturn disposables;\n\t}\n\n\t/**\n\t * Returns an array of picks and separators as needed. If the picks are resolved\n\t * long running, the provided cancellation token should be used to cancel the\n\t * operation when the token signals this.\n\t *\n\t * The implementor is responsible for filtering and sorting the picks given the\n\t * provided `filter`.\n\t *\n\t * @param filter a filter to apply to the picks.\n\t * @param disposables can be used to register disposables that should be cleaned\n\t * up when the picker closes.\n\t * @param token for long running tasks, implementors need to check on cancellation\n\t * through this token.\n\t * @returns the picks either directly, as promise or combined fast and slow results.\n\t * Pickers can return `null` to signal that no change in picks is needed.\n\t */\n\tprotected abstract _getPicks(filter: string, disposables: DisposableStore, token: CancellationToken, runOptions?: IQuickAccessProviderRunOptions): Picks | Promise | FastAndSlowPicks> | FastAndSlowPicks | null;\n}\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\nimport * as dom from 'vs/base/browser/dom';\nimport { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';\nimport { FindInput } from 'vs/base/browser/ui/findinput/findInput';\nimport { IInputBoxStyles, IRange, MessageType } from 'vs/base/browser/ui/inputbox/inputBox';\nimport { IToggleStyles, Toggle } from 'vs/base/browser/ui/toggle/toggle';\nimport { Disposable, IDisposable } from 'vs/base/common/lifecycle';\nimport Severity from 'vs/base/common/severity';\nimport 'vs/css!./media/quickInput';\n\nconst $ = dom.$;\n\nexport class QuickInputBox extends Disposable {\n\n\tprivate container: HTMLElement;\n\tprivate findInput: FindInput;\n\n\tconstructor(\n\t\tprivate parent: HTMLElement,\n\t\tinputBoxStyles: IInputBoxStyles,\n\t\ttoggleStyles: IToggleStyles\n\t) {\n\t\tsuper();\n\t\tthis.container = dom.append(this.parent, $('.quick-input-box'));\n\t\tthis.findInput = this._register(new FindInput(this.container, undefined, { label: '', inputBoxStyles, toggleStyles }));\n\t\tconst input = this.findInput.inputBox.inputElement;\n\t\tinput.role = 'combobox';\n\t\tinput.ariaHasPopup = 'menu';\n\t\tinput.ariaAutoComplete = 'list';\n\t\tinput.ariaExpanded = 'true';\n\t}\n\n\tonKeyDown = (handler: (event: StandardKeyboardEvent) => void): IDisposable => {\n\t\treturn dom.addStandardDisposableListener(this.findInput.inputBox.inputElement, dom.EventType.KEY_DOWN, handler);\n\t};\n\n\tonDidChange = (handler: (event: string) => void): IDisposable => {\n\t\treturn this.findInput.onDidChange(handler);\n\t};\n\n\tget value() {\n\t\treturn this.findInput.getValue();\n\t}\n\n\tset value(value: string) {\n\t\tthis.findInput.setValue(value);\n\t}\n\n\tselect(range: IRange | null = null): void {\n\t\tthis.findInput.inputBox.select(range);\n\t}\n\n\tgetSelection(): IRange | null {\n\t\treturn this.findInput.inputBox.getSelection();\n\t}\n\n\tisSelectionAtEnd(): boolean {\n\t\treturn this.findInput.inputBox.isSelectionAtEnd();\n\t}\n\n\tget placeholder() {\n\t\treturn this.findInput.inputBox.inputElement.getAttribute('placeholder') || '';\n\t}\n\n\tset placeholder(placeholder: string) {\n\t\tthis.findInput.inputBox.setPlaceHolder(placeholder);\n\t}\n\n\tget password() {\n\t\treturn this.findInput.inputBox.inputElement.type === 'password';\n\t}\n\n\tset password(password: boolean) {\n\t\tthis.findInput.inputBox.inputElement.type = password ? 'password' : 'text';\n\t}\n\n\tset enabled(enabled: boolean) {\n\t\t// We can't disable the input box because it is still used for\n\t\t// navigating the list. Instead, we disable the list and the OK\n\t\t// so that nothing can be selected.\n\t\t// TODO: should this be what we do for all find inputs? Or maybe some _other_ API\n\t\t// on findInput to change it to readonly?\n\t\tthis.findInput.inputBox.inputElement.toggleAttribute('readonly', !enabled);\n\t\t// TODO: styles of the quick pick need to be moved to the CSS instead of being in line\n\t\t// so things like this can be done in CSS\n\t\t// this.findInput.inputBox.inputElement.classList.toggle('disabled', !enabled);\n\t}\n\n\tset toggles(toggles: Toggle[] | undefined) {\n\t\tthis.findInput.setAdditionalToggles(toggles);\n\t}\n\n\tsetAttribute(name: string, value: string): void {\n\t\tthis.findInput.inputBox.inputElement.setAttribute(name, value);\n\t}\n\n\tshowDecoration(decoration: Severity): void {\n\t\tif (decoration === Severity.Ignore) {\n\t\t\tthis.findInput.clearMessage();\n\t\t} else {\n\t\t\tthis.findInput.showMessage({ type: decoration === Severity.Info ? MessageType.INFO : decoration === Severity.Warning ? MessageType.WARNING : MessageType.ERROR, content: '' });\n\t\t}\n\t}\n\n\tstylesForType(decoration: Severity) {\n\t\treturn this.findInput.inputBox.stylesForType(decoration === Severity.Info ? MessageType.INFO : decoration === Severity.Warning ? MessageType.WARNING : MessageType.ERROR);\n\t}\n\n\tsetFocus(): void {\n\t\tthis.findInput.focus();\n\t}\n\n\tlayout(): void {\n\t\tthis.findInput.inputBox.layout();\n\t}\n}\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\nimport * as dom from 'vs/base/browser/dom';\nimport { DomEmitter } from 'vs/base/browser/event';\nimport { Event } from 'vs/base/common/event';\nimport { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';\nimport { Gesture, EventType as GestureEventType } from 'vs/base/browser/touch';\nimport { renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels';\nimport { IdGenerator } from 'vs/base/common/idGenerator';\nimport { KeyCode } from 'vs/base/common/keyCodes';\nimport { parseLinkedText } from 'vs/base/common/linkedText';\nimport { URI } from 'vs/base/common/uri';\nimport 'vs/css!./media/quickInput';\nimport { localize } from 'vs/nls';\nimport { DisposableStore } from 'vs/base/common/lifecycle';\nimport { IQuickInputButton } from 'vs/platform/quickinput/common/quickInput';\nimport { IAction } from 'vs/base/common/actions';\n\nconst iconPathToClass: Record = {};\nconst iconClassGenerator = new IdGenerator('quick-input-button-icon-');\n\nfunction getIconClass(iconPath: { dark: URI; light?: URI } | undefined): string | undefined {\n\tif (!iconPath) {\n\t\treturn undefined;\n\t}\n\tlet iconClass: string;\n\n\tconst key = iconPath.dark.toString();\n\tif (iconPathToClass[key]) {\n\t\ticonClass = iconPathToClass[key];\n\t} else {\n\t\ticonClass = iconClassGenerator.nextId();\n\t\tdom.createCSSRule(`.${iconClass}, .hc-light .${iconClass}`, `background-image: ${dom.asCSSUrl(iconPath.light || iconPath.dark)}`);\n\t\tdom.createCSSRule(`.vs-dark .${iconClass}, .hc-black .${iconClass}`, `background-image: ${dom.asCSSUrl(iconPath.dark)}`);\n\t\ticonPathToClass[key] = iconClass;\n\t}\n\n\treturn iconClass;\n}\n\nexport function quickInputButtonToAction(button: IQuickInputButton, id: string, run: () => unknown): IAction {\n\tlet cssClasses = button.iconClass || getIconClass(button.iconPath);\n\tif (button.alwaysVisible) {\n\t\tcssClasses = cssClasses ? `${cssClasses} always-visible` : 'always-visible';\n\t}\n\n\treturn {\n\t\tid,\n\t\tlabel: '',\n\t\ttooltip: button.tooltip || '',\n\t\tclass: cssClasses,\n\t\tenabled: true,\n\t\trun\n\t};\n}\n\nexport function renderQuickInputDescription(description: string, container: HTMLElement, actionHandler: { callback: (content: string) => void; disposables: DisposableStore }) {\n\tdom.reset(container);\n\tconst parsed = parseLinkedText(description);\n\tlet tabIndex = 0;\n\tfor (const node of parsed.nodes) {\n\t\tif (typeof node === 'string') {\n\t\t\tcontainer.append(...renderLabelWithIcons(node));\n\t\t} else {\n\t\t\tlet title = node.title;\n\n\t\t\tif (!title && node.href.startsWith('command:')) {\n\t\t\t\ttitle = localize('executeCommand', \"Click to execute command '{0}'\", node.href.substring('command:'.length));\n\t\t\t} else if (!title) {\n\t\t\t\ttitle = node.href;\n\t\t\t}\n\n\t\t\tconst anchor = dom.$('a', { href: node.href, title, tabIndex: tabIndex++ }, node.label);\n\t\t\tanchor.style.textDecoration = 'underline';\n\t\t\tconst handleOpen = (e: unknown) => {\n\t\t\t\tif (dom.isEventLike(e)) {\n\t\t\t\t\tdom.EventHelper.stop(e, true);\n\t\t\t\t}\n\n\t\t\t\tactionHandler.callback(node.href);\n\t\t\t};\n\n\t\t\tconst onClick = actionHandler.disposables.add(new DomEmitter(anchor, dom.EventType.CLICK)).event;\n\t\t\tconst onKeydown = actionHandler.disposables.add(new DomEmitter(anchor, dom.EventType.KEY_DOWN)).event;\n\t\t\tconst onSpaceOrEnter = Event.chain(onKeydown, $ => $.filter(e => {\n\t\t\t\tconst event = new StandardKeyboardEvent(e);\n\n\t\t\t\treturn event.equals(KeyCode.Space) || event.equals(KeyCode.Enter);\n\t\t\t}));\n\n\t\t\tactionHandler.disposables.add(Gesture.addTarget(anchor));\n\t\t\tconst onTap = actionHandler.disposables.add(new DomEmitter(anchor, GestureEventType.Tap)).event;\n\n\t\t\tEvent.any(onClick, onTap, onSpaceOrEnter)(handleOpen, null, actionHandler.disposables);\n\t\t\tcontainer.appendChild(anchor);\n\t\t}\n\t}\n}\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\nimport { CancellationToken } from 'vs/base/common/cancellation';\nimport { Event } from 'vs/base/common/event';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\nimport { IQuickAccessController } from 'vs/platform/quickinput/common/quickAccess';\nimport { IMatch } from 'vs/base/common/filters';\nimport { IItemAccessor } from 'vs/base/common/fuzzyScorer';\nimport { ResolvedKeybinding } from 'vs/base/common/keybindings';\nimport { IDisposable } from 'vs/base/common/lifecycle';\nimport { URI } from 'vs/base/common/uri';\nimport { IMarkdownString } from 'vs/base/common/htmlContent';\n\nexport interface IQuickPickItemHighlights {\n\tlabel?: IMatch[];\n\tdescription?: IMatch[];\n\tdetail?: IMatch[];\n}\n\nexport type QuickPickItem = IQuickPickSeparator | IQuickPickItem;\n\nexport interface IQuickPickItem {\n\ttype?: 'item';\n\tlabel: string;\n\tariaLabel?: string;\n\tdescription?: string;\n\tdetail?: string;\n\ttooltip?: string | IMarkdownString;\n\t/**\n\t * Allows to show a keybinding next to the item to indicate\n\t * how the item can be triggered outside of the picker using\n\t * keyboard shortcut.\n\t */\n\tkeybinding?: ResolvedKeybinding;\n\ticonClasses?: readonly string[];\n\ticonPath?: { dark: URI; light?: URI };\n\ticonClass?: string;\n\titalic?: boolean;\n\tstrikethrough?: boolean;\n\thighlights?: IQuickPickItemHighlights;\n\tbuttons?: readonly IQuickInputButton[];\n\tpicked?: boolean;\n\t/**\n\t * Used when we're in multi-select mode. Renders a disabled checkbox.\n\t */\n\tdisabled?: boolean;\n\talwaysShow?: boolean;\n}\n\nexport interface IQuickPickSeparator {\n\ttype: 'separator';\n\tlabel?: string;\n\tdescription?: string;\n\tariaLabel?: string;\n\tbuttons?: readonly IQuickInputButton[];\n\ttooltip?: string | IMarkdownString;\n}\n\nexport interface IKeyMods {\n\treadonly ctrlCmd: boolean;\n\treadonly alt: boolean;\n}\n\nexport const NO_KEY_MODS: IKeyMods = { ctrlCmd: false, alt: false };\n\nexport interface IQuickNavigateConfiguration {\n\tkeybindings: readonly ResolvedKeybinding[];\n}\n\nexport interface IPickOptions {\n\n\t/**\n\t * an optional string to show as the title of the quick input\n\t */\n\ttitle?: string;\n\n\t/**\n\t * an optional string to show as placeholder in the input box to guide the user what she picks on\n\t */\n\tplaceHolder?: string;\n\n\t/**\n\t * an optional flag to include the description when filtering the picks\n\t */\n\tmatchOnDescription?: boolean;\n\n\t/**\n\t * an optional flag to include the detail when filtering the picks\n\t */\n\tmatchOnDetail?: boolean;\n\n\t/**\n\t * an optional flag to filter the picks based on label. Defaults to true.\n\t */\n\tmatchOnLabel?: boolean;\n\n\t/**\n\t * an optional flag to not close the picker on focus lost\n\t */\n\tignoreFocusLost?: boolean;\n\n\t/**\n\t * an optional flag to make this picker multi-select\n\t */\n\tcanPickMany?: boolean;\n\n\t/**\n\t * enables quick navigate in the picker to open an element without typing\n\t */\n\tquickNavigate?: IQuickNavigateConfiguration;\n\n\t/**\n\t * Hides the input box from the picker UI. This is typically used\n\t * in combination with quick-navigation where no search UI should\n\t * be presented.\n\t */\n\thideInput?: boolean;\n\n\t/**\n\t * a context key to set when this picker is active\n\t */\n\tcontextKey?: string;\n\n\t/**\n\t * an optional property for the item to focus initially.\n\t */\n\tactiveItem?: Promise | T;\n\n\tonKeyMods?: (keyMods: IKeyMods) => void;\n\tonDidFocus?: (entry: T) => void;\n\tonDidTriggerItemButton?: (context: IQuickPickItemButtonContext) => void;\n\tonDidTriggerSeparatorButton?: (context: IQuickPickSeparatorButtonEvent) => void;\n}\n\nexport enum QuickInputHideReason {\n\n\t/**\n\t * Focus moved away from the quick input.\n\t */\n\tBlur = 1,\n\n\t/**\n\t * An explicit user gesture, e.g. pressing Escape key.\n\t */\n\tGesture,\n\n\t/**\n\t * Anything else.\n\t */\n\tOther\n}\n\nexport interface IQuickInputHideEvent {\n\treason: QuickInputHideReason;\n}\n\n/**\n * A collection of the different types of QuickInput\n */\nexport const enum QuickInputType {\n\tQuickPick = 'quickPick',\n\tInputBox = 'inputBox',\n\tQuickWidget = 'quickWidget'\n}\n\n/**\n * Represents a quick input control that allows users to make selections or provide input quickly.\n */\nexport interface IQuickInput extends IDisposable {\n\n\t/**\n\t * The type of the quick input.\n\t */\n\treadonly type: QuickInputType;\n\n\t/**\n\t * An event that is fired when the quick input is hidden.\n\t */\n\treadonly onDidHide: Event;\n\n\t/**\n\t * The title of the quick input.\n\t */\n\ttitle: string | undefined;\n\n\t/**\n\t * The context key associated with the quick input.\n\t */\n\tcontextKey: string | undefined;\n\n\t/**\n\t * Indicates whether the quick input is busy. Renders a progress bar if true.\n\t */\n\tbusy: boolean;\n\n\t/**\n\t * Indicates whether the quick input should be hidden when it loses focus.\n\t */\n\tignoreFocusOut: boolean;\n\n\t/**\n\t * Shows the quick input.\n\t */\n\tshow(): void;\n\n\t/**\n\t * Hides the quick input.\n\t */\n\thide(): void;\n\n\t/**\n\t * Notifies that the quick input has been hidden.\n\t * @param reason The reason why the quick input was hidden.\n\t */\n\tdidHide(reason?: QuickInputHideReason): void;\n\n\t/**\n\t * Notifies that the quick input will be hidden.\n\t * @param reason The reason why the quick input will be hidden.\n\t */\n\twillHide(reason?: QuickInputHideReason): void;\n}\n\nexport interface IQuickPickWillAcceptEvent {\n\n\t/**\n\t * Allows to disable the default accept handling\n\t * of the picker. If `veto` is called, the picker\n\t * will not trigger the `onDidAccept` event.\n\t */\n\tveto(): void;\n}\n\nexport interface IQuickPickDidAcceptEvent {\n\n\t/**\n\t * Signals if the picker item is to be accepted\n\t * in the background while keeping the picker open.\n\t */\n\tinBackground: boolean;\n}\n\n/**\n * Represents the activation behavior for items in a quick input. This means which item will be\n * \"active\" (aka focused).\n */\nexport enum ItemActivation {\n\t/**\n\t * No item will be active.\n\t */\n\tNONE,\n\t/**\n\t * First item will be active.\n\t */\n\tFIRST,\n\t/**\n\t * Second item will be active.\n\t */\n\tSECOND,\n\t/**\n\t * Last item will be active.\n\t */\n\tLAST\n}\n\n/**\n * Represents the focus options for a quick pick.\n */\nexport enum QuickPickFocus {\n\t/**\n\t * Focus the first item in the list.\n\t */\n\tFirst = 1,\n\t/**\n\t * Focus the second item in the list.\n\t */\n\tSecond,\n\t/**\n\t * Focus the last item in the list.\n\t */\n\tLast,\n\t/**\n\t * Focus the next item in the list.\n\t */\n\tNext,\n\t/**\n\t * Focus the previous item in the list.\n\t */\n\tPrevious,\n\t/**\n\t * Focus the next page in the list.\n\t */\n\tNextPage,\n\t/**\n\t * Focus the previous page in the list.\n\t */\n\tPreviousPage,\n\t/**\n\t * Focus the first item under the next separator.\n\t */\n\tNextSeparator,\n\t/**\n\t * Focus the first item under the current separator.\n\t */\n\tPreviousSeparator\n}\n\n/**\n * Represents a quick pick control that allows the user to select an item from a list of options.\n */\nexport interface IQuickPick extends IQuickInput {\n\n\t/**\n\t * The current value of the quick pick input.\n\t */\n\tvalue: string;\n\n\t/**\n\t * A method that allows to massage the value used for filtering, e.g, to remove certain parts.\n\t * @param value The value to be filtered.\n\t * @returns The filtered value.\n\t */\n\tfilterValue: (value: string) => string;\n\n\t/**\n\t * The ARIA label for the quick pick input.\n\t */\n\tariaLabel: string | undefined;\n\n\t/**\n\t * The placeholder text for the quick pick input.\n\t */\n\tplaceholder: string | undefined;\n\n\t/**\n\t * An event that is fired when the value of the quick pick input changes.\n\t */\n\treadonly onDidChangeValue: Event;\n\n\t/**\n\t * An event that is fired when the quick pick is about to accept the selected item.\n\t */\n\treadonly onWillAccept: Event;\n\n\t/**\n\t * An event that is fired when the quick pick has accepted the selected item.\n\t */\n\treadonly onDidAccept: Event;\n\n\t/**\n\t * If enabled, the `onDidAccept` event will be fired when pressing the arrow-right key to accept the selected item without closing the picker.\n\t */\n\tcanAcceptInBackground: boolean;\n\n\t/**\n\t * An event that is fired when an item button is triggered.\n\t */\n\treadonly onDidTriggerItemButton: Event>;\n\n\t/**\n\t * An event that is fired when a separator button is triggered.\n\t */\n\treadonly onDidTriggerSeparatorButton: Event;\n\n\t/**\n\t * The items to be displayed in the quick pick.\n\t */\n\titems: ReadonlyArray;\n\n\t/**\n\t * Whether multiple items can be selected. If so, checkboxes will be rendered.\n\t */\n\tcanSelectMany: boolean;\n\n\t/**\n\t * Whether to match on the description of the items.\n\t */\n\tmatchOnDescription: boolean;\n\n\t/**\n\t * Whether to match on the detail of the items.\n\t */\n\tmatchOnDetail: boolean;\n\n\t/**\n\t * Whether to match on the label of the items.\n\t */\n\tmatchOnLabel: boolean;\n\n\t/**\n\t * Whether to sort the items by label.\n\t */\n\tsortByLabel: boolean;\n\n\t/**\n\t * Whether to keep the scroll position when the quick pick input is updated.\n\t */\n\tkeepScrollPosition: boolean;\n\n\t/**\n\t * The configuration for quick navigation.\n\t */\n\tquickNavigate: IQuickNavigateConfiguration | undefined;\n\n\t/**\n\t * The currently active items.\n\t */\n\tactiveItems: ReadonlyArray;\n\n\t/**\n\t * An event that is fired when the active items change.\n\t */\n\treadonly onDidChangeActive: Event;\n\n\t/**\n\t * The item activation behavior for the next time `items` is set. Item activation means which\n\t * item is \"active\" (aka focused) when the quick pick is opened or when `items` is set.\n\t */\n\titemActivation: ItemActivation;\n\n\t/**\n\t * The currently selected items.\n\t */\n\tselectedItems: ReadonlyArray;\n\n\t/**\n\t * An event that is fired when the selected items change.\n\t */\n\treadonly onDidChangeSelection: Event;\n\n\t/**\n\t * The key modifiers.\n\t */\n\treadonly keyMods: IKeyMods;\n\n\t/**\n\t * The selection range for the value in the input.\n\t */\n\tvalueSelection: Readonly<[number, number]> | undefined;\n\n\t/**\n\t * Hides the input box from the picker UI. This is typically used in combination with quick-navigation where no search UI should be presented.\n\t */\n\thideInput: boolean;\n\n\t/**\n\t * Focus a particular item in the list. Used internally for keyboard navigation.\n\t * @param focus The focus behavior.\n\t */\n\tfocus(focus: QuickPickFocus): void;\n\n\t/**\n\t * Programmatically accepts an item. Used internally for keyboard navigation.\n\t * @param inBackground Whether you are accepting an item in the background and keeping the picker open.\n\t */\n\taccept(inBackground?: boolean): void;\n}\n\n/**\n * Represents a toggle for quick input.\n */\nexport interface IQuickInputToggle {\n}\n\n/**\n * Represents an input box in a quick input dialog.\n */\nexport interface IInputBox extends IQuickInput {\n\n\t/**\n\t * Value shown in the input box.\n\t */\n\tvalue: string;\n\n\t/**\n\t * Value shown as example for input.\n\t */\n\tplaceholder: string | undefined;\n\n\t/**\n\t * Event called when the input value changes.\n\t */\n\treadonly onDidChangeValue: Event;\n\n\t/**\n\t * Event called when the user submits the input.\n\t */\n\treadonly onDidAccept: Event;\n\n\t/**\n\t * An optional validation message indicating a problem with the current input value.\n\t * Returning undefined clears the validation message.\n\t */\n\tvalidationMessage: string | undefined;\n}\n\n/**\n * Represents a button in the quick input UI.\n */\nexport interface IQuickInputButton {\n\t/**\n\t * The path to the icon for the button.\n\t * Either `iconPath` or `iconClass` is required.\n\t */\n\ticonPath?: { dark: URI; light?: URI };\n\t/**\n\t * The CSS class for the icon of the button.\n\t * Either `iconPath` or `iconClass` is required.\n\t */\n\ticonClass?: string;\n\t/**\n\t * The tooltip text for the button.\n\t */\n\ttooltip?: string;\n\t/**\n\t * Whether to always show the button.\n\t * By default, buttons are only visible when hovering over them with the mouse.\n\t */\n\talwaysVisible?: boolean;\n}\n\n/**\n * Represents an event that occurs when a button associated with a quick pick item is clicked.\n * @template T - The type of the quick pick item.\n */\nexport interface IQuickPickItemButtonEvent {\n\t/**\n\t * The button that was clicked.\n\t */\n\tbutton: IQuickInputButton;\n\t/**\n\t * The quick pick item associated with the button.\n\t */\n\titem: T;\n}\n\n/**\n * Represents an event that occurs when a separator button is clicked in a quick pick.\n */\nexport interface IQuickPickSeparatorButtonEvent {\n\t/**\n\t * The button that was clicked.\n\t */\n\tbutton: IQuickInputButton;\n\t/**\n\t * The separator associated with the button.\n\t */\n\tseparator: IQuickPickSeparator;\n}\n\n/**\n * Represents a context for a button associated with a quick pick item.\n * @template T - The type of the quick pick item.\n */\nexport interface IQuickPickItemButtonContext extends IQuickPickItemButtonEvent {\n\t/**\n\t * Removes the associated item from the quick pick.\n\t */\n\tremoveItem(): void;\n}\n\nexport type QuickPickInput = T | IQuickPickSeparator;\n\n\n//#region Fuzzy Scorer Support\n\nexport type IQuickPickItemWithResource = IQuickPickItem & { resource?: URI };\n\nexport class QuickPickItemScorerAccessor implements IItemAccessor {\n\n\tconstructor(private options?: { skipDescription?: boolean; skipPath?: boolean }) { }\n}\n\nexport const quickPickItemScorerAccessor = new QuickPickItemScorerAccessor();\n\n//#endregion\n\nexport const IQuickInputService = createDecorator('quickInputService');\n\nexport type Omit = Pick>;\n\nexport interface IQuickInputService {\n\n\treadonly _serviceBrand: undefined;\n\n\t/**\n\t * Provides access to the quick access providers.\n\t */\n\treadonly quickAccess: IQuickAccessController;\n\n\t/**\n\t * Opens the quick input box for selecting items and returns a promise\n\t * with the user selected item(s) if any.\n\t */\n\tpick(picks: Promise[]> | QuickPickInput[], options?: IPickOptions & { canPickMany: true }, token?: CancellationToken): Promise;\n\tpick(picks: Promise[]> | QuickPickInput[], options?: IPickOptions & { canPickMany: false }, token?: CancellationToken): Promise;\n\tpick(picks: Promise[]> | QuickPickInput[], options?: Omit, 'canPickMany'>, token?: CancellationToken): Promise;\n\n\t/**\n\t * Provides raw access to the quick pick controller.\n\t */\n\tcreateQuickPick(): IQuickPick;\n\n\t/**\n\t * Provides raw access to the input box controller.\n\t */\n\tcreateInputBox(): IInputBox;\n\n\t/**\n\t * The current quick pick that is visible. Undefined if none is open.\n\t */\n\tcurrentQuickInput: IQuickInput | undefined;\n}\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\nimport * as dom from 'vs/base/browser/dom';\nimport { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';\nimport { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';\nimport { Button, IButtonStyles } from 'vs/base/browser/ui/button/button';\nimport { CountBadge, ICountBadgeStyles } from 'vs/base/browser/ui/countBadge/countBadge';\nimport { IHoverDelegate, IHoverDelegateOptions } from 'vs/base/browser/ui/hover/hoverDelegate';\nimport { IInputBoxStyles } from 'vs/base/browser/ui/inputbox/inputBox';\nimport { IKeybindingLabelStyles } from 'vs/base/browser/ui/keybindingLabel/keybindingLabel';\nimport { IListStyles } from 'vs/base/browser/ui/list/listWidget';\nimport { IProgressBarStyles, ProgressBar } from 'vs/base/browser/ui/progressbar/progressbar';\nimport { IToggleStyles, Toggle } from 'vs/base/browser/ui/toggle/toggle';\nimport { equals } from 'vs/base/common/arrays';\nimport { TimeoutTimer } from 'vs/base/common/async';\nimport { Codicon } from 'vs/base/common/codicons';\nimport { Emitter, Event, EventBufferer } from 'vs/base/common/event';\nimport { KeyCode } from 'vs/base/common/keyCodes';\nimport { Disposable, DisposableStore } from 'vs/base/common/lifecycle';\nimport { isIOS } from 'vs/base/common/platform';\nimport Severity from 'vs/base/common/severity';\nimport { ThemeIcon } from 'vs/base/common/themables';\nimport 'vs/css!./media/quickInput';\nimport { localize } from 'vs/nls';\nimport { IInputBox, IKeyMods, IQuickInput, IQuickInputButton, IQuickInputHideEvent, IQuickInputToggle, IQuickNavigateConfiguration, IQuickPick, IQuickPickDidAcceptEvent, IQuickPickItem, IQuickPickItemButtonEvent, IQuickPickSeparator, IQuickPickSeparatorButtonEvent, IQuickPickWillAcceptEvent, ItemActivation, NO_KEY_MODS, QuickInputHideReason, QuickInputType } from 'vs/platform/quickinput/common/quickInput';\nimport { QuickInputBox } from './quickInputBox';\nimport { quickInputButtonToAction, renderQuickInputDescription } from './quickInputUtils';\nimport { IConfigurationService } from 'vs/platform/configuration/common/configuration';\nimport { IHoverService, WorkbenchHoverDelegate } from 'vs/platform/hover/browser/hover';\nimport { QuickInputTree } from 'vs/platform/quickinput/browser/quickInputTree';\nimport { QuickPickFocus } from '../common/quickInput';\nimport { IHoverOptions } from 'vs/base/browser/ui/hover/hover';\nimport { ContextKeyExpr, RawContextKey } from 'vs/platform/contextkey/common/contextkey';\n\nexport const inQuickInputContextKeyValue = 'inQuickInput';\nexport const InQuickInputContextKey = new RawContextKey(inQuickInputContextKeyValue, false, localize('inQuickInput', \"Whether keyboard focus is inside the quick input control\"));\nexport const inQuickInputContext = ContextKeyExpr.has(inQuickInputContextKeyValue);\n\nexport const quickInputTypeContextKeyValue = 'quickInputType';\nexport const QuickInputTypeContextKey = new RawContextKey(quickInputTypeContextKeyValue, undefined, localize('quickInputType', \"The type of the currently visible quick input\"));\n\nexport const endOfQuickInputBoxContextKeyValue = 'cursorAtEndOfQuickInputBox';\nexport const EndOfQuickInputBoxContextKey = new RawContextKey(endOfQuickInputBoxContextKeyValue, false, localize('cursorAtEndOfQuickInputBox', \"Whether the cursor in the quick input is at the end of the input box\"));\nexport const endOfQuickInputBoxContext = ContextKeyExpr.has(endOfQuickInputBoxContextKeyValue);\n\nexport interface IQuickInputOptions {\n\tidPrefix: string;\n\tcontainer: HTMLElement;\n\tignoreFocusOut(): boolean;\n\tbackKeybindingLabel(): string | undefined;\n\tsetContextKey(id?: string): void;\n\tlinkOpenerDelegate(content: string): void;\n\treturnFocus(): void;\n\t/**\n\t * @todo With IHover in vs/editor, can we depend on the service directly\n\t * instead of passing it through a hover delegate?\n\t */\n\thoverDelegate: IHoverDelegate;\n\tstyles: IQuickInputStyles;\n}\n\nexport interface IQuickInputStyles {\n\treadonly widget: IQuickInputWidgetStyles;\n\treadonly inputBox: IInputBoxStyles;\n\treadonly toggle: IToggleStyles;\n\treadonly countBadge: ICountBadgeStyles;\n\treadonly button: IButtonStyles;\n\treadonly progressBar: IProgressBarStyles;\n\treadonly keybindingLabel: IKeybindingLabelStyles;\n\treadonly list: IListStyles;\n\treadonly pickerGroup: { pickerGroupBorder: string | undefined; pickerGroupForeground: string | undefined };\n}\n\nexport interface IQuickInputWidgetStyles {\n\treadonly quickInputBackground: string | undefined;\n\treadonly quickInputForeground: string | undefined;\n\treadonly quickInputTitleBackground: string | undefined;\n\treadonly widgetBorder: string | undefined;\n\treadonly widgetShadow: string | undefined;\n}\n\nexport type Writeable = { -readonly [P in keyof T]: T[P] };\n\nexport const backButton = {\n\ticonClass: ThemeIcon.asClassName(Codicon.quickInputBack),\n\ttooltip: localize('quickInput.back', \"Back\"),\n\thandle: -1 // TODO\n};\n\nexport interface QuickInputUI {\n\tcontainer: HTMLElement;\n\tstyleSheet: HTMLStyleElement;\n\tleftActionBar: ActionBar;\n\ttitleBar: HTMLElement;\n\ttitle: HTMLElement;\n\tdescription1: HTMLElement;\n\tdescription2: HTMLElement;\n\twidget: HTMLElement;\n\trightActionBar: ActionBar;\n\tcheckAll: HTMLInputElement;\n\tinputContainer: HTMLElement;\n\tfilterContainer: HTMLElement;\n\tinputBox: QuickInputBox;\n\tvisibleCountContainer: HTMLElement;\n\tvisibleCount: CountBadge;\n\tcountContainer: HTMLElement;\n\tcount: CountBadge;\n\tokContainer: HTMLElement;\n\tok: Button;\n\tmessage: HTMLElement;\n\tcustomButtonContainer: HTMLElement;\n\tcustomButton: Button;\n\tprogressBar: ProgressBar;\n\tlist: QuickInputTree;\n\tonDidAccept: Event;\n\tonDidCustom: Event;\n\tonDidTriggerButton: Event;\n\tignoreFocusOut: boolean;\n\tkeyMods: Writeable;\n\tshow(controller: QuickInput): void;\n\tsetVisibilities(visibilities: Visibilities): void;\n\tsetEnabled(enabled: boolean): void;\n\tsetContextKey(contextKey?: string): void;\n\tlinkOpenerDelegate(content: string): void;\n\thide(): void;\n}\n\nexport type Visibilities = {\n\ttitle?: boolean;\n\tdescription?: boolean;\n\tcheckAll?: boolean;\n\tinputBox?: boolean;\n\tcheckBox?: boolean;\n\tvisibleCount?: boolean;\n\tcount?: boolean;\n\tmessage?: boolean;\n\tlist?: boolean;\n\tok?: boolean;\n\tcustomButton?: boolean;\n\tprogressBar?: boolean;\n};\n\nabstract class QuickInput extends Disposable implements IQuickInput {\n\tprotected static readonly noPromptMessage = localize('inputModeEntry', \"Press 'Enter' to confirm your input or 'Escape' to cancel\");\n\n\tprivate _title: string | undefined;\n\tprivate _description: string | undefined;\n\tprivate _widget: HTMLElement | undefined;\n\tprivate _widgetUpdated = false;\n\tprivate _steps: number | undefined;\n\tprivate _totalSteps: number | undefined;\n\tprotected visible = false;\n\tprivate _enabled = true;\n\tprivate _contextKey: string | undefined;\n\tprivate _busy = false;\n\tprivate _ignoreFocusOut = false;\n\tprivate _buttons: IQuickInputButton[] = [];\n\tprivate buttonsUpdated = false;\n\tprivate _toggles: IQuickInputToggle[] = [];\n\tprivate togglesUpdated = false;\n\tprotected noValidationMessage = QuickInput.noPromptMessage;\n\tprivate _validationMessage: string | undefined;\n\tprivate _lastValidationMessage: string | undefined;\n\tprivate _severity: Severity = Severity.Ignore;\n\tprivate _lastSeverity: Severity | undefined;\n\tprivate readonly onDidTriggerButtonEmitter = this._register(new Emitter());\n\tprivate readonly onDidHideEmitter = this._register(new Emitter());\n\tprivate readonly onWillHideEmitter = this._register(new Emitter());\n\tprivate readonly onDisposeEmitter = this._register(new Emitter());\n\n\tprotected readonly visibleDisposables = this._register(new DisposableStore());\n\n\tprivate busyDelay: TimeoutTimer | undefined;\n\n\tabstract type: QuickInputType;\n\n\tconstructor(\n\t\tprotected ui: QuickInputUI\n\t) {\n\t\tsuper();\n\t}\n\n\tget title() {\n\t\treturn this._title;\n\t}\n\n\tset title(title: string | undefined) {\n\t\tthis._title = title;\n\t\tthis.update();\n\t}\n\n\tget description() {\n\t\treturn this._description;\n\t}\n\n\tset description(description: string | undefined) {\n\t\tthis._description = description;\n\t\tthis.update();\n\t}\n\n\tget step() {\n\t\treturn this._steps;\n\t}\n\n\tset step(step: number | undefined) {\n\t\tthis._steps = step;\n\t\tthis.update();\n\t}\n\n\tget totalSteps() {\n\t\treturn this._totalSteps;\n\t}\n\n\tset totalSteps(totalSteps: number | undefined) {\n\t\tthis._totalSteps = totalSteps;\n\t\tthis.update();\n\t}\n\n\tget enabled() {\n\t\treturn this._enabled;\n\t}\n\n\tset enabled(enabled: boolean) {\n\t\tthis._enabled = enabled;\n\t\tthis.update();\n\t}\n\n\tget contextKey() {\n\t\treturn this._contextKey;\n\t}\n\n\tset contextKey(contextKey: string | undefined) {\n\t\tthis._contextKey = contextKey;\n\t\tthis.update();\n\t}\n\n\tget busy() {\n\t\treturn this._busy;\n\t}\n\n\tset busy(busy: boolean) {\n\t\tthis._busy = busy;\n\t\tthis.update();\n\t}\n\n\tget ignoreFocusOut() {\n\t\treturn this._ignoreFocusOut;\n\t}\n\n\tset ignoreFocusOut(ignoreFocusOut: boolean) {\n\t\tconst shouldUpdate = this._ignoreFocusOut !== ignoreFocusOut && !isIOS;\n\t\tthis._ignoreFocusOut = ignoreFocusOut && !isIOS;\n\t\tif (shouldUpdate) {\n\t\t\tthis.update();\n\t\t}\n\t}\n\n\tget buttons() {\n\t\treturn this._buttons;\n\t}\n\n\tset buttons(buttons: IQuickInputButton[]) {\n\t\tthis._buttons = buttons;\n\t\tthis.buttonsUpdated = true;\n\t\tthis.update();\n\t}\n\n\tget toggles() {\n\t\treturn this._toggles;\n\t}\n\n\tset toggles(toggles: IQuickInputToggle[]) {\n\t\tthis._toggles = toggles ?? [];\n\t\tthis.togglesUpdated = true;\n\t\tthis.update();\n\t}\n\n\tget validationMessage() {\n\t\treturn this._validationMessage;\n\t}\n\n\tset validationMessage(validationMessage: string | undefined) {\n\t\tthis._validationMessage = validationMessage;\n\t\tthis.update();\n\t}\n\n\tget severity() {\n\t\treturn this._severity;\n\t}\n\n\tset severity(severity: Severity) {\n\t\tthis._severity = severity;\n\t\tthis.update();\n\t}\n\n\tshow(): void {\n\t\tif (this.visible) {\n\t\t\treturn;\n\t\t}\n\t\tthis.visibleDisposables.add(\n\t\t\tthis.ui.onDidTriggerButton(button => {\n\t\t\t\tif (this.buttons.indexOf(button) !== -1) {\n\t\t\t\t\tthis.onDidTriggerButtonEmitter.fire(button);\n\t\t\t\t}\n\t\t\t}),\n\t\t);\n\t\tthis.ui.show(this);\n\n\t\t// update properties in the controller that get reset in the ui.show() call\n\t\tthis.visible = true;\n\t\t// This ensures the message/prompt gets rendered\n\t\tthis._lastValidationMessage = undefined;\n\t\t// This ensures the input box has the right severity applied\n\t\tthis._lastSeverity = undefined;\n\t\tif (this.buttons.length) {\n\t\t\t// if there are buttons, the ui.show() clears them out of the UI so we should\n\t\t\t// rerender them.\n\t\t\tthis.buttonsUpdated = true;\n\t\t}\n\t\tif (this.toggles.length) {\n\t\t\t// if there are toggles, the ui.show() clears them out of the UI so we should\n\t\t\t// rerender them.\n\t\t\tthis.togglesUpdated = true;\n\t\t}\n\n\t\tthis.update();\n\t}\n\n\thide(): void {\n\t\tif (!this.visible) {\n\t\t\treturn;\n\t\t}\n\t\tthis.ui.hide();\n\t}\n\n\tdidHide(reason = QuickInputHideReason.Other): void {\n\t\tthis.visible = false;\n\t\tthis.visibleDisposables.clear();\n\t\tthis.onDidHideEmitter.fire({ reason });\n\t}\n\n\treadonly onDidHide = this.onDidHideEmitter.event;\n\n\twillHide(reason = QuickInputHideReason.Other): void {\n\t\tthis.onWillHideEmitter.fire({ reason });\n\t}\n\n\tprotected update() {\n\t\tif (!this.visible) {\n\t\t\treturn;\n\t\t}\n\t\tconst title = this.getTitle();\n\t\tif (title && this.ui.title.textContent !== title) {\n\t\t\tthis.ui.title.textContent = title;\n\t\t} else if (!title && this.ui.title.innerHTML !== ' ') {\n\t\t\tthis.ui.title.innerText = '\\u00a0';\n\t\t}\n\t\tconst description = this.getDescription();\n\t\tif (this.ui.description1.textContent !== description) {\n\t\t\tthis.ui.description1.textContent = description;\n\t\t}\n\t\tif (this.ui.description2.textContent !== description) {\n\t\t\tthis.ui.description2.textContent = description;\n\t\t}\n\t\tif (this._widgetUpdated) {\n\t\t\tthis._widgetUpdated = false;\n\t\t\tif (this._widget) {\n\t\t\t\tdom.reset(this.ui.widget, this._widget);\n\t\t\t} else {\n\t\t\t\tdom.reset(this.ui.widget);\n\t\t\t}\n\t\t}\n\t\tif (this.busy && !this.busyDelay) {\n\t\t\tthis.busyDelay = new TimeoutTimer();\n\t\t\tthis.busyDelay.setIfNotSet(() => {\n\t\t\t\tif (this.visible) {\n\t\t\t\t\tthis.ui.progressBar.infinite();\n\t\t\t\t}\n\t\t\t}, 800);\n\t\t}\n\t\tif (!this.busy && this.busyDelay) {\n\t\t\tthis.ui.progressBar.stop();\n\t\t\tthis.busyDelay.cancel();\n\t\t\tthis.busyDelay = undefined;\n\t\t}\n\t\tif (this.buttonsUpdated) {\n\t\t\tthis.buttonsUpdated = false;\n\t\t\tthis.ui.leftActionBar.clear();\n\t\t\tconst leftButtons = this.buttons\n\t\t\t\t.filter(button => button === backButton)\n\t\t\t\t.map((button, index) => quickInputButtonToAction(\n\t\t\t\t\tbutton,\n\t\t\t\t\t`id-${index}`,\n\t\t\t\t\tasync () => this.onDidTriggerButtonEmitter.fire(button)\n\t\t\t\t));\n\t\t\tthis.ui.leftActionBar.push(leftButtons, { icon: true, label: false });\n\t\t\tthis.ui.rightActionBar.clear();\n\t\t\tconst rightButtons = this.buttons\n\t\t\t\t.filter(button => button !== backButton)\n\t\t\t\t.map((button, index) => quickInputButtonToAction(\n\t\t\t\t\tbutton,\n\t\t\t\t\t`id-${index}`,\n\t\t\t\t\tasync () => this.onDidTriggerButtonEmitter.fire(button)\n\t\t\t\t));\n\t\t\tthis.ui.rightActionBar.push(rightButtons, { icon: true, label: false });\n\t\t}\n\t\tif (this.togglesUpdated) {\n\t\t\tthis.togglesUpdated = false;\n\t\t\t// HACK: Filter out toggles here that are not concrete Toggle objects. This is to workaround\n\t\t\t// a layering issue as quick input's interface is in common but Toggle is in browser and\n\t\t\t// it requires a HTMLElement on its interface\n\t\t\tconst concreteToggles = this.toggles?.filter(opts => opts instanceof Toggle) as Toggle[] ?? [];\n\t\t\tthis.ui.inputBox.toggles = concreteToggles;\n\t\t}\n\t\tthis.ui.ignoreFocusOut = this.ignoreFocusOut;\n\t\tthis.ui.setEnabled(this.enabled);\n\t\tthis.ui.setContextKey(this.contextKey);\n\n\t\tconst validationMessage = this.validationMessage || this.noValidationMessage;\n\t\tif (this._lastValidationMessage !== validationMessage) {\n\t\t\tthis._lastValidationMessage = validationMessage;\n\t\t\tdom.reset(this.ui.message);\n\t\t\trenderQuickInputDescription(validationMessage, this.ui.message, {\n\t\t\t\tcallback: (content) => {\n\t\t\t\t\tthis.ui.linkOpenerDelegate(content);\n\t\t\t\t},\n\t\t\t\tdisposables: this.visibleDisposables,\n\t\t\t});\n\t\t}\n\t\tif (this._lastSeverity !== this.severity) {\n\t\t\tthis._lastSeverity = this.severity;\n\t\t\tthis.showMessageDecoration(this.severity);\n\t\t}\n\t}\n\n\tprivate getTitle() {\n\t\tif (this.title && this.step) {\n\t\t\treturn `${this.title} (${this.getSteps()})`;\n\t\t}\n\t\tif (this.title) {\n\t\t\treturn this.title;\n\t\t}\n\t\tif (this.step) {\n\t\t\treturn this.getSteps();\n\t\t}\n\t\treturn '';\n\t}\n\n\tprivate getDescription() {\n\t\treturn this.description || '';\n\t}\n\n\tprivate getSteps() {\n\t\tif (this.step && this.totalSteps) {\n\t\t\treturn localize('quickInput.steps', \"{0}/{1}\", this.step, this.totalSteps);\n\t\t}\n\t\tif (this.step) {\n\t\t\treturn String(this.step);\n\t\t}\n\t\treturn '';\n\t}\n\n\tprotected showMessageDecoration(severity: Severity) {\n\t\tthis.ui.inputBox.showDecoration(severity);\n\t\tif (severity !== Severity.Ignore) {\n\t\t\tconst styles = this.ui.inputBox.stylesForType(severity);\n\t\t\tthis.ui.message.style.color = styles.foreground ? `${styles.foreground}` : '';\n\t\t\tthis.ui.message.style.backgroundColor = styles.background ? `${styles.background}` : '';\n\t\t\tthis.ui.message.style.border = styles.border ? `1px solid ${styles.border}` : '';\n\t\t\tthis.ui.message.style.marginBottom = '-2px';\n\t\t} else {\n\t\t\tthis.ui.message.style.color = '';\n\t\t\tthis.ui.message.style.backgroundColor = '';\n\t\t\tthis.ui.message.style.border = '';\n\t\t\tthis.ui.message.style.marginBottom = '';\n\t\t}\n\t}\n\n\toverride dispose(): void {\n\t\tthis.hide();\n\t\tthis.onDisposeEmitter.fire();\n\n\t\tsuper.dispose();\n\t}\n}\n\nexport class QuickPick extends QuickInput implements IQuickPick {\n\n\tprivate static readonly DEFAULT_ARIA_LABEL = localize('quickInputBox.ariaLabel', \"Type to narrow down results.\");\n\n\tprivate _value = '';\n\tprivate _ariaLabel: string | undefined;\n\tprivate _placeholder: string | undefined;\n\tprivate readonly onDidChangeValueEmitter = this._register(new Emitter());\n\tprivate readonly onWillAcceptEmitter = this._register(new Emitter());\n\tprivate readonly onDidAcceptEmitter = this._register(new Emitter());\n\tprivate readonly onDidCustomEmitter = this._register(new Emitter());\n\tprivate _items: Array = [];\n\tprivate itemsUpdated = false;\n\tprivate _canSelectMany = false;\n\tprivate _canAcceptInBackground = false;\n\tprivate _matchOnDescription = false;\n\tprivate _matchOnDetail = false;\n\tprivate _matchOnLabel = true;\n\tprivate _matchOnLabelMode: 'fuzzy' | 'contiguous' = 'fuzzy';\n\tprivate _sortByLabel = true;\n\tprivate _keepScrollPosition = false;\n\tprivate _itemActivation = ItemActivation.FIRST;\n\tprivate _activeItems: T[] = [];\n\tprivate activeItemsUpdated = false;\n\tprivate activeItemsToConfirm: T[] | null = [];\n\tprivate readonly onDidChangeActiveEmitter = this._register(new Emitter());\n\tprivate _selectedItems: T[] = [];\n\tprivate selectedItemsUpdated = false;\n\tprivate selectedItemsToConfirm: T[] | null = [];\n\tprivate readonly onDidChangeSelectionEmitter = this._register(new Emitter());\n\tprivate readonly onDidTriggerItemButtonEmitter = this._register(new Emitter>());\n\tprivate readonly onDidTriggerSeparatorButtonEmitter = this._register(new Emitter());\n\tprivate _valueSelection: Readonly<[number, number]> | undefined;\n\tprivate valueSelectionUpdated = true;\n\tprivate _ok: boolean | 'default' = 'default';\n\tprivate _customButton = false;\n\tprivate _customButtonLabel: string | undefined;\n\tprivate _customButtonHover: string | undefined;\n\tprivate _quickNavigate: IQuickNavigateConfiguration | undefined;\n\tprivate _hideInput: boolean | undefined;\n\tprivate _hideCountBadge: boolean | undefined;\n\tprivate _hideCheckAll: boolean | undefined;\n\tprivate _focusEventBufferer = new EventBufferer();\n\n\treadonly type = QuickInputType.QuickPick;\n\n\tget quickNavigate() {\n\t\treturn this._quickNavigate;\n\t}\n\n\tset quickNavigate(quickNavigate: IQuickNavigateConfiguration | undefined) {\n\t\tthis._quickNavigate = quickNavigate;\n\t\tthis.update();\n\t}\n\n\tget value() {\n\t\treturn this._value;\n\t}\n\n\tset value(value: string) {\n\t\tthis.doSetValue(value);\n\t}\n\n\tprivate doSetValue(value: string, skipUpdate?: boolean): void {\n\t\tif (this._value !== value) {\n\t\t\tthis._value = value;\n\t\t\tif (!skipUpdate) {\n\t\t\t\tthis.update();\n\t\t\t}\n\t\t\tif (this.visible) {\n\t\t\t\tconst didFilter = this.ui.list.filter(this.filterValue(this._value));\n\t\t\t\tif (didFilter) {\n\t\t\t\t\tthis.trySelectFirst();\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.onDidChangeValueEmitter.fire(this._value);\n\t\t}\n\t}\n\n\tfilterValue = (value: string) => value;\n\n\tset ariaLabel(ariaLabel: string | undefined) {\n\t\tthis._ariaLabel = ariaLabel;\n\t\tthis.update();\n\t}\n\n\tget ariaLabel() {\n\t\treturn this._ariaLabel;\n\t}\n\n\tget placeholder() {\n\t\treturn this._placeholder;\n\t}\n\n\tset placeholder(placeholder: string | undefined) {\n\t\tthis._placeholder = placeholder;\n\t\tthis.update();\n\t}\n\n\tonDidChangeValue = this.onDidChangeValueEmitter.event;\n\n\tonWillAccept = this.onWillAcceptEmitter.event;\n\tonDidAccept = this.onDidAcceptEmitter.event;\n\n\tget items() {\n\t\treturn this._items;\n\t}\n\n\tget scrollTop() {\n\t\treturn this.ui.list.scrollTop;\n\t}\n\n\tprivate set scrollTop(scrollTop: number) {\n\t\tthis.ui.list.scrollTop = scrollTop;\n\t}\n\n\tset items(items: Array) {\n\t\tthis._items = items;\n\t\tthis.itemsUpdated = true;\n\t\tthis.update();\n\t}\n\n\tget canSelectMany() {\n\t\treturn this._canSelectMany;\n\t}\n\n\tset canSelectMany(canSelectMany: boolean) {\n\t\tthis._canSelectMany = canSelectMany;\n\t\tthis.update();\n\t}\n\n\tget canAcceptInBackground() {\n\t\treturn this._canAcceptInBackground;\n\t}\n\n\tset canAcceptInBackground(canAcceptInBackground: boolean) {\n\t\tthis._canAcceptInBackground = canAcceptInBackground;\n\t}\n\n\tget matchOnDescription() {\n\t\treturn this._matchOnDescription;\n\t}\n\n\tset matchOnDescription(matchOnDescription: boolean) {\n\t\tthis._matchOnDescription = matchOnDescription;\n\t\tthis.update();\n\t}\n\n\tget matchOnDetail() {\n\t\treturn this._matchOnDetail;\n\t}\n\n\tset matchOnDetail(matchOnDetail: boolean) {\n\t\tthis._matchOnDetail = matchOnDetail;\n\t\tthis.update();\n\t}\n\n\tget matchOnLabel() {\n\t\treturn this._matchOnLabel;\n\t}\n\n\tset matchOnLabel(matchOnLabel: boolean) {\n\t\tthis._matchOnLabel = matchOnLabel;\n\t\tthis.update();\n\t}\n\n\tget matchOnLabelMode() {\n\t\treturn this._matchOnLabelMode;\n\t}\n\n\tset matchOnLabelMode(matchOnLabelMode: 'fuzzy' | 'contiguous') {\n\t\tthis._matchOnLabelMode = matchOnLabelMode;\n\t\tthis.update();\n\t}\n\n\tget sortByLabel() {\n\t\treturn this._sortByLabel;\n\t}\n\n\tset sortByLabel(sortByLabel: boolean) {\n\t\tthis._sortByLabel = sortByLabel;\n\t\tthis.update();\n\t}\n\n\tget keepScrollPosition() {\n\t\treturn this._keepScrollPosition;\n\t}\n\n\tset keepScrollPosition(keepScrollPosition: boolean) {\n\t\tthis._keepScrollPosition = keepScrollPosition;\n\t}\n\n\tget itemActivation() {\n\t\treturn this._itemActivation;\n\t}\n\n\tset itemActivation(itemActivation: ItemActivation) {\n\t\tthis._itemActivation = itemActivation;\n\t}\n\n\tget activeItems() {\n\t\treturn this._activeItems;\n\t}\n\n\tset activeItems(activeItems: T[]) {\n\t\tthis._activeItems = activeItems;\n\t\tthis.activeItemsUpdated = true;\n\t\tthis.update();\n\t}\n\n\tonDidChangeActive = this.onDidChangeActiveEmitter.event;\n\n\tget selectedItems() {\n\t\treturn this._selectedItems;\n\t}\n\n\tset selectedItems(selectedItems: T[]) {\n\t\tthis._selectedItems = selectedItems;\n\t\tthis.selectedItemsUpdated = true;\n\t\tthis.update();\n\t}\n\n\tget keyMods() {\n\t\tif (this._quickNavigate) {\n\t\t\t// Disable keyMods when quick navigate is enabled\n\t\t\t// because in this model the interaction is purely\n\t\t\t// keyboard driven and Ctrl/Alt are typically\n\t\t\t// pressed and hold during this interaction.\n\t\t\treturn NO_KEY_MODS;\n\t\t}\n\t\treturn this.ui.keyMods;\n\t}\n\n\tget valueSelection() {\n\t\tconst selection = this.ui.inputBox.getSelection();\n\t\tif (!selection) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn [selection.start, selection.end];\n\t}\n\n\tset valueSelection(valueSelection: Readonly<[number, number]> | undefined) {\n\t\tthis._valueSelection = valueSelection;\n\t\tthis.valueSelectionUpdated = true;\n\t\tthis.update();\n\t}\n\n\tget customButton() {\n\t\treturn this._customButton;\n\t}\n\n\tset customButton(showCustomButton: boolean) {\n\t\tthis._customButton = showCustomButton;\n\t\tthis.update();\n\t}\n\n\tget customLabel() {\n\t\treturn this._customButtonLabel;\n\t}\n\n\tset customLabel(label: string | undefined) {\n\t\tthis._customButtonLabel = label;\n\t\tthis.update();\n\t}\n\n\tget customHover() {\n\t\treturn this._customButtonHover;\n\t}\n\n\tset customHover(hover: string | undefined) {\n\t\tthis._customButtonHover = hover;\n\t\tthis.update();\n\t}\n\n\tget ok() {\n\t\treturn this._ok;\n\t}\n\n\tset ok(showOkButton: boolean | 'default') {\n\t\tthis._ok = showOkButton;\n\t\tthis.update();\n\t}\n\n\tget hideInput() {\n\t\treturn !!this._hideInput;\n\t}\n\n\tset hideInput(hideInput: boolean) {\n\t\tthis._hideInput = hideInput;\n\t\tthis.update();\n\t}\n\n\tonDidChangeSelection = this.onDidChangeSelectionEmitter.event;\n\n\tonDidTriggerItemButton = this.onDidTriggerItemButtonEmitter.event;\n\n\tonDidTriggerSeparatorButton = this.onDidTriggerSeparatorButtonEmitter.event;\n\n\tprivate trySelectFirst() {\n\t\tif (!this.canSelectMany) {\n\t\t\tthis.ui.list.focus(QuickPickFocus.First);\n\t\t}\n\t}\n\n\toverride show() {\n\t\tif (!this.visible) {\n\t\t\tthis.visibleDisposables.add(\n\t\t\t\tthis.ui.inputBox.onDidChange(value => {\n\t\t\t\t\tthis.doSetValue(value, true /* skip update since this originates from the UI */);\n\t\t\t\t}));\n\t\t\tthis.visibleDisposables.add(this.ui.onDidAccept(() => {\n\t\t\t\tif (this.canSelectMany) {\n\t\t\t\t\t// if there are no checked elements, it means that an onDidChangeSelection never fired to overwrite\n\t\t\t\t\t// `_selectedItems`. In that case, we should emit one with an empty array to ensure that\n\t\t\t\t\t// `.selectedItems` is up to date.\n\t\t\t\t\tif (!this.ui.list.getCheckedElements().length) {\n\t\t\t\t\t\tthis._selectedItems = [];\n\t\t\t\t\t\tthis.onDidChangeSelectionEmitter.fire(this.selectedItems);\n\t\t\t\t\t}\n\t\t\t\t} else if (this.activeItems[0]) {\n\t\t\t\t\t// For single-select, we set `selectedItems` to the item that was accepted.\n\t\t\t\t\tthis._selectedItems = [this.activeItems[0]];\n\t\t\t\t\tthis.onDidChangeSelectionEmitter.fire(this.selectedItems);\n\t\t\t\t}\n\t\t\t\tthis.handleAccept(false);\n\t\t\t}));\n\t\t\tthis.visibleDisposables.add(this.ui.onDidCustom(() => {\n\t\t\t\tthis.onDidCustomEmitter.fire();\n\t\t\t}));\n\t\t\tthis.visibleDisposables.add(this._focusEventBufferer.wrapEvent(\n\t\t\t\tthis.ui.list.onDidChangeFocus,\n\t\t\t\t// Only fire the last event\n\t\t\t\t(_, e) => e\n\t\t\t)(focusedItems => {\n\t\t\t\tif (this.activeItemsUpdated) {\n\t\t\t\t\treturn; // Expect another event.\n\t\t\t\t}\n\t\t\t\tif (this.activeItemsToConfirm !== this._activeItems && equals(focusedItems, this._activeItems, (a, b) => a === b)) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tthis._activeItems = focusedItems as T[];\n\t\t\t\tthis.onDidChangeActiveEmitter.fire(focusedItems as T[]);\n\t\t\t}));\n\t\t\tthis.visibleDisposables.add(this.ui.list.onDidChangeSelection(({ items: selectedItems, event }) => {\n\t\t\t\tif (this.canSelectMany) {\n\t\t\t\t\tif (selectedItems.length) {\n\t\t\t\t\t\tthis.ui.list.setSelectedElements([]);\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (this.selectedItemsToConfirm !== this._selectedItems && equals(selectedItems, this._selectedItems, (a, b) => a === b)) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tthis._selectedItems = selectedItems as T[];\n\t\t\t\tthis.onDidChangeSelectionEmitter.fire(selectedItems as T[]);\n\t\t\t\tif (selectedItems.length) {\n\t\t\t\t\tthis.handleAccept(dom.isMouseEvent(event) && event.button === 1 /* mouse middle click */);\n\t\t\t\t}\n\t\t\t}));\n\t\t\tthis.visibleDisposables.add(this.ui.list.onChangedCheckedElements(checkedItems => {\n\t\t\t\tif (!this.canSelectMany) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (this.selectedItemsToConfirm !== this._selectedItems && equals(checkedItems, this._selectedItems, (a, b) => a === b)) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tthis._selectedItems = checkedItems as T[];\n\t\t\t\tthis.onDidChangeSelectionEmitter.fire(checkedItems as T[]);\n\t\t\t}));\n\t\t\tthis.visibleDisposables.add(this.ui.list.onButtonTriggered(event => this.onDidTriggerItemButtonEmitter.fire(event as IQuickPickItemButtonEvent)));\n\t\t\tthis.visibleDisposables.add(this.ui.list.onSeparatorButtonTriggered(event => this.onDidTriggerSeparatorButtonEmitter.fire(event)));\n\t\t\tthis.visibleDisposables.add(this.registerQuickNavigation());\n\t\t\tthis.valueSelectionUpdated = true;\n\t\t}\n\t\tsuper.show(); // TODO: Why have show() bubble up while update() trickles down?\n\t}\n\n\tprivate handleAccept(inBackground: boolean): void {\n\n\t\t// Figure out veto via `onWillAccept` event\n\t\tlet veto = false;\n\t\tthis.onWillAcceptEmitter.fire({ veto: () => veto = true });\n\n\t\t// Continue with `onDidAccept` if no veto\n\t\tif (!veto) {\n\t\t\tthis.onDidAcceptEmitter.fire({ inBackground });\n\t\t}\n\t}\n\n\tprivate registerQuickNavigation() {\n\t\treturn dom.addDisposableListener(this.ui.container, dom.EventType.KEY_UP, e => {\n\t\t\tif (this.canSelectMany || !this._quickNavigate) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst keyboardEvent: StandardKeyboardEvent = new StandardKeyboardEvent(e);\n\t\t\tconst keyCode = keyboardEvent.keyCode;\n\n\t\t\t// Select element when keys are pressed that signal it\n\t\t\tconst quickNavKeys = this._quickNavigate.keybindings;\n\t\t\tconst wasTriggerKeyPressed = quickNavKeys.some(k => {\n\t\t\t\tconst chords = k.getChords();\n\t\t\t\tif (chords.length > 1) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tif (chords[0].shiftKey && keyCode === KeyCode.Shift) {\n\t\t\t\t\tif (keyboardEvent.ctrlKey || keyboardEvent.altKey || keyboardEvent.metaKey) {\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\n\t\t\t\t\t}\n\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tif (chords[0].altKey && keyCode === KeyCode.Alt) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tif (chords[0].ctrlKey && keyCode === KeyCode.Ctrl) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tif (chords[0].metaKey && keyCode === KeyCode.Meta) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\treturn false;\n\t\t\t});\n\n\t\t\tif (wasTriggerKeyPressed) {\n\t\t\t\tif (this.activeItems[0]) {\n\t\t\t\t\tthis._selectedItems = [this.activeItems[0]];\n\t\t\t\t\tthis.onDidChangeSelectionEmitter.fire(this.selectedItems);\n\t\t\t\t\tthis.handleAccept(false);\n\t\t\t\t}\n\t\t\t\t// Unset quick navigate after press. It is only valid once\n\t\t\t\t// and should not result in any behaviour change afterwards\n\t\t\t\t// if the picker remains open because there was no active item\n\t\t\t\tthis._quickNavigate = undefined;\n\t\t\t}\n\t\t});\n\t}\n\n\tprotected override update() {\n\t\tif (!this.visible) {\n\t\t\treturn;\n\t\t}\n\t\t// store the scrollTop before it is reset\n\t\tconst scrollTopBefore = this.keepScrollPosition ? this.scrollTop : 0;\n\t\tconst hasDescription = !!this.description;\n\t\tconst visibilities: Visibilities = {\n\t\t\ttitle: !!this.title || !!this.step || !!this.buttons.length,\n\t\t\tdescription: hasDescription,\n\t\t\tcheckAll: this.canSelectMany && !this._hideCheckAll,\n\t\t\tcheckBox: this.canSelectMany,\n\t\t\tinputBox: !this._hideInput,\n\t\t\tprogressBar: !this._hideInput || hasDescription,\n\t\t\tvisibleCount: true,\n\t\t\tcount: this.canSelectMany && !this._hideCountBadge,\n\t\t\tok: this.ok === 'default' ? this.canSelectMany : this.ok,\n\t\t\tlist: true,\n\t\t\tmessage: !!this.validationMessage,\n\t\t\tcustomButton: this.customButton\n\t\t};\n\t\tthis.ui.setVisibilities(visibilities);\n\t\tsuper.update();\n\t\tif (this.ui.inputBox.value !== this.value) {\n\t\t\tthis.ui.inputBox.value = this.value;\n\t\t}\n\t\tif (this.valueSelectionUpdated) {\n\t\t\tthis.valueSelectionUpdated = false;\n\t\t\tthis.ui.inputBox.select(this._valueSelection && { start: this._valueSelection[0], end: this._valueSelection[1] });\n\t\t}\n\t\tif (this.ui.inputBox.placeholder !== (this.placeholder || '')) {\n\t\t\tthis.ui.inputBox.placeholder = (this.placeholder || '');\n\t\t}\n\n\t\tlet ariaLabel = this.ariaLabel;\n\t\t// Only set aria label to the input box placeholder if we actually have an input box.\n\t\tif (!ariaLabel && visibilities.inputBox) {\n\t\t\tariaLabel = this.placeholder || QuickPick.DEFAULT_ARIA_LABEL;\n\t\t\t// If we have a title, include it in the aria label.\n\t\t\tif (this.title) {\n\t\t\t\tariaLabel += ` - ${this.title}`;\n\t\t\t}\n\t\t}\n\t\tif (this.ui.list.ariaLabel !== ariaLabel) {\n\t\t\tthis.ui.list.ariaLabel = ariaLabel ?? null;\n\t\t}\n\t\tthis.ui.list.matchOnDescription = this.matchOnDescription;\n\t\tthis.ui.list.matchOnDetail = this.matchOnDetail;\n\t\tthis.ui.list.matchOnLabel = this.matchOnLabel;\n\t\tthis.ui.list.matchOnLabelMode = this.matchOnLabelMode;\n\t\tthis.ui.list.sortByLabel = this.sortByLabel;\n\t\tif (this.itemsUpdated) {\n\t\t\tthis.itemsUpdated = false;\n\t\t\tthis._focusEventBufferer.bufferEvents(() => {\n\t\t\t\tthis.ui.list.setElements(this.items);\n\t\t\t\t// We want focus to exist in the list if there are items so that space can be used to toggle\n\t\t\t\tthis.ui.list.shouldLoop = !this.canSelectMany;\n\t\t\t\tthis.ui.list.filter(this.filterValue(this.ui.inputBox.value));\n\t\t\t\tthis.ui.checkAll.checked = this.ui.list.getAllVisibleChecked();\n\t\t\t\tthis.ui.visibleCount.setCount(this.ui.list.getVisibleCount());\n\t\t\t\tthis.ui.count.setCount(this.ui.list.getCheckedCount());\n\t\t\t\tswitch (this._itemActivation) {\n\t\t\t\t\tcase ItemActivation.NONE:\n\t\t\t\t\t\tthis._itemActivation = ItemActivation.FIRST; // only valid once, then unset\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase ItemActivation.SECOND:\n\t\t\t\t\t\tthis.ui.list.focus(QuickPickFocus.Second);\n\t\t\t\t\t\tthis._itemActivation = ItemActivation.FIRST; // only valid once, then unset\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase ItemActivation.LAST:\n\t\t\t\t\t\tthis.ui.list.focus(QuickPickFocus.Last);\n\t\t\t\t\t\tthis._itemActivation = ItemActivation.FIRST; // only valid once, then unset\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tthis.trySelectFirst();\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t\tif (this.ui.container.classList.contains('show-checkboxes') !== !!this.canSelectMany) {\n\t\t\tif (this.canSelectMany) {\n\t\t\t\tthis.ui.list.clearFocus();\n\t\t\t} else {\n\t\t\t\tthis.trySelectFirst();\n\t\t\t}\n\t\t}\n\t\tif (this.activeItemsUpdated) {\n\t\t\tthis.activeItemsUpdated = false;\n\t\t\tthis.activeItemsToConfirm = this._activeItems;\n\t\t\tthis.ui.list.setFocusedElements(this.activeItems);\n\t\t\tif (this.activeItemsToConfirm === this._activeItems) {\n\t\t\t\tthis.activeItemsToConfirm = null;\n\t\t\t}\n\t\t}\n\t\tif (this.selectedItemsUpdated) {\n\t\t\tthis.selectedItemsUpdated = false;\n\t\t\tthis.selectedItemsToConfirm = this._selectedItems;\n\t\t\tif (this.canSelectMany) {\n\t\t\t\tthis.ui.list.setCheckedElements(this.selectedItems);\n\t\t\t} else {\n\t\t\t\tthis.ui.list.setSelectedElements(this.selectedItems);\n\t\t\t}\n\t\t\tif (this.selectedItemsToConfirm === this._selectedItems) {\n\t\t\t\tthis.selectedItemsToConfirm = null;\n\t\t\t}\n\t\t}\n\t\tthis.ui.customButton.label = this.customLabel || '';\n\t\tthis.ui.customButton.element.title = this.customHover || '';\n\t\tif (!visibilities.inputBox) {\n\t\t\t// we need to move focus into the tree to detect keybindings\n\t\t\t// properly when the input box is not visible (quick nav)\n\t\t\tthis.ui.list.domFocus();\n\n\t\t\t// Focus the first element in the list if multiselect is enabled\n\t\t\tif (this.canSelectMany) {\n\t\t\t\tthis.ui.list.focus(QuickPickFocus.First);\n\t\t\t}\n\t\t}\n\n\t\t// Set the scroll position to what it was before updating the items\n\t\tif (this.keepScrollPosition) {\n\t\t\tthis.scrollTop = scrollTopBefore;\n\t\t}\n\t}\n\n\tfocus(focus: QuickPickFocus): void {\n\t\tthis.ui.list.focus(focus);\n\t\t// To allow things like space to check/uncheck items\n\t\tif (this.canSelectMany) {\n\t\t\tthis.ui.list.domFocus();\n\t\t}\n\t}\n\n\taccept(inBackground?: boolean | undefined): void {\n\t\tif (inBackground && !this._canAcceptInBackground) {\n\t\t\treturn; // needs to be enabled\n\t\t}\n\n\t\tif (this.activeItems[0]) {\n\t\t\tthis._selectedItems = [this.activeItems[0]];\n\t\t\tthis.onDidChangeSelectionEmitter.fire(this.selectedItems);\n\t\t\tthis.handleAccept(inBackground ?? false);\n\t\t}\n\t}\n}\n\nexport class InputBox extends QuickInput implements IInputBox {\n\tprivate _value = '';\n\tprivate _valueSelection: Readonly<[number, number]> | undefined;\n\tprivate valueSelectionUpdated = true;\n\tprivate _placeholder: string | undefined;\n\tprivate _password = false;\n\tprivate readonly onDidValueChangeEmitter = this._register(new Emitter());\n\tprivate readonly onDidAcceptEmitter = this._register(new Emitter());\n\n\treadonly type = QuickInputType.InputBox;\n\n\tget value() {\n\t\treturn this._value;\n\t}\n\n\tset value(value: string) {\n\t\tthis._value = value || '';\n\t\tthis.update();\n\t}\n\n\tget placeholder() {\n\t\treturn this._placeholder;\n\t}\n\n\tset placeholder(placeholder: string | undefined) {\n\t\tthis._placeholder = placeholder;\n\t\tthis.update();\n\t}\n\n\tget password() {\n\t\treturn this._password;\n\t}\n\n\tset password(password: boolean) {\n\t\tthis._password = password;\n\t\tthis.update();\n\t}\n\n\treadonly onDidChangeValue = this.onDidValueChangeEmitter.event;\n\n\treadonly onDidAccept = this.onDidAcceptEmitter.event;\n\n\toverride show() {\n\t\tif (!this.visible) {\n\t\t\tthis.visibleDisposables.add(\n\t\t\t\tthis.ui.inputBox.onDidChange(value => {\n\t\t\t\t\tif (value === this.value) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tthis._value = value;\n\t\t\t\t\tthis.onDidValueChangeEmitter.fire(value);\n\t\t\t\t}));\n\t\t\tthis.visibleDisposables.add(this.ui.onDidAccept(() => this.onDidAcceptEmitter.fire()));\n\t\t\tthis.valueSelectionUpdated = true;\n\t\t}\n\t\tsuper.show();\n\t}\n\n\tprotected override update() {\n\t\tif (!this.visible) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.ui.container.classList.remove('hidden-input');\n\t\tconst visibilities: Visibilities = {\n\t\t\ttitle: !!this.title || !!this.step || !!this.buttons.length,\n\t\t\tdescription: !!this.description || !!this.step,\n\t\t\tinputBox: true,\n\t\t\tmessage: true,\n\t\t\tprogressBar: true\n\t\t};\n\n\t\tthis.ui.setVisibilities(visibilities);\n\t\tsuper.update();\n\t\tif (this.ui.inputBox.value !== this.value) {\n\t\t\tthis.ui.inputBox.value = this.value;\n\t\t}\n\t\tif (this.valueSelectionUpdated) {\n\t\t\tthis.valueSelectionUpdated = false;\n\t\t\tthis.ui.inputBox.select(this._valueSelection && { start: this._valueSelection[0], end: this._valueSelection[1] });\n\t\t}\n\t\tif (this.ui.inputBox.placeholder !== (this.placeholder || '')) {\n\t\t\tthis.ui.inputBox.placeholder = (this.placeholder || '');\n\t\t}\n\t\tif (this.ui.inputBox.password !== this.password) {\n\t\t\tthis.ui.inputBox.password = this.password;\n\t\t}\n\t}\n}\n\nexport class QuickInputHoverDelegate extends WorkbenchHoverDelegate {\n\n\tconstructor(\n\t\t@IConfigurationService configurationService: IConfigurationService,\n\t\t@IHoverService hoverService: IHoverService\n\t) {\n\t\tsuper('element', false, (options) => this.getOverrideOptions(options), configurationService, hoverService);\n\t}\n\n\tprivate getOverrideOptions(options: IHoverDelegateOptions): Partial {\n\t\t// Only show the hover hint if the content is of a decent size\n\t\tconst showHoverHint = (\n\t\t\toptions.content instanceof HTMLElement\n\t\t\t\t? options.content.textContent ?? ''\n\t\t\t\t: typeof options.content === 'string'\n\t\t\t\t\t? options.content\n\t\t\t\t\t: options.content.value\n\t\t).includes('\\n');\n\n\t\treturn {\n\t\t\tpersistence: {\n\t\t\t\thideOnKeyDown: false,\n\t\t\t},\n\t\t\tappearance: {\n\t\t\t\tshowHoverHint,\n\t\t\t\tskipFadeInAnimation: true,\n\t\t\t},\n\t\t};\n\t}\n}\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\nimport * as Assert from 'vs/base/common/assert';\nimport * as Types from 'vs/base/common/types';\n\nexport interface IRegistry {\n\n\t/**\n\t * Adds the extension functions and properties defined by data to the\n\t * platform. The provided id must be unique.\n\t * @param id a unique identifier\n\t * @param data a contribution\n\t */\n\tadd(id: string, data: any): void;\n\n\t/**\n\t * Returns the extension functions and properties defined by the specified key or null.\n\t * @param id an extension identifier\n\t */\n\tas(id: string): T;\n}\n\nclass RegistryImpl implements IRegistry {\n\n\tprivate readonly data = new Map();\n\n\tpublic add(id: string, data: any): void {\n\t\tAssert.ok(Types.isString(id));\n\t\tAssert.ok(Types.isObject(data));\n\t\tAssert.ok(!this.data.has(id), 'There is already an extension with this id');\n\n\t\tthis.data.set(id, data);\n\t}\n\n\tpublic as(id: string): any {\n\t\treturn this.data.get(id) || null;\n\t}\n}\n\nexport const Registry: IRegistry = new RegistryImpl();\n","\nimport { Registry } from 'vs/platform/registry/common/platform';\n\nexport interface FileAdditionalNativeProperties {\n\t/**\n\t * The real path to the file on the users filesystem. Only available on electron.\n\t */\n\treadonly path?: string;\n}\n\n\n//#region Editor / Resources DND\n\nexport const CodeDataTransfers = {\n\tEDITORS: 'CodeEditors',\n\tFILES: 'CodeFiles'\n};\n\nexport interface IDragAndDropContributionRegistry {\n}\n\nclass DragAndDropContributionRegistry implements IDragAndDropContributionRegistry {\n}\n\nexport const Extensions = {\n\tDragAndDropContribution: 'workbench.contributions.dragAndDrop'\n};\n\nRegistry.add(Extensions.DragAndDropContribution, new DragAndDropContributionRegistry());\n\n//#endregion\n\n//#region DND Utilities\n\n/**\n * A singleton to store transfer data during drag & drop operations that are only valid within the application.\n */\nexport class LocalSelectionTransfer {\n\n\tprivate static readonly INSTANCE = new LocalSelectionTransfer();\n\n\tprivate data?: T[];\n\tprivate proto?: T;\n\n\tprivate constructor() {\n\t\t// protect against external instantiation\n\t}\n\n\tstatic getInstance(): LocalSelectionTransfer {\n\t\treturn LocalSelectionTransfer.INSTANCE as LocalSelectionTransfer;\n\t}\n\n\thasData(proto: T): boolean {\n\t\treturn proto && proto === this.proto;\n\t}\n\n\tgetData(proto: T): T[] | undefined {\n\t\tif (this.hasData(proto)) {\n\t\t\treturn this.data;\n\t\t}\n\n\t\treturn undefined;\n\t}\n}\n\n//#endregion\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\nimport { DataTransfers } from 'vs/base/browser/dnd';\nimport { createFileDataTransferItem, createStringDataTransferItem, IDataTransferItem, UriList, VSDataTransfer } from 'vs/base/common/dataTransfer';\nimport { Mimes } from 'vs/base/common/mime';\nimport { URI } from 'vs/base/common/uri';\nimport { CodeDataTransfers, FileAdditionalNativeProperties } from 'vs/platform/dnd/browser/dnd';\n\n\nexport function toVSDataTransfer(dataTransfer: DataTransfer) {\n\tconst vsDataTransfer = new VSDataTransfer();\n\tfor (const item of dataTransfer.items) {\n\t\tconst type = item.type;\n\t\tif (item.kind === 'string') {\n\t\t\tconst asStringValue = new Promise(resolve => item.getAsString(resolve));\n\t\t\tvsDataTransfer.append(type, createStringDataTransferItem(asStringValue));\n\t\t} else if (item.kind === 'file') {\n\t\t\tconst file = item.getAsFile();\n\t\t\tif (file) {\n\t\t\t\tvsDataTransfer.append(type, createFileDataTransferItemFromFile(file));\n\t\t\t}\n\t\t}\n\t}\n\treturn vsDataTransfer;\n}\n\nfunction createFileDataTransferItemFromFile(file: File): IDataTransferItem {\n\tconst uri = (file as FileAdditionalNativeProperties).path ? URI.parse((file as FileAdditionalNativeProperties).path!) : undefined;\n\treturn createFileDataTransferItem(file.name, uri, async () => {\n\t\treturn new Uint8Array(await file.arrayBuffer());\n\t});\n}\n\nconst INTERNAL_DND_MIME_TYPES = Object.freeze([\n\tCodeDataTransfers.EDITORS,\n\tCodeDataTransfers.FILES,\n\tDataTransfers.RESOURCES,\n\tDataTransfers.INTERNAL_URI_LIST,\n]);\n\nexport function toExternalVSDataTransfer(sourceDataTransfer: DataTransfer, overwriteUriList = false): VSDataTransfer {\n\tconst vsDataTransfer = toVSDataTransfer(sourceDataTransfer);\n\n\t// Try to expose the internal uri-list type as the standard type\n\tconst uriList = vsDataTransfer.get(DataTransfers.INTERNAL_URI_LIST);\n\tif (uriList) {\n\t\tvsDataTransfer.replace(Mimes.uriList, uriList);\n\t} else {\n\t\tif (overwriteUriList || !vsDataTransfer.has(Mimes.uriList)) {\n\t\t\t// Otherwise, fallback to adding dragged resources to the uri list\n\t\t\tconst editorData: string[] = [];\n\t\t\tfor (const item of sourceDataTransfer.items) {\n\t\t\t\tconst file = item.getAsFile();\n\t\t\t\tif (file) {\n\t\t\t\t\tconst path = (file as FileAdditionalNativeProperties).path;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tif (path) {\n\t\t\t\t\t\t\teditorData.push(URI.file(path).toString());\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\teditorData.push(URI.parse(file.name, true).toString());\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch {\n\t\t\t\t\t\t// Parsing failed. Leave out from list\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (editorData.length) {\n\t\t\t\tvsDataTransfer.replace(Mimes.uriList, createStringDataTransferItem(UriList.create(editorData)));\n\t\t\t}\n\t\t}\n\t}\n\n\tfor (const internal of INTERNAL_DND_MIME_TYPES) {\n\t\tvsDataTransfer.delete(internal);\n\t}\n\n\treturn vsDataTransfer;\n}\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\nimport { Emitter } from 'vs/base/common/event';\nimport { IJSONSchema } from 'vs/base/common/jsonSchema';\nimport * as platform from 'vs/platform/registry/common/platform';\n\nexport const Extensions = {\n\tJSONContribution: 'base.contributions.json'\n};\n\nexport interface IJSONContributionRegistry {\n\n\t/**\n\t * Register a schema to the registry.\n\t */\n\tregisterSchema(uri: string, unresolvedSchemaContent: IJSONSchema): void;\n\n\n\t/**\n\t * Notifies all listeners that the content of the given schema has changed.\n\t * @param uri The id of the schema\n\t */\n\tnotifySchemaChanged(uri: string): void;\n}\n\n\n\nfunction normalizeId(id: string) {\n\tif (id.length > 0 && id.charAt(id.length - 1) === '#') {\n\t\treturn id.substring(0, id.length - 1);\n\t}\n\treturn id;\n}\n\n\n\nclass JSONContributionRegistry implements IJSONContributionRegistry {\n\n\tprivate schemasById: { [id: string]: IJSONSchema };\n\n\tprivate readonly _onDidChangeSchema = new Emitter();\n\n\tconstructor() {\n\t\tthis.schemasById = {};\n\t}\n\n\tpublic registerSchema(uri: string, unresolvedSchemaContent: IJSONSchema): void {\n\t\tthis.schemasById[normalizeId(uri)] = unresolvedSchemaContent;\n\t\tthis._onDidChangeSchema.fire(uri);\n\t}\n\n\tpublic notifySchemaChanged(uri: string): void {\n\t\tthis._onDidChangeSchema.fire(uri);\n\t}\n\n}\n\nconst jsonContributionRegistry = new JSONContributionRegistry();\nplatform.Registry.add(Extensions.JSONContribution, jsonContributionRegistry);\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\nimport { distinct } from 'vs/base/common/arrays';\nimport { IStringDictionary } from 'vs/base/common/collections';\nimport { Emitter } from 'vs/base/common/event';\nimport { IJSONSchema } from 'vs/base/common/jsonSchema';\nimport * as types from 'vs/base/common/types';\nimport * as nls from 'vs/nls';\nimport { getLanguageTagSettingPlainKey } from 'vs/platform/configuration/common/configuration';\nimport { Extensions as JSONExtensions, IJSONContributionRegistry } from 'vs/platform/jsonschemas/common/jsonContributionRegistry';\nimport { PolicyName } from 'vs/platform/policy/common/policy';\nimport { Registry } from 'vs/platform/registry/common/platform';\n\nexport const Extensions = {\n\tConfiguration: 'base.contributions.configuration'\n};\n\nexport interface IConfigurationRegistry {\n\n\t/**\n\t * Register a configuration to the registry.\n\t */\n\tregisterConfiguration(configuration: IConfigurationNode): void;\n\n\t/**\n\t * Register multiple default configurations to the registry.\n\t */\n\tregisterDefaultConfigurations(defaultConfigurations: IConfigurationDefaults[]): void;\n\n\t/**\n\t * Returns all configurations settings of all configuration nodes contributed to this registry.\n\t */\n\tgetConfigurationProperties(): IStringDictionary;\n\n\t/**\n\t * Register the identifiers for editor configurations\n\t */\n\tregisterOverrideIdentifiers(identifiers: string[]): void;\n}\n\nexport const enum ConfigurationScope {\n\t/**\n\t * Application specific configuration, which can be configured only in local user settings.\n\t */\n\tAPPLICATION = 1,\n\t/**\n\t * Machine specific configuration, which can be configured only in local and remote user settings.\n\t */\n\tMACHINE,\n\t/**\n\t * Window specific configuration, which can be configured in the user or workspace settings.\n\t */\n\tWINDOW,\n\t/**\n\t * Resource specific configuration, which can be configured in the user, workspace or folder settings.\n\t */\n\tRESOURCE,\n\t/**\n\t * Resource specific configuration that can be configured in language specific settings\n\t */\n\tLANGUAGE_OVERRIDABLE,\n\t/**\n\t * Machine specific configuration that can also be configured in workspace or folder settings.\n\t */\n\tMACHINE_OVERRIDABLE,\n}\n\nexport interface IPolicy {\n\n\t/**\n\t * The policy name.\n\t */\n\treadonly name: PolicyName;\n}\n\nexport interface IConfigurationPropertySchema extends IJSONSchema {\n\n\tscope?: ConfigurationScope;\n\n\t/**\n\t * When restricted, value of this configuration will be read only from trusted sources.\n\t * For eg., If the workspace is not trusted, then the value of this configuration is not read from workspace settings file.\n\t */\n\trestricted?: boolean;\n\n\t/**\n\t * When `false` this property is excluded from the registry. Default is to include.\n\t */\n\tincluded?: boolean;\n\n\t/**\n\t * List of tags associated to the property.\n\t * - A tag can be used for filtering\n\t * - Use `experimental` tag for marking the setting as experimental. **Note:** Defaults of experimental settings can be changed by the running experiments.\n\t */\n\ttags?: string[];\n\n\t/**\n\t * When specified, this setting's value can always be overwritten by\n\t * a system-wide policy.\n\t */\n\tpolicy?: IPolicy;\n}\n\nexport interface IExtensionInfo {\n}\n\nexport interface IConfigurationNode {\n\tid?: string;\n\torder?: number;\n\ttype?: string | string[];\n\ttitle?: string;\n\tproperties?: IStringDictionary;\n\tallOf?: IConfigurationNode[];\n\tscope?: ConfigurationScope;\n\textensionInfo?: IExtensionInfo;\n\trestrictedProperties?: string[];\n}\n\nexport interface IConfigurationDefaults {\n\toverrides: IStringDictionary;\n\tsource?: IExtensionInfo | string;\n}\n\nexport type IRegisteredConfigurationPropertySchema = IConfigurationPropertySchema & {\n\tdefaultDefaultValue?: any;\n\tsource?: IExtensionInfo; // Source of the Property\n\tdefaultValueSource?: IExtensionInfo | string; // Source of the Default Value\n};\n\nexport type IConfigurationDefaultOverride = {\n\treadonly value: any;\n\treadonly source?: IExtensionInfo | string; // Source of the default override\n\treadonly valuesSources?: Map; // Source of each value in default language overrides\n};\n\nexport const allSettings: { properties: IStringDictionary; patternProperties: IStringDictionary } = { properties: {}, patternProperties: {} };\nexport const applicationSettings: { properties: IStringDictionary; patternProperties: IStringDictionary } = { properties: {}, patternProperties: {} };\nexport const machineSettings: { properties: IStringDictionary; patternProperties: IStringDictionary } = { properties: {}, patternProperties: {} };\nexport const machineOverridableSettings: { properties: IStringDictionary; patternProperties: IStringDictionary } = { properties: {}, patternProperties: {} };\nexport const windowSettings: { properties: IStringDictionary; patternProperties: IStringDictionary } = { properties: {}, patternProperties: {} };\nexport const resourceSettings: { properties: IStringDictionary; patternProperties: IStringDictionary } = { properties: {}, patternProperties: {} };\n\nexport const resourceLanguageSettingsSchemaId = 'vscode://schemas/settings/resourceLanguage';\n\nconst contributionRegistry = Registry.as(JSONExtensions.JSONContribution);\n\nclass ConfigurationRegistry implements IConfigurationRegistry {\n\n\tprivate readonly configurationDefaultsOverrides: Map;\n\tprivate readonly defaultLanguageConfigurationOverridesNode: IConfigurationNode;\n\tprivate readonly configurationContributors: IConfigurationNode[];\n\tprivate readonly configurationProperties: IStringDictionary;\n\tprivate readonly policyConfigurations: Map;\n\tprivate readonly excludedConfigurationProperties: IStringDictionary;\n\tprivate readonly resourceLanguageSettingsSchema: IJSONSchema;\n\tprivate readonly overrideIdentifiers = new Set();\n\n\tprivate readonly _onDidSchemaChange = new Emitter();\n\n\tprivate readonly _onDidUpdateConfiguration = new Emitter<{ properties: ReadonlySet; defaultsOverrides?: boolean }>();\n\n\tconstructor() {\n\t\tthis.configurationDefaultsOverrides = new Map();\n\t\tthis.defaultLanguageConfigurationOverridesNode = {\n\t\t\tid: 'defaultOverrides',\n\t\t\ttitle: nls.localize('defaultLanguageConfigurationOverrides.title', \"Default Language Configuration Overrides\"),\n\t\t\tproperties: {}\n\t\t};\n\t\tthis.configurationContributors = [this.defaultLanguageConfigurationOverridesNode];\n\t\tthis.resourceLanguageSettingsSchema = {\n\t\t\tproperties: {},\n\t\t\tpatternProperties: {},\n\t\t\tadditionalProperties: true,\n\t\t\tallowTrailingCommas: true,\n\t\t\tallowComments: true\n\t\t};\n\t\tthis.configurationProperties = {};\n\t\tthis.policyConfigurations = new Map();\n\t\tthis.excludedConfigurationProperties = {};\n\n\t\tcontributionRegistry.registerSchema(resourceLanguageSettingsSchemaId, this.resourceLanguageSettingsSchema);\n\t\tthis.registerOverridePropertyPatternKey();\n\t}\n\n\tpublic registerConfiguration(configuration: IConfigurationNode, validate: boolean = true): void {\n\t\tthis.registerConfigurations([configuration], validate);\n\t}\n\n\tpublic registerConfigurations(configurations: IConfigurationNode[], validate: boolean = true): void {\n\t\tconst properties = new Set();\n\t\tthis.doRegisterConfigurations(configurations, validate, properties);\n\n\t\tcontributionRegistry.registerSchema(resourceLanguageSettingsSchemaId, this.resourceLanguageSettingsSchema);\n\t\tthis._onDidSchemaChange.fire();\n\t\tthis._onDidUpdateConfiguration.fire({ properties });\n\t}\n\n\tpublic registerDefaultConfigurations(configurationDefaults: IConfigurationDefaults[]): void {\n\t\tconst properties = new Set();\n\t\tthis.doRegisterDefaultConfigurations(configurationDefaults, properties);\n\t\tthis._onDidSchemaChange.fire();\n\t\tthis._onDidUpdateConfiguration.fire({ properties, defaultsOverrides: true });\n\t}\n\n\tprivate doRegisterDefaultConfigurations(configurationDefaults: IConfigurationDefaults[], bucket: Set) {\n\n\t\tconst overrideIdentifiers: string[] = [];\n\n\t\tfor (const { overrides, source } of configurationDefaults) {\n\t\t\tfor (const key in overrides) {\n\t\t\t\tbucket.add(key);\n\n\t\t\t\tif (OVERRIDE_PROPERTY_REGEX.test(key)) {\n\t\t\t\t\tconst configurationDefaultOverride = this.configurationDefaultsOverrides.get(key);\n\t\t\t\t\tconst valuesSources = configurationDefaultOverride?.valuesSources ?? new Map();\n\t\t\t\t\tif (source) {\n\t\t\t\t\t\tfor (const configuration of Object.keys(overrides[key])) {\n\t\t\t\t\t\t\tvaluesSources.set(configuration, source);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tconst defaultValue = { ...(configurationDefaultOverride?.value || {}), ...overrides[key] };\n\t\t\t\t\tthis.configurationDefaultsOverrides.set(key, { source, value: defaultValue, valuesSources });\n\t\t\t\t\tconst plainKey = getLanguageTagSettingPlainKey(key);\n\t\t\t\t\tconst property: IRegisteredConfigurationPropertySchema = {\n\t\t\t\t\t\ttype: 'object',\n\t\t\t\t\t\tdefault: defaultValue,\n\t\t\t\t\t\tdescription: nls.localize('defaultLanguageConfiguration.description', \"Configure settings to be overridden for the {0} language.\", plainKey),\n\t\t\t\t\t\t$ref: resourceLanguageSettingsSchemaId,\n\t\t\t\t\t\tdefaultDefaultValue: defaultValue,\n\t\t\t\t\t\tsource: types.isString(source) ? undefined : source,\n\t\t\t\t\t\tdefaultValueSource: source\n\t\t\t\t\t};\n\t\t\t\t\toverrideIdentifiers.push(...overrideIdentifiersFromKey(key));\n\t\t\t\t\tthis.configurationProperties[key] = property;\n\t\t\t\t\tthis.defaultLanguageConfigurationOverridesNode.properties![key] = property;\n\t\t\t\t} else {\n\t\t\t\t\tthis.configurationDefaultsOverrides.set(key, { value: overrides[key], source });\n\t\t\t\t\tconst property = this.configurationProperties[key];\n\t\t\t\t\tif (property) {\n\t\t\t\t\t\tthis.updatePropertyDefaultValue(key, property);\n\t\t\t\t\t\tthis.updateSchema(key, property);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthis.doRegisterOverrideIdentifiers(overrideIdentifiers);\n\t}\n\n\tpublic registerOverrideIdentifiers(overrideIdentifiers: string[]): void {\n\t\tthis.doRegisterOverrideIdentifiers(overrideIdentifiers);\n\t\tthis._onDidSchemaChange.fire();\n\t}\n\n\tprivate doRegisterOverrideIdentifiers(overrideIdentifiers: string[]) {\n\t\tfor (const overrideIdentifier of overrideIdentifiers) {\n\t\t\tthis.overrideIdentifiers.add(overrideIdentifier);\n\t\t}\n\t\tthis.updateOverridePropertyPatternKey();\n\t}\n\n\tprivate doRegisterConfigurations(configurations: IConfigurationNode[], validate: boolean, bucket: Set): void {\n\n\t\tconfigurations.forEach(configuration => {\n\n\t\t\tthis.validateAndRegisterProperties(configuration, validate, configuration.extensionInfo, configuration.restrictedProperties, undefined, bucket);\n\n\t\t\tthis.configurationContributors.push(configuration);\n\t\t\tthis.registerJSONConfiguration(configuration);\n\t\t});\n\t}\n\n\tprivate validateAndRegisterProperties(configuration: IConfigurationNode, validate: boolean = true, extensionInfo: IExtensionInfo | undefined, restrictedProperties: string[] | undefined, scope: ConfigurationScope = ConfigurationScope.WINDOW, bucket: Set): void {\n\t\tscope = types.isUndefinedOrNull(configuration.scope) ? scope : configuration.scope;\n\t\tconst properties = configuration.properties;\n\t\tif (properties) {\n\t\t\tfor (const key in properties) {\n\t\t\t\tconst property: IRegisteredConfigurationPropertySchema = properties[key];\n\t\t\t\tif (validate && validateProperty(key, property)) {\n\t\t\t\t\tdelete properties[key];\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tproperty.source = extensionInfo;\n\n\t\t\t\t// update default value\n\t\t\t\tproperty.defaultDefaultValue = properties[key].default;\n\t\t\t\tthis.updatePropertyDefaultValue(key, property);\n\n\t\t\t\t// update scope\n\t\t\t\tif (OVERRIDE_PROPERTY_REGEX.test(key)) {\n\t\t\t\t\tproperty.scope = undefined; // No scope for overridable properties `[${identifier}]`\n\t\t\t\t} else {\n\t\t\t\t\tproperty.scope = types.isUndefinedOrNull(property.scope) ? scope : property.scope;\n\t\t\t\t\tproperty.restricted = types.isUndefinedOrNull(property.restricted) ? !!restrictedProperties?.includes(key) : property.restricted;\n\t\t\t\t}\n\n\t\t\t\t// Add to properties maps\n\t\t\t\t// Property is included by default if 'included' is unspecified\n\t\t\t\tif (properties[key].hasOwnProperty('included') && !properties[key].included) {\n\t\t\t\t\tthis.excludedConfigurationProperties[key] = properties[key];\n\t\t\t\t\tdelete properties[key];\n\t\t\t\t\tcontinue;\n\t\t\t\t} else {\n\t\t\t\t\tthis.configurationProperties[key] = properties[key];\n\t\t\t\t\tif (properties[key].policy?.name) {\n\t\t\t\t\t\tthis.policyConfigurations.set(properties[key].policy!.name, key);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (!properties[key].deprecationMessage && properties[key].markdownDeprecationMessage) {\n\t\t\t\t\t// If not set, default deprecationMessage to the markdown source\n\t\t\t\t\tproperties[key].deprecationMessage = properties[key].markdownDeprecationMessage;\n\t\t\t\t}\n\n\t\t\t\tbucket.add(key);\n\t\t\t}\n\t\t}\n\t\tconst subNodes = configuration.allOf;\n\t\tif (subNodes) {\n\t\t\tfor (const node of subNodes) {\n\t\t\t\tthis.validateAndRegisterProperties(node, validate, extensionInfo, restrictedProperties, scope, bucket);\n\t\t\t}\n\t\t}\n\t}\n\n\tgetConfigurationProperties(): IStringDictionary {\n\t\treturn this.configurationProperties;\n\t}\n\n\tgetPolicyConfigurations(): Map {\n\t\treturn this.policyConfigurations;\n\t}\n\n\tprivate registerJSONConfiguration(configuration: IConfigurationNode) {\n\t\tconst register = (configuration: IConfigurationNode) => {\n\t\t\tconst properties = configuration.properties;\n\t\t\tif (properties) {\n\t\t\t\tfor (const key in properties) {\n\t\t\t\t\tthis.updateSchema(key, properties[key]);\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst subNodes = configuration.allOf;\n\t\t\tsubNodes?.forEach(register);\n\t\t};\n\t\tregister(configuration);\n\t}\n\n\tprivate updateSchema(key: string, property: IConfigurationPropertySchema): void {\n\t\tallSettings.properties[key] = property;\n\t\tswitch (property.scope) {\n\t\t\tcase ConfigurationScope.APPLICATION:\n\t\t\t\tapplicationSettings.properties[key] = property;\n\t\t\t\tbreak;\n\t\t\tcase ConfigurationScope.MACHINE:\n\t\t\t\tmachineSettings.properties[key] = property;\n\t\t\t\tbreak;\n\t\t\tcase ConfigurationScope.MACHINE_OVERRIDABLE:\n\t\t\t\tmachineOverridableSettings.properties[key] = property;\n\t\t\t\tbreak;\n\t\t\tcase ConfigurationScope.WINDOW:\n\t\t\t\twindowSettings.properties[key] = property;\n\t\t\t\tbreak;\n\t\t\tcase ConfigurationScope.RESOURCE:\n\t\t\t\tresourceSettings.properties[key] = property;\n\t\t\t\tbreak;\n\t\t\tcase ConfigurationScope.LANGUAGE_OVERRIDABLE:\n\t\t\t\tresourceSettings.properties[key] = property;\n\t\t\t\tthis.resourceLanguageSettingsSchema.properties![key] = property;\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tprivate updateOverridePropertyPatternKey(): void {\n\t\tfor (const overrideIdentifier of this.overrideIdentifiers.values()) {\n\t\t\tconst overrideIdentifierProperty = `[${overrideIdentifier}]`;\n\t\t\tconst resourceLanguagePropertiesSchema: IJSONSchema = {\n\t\t\t\ttype: 'object',\n\t\t\t\tdescription: nls.localize('overrideSettings.defaultDescription', \"Configure editor settings to be overridden for a language.\"),\n\t\t\t\terrorMessage: nls.localize('overrideSettings.errorMessage', \"This setting does not support per-language configuration.\"),\n\t\t\t\t$ref: resourceLanguageSettingsSchemaId,\n\t\t\t};\n\t\t\tthis.updatePropertyDefaultValue(overrideIdentifierProperty, resourceLanguagePropertiesSchema);\n\t\t\tallSettings.properties[overrideIdentifierProperty] = resourceLanguagePropertiesSchema;\n\t\t\tapplicationSettings.properties[overrideIdentifierProperty] = resourceLanguagePropertiesSchema;\n\t\t\tmachineSettings.properties[overrideIdentifierProperty] = resourceLanguagePropertiesSchema;\n\t\t\tmachineOverridableSettings.properties[overrideIdentifierProperty] = resourceLanguagePropertiesSchema;\n\t\t\twindowSettings.properties[overrideIdentifierProperty] = resourceLanguagePropertiesSchema;\n\t\t\tresourceSettings.properties[overrideIdentifierProperty] = resourceLanguagePropertiesSchema;\n\t\t}\n\t}\n\n\tprivate registerOverridePropertyPatternKey(): void {\n\t\tconst resourceLanguagePropertiesSchema: IJSONSchema = {\n\t\t\ttype: 'object',\n\t\t\tdescription: nls.localize('overrideSettings.defaultDescription', \"Configure editor settings to be overridden for a language.\"),\n\t\t\terrorMessage: nls.localize('overrideSettings.errorMessage', \"This setting does not support per-language configuration.\"),\n\t\t\t$ref: resourceLanguageSettingsSchemaId,\n\t\t};\n\t\tallSettings.patternProperties[OVERRIDE_PROPERTY_PATTERN] = resourceLanguagePropertiesSchema;\n\t\tapplicationSettings.patternProperties[OVERRIDE_PROPERTY_PATTERN] = resourceLanguagePropertiesSchema;\n\t\tmachineSettings.patternProperties[OVERRIDE_PROPERTY_PATTERN] = resourceLanguagePropertiesSchema;\n\t\tmachineOverridableSettings.patternProperties[OVERRIDE_PROPERTY_PATTERN] = resourceLanguagePropertiesSchema;\n\t\twindowSettings.patternProperties[OVERRIDE_PROPERTY_PATTERN] = resourceLanguagePropertiesSchema;\n\t\tresourceSettings.patternProperties[OVERRIDE_PROPERTY_PATTERN] = resourceLanguagePropertiesSchema;\n\t\tthis._onDidSchemaChange.fire();\n\t}\n\n\tprivate updatePropertyDefaultValue(key: string, property: IRegisteredConfigurationPropertySchema): void {\n\t\tconst configurationdefaultOverride = this.configurationDefaultsOverrides.get(key);\n\t\tlet defaultValue = configurationdefaultOverride?.value;\n\t\tlet defaultSource = configurationdefaultOverride?.source;\n\t\tif (types.isUndefined(defaultValue)) {\n\t\t\tdefaultValue = property.defaultDefaultValue;\n\t\t\tdefaultSource = undefined;\n\t\t}\n\t\tif (types.isUndefined(defaultValue)) {\n\t\t\tdefaultValue = getDefaultValue(property.type);\n\t\t}\n\t\tproperty.default = defaultValue;\n\t\tproperty.defaultValueSource = defaultSource;\n\t}\n}\n\nconst OVERRIDE_IDENTIFIER_PATTERN = `\\\\[([^\\\\]]+)\\\\]`;\nconst OVERRIDE_IDENTIFIER_REGEX = new RegExp(OVERRIDE_IDENTIFIER_PATTERN, 'g');\nexport const OVERRIDE_PROPERTY_PATTERN = `^(${OVERRIDE_IDENTIFIER_PATTERN})+$`;\nexport const OVERRIDE_PROPERTY_REGEX = new RegExp(OVERRIDE_PROPERTY_PATTERN);\n\nexport function overrideIdentifiersFromKey(key: string): string[] {\n\tconst identifiers: string[] = [];\n\tif (OVERRIDE_PROPERTY_REGEX.test(key)) {\n\t\tlet matches = OVERRIDE_IDENTIFIER_REGEX.exec(key);\n\t\twhile (matches?.length) {\n\t\t\tconst identifier = matches[1].trim();\n\t\t\tif (identifier) {\n\t\t\t\tidentifiers.push(identifier);\n\t\t\t}\n\t\t\tmatches = OVERRIDE_IDENTIFIER_REGEX.exec(key);\n\t\t}\n\t}\n\treturn distinct(identifiers);\n}\n\nexport function getDefaultValue(type: string | string[] | undefined): any {\n\tconst t = Array.isArray(type) ? (type)[0] : type;\n\tswitch (t) {\n\t\tcase 'boolean':\n\t\t\treturn false;\n\t\tcase 'integer':\n\t\tcase 'number':\n\t\t\treturn 0;\n\t\tcase 'string':\n\t\t\treturn '';\n\t\tcase 'array':\n\t\t\treturn [];\n\t\tcase 'object':\n\t\t\treturn {};\n\t\tdefault:\n\t\t\treturn null;\n\t}\n}\n\nconst configurationRegistry = new ConfigurationRegistry();\nRegistry.add(Extensions.Configuration, configurationRegistry);\n\nexport function validateProperty(property: string, schema: IRegisteredConfigurationPropertySchema): string | null {\n\tif (!property.trim()) {\n\t\treturn nls.localize('config.property.empty', \"Cannot register an empty property\");\n\t}\n\tif (OVERRIDE_PROPERTY_REGEX.test(property)) {\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);\n\t}\n\tif (configurationRegistry.getConfigurationProperties()[property] !== undefined) {\n\t\treturn nls.localize('config.property.duplicate', \"Cannot register '{0}'. This property is already registered.\", property);\n\t}\n\tif (schema.policy?.name && configurationRegistry.getPolicyConfigurations().get(schema.policy?.name) !== undefined) {\n\t\treturn nls.localize('config.policy.duplicate', \"Cannot register '{0}'. The associated policy {1} is already registered with {2}.\", property, schema.policy?.name, configurationRegistry.getPolicyConfigurations().get(schema.policy?.name));\n\t}\n\treturn null;\n}\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\nimport { diffEditorDefaultOptions } from 'vs/editor/common/config/diffEditor';\nimport { editorOptionsRegistry } from 'vs/editor/common/config/editorOptions';\nimport { EDITOR_MODEL_DEFAULTS } from 'vs/editor/common/core/textModelDefaults';\nimport * as nls from 'vs/nls';\nimport { ConfigurationScope, Extensions, IConfigurationNode, IConfigurationPropertySchema, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';\nimport { Registry } from 'vs/platform/registry/common/platform';\n\nexport const editorConfigurationBaseNode = Object.freeze({\n\tid: 'editor',\n\torder: 5,\n\ttype: 'object',\n\ttitle: nls.localize('editorConfigurationTitle', \"Editor\"),\n\tscope: ConfigurationScope.LANGUAGE_OVERRIDABLE,\n});\n\nconst editorConfiguration: IConfigurationNode = {\n\t...editorConfigurationBaseNode,\n\tproperties: {\n\t\t'editor.tabSize': {\n\t\t\ttype: 'number',\n\t\t\tdefault: EDITOR_MODEL_DEFAULTS.tabSize,\n\t\t\tminimum: 1,\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 {0} is on.\", '`#editor.detectIndentation#`')\n\t\t},\n\t\t'editor.indentSize': {\n\t\t\t'anyOf': [\n\t\t\t\t{\n\t\t\t\t\ttype: 'string',\n\t\t\t\t\tenum: ['tabSize']\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\ttype: 'number',\n\t\t\t\t\tminimum: 1\n\t\t\t\t}\n\t\t\t],\n\t\t\tdefault: 'tabSize',\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.\")\n\t\t},\n\t\t'editor.insertSpaces': {\n\t\t\ttype: 'boolean',\n\t\t\tdefault: EDITOR_MODEL_DEFAULTS.insertSpaces,\n\t\t\tmarkdownDescription: nls.localize('insertSpaces', \"Insert spaces when pressing `Tab`. This setting is overridden based on the file contents when {0} is on.\", '`#editor.detectIndentation#`')\n\t\t},\n\t\t'editor.detectIndentation': {\n\t\t\ttype: 'boolean',\n\t\t\tdefault: EDITOR_MODEL_DEFAULTS.detectIndentation,\n\t\t\tmarkdownDescription: nls.localize('detectIndentation', \"Controls whether {0} and {1} will be automatically detected when a file is opened based on the file contents.\", '`#editor.tabSize#`', '`#editor.insertSpaces#`')\n\t\t},\n\t\t'editor.trimAutoWhitespace': {\n\t\t\ttype: 'boolean',\n\t\t\tdefault: EDITOR_MODEL_DEFAULTS.trimAutoWhitespace,\n\t\t\tdescription: nls.localize('trimAutoWhitespace', \"Remove trailing auto inserted whitespace.\")\n\t\t},\n\t\t'editor.largeFileOptimizations': {\n\t\t\ttype: 'boolean',\n\t\t\tdefault: EDITOR_MODEL_DEFAULTS.largeFileOptimizations,\n\t\t\tdescription: nls.localize('largeFileOptimizations', \"Special handling for large files to disable certain memory intensive features.\")\n\t\t},\n\t\t'editor.wordBasedSuggestions': {\n\t\t\tenum: ['off', 'currentDocument', 'matchingDocuments', 'allDocuments'],\n\t\t\tdefault: 'matchingDocuments',\n\t\t\tenumDescriptions: [\n\t\t\t\tnls.localize('wordBasedSuggestions.off', 'Turn off Word Based Suggestions.'),\n\t\t\t\tnls.localize('wordBasedSuggestions.currentDocument', 'Only suggest words from the active document.'),\n\t\t\t\tnls.localize('wordBasedSuggestions.matchingDocuments', 'Suggest words from all open documents of the same language.'),\n\t\t\t\tnls.localize('wordBasedSuggestions.allDocuments', 'Suggest words from all open documents.')\n\t\t\t],\n\t\t\tdescription: nls.localize('wordBasedSuggestions', \"Controls whether completions should be computed based on words in the document and from which documents they are computed.\")\n\t\t},\n\t\t'editor.semanticHighlighting.enabled': {\n\t\t\tenum: [true, false, 'configuredByTheme'],\n\t\t\tenumDescriptions: [\n\t\t\t\tnls.localize('semanticHighlighting.true', 'Semantic highlighting enabled for all color themes.'),\n\t\t\t\tnls.localize('semanticHighlighting.false', 'Semantic highlighting disabled for all color themes.'),\n\t\t\t\tnls.localize('semanticHighlighting.configuredByTheme', 'Semantic highlighting is configured by the current color theme\\'s `semanticHighlighting` setting.')\n\t\t\t],\n\t\t\tdefault: 'configuredByTheme',\n\t\t\tdescription: nls.localize('semanticHighlighting.enabled', \"Controls whether the semanticHighlighting is shown for the languages that support it.\")\n\t\t},\n\t\t'editor.stablePeek': {\n\t\t\ttype: 'boolean',\n\t\t\tdefault: false,\n\t\t\tmarkdownDescription: nls.localize('stablePeek', \"Keep peek editors open even when double-clicking their content or when hitting `Escape`.\")\n\t\t},\n\t\t'editor.maxTokenizationLineLength': {\n\t\t\ttype: 'integer',\n\t\t\tdefault: 20_000,\n\t\t\tdescription: nls.localize('maxTokenizationLineLength', \"Lines above this length will not be tokenized for performance reasons\")\n\t\t},\n\t\t'editor.experimental.asyncTokenization': {\n\t\t\ttype: 'boolean',\n\t\t\tdefault: false,\n\t\t\tdescription: nls.localize('editor.experimental.asyncTokenization', \"Controls whether the tokenization should happen asynchronously on a web worker.\"),\n\t\t\ttags: ['experimental'],\n\t\t},\n\t\t'editor.experimental.asyncTokenizationLogging': {\n\t\t\ttype: 'boolean',\n\t\t\tdefault: false,\n\t\t\tdescription: nls.localize('editor.experimental.asyncTokenizationLogging', \"Controls whether async tokenization should be logged. For debugging only.\"),\n\t\t},\n\t\t'editor.experimental.asyncTokenizationVerification': {\n\t\t\ttype: 'boolean',\n\t\t\tdefault: false,\n\t\t\tdescription: nls.localize('editor.experimental.asyncTokenizationVerification', \"Controls whether async tokenization should be verified against legacy background tokenization. Might slow down tokenization. For debugging only.\"),\n\t\t\ttags: ['experimental'],\n\t\t},\n\t\t'editor.language.brackets': {\n\t\t\ttype: ['array', 'null'],\n\t\t\tdefault: null, // We want to distinguish the empty array from not configured.\n\t\t\tdescription: nls.localize('schema.brackets', 'Defines the bracket symbols that increase or decrease the indentation.'),\n\t\t\titems: {\n\t\t\t\ttype: 'array',\n\t\t\t\titems: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: 'string',\n\t\t\t\t\t\tdescription: nls.localize('schema.openBracket', 'The opening bracket character or string sequence.')\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: 'string',\n\t\t\t\t\t\tdescription: nls.localize('schema.closeBracket', 'The closing bracket character or string sequence.')\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t'editor.language.colorizedBracketPairs': {\n\t\t\ttype: ['array', 'null'],\n\t\t\tdefault: null, // We want to distinguish the empty array from not configured.\n\t\t\tdescription: nls.localize('schema.colorizedBracketPairs', 'Defines the bracket pairs that are colorized by their nesting level if bracket pair colorization is enabled.'),\n\t\t\titems: {\n\t\t\t\ttype: 'array',\n\t\t\t\titems: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: 'string',\n\t\t\t\t\t\tdescription: nls.localize('schema.openBracket', 'The opening bracket character or string sequence.')\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: 'string',\n\t\t\t\t\t\tdescription: nls.localize('schema.closeBracket', 'The closing bracket character or string sequence.')\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t'diffEditor.maxComputationTime': {\n\t\t\ttype: 'number',\n\t\t\tdefault: diffEditorDefaultOptions.maxComputationTime,\n\t\t\tdescription: nls.localize('maxComputationTime', \"Timeout in milliseconds after which diff computation is cancelled. Use 0 for no timeout.\")\n\t\t},\n\t\t'diffEditor.maxFileSize': {\n\t\t\ttype: 'number',\n\t\t\tdefault: diffEditorDefaultOptions.maxFileSize,\n\t\t\tdescription: nls.localize('maxFileSize', \"Maximum file size in MB for which to compute diffs. Use 0 for no limit.\")\n\t\t},\n\t\t'diffEditor.renderSideBySide': {\n\t\t\ttype: 'boolean',\n\t\t\tdefault: diffEditorDefaultOptions.renderSideBySide,\n\t\t\tdescription: nls.localize('sideBySide', \"Controls whether the diff editor shows the diff side by side or inline.\")\n\t\t},\n\t\t'diffEditor.renderSideBySideInlineBreakpoint': {\n\t\t\ttype: 'number',\n\t\t\tdefault: diffEditorDefaultOptions.renderSideBySideInlineBreakpoint,\n\t\t\tdescription: nls.localize('renderSideBySideInlineBreakpoint', \"If the diff editor width is smaller than this value, the inline view is used.\")\n\t\t},\n\t\t'diffEditor.useInlineViewWhenSpaceIsLimited': {\n\t\t\ttype: 'boolean',\n\t\t\tdefault: diffEditorDefaultOptions.useInlineViewWhenSpaceIsLimited,\n\t\t\tdescription: nls.localize('useInlineViewWhenSpaceIsLimited', \"If enabled and the editor width is too small, the inline view is used.\")\n\t\t},\n\t\t'diffEditor.renderMarginRevertIcon': {\n\t\t\ttype: 'boolean',\n\t\t\tdefault: diffEditorDefaultOptions.renderMarginRevertIcon,\n\t\t\tdescription: nls.localize('renderMarginRevertIcon', \"When enabled, the diff editor shows arrows in its glyph margin to revert changes.\")\n\t\t},\n\t\t'diffEditor.renderGutterMenu': {\n\t\t\ttype: 'boolean',\n\t\t\tdefault: diffEditorDefaultOptions.renderGutterMenu,\n\t\t\tdescription: nls.localize('renderGutterMenu', \"When enabled, the diff editor shows a special gutter for revert and stage actions.\")\n\t\t},\n\t\t'diffEditor.ignoreTrimWhitespace': {\n\t\t\ttype: 'boolean',\n\t\t\tdefault: diffEditorDefaultOptions.ignoreTrimWhitespace,\n\t\t\tdescription: nls.localize('ignoreTrimWhitespace', \"When enabled, the diff editor ignores changes in leading or trailing whitespace.\")\n\t\t},\n\t\t'diffEditor.renderIndicators': {\n\t\t\ttype: 'boolean',\n\t\t\tdefault: diffEditorDefaultOptions.renderIndicators,\n\t\t\tdescription: nls.localize('renderIndicators', \"Controls whether the diff editor shows +/- indicators for added/removed changes.\")\n\t\t},\n\t\t'diffEditor.codeLens': {\n\t\t\ttype: 'boolean',\n\t\t\tdefault: diffEditorDefaultOptions.diffCodeLens,\n\t\t\tdescription: nls.localize('codeLens', \"Controls whether the editor shows CodeLens.\")\n\t\t},\n\t\t'diffEditor.wordWrap': {\n\t\t\ttype: 'string',\n\t\t\tenum: ['off', 'on', 'inherit'],\n\t\t\tdefault: diffEditorDefaultOptions.diffWordWrap,\n\t\t\tmarkdownEnumDescriptions: [\n\t\t\t\tnls.localize('wordWrap.off', \"Lines will never wrap.\"),\n\t\t\t\tnls.localize('wordWrap.on', \"Lines will wrap at the viewport width.\"),\n\t\t\t\tnls.localize('wordWrap.inherit', \"Lines will wrap according to the {0} setting.\", '`#editor.wordWrap#`'),\n\t\t\t]\n\t\t},\n\t\t'diffEditor.diffAlgorithm': {\n\t\t\ttype: 'string',\n\t\t\tenum: ['legacy', 'advanced'],\n\t\t\tdefault: diffEditorDefaultOptions.diffAlgorithm,\n\t\t\tmarkdownEnumDescriptions: [\n\t\t\t\tnls.localize('diffAlgorithm.legacy', \"Uses the legacy diffing algorithm.\"),\n\t\t\t\tnls.localize('diffAlgorithm.advanced', \"Uses the advanced diffing algorithm.\"),\n\t\t\t],\n\t\t\ttags: ['experimental'],\n\t\t},\n\t\t'diffEditor.hideUnchangedRegions.enabled': {\n\t\t\ttype: 'boolean',\n\t\t\tdefault: diffEditorDefaultOptions.hideUnchangedRegions.enabled,\n\t\t\tmarkdownDescription: nls.localize('hideUnchangedRegions.enabled', \"Controls whether the diff editor shows unchanged regions.\"),\n\t\t},\n\t\t'diffEditor.hideUnchangedRegions.revealLineCount': {\n\t\t\ttype: 'integer',\n\t\t\tdefault: diffEditorDefaultOptions.hideUnchangedRegions.revealLineCount,\n\t\t\tmarkdownDescription: nls.localize('hideUnchangedRegions.revealLineCount', \"Controls how many lines are used for unchanged regions.\"),\n\t\t\tminimum: 1,\n\t\t},\n\t\t'diffEditor.hideUnchangedRegions.minimumLineCount': {\n\t\t\ttype: 'integer',\n\t\t\tdefault: diffEditorDefaultOptions.hideUnchangedRegions.minimumLineCount,\n\t\t\tmarkdownDescription: nls.localize('hideUnchangedRegions.minimumLineCount', \"Controls how many lines are used as a minimum for unchanged regions.\"),\n\t\t\tminimum: 1,\n\t\t},\n\t\t'diffEditor.hideUnchangedRegions.contextLineCount': {\n\t\t\ttype: 'integer',\n\t\t\tdefault: diffEditorDefaultOptions.hideUnchangedRegions.contextLineCount,\n\t\t\tmarkdownDescription: nls.localize('hideUnchangedRegions.contextLineCount', \"Controls how many lines are used as context when comparing unchanged regions.\"),\n\t\t\tminimum: 1,\n\t\t},\n\t\t'diffEditor.experimental.showMoves': {\n\t\t\ttype: 'boolean',\n\t\t\tdefault: diffEditorDefaultOptions.experimental.showMoves,\n\t\t\tmarkdownDescription: nls.localize('showMoves', \"Controls whether the diff editor should show detected code moves.\")\n\t\t},\n\t\t'diffEditor.experimental.showEmptyDecorations': {\n\t\t\ttype: 'boolean',\n\t\t\tdefault: diffEditorDefaultOptions.experimental.showEmptyDecorations,\n\t\t\tdescription: nls.localize('showEmptyDecorations', \"Controls whether the diff editor shows empty decorations to see where characters got inserted or deleted.\"),\n\t\t}\n\t}\n};\n\nfunction isConfigurationPropertySchema(x: IConfigurationPropertySchema | { [path: string]: IConfigurationPropertySchema }): x is IConfigurationPropertySchema {\n\treturn (typeof x.type !== 'undefined' || typeof x.anyOf !== 'undefined');\n}\n\n// Add properties from the Editor Option Registry\nfor (const editorOption of editorOptionsRegistry) {\n\tconst schema = editorOption.schema;\n\tif (typeof schema !== 'undefined') {\n\t\tif (isConfigurationPropertySchema(schema)) {\n\t\t\t// This is a single schema contribution\n\t\t\teditorConfiguration.properties![`editor.${editorOption.name}`] = schema;\n\t\t} else {\n\t\t\tfor (const key in schema) {\n\t\t\t\tif (Object.hasOwnProperty.call(schema, key)) {\n\t\t\t\t\teditorConfiguration.properties![key] = schema[key];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nlet cachedEditorConfigurationKeys: { [key: string]: boolean } | null = null;\nfunction getEditorConfigurationKeys(): { [key: string]: boolean } {\n\tif (cachedEditorConfigurationKeys === null) {\n\t\tcachedEditorConfigurationKeys = <{ [key: string]: boolean }>Object.create(null);\n\t\tObject.keys(editorConfiguration.properties!).forEach((prop) => {\n\t\t\tcachedEditorConfigurationKeys![prop] = true;\n\t\t});\n\t}\n\treturn cachedEditorConfigurationKeys;\n}\n\nexport function isEditorConfigurationKey(key: string): boolean {\n\tconst editorConfigurationKeys = getEditorConfigurationKeys();\n\treturn (editorConfigurationKeys[`editor.${key}`] || false);\n}\n\nexport function isDiffEditorConfigurationKey(key: string): boolean {\n\tconst editorConfigurationKeys = getEditorConfigurationKeys();\n\treturn (editorConfigurationKeys[`diffEditor.${key}`] || false);\n}\n\nconst configurationRegistry = Registry.as(Extensions.Configuration);\nconfigurationRegistry.registerConfiguration(editorConfiguration);\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\nimport * as nls from 'vs/nls';\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { ILanguageExtensionPoint } from 'vs/editor/common/languages/language';\nimport { Registry } from 'vs/platform/registry/common/platform';\nimport { IDisposable } from 'vs/base/common/lifecycle';\nimport { Mimes } from 'vs/base/common/mime';\nimport { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry';\n\n// Define extension point ids\nexport const Extensions = {\n\tModesRegistry: 'editor.modesRegistry'\n};\n\nexport class EditorModesRegistry {\n\n\tprivate readonly _languages: ILanguageExtensionPoint[];\n\n\tprivate readonly _onDidChangeLanguages = new Emitter();\n\tpublic readonly onDidChangeLanguages: Event = this._onDidChangeLanguages.event;\n\n\tconstructor() {\n\t\tthis._languages = [];\n\t}\n\n\tpublic registerLanguage(def: ILanguageExtensionPoint): IDisposable {\n\t\tthis._languages.push(def);\n\t\tthis._onDidChangeLanguages.fire(undefined);\n\t\treturn {\n\t\t\tdispose: () => {\n\t\t\t\tfor (let i = 0, len = this._languages.length; i < len; i++) {\n\t\t\t\t\tif (this._languages[i] === def) {\n\t\t\t\t\t\tthis._languages.splice(i, 1);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n\n\tpublic getLanguages(): ReadonlyArray {\n\t\treturn this._languages;\n\t}\n}\n\nexport const ModesRegistry = new EditorModesRegistry();\nRegistry.add(Extensions.ModesRegistry, ModesRegistry);\n\nexport const PLAINTEXT_LANGUAGE_ID = 'plaintext';\nexport const PLAINTEXT_EXTENSION = '.txt';\n\nModesRegistry.registerLanguage({\n\tid: PLAINTEXT_LANGUAGE_ID,\n\textensions: [PLAINTEXT_EXTENSION],\n\taliases: [nls.localize('plainText.alias', \"Plain Text\"), 'text'],\n\tmimetypes: [Mimes.text]\n});\n\nRegistry.as(ConfigurationExtensions.Configuration)\n\t.registerDefaultConfigurations([{\n\t\toverrides: {\n\t\t\t'[plaintext]': {\n\t\t\t\t'editor.unicodeHighlight.ambiguousCharacters': false,\n\t\t\t\t'editor.unicodeHighlight.invisibleCharacters': false\n\t\t\t}\n\t\t}\n\t}]);\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\nimport { MarkdownRenderOptions, MarkedOptions, renderMarkdown } from 'vs/base/browser/markdownRenderer';\nimport { createTrustedTypesPolicy } from 'vs/base/browser/trustedTypes';\nimport { onUnexpectedError } from 'vs/base/common/errors';\nimport { Emitter } from 'vs/base/common/event';\nimport { IMarkdownString, MarkdownStringTrustedOptions } from 'vs/base/common/htmlContent';\nimport { DisposableStore, IDisposable } from 'vs/base/common/lifecycle';\nimport 'vs/css!./renderedMarkdown';\nimport { applyFontInfo } from 'vs/editor/browser/config/domFontInfo';\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\nimport { ILanguageService } from 'vs/editor/common/languages/language';\nimport { PLAINTEXT_LANGUAGE_ID } from 'vs/editor/common/languages/modesRegistry';\nimport { tokenizeToString } from 'vs/editor/common/languages/textToHtmlTokenizer';\nimport { IOpenerService } from 'vs/platform/opener/common/opener';\n\nexport interface IMarkdownRenderResult extends IDisposable {\n\treadonly element: HTMLElement;\n}\n\nexport interface IMarkdownRendererOptions {\n\treadonly editor?: ICodeEditor;\n\treadonly codeBlockFontFamily?: string;\n\treadonly codeBlockFontSize?: string;\n}\n\n/**\n * Markdown renderer that can render codeblocks with the editor mechanics. This\n * renderer should always be preferred.\n */\nexport class MarkdownRenderer {\n\n\tprivate static _ttpTokenizer = createTrustedTypesPolicy('tokenizeToString', {\n\t\tcreateHTML(html: string) {\n\t\t\treturn html;\n\t\t}\n\t});\n\n\tprivate readonly _onDidRenderAsync = new Emitter();\n\treadonly onDidRenderAsync = this._onDidRenderAsync.event;\n\n\tconstructor(\n\t\tprivate readonly _options: IMarkdownRendererOptions,\n\t\t@ILanguageService private readonly _languageService: ILanguageService,\n\t\t@IOpenerService private readonly _openerService: IOpenerService,\n\t) { }\n\n\tdispose(): void {\n\t\tthis._onDidRenderAsync.dispose();\n\t}\n\n\trender(markdown: IMarkdownString | undefined, options?: MarkdownRenderOptions, markedOptions?: MarkedOptions): IMarkdownRenderResult {\n\t\tif (!markdown) {\n\t\t\tconst element = document.createElement('span');\n\t\t\treturn { element, dispose: () => { } };\n\t\t}\n\n\t\tconst disposables = new DisposableStore();\n\t\tconst rendered = disposables.add(renderMarkdown(markdown, { ...this._getRenderOptions(markdown, disposables), ...options }, markedOptions));\n\t\trendered.element.classList.add('rendered-markdown');\n\t\treturn {\n\t\t\telement: rendered.element,\n\t\t\tdispose: () => disposables.dispose()\n\t\t};\n\t}\n\n\tprotected _getRenderOptions(markdown: IMarkdownString, disposables: DisposableStore): MarkdownRenderOptions {\n\t\treturn {\n\t\t\tcodeBlockRenderer: async (languageAlias, value) => {\n\t\t\t\t// In markdown,\n\t\t\t\t// it is possible that we stumble upon language aliases (e.g.js instead of javascript)\n\t\t\t\t// it is possible no alias is given in which case we fall back to the current editor lang\n\t\t\t\tlet languageId: string | undefined | null;\n\t\t\t\tif (languageAlias) {\n\t\t\t\t\tlanguageId = this._languageService.getLanguageIdByLanguageName(languageAlias);\n\t\t\t\t} else if (this._options.editor) {\n\t\t\t\t\tlanguageId = this._options.editor.getModel()?.getLanguageId();\n\t\t\t\t}\n\t\t\t\tif (!languageId) {\n\t\t\t\t\tlanguageId = PLAINTEXT_LANGUAGE_ID;\n\t\t\t\t}\n\t\t\t\tconst html = await tokenizeToString(this._languageService, value, languageId);\n\n\t\t\t\tconst element = document.createElement('span');\n\n\t\t\t\telement.innerHTML = (MarkdownRenderer._ttpTokenizer?.createHTML(html) ?? html) as string;\n\n\t\t\t\t// use \"good\" font\n\t\t\t\tif (this._options.editor) {\n\t\t\t\t\tconst fontInfo = this._options.editor.getOption(EditorOption.fontInfo);\n\t\t\t\t\tapplyFontInfo(element, fontInfo);\n\t\t\t\t} else if (this._options.codeBlockFontFamily) {\n\t\t\t\t\telement.style.fontFamily = this._options.codeBlockFontFamily;\n\t\t\t\t}\n\n\t\t\t\tif (this._options.codeBlockFontSize !== undefined) {\n\t\t\t\t\telement.style.fontSize = this._options.codeBlockFontSize;\n\t\t\t\t}\n\n\t\t\t\treturn element;\n\t\t\t},\n\t\t\tasyncRenderCallback: () => this._onDidRenderAsync.fire(),\n\t\t\tactionHandler: {\n\t\t\t\tcallback: (link) => openLinkFromMarkdown(this._openerService, link, markdown.isTrusted),\n\t\t\t\tdisposables: disposables\n\t\t\t}\n\t\t};\n\t}\n}\n\nexport async function openLinkFromMarkdown(openerService: IOpenerService, link: string, isTrusted: boolean | MarkdownStringTrustedOptions | undefined): Promise {\n\ttry {\n\t\treturn await openerService.open(link, {\n\t\t\tfromUserGesture: true,\n\t\t\tallowContributedOpeners: true,\n\t\t\tallowCommands: toAllowCommandsOption(isTrusted),\n\t\t});\n\t} catch (e) {\n\t\tonUnexpectedError(e);\n\t\treturn false;\n\t}\n}\n\nfunction toAllowCommandsOption(isTrusted: boolean | MarkdownStringTrustedOptions | undefined): boolean | readonly string[] {\n\tif (isTrusted === true) {\n\t\treturn true; // Allow all commands\n\t}\n\n\tif (isTrusted && Array.isArray(isTrusted.enabledCommands)) {\n\t\treturn isTrusted.enabledCommands; // Allow subset of commands\n\t}\n\n\treturn false; // Block commands\n}\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\nimport 'vs/css!./hover';\nimport { DisposableStore } from 'vs/base/common/lifecycle';\nimport { Event, Emitter } from 'vs/base/common/event';\nimport * as dom from 'vs/base/browser/dom';\nimport { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';\nimport { KeyCode } from 'vs/base/common/keyCodes';\nimport { IConfigurationService } from 'vs/platform/configuration/common/configuration';\nimport { EDITOR_FONT_DEFAULTS, IEditorOptions } from 'vs/editor/common/config/editorOptions';\nimport { HoverAction, HoverPosition, HoverWidget as BaseHoverWidget, getHoverAccessibleViewHint } from 'vs/base/browser/ui/hover/hoverWidget';\nimport { Widget } from 'vs/base/browser/ui/widget';\nimport { AnchorPosition } from 'vs/base/browser/ui/contextview/contextview';\nimport { IOpenerService } from 'vs/platform/opener/common/opener';\nimport { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';\nimport { MarkdownRenderer, openLinkFromMarkdown } from 'vs/editor/browser/widget/markdownRenderer/browser/markdownRenderer';\nimport { isMarkdownString } from 'vs/base/common/htmlContent';\nimport { localize } from 'vs/nls';\nimport { isMacintosh } from 'vs/base/common/platform';\nimport { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';\nimport { status } from 'vs/base/browser/ui/aria/aria';\nimport { IHoverOptions, IHoverTarget, IHoverWidget } from 'vs/base/browser/ui/hover/hover';\n\nconst $ = dom.$;\ntype TargetRect = {\n\tleft: number;\n\tright: number;\n\ttop: number;\n\tbottom: number;\n\twidth: number;\n\theight: number;\n\tcenter: { x: number; y: number };\n};\n\nconst enum Constants {\n\tPointerSize = 3,\n\tHoverBorderWidth = 2,\n\tHoverWindowEdgeMargin = 2,\n}\n\nexport class HoverWidget extends Widget implements IHoverWidget {\n\tprivate readonly _messageListeners = new DisposableStore();\n\tprivate readonly _lockMouseTracker: CompositeMouseTracker;\n\n\tprivate readonly _hover: BaseHoverWidget;\n\tprivate readonly _hoverPointer: HTMLElement | undefined;\n\tprivate readonly _hoverContainer: HTMLElement;\n\tprivate readonly _target: IHoverTarget;\n\tprivate readonly _linkHandler: (url: string) => any;\n\n\tprivate _isDisposed: boolean = false;\n\tprivate _hoverPosition: HoverPosition;\n\tprivate _forcePosition: boolean = false;\n\tprivate _x: number = 0;\n\tprivate _y: number = 0;\n\tprivate _isLocked: boolean = false;\n\tprivate _enableFocusTraps: boolean = false;\n\tprivate _addedFocusTrap: boolean = false;\n\n\tprivate get _targetWindow(): Window {\n\t\treturn dom.getWindow(this._target.targetElements[0]);\n\t}\n\tprivate get _targetDocumentElement(): HTMLElement {\n\t\treturn dom.getWindow(this._target.targetElements[0]).document.documentElement;\n\t}\n\n\tget isDisposed(): boolean { return this._isDisposed; }\n\tget isMouseIn(): boolean { return this._lockMouseTracker.isMouseIn; }\n\tget domNode(): HTMLElement { return this._hover.containerDomNode; }\n\n\tprivate readonly _onDispose = this._register(new Emitter());\n\tget onDispose(): Event { return this._onDispose.event; }\n\tprivate readonly _onRequestLayout = this._register(new Emitter());\n\tget onRequestLayout(): Event { return this._onRequestLayout.event; }\n\n\tget anchor(): AnchorPosition { return this._hoverPosition === HoverPosition.BELOW ? AnchorPosition.BELOW : AnchorPosition.ABOVE; }\n\tget x(): number { return this._x; }\n\tget y(): number { return this._y; }\n\n\t/**\n\t * Whether the hover is \"locked\" by holding the alt/option key. When locked, the hover will not\n\t * hide and can be hovered regardless of whether the `hideOnHover` hover option is set.\n\t */\n\tget isLocked(): boolean { return this._isLocked; }\n\tset isLocked(value: boolean) {\n\t\tif (this._isLocked === value) {\n\t\t\treturn;\n\t\t}\n\t\tthis._isLocked = value;\n\t\tthis._hoverContainer.classList.toggle('locked', this._isLocked);\n\t}\n\n\tconstructor(\n\t\toptions: IHoverOptions,\n\t\t@IKeybindingService private readonly _keybindingService: IKeybindingService,\n\t\t@IConfigurationService private readonly _configurationService: IConfigurationService,\n\t\t@IOpenerService private readonly _openerService: IOpenerService,\n\t\t@IInstantiationService private readonly _instantiationService: IInstantiationService,\n\t\t@IAccessibilityService private readonly _accessibilityService: IAccessibilityService\n\t) {\n\t\tsuper();\n\n\t\tthis._linkHandler = options.linkHandler || (url => {\n\t\t\treturn openLinkFromMarkdown(this._openerService, url, isMarkdownString(options.content) ? options.content.isTrusted : undefined);\n\t\t});\n\n\t\tthis._target = 'targetElements' in options.target ? options.target : new ElementHoverTarget(options.target);\n\n\t\tthis._hoverPointer = options.appearance?.showPointer ? $('div.workbench-hover-pointer') : undefined;\n\t\tthis._hover = this._register(new BaseHoverWidget());\n\t\tthis._hover.containerDomNode.classList.add('workbench-hover', 'fadeIn');\n\t\tif (options.appearance?.compact) {\n\t\t\tthis._hover.containerDomNode.classList.add('workbench-hover', 'compact');\n\t\t}\n\t\tif (options.appearance?.skipFadeInAnimation) {\n\t\t\tthis._hover.containerDomNode.classList.add('skip-fade-in');\n\t\t}\n\t\tif (options.additionalClasses) {\n\t\t\tthis._hover.containerDomNode.classList.add(...options.additionalClasses);\n\t\t}\n\t\tif (options.position?.forcePosition) {\n\t\t\tthis._forcePosition = true;\n\t\t}\n\t\tif (options.trapFocus) {\n\t\t\tthis._enableFocusTraps = true;\n\t\t}\n\n\t\tthis._hoverPosition = options.position?.hoverPosition ?? HoverPosition.ABOVE;\n\n\t\t// Don't allow mousedown out of the widget, otherwise preventDefault will call and text will\n\t\t// not be selected.\n\t\tthis.onmousedown(this._hover.containerDomNode, e => e.stopPropagation());\n\n\t\t// Hide hover on escape\n\t\tthis.onkeydown(this._hover.containerDomNode, e => {\n\t\t\tif (e.equals(KeyCode.Escape)) {\n\t\t\t\tthis.dispose();\n\t\t\t}\n\t\t});\n\n\t\t// Hide when the window loses focus\n\t\tthis._register(dom.addDisposableListener(this._targetWindow, 'blur', () => this.dispose()));\n\n\t\tconst rowElement = $('div.hover-row.markdown-hover');\n\t\tconst contentsElement = $('div.hover-contents');\n\t\tif (typeof options.content === 'string') {\n\t\t\tcontentsElement.textContent = options.content;\n\t\t\tcontentsElement.style.whiteSpace = 'pre-wrap';\n\n\t\t} else if (options.content instanceof HTMLElement) {\n\t\t\tcontentsElement.appendChild(options.content);\n\t\t\tcontentsElement.classList.add('html-hover-contents');\n\n\t\t} else {\n\t\t\tconst markdown = options.content;\n\t\t\tconst mdRenderer = this._instantiationService.createInstance(\n\t\t\t\tMarkdownRenderer,\n\t\t\t\t{ codeBlockFontFamily: this._configurationService.getValue('editor').fontFamily || EDITOR_FONT_DEFAULTS.fontFamily }\n\t\t\t);\n\n\t\t\tconst { element } = mdRenderer.render(markdown, {\n\t\t\t\tactionHandler: {\n\t\t\t\t\tcallback: (content) => this._linkHandler(content),\n\t\t\t\t\tdisposables: this._messageListeners\n\t\t\t\t},\n\t\t\t\tasyncRenderCallback: () => {\n\t\t\t\t\tcontentsElement.classList.add('code-hover-contents');\n\t\t\t\t\tthis.layout();\n\t\t\t\t\t// This changes the dimensions of the hover so trigger a layout\n\t\t\t\t\tthis._onRequestLayout.fire();\n\t\t\t\t}\n\t\t\t});\n\t\t\tcontentsElement.appendChild(element);\n\t\t}\n\t\trowElement.appendChild(contentsElement);\n\t\tthis._hover.contentsDomNode.appendChild(rowElement);\n\n\t\tif (options.actions && options.actions.length > 0) {\n\t\t\tconst statusBarElement = $('div.hover-row.status-bar');\n\t\t\tconst actionsElement = $('div.actions');\n\t\t\toptions.actions.forEach(action => {\n\t\t\t\tconst keybinding = this._keybindingService.lookupKeybinding(action.commandId);\n\t\t\t\tconst keybindingLabel = keybinding ? keybinding.getLabel() : null;\n\t\t\t\tHoverAction.render(actionsElement, {\n\t\t\t\t\tlabel: action.label,\n\t\t\t\t\tcommandId: action.commandId,\n\t\t\t\t\trun: e => {\n\t\t\t\t\t\taction.run(e);\n\t\t\t\t\t\tthis.dispose();\n\t\t\t\t\t},\n\t\t\t\t\ticonClass: action.iconClass\n\t\t\t\t}, keybindingLabel);\n\t\t\t});\n\t\t\tstatusBarElement.appendChild(actionsElement);\n\t\t\tthis._hover.containerDomNode.appendChild(statusBarElement);\n\t\t}\n\n\t\tthis._hoverContainer = $('div.workbench-hover-container');\n\t\tif (this._hoverPointer) {\n\t\t\tthis._hoverContainer.appendChild(this._hoverPointer);\n\t\t}\n\t\tthis._hoverContainer.appendChild(this._hover.containerDomNode);\n\n\t\t// Determine whether to hide on hover\n\t\tlet hideOnHover: boolean;\n\t\tif (options.actions && options.actions.length > 0) {\n\t\t\t// If there are actions, require hover so they can be accessed\n\t\t\thideOnHover = false;\n\t\t} else {\n\t\t\tif (options.persistence?.hideOnHover === undefined) {\n\t\t\t\t// When unset, will default to true when it's a string or when it's markdown that\n\t\t\t\t// appears to have a link using a naive check for '](' and ''\n\t\t\t\thideOnHover = typeof options.content === 'string' ||\n\t\t\t\t\tisMarkdownString(options.content) && !options.content.value.includes('](') && !options.content.value.includes('');\n\t\t\t} else {\n\t\t\t\t// It's set explicitly\n\t\t\t\thideOnHover = options.persistence.hideOnHover;\n\t\t\t}\n\t\t}\n\n\t\t// Show the hover hint if needed\n\t\tif (hideOnHover && options.appearance?.showHoverHint) {\n\t\t\tconst statusBarElement = $('div.hover-row.status-bar');\n\t\t\tconst infoElement = $('div.info');\n\t\t\tinfoElement.textContent = localize('hoverhint', 'Hold {0} key to mouse over', isMacintosh ? 'Option' : 'Alt');\n\t\t\tstatusBarElement.appendChild(infoElement);\n\t\t\tthis._hover.containerDomNode.appendChild(statusBarElement);\n\t\t}\n\n\t\tconst mouseTrackerTargets = [...this._target.targetElements];\n\t\tif (!hideOnHover) {\n\t\t\tmouseTrackerTargets.push(this._hoverContainer);\n\t\t}\n\t\tconst mouseTracker = this._register(new CompositeMouseTracker(mouseTrackerTargets));\n\t\tthis._register(mouseTracker.onMouseOut(() => {\n\t\t\tif (!this._isLocked) {\n\t\t\t\tthis.dispose();\n\t\t\t}\n\t\t}));\n\n\t\t// Setup another mouse tracker when hideOnHover is set in order to track the hover as well\n\t\t// when it is locked. This ensures the hover will hide on mouseout after alt has been\n\t\t// released to unlock the element.\n\t\tif (hideOnHover) {\n\t\t\tconst mouseTracker2Targets = [...this._target.targetElements, this._hoverContainer];\n\t\t\tthis._lockMouseTracker = this._register(new CompositeMouseTracker(mouseTracker2Targets));\n\t\t\tthis._register(this._lockMouseTracker.onMouseOut(() => {\n\t\t\t\tif (!this._isLocked) {\n\t\t\t\t\tthis.dispose();\n\t\t\t\t}\n\t\t\t}));\n\t\t} else {\n\t\t\tthis._lockMouseTracker = mouseTracker;\n\t\t}\n\t}\n\n\tprivate addFocusTrap() {\n\t\tif (!this._enableFocusTraps || this._addedFocusTrap) {\n\t\t\treturn;\n\t\t}\n\t\tthis._addedFocusTrap = true;\n\n\t\t// Add a hover tab loop if the hover has at least one element with a valid tabIndex\n\t\tconst firstContainerFocusElement = this._hover.containerDomNode;\n\t\tconst lastContainerFocusElement = this.findLastFocusableChild(this._hover.containerDomNode);\n\t\tif (lastContainerFocusElement) {\n\t\t\tconst beforeContainerFocusElement = dom.prepend(this._hoverContainer, $('div'));\n\t\t\tconst afterContainerFocusElement = dom.append(this._hoverContainer, $('div'));\n\t\t\tbeforeContainerFocusElement.tabIndex = 0;\n\t\t\tafterContainerFocusElement.tabIndex = 0;\n\t\t\tthis._register(dom.addDisposableListener(afterContainerFocusElement, 'focus', (e) => {\n\t\t\t\tfirstContainerFocusElement.focus();\n\t\t\t\te.preventDefault();\n\t\t\t}));\n\t\t\tthis._register(dom.addDisposableListener(beforeContainerFocusElement, 'focus', (e) => {\n\t\t\t\tlastContainerFocusElement.focus();\n\t\t\t\te.preventDefault();\n\t\t\t}));\n\t\t}\n\t}\n\n\tprivate findLastFocusableChild(root: Node): HTMLElement | undefined {\n\t\tif (root.hasChildNodes()) {\n\t\t\tfor (let i = 0; i < root.childNodes.length; i++) {\n\t\t\t\tconst node = root.childNodes.item(root.childNodes.length - i - 1);\n\t\t\t\tif (node.nodeType === node.ELEMENT_NODE) {\n\t\t\t\t\tconst parsedNode = node as HTMLElement;\n\t\t\t\t\tif (typeof parsedNode.tabIndex === 'number' && parsedNode.tabIndex >= 0) {\n\t\t\t\t\t\treturn parsedNode;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tconst recursivelyFoundElement = this.findLastFocusableChild(node);\n\t\t\t\tif (recursivelyFoundElement) {\n\t\t\t\t\treturn recursivelyFoundElement;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tpublic render(container: HTMLElement): void {\n\t\tcontainer.appendChild(this._hoverContainer);\n\t\tconst hoverFocused = this._hoverContainer.contains(this._hoverContainer.ownerDocument.activeElement);\n\t\tconst accessibleViewHint = hoverFocused && getHoverAccessibleViewHint(this._configurationService.getValue('accessibility.verbosity.hover') === true && this._accessibilityService.isScreenReaderOptimized(), this._keybindingService.lookupKeybinding('editor.action.accessibleView')?.getAriaLabel());\n\t\tif (accessibleViewHint) {\n\n\t\t\tstatus(accessibleViewHint);\n\t\t}\n\t\tthis.layout();\n\t\tthis.addFocusTrap();\n\t}\n\n\tpublic layout() {\n\t\tthis._hover.containerDomNode.classList.remove('right-aligned');\n\t\tthis._hover.contentsDomNode.style.maxHeight = '';\n\n\t\tconst getZoomAccountedBoundingClientRect = (e: HTMLElement) => {\n\t\t\tconst zoom = dom.getDomNodeZoomLevel(e);\n\n\t\t\tconst boundingRect = e.getBoundingClientRect();\n\t\t\treturn {\n\t\t\t\ttop: boundingRect.top * zoom,\n\t\t\t\tbottom: boundingRect.bottom * zoom,\n\t\t\t\tright: boundingRect.right * zoom,\n\t\t\t\tleft: boundingRect.left * zoom,\n\t\t\t};\n\t\t};\n\n\t\tconst targetBounds = this._target.targetElements.map(e => getZoomAccountedBoundingClientRect(e));\n\t\tconst { top, right, bottom, left } = targetBounds[0];\n\t\tconst width = right - left;\n\t\tconst height = bottom - top;\n\n\t\tconst targetRect: TargetRect = {\n\t\t\ttop, right, bottom, left, width, height,\n\t\t\tcenter: {\n\t\t\t\tx: left + (width / 2),\n\t\t\t\ty: top + (height / 2)\n\t\t\t}\n\t\t};\n\n\t\t// These calls adjust the position depending on spacing.\n\t\tthis.adjustHorizontalHoverPosition(targetRect);\n\t\tthis.adjustVerticalHoverPosition(targetRect);\n\t\t// This call limits the maximum height of the hover.\n\t\tthis.adjustHoverMaxHeight(targetRect);\n\n\t\t// Offset the hover position if there is a pointer so it aligns with the target element\n\t\tthis._hoverContainer.style.padding = '';\n\t\tthis._hoverContainer.style.margin = '';\n\t\tif (this._hoverPointer) {\n\t\t\tswitch (this._hoverPosition) {\n\t\t\t\tcase HoverPosition.RIGHT:\n\t\t\t\t\ttargetRect.left += Constants.PointerSize;\n\t\t\t\t\ttargetRect.right += Constants.PointerSize;\n\t\t\t\t\tthis._hoverContainer.style.paddingLeft = `${Constants.PointerSize}px`;\n\t\t\t\t\tthis._hoverContainer.style.marginLeft = `${-Constants.PointerSize}px`;\n\t\t\t\t\tbreak;\n\t\t\t\tcase HoverPosition.LEFT:\n\t\t\t\t\ttargetRect.left -= Constants.PointerSize;\n\t\t\t\t\ttargetRect.right -= Constants.PointerSize;\n\t\t\t\t\tthis._hoverContainer.style.paddingRight = `${Constants.PointerSize}px`;\n\t\t\t\t\tthis._hoverContainer.style.marginRight = `${-Constants.PointerSize}px`;\n\t\t\t\t\tbreak;\n\t\t\t\tcase HoverPosition.BELOW:\n\t\t\t\t\ttargetRect.top += Constants.PointerSize;\n\t\t\t\t\ttargetRect.bottom += Constants.PointerSize;\n\t\t\t\t\tthis._hoverContainer.style.paddingTop = `${Constants.PointerSize}px`;\n\t\t\t\t\tthis._hoverContainer.style.marginTop = `${-Constants.PointerSize}px`;\n\t\t\t\t\tbreak;\n\t\t\t\tcase HoverPosition.ABOVE:\n\t\t\t\t\ttargetRect.top -= Constants.PointerSize;\n\t\t\t\t\ttargetRect.bottom -= Constants.PointerSize;\n\t\t\t\t\tthis._hoverContainer.style.paddingBottom = `${Constants.PointerSize}px`;\n\t\t\t\t\tthis._hoverContainer.style.marginBottom = `${-Constants.PointerSize}px`;\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\ttargetRect.center.x = targetRect.left + (width / 2);\n\t\t\ttargetRect.center.y = targetRect.top + (height / 2);\n\t\t}\n\n\t\tthis.computeXCordinate(targetRect);\n\t\tthis.computeYCordinate(targetRect);\n\n\t\tif (this._hoverPointer) {\n\t\t\t// reset\n\t\t\tthis._hoverPointer.classList.remove('top');\n\t\t\tthis._hoverPointer.classList.remove('left');\n\t\t\tthis._hoverPointer.classList.remove('right');\n\t\t\tthis._hoverPointer.classList.remove('bottom');\n\n\t\t\tthis.setHoverPointerPosition(targetRect);\n\t\t}\n\n\t\tthis._hover.onContentsChanged();\n\t}\n\n\tprivate computeXCordinate(target: TargetRect): void {\n\t\tconst hoverWidth = this._hover.containerDomNode.clientWidth + Constants.HoverBorderWidth;\n\n\t\tif (this._target.x !== undefined) {\n\t\t\tthis._x = this._target.x;\n\t\t}\n\n\t\telse if (this._hoverPosition === HoverPosition.RIGHT) {\n\t\t\tthis._x = target.right;\n\t\t}\n\n\t\telse if (this._hoverPosition === HoverPosition.LEFT) {\n\t\t\tthis._x = target.left - hoverWidth;\n\t\t}\n\n\t\telse {\n\t\t\tif (this._hoverPointer) {\n\t\t\t\tthis._x = target.center.x - (this._hover.containerDomNode.clientWidth / 2);\n\t\t\t} else {\n\t\t\t\tthis._x = target.left;\n\t\t\t}\n\n\t\t\t// Hover is going beyond window towards right end\n\t\t\tif (this._x + hoverWidth >= this._targetDocumentElement.clientWidth) {\n\t\t\t\tthis._hover.containerDomNode.classList.add('right-aligned');\n\t\t\t\tthis._x = Math.max(this._targetDocumentElement.clientWidth - hoverWidth - Constants.HoverWindowEdgeMargin, this._targetDocumentElement.clientLeft);\n\t\t\t}\n\t\t}\n\n\t\t// Hover is going beyond window towards left end\n\t\tif (this._x < this._targetDocumentElement.clientLeft) {\n\t\t\tthis._x = target.left + Constants.HoverWindowEdgeMargin;\n\t\t}\n\n\t}\n\n\tprivate computeYCordinate(target: TargetRect): void {\n\t\tif (this._target.y !== undefined) {\n\t\t\tthis._y = this._target.y;\n\t\t}\n\n\t\telse if (this._hoverPosition === HoverPosition.ABOVE) {\n\t\t\tthis._y = target.top;\n\t\t}\n\n\t\telse if (this._hoverPosition === HoverPosition.BELOW) {\n\t\t\tthis._y = target.bottom - 2;\n\t\t}\n\n\t\telse {\n\t\t\tif (this._hoverPointer) {\n\t\t\t\tthis._y = target.center.y + (this._hover.containerDomNode.clientHeight / 2);\n\t\t\t} else {\n\t\t\t\tthis._y = target.bottom;\n\t\t\t}\n\t\t}\n\n\t\t// Hover on bottom is going beyond window\n\t\tif (this._y > this._targetWindow.innerHeight) {\n\t\t\tthis._y = target.bottom;\n\t\t}\n\t}\n\n\tprivate adjustHorizontalHoverPosition(target: TargetRect): void {\n\t\t// Do not adjust horizontal hover position if x cordiante is provided\n\t\tif (this._target.x !== undefined) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst hoverPointerOffset = (this._hoverPointer ? Constants.PointerSize : 0);\n\n\t\t// When force position is enabled, restrict max width\n\t\tif (this._forcePosition) {\n\t\t\tconst padding = hoverPointerOffset + Constants.HoverBorderWidth;\n\t\t\tif (this._hoverPosition === HoverPosition.RIGHT) {\n\t\t\t\tthis._hover.containerDomNode.style.maxWidth = `${this._targetDocumentElement.clientWidth - target.right - padding}px`;\n\t\t\t} else if (this._hoverPosition === HoverPosition.LEFT) {\n\t\t\t\tthis._hover.containerDomNode.style.maxWidth = `${target.left - padding}px`;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Position hover on right to target\n\t\tif (this._hoverPosition === HoverPosition.RIGHT) {\n\t\t\tconst roomOnRight = this._targetDocumentElement.clientWidth - target.right;\n\t\t\t// Hover on the right is going beyond window.\n\t\t\tif (roomOnRight < this._hover.containerDomNode.clientWidth + hoverPointerOffset) {\n\t\t\t\tconst roomOnLeft = target.left;\n\t\t\t\t// There's enough room on the left, flip the hover position\n\t\t\t\tif (roomOnLeft >= this._hover.containerDomNode.clientWidth + hoverPointerOffset) {\n\t\t\t\t\tthis._hoverPosition = HoverPosition.LEFT;\n\t\t\t\t}\n\t\t\t\t// Hover on the left would go beyond window too\n\t\t\t\telse {\n\t\t\t\t\tthis._hoverPosition = HoverPosition.BELOW;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// Position hover on left to target\n\t\telse if (this._hoverPosition === HoverPosition.LEFT) {\n\n\t\t\tconst roomOnLeft = target.left;\n\t\t\t// Hover on the left is going beyond window.\n\t\t\tif (roomOnLeft < this._hover.containerDomNode.clientWidth + hoverPointerOffset) {\n\t\t\t\tconst roomOnRight = this._targetDocumentElement.clientWidth - target.right;\n\t\t\t\t// There's enough room on the right, flip the hover position\n\t\t\t\tif (roomOnRight >= this._hover.containerDomNode.clientWidth + hoverPointerOffset) {\n\t\t\t\t\tthis._hoverPosition = HoverPosition.RIGHT;\n\t\t\t\t}\n\t\t\t\t// Hover on the right would go beyond window too\n\t\t\t\telse {\n\t\t\t\t\tthis._hoverPosition = HoverPosition.BELOW;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Hover on the left is going beyond window.\n\t\t\tif (target.left - this._hover.containerDomNode.clientWidth - hoverPointerOffset <= this._targetDocumentElement.clientLeft) {\n\t\t\t\tthis._hoverPosition = HoverPosition.RIGHT;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate adjustVerticalHoverPosition(target: TargetRect): void {\n\t\t// Do not adjust vertical hover position if the y coordinate is provided\n\t\t// or the position is forced\n\t\tif (this._target.y !== undefined || this._forcePosition) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst hoverPointerOffset = (this._hoverPointer ? Constants.PointerSize : 0);\n\n\t\t// Position hover on top of the target\n\t\tif (this._hoverPosition === HoverPosition.ABOVE) {\n\t\t\t// Hover on top is going beyond window\n\t\t\tif (target.top - this._hover.containerDomNode.clientHeight - hoverPointerOffset < 0) {\n\t\t\t\tthis._hoverPosition = HoverPosition.BELOW;\n\t\t\t}\n\t\t}\n\n\t\t// Position hover below the target\n\t\telse if (this._hoverPosition === HoverPosition.BELOW) {\n\t\t\t// Hover on bottom is going beyond window\n\t\t\tif (target.bottom + this._hover.containerDomNode.clientHeight + hoverPointerOffset > this._targetWindow.innerHeight) {\n\t\t\t\tthis._hoverPosition = HoverPosition.ABOVE;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate adjustHoverMaxHeight(target: TargetRect): void {\n\t\tlet maxHeight = this._targetWindow.innerHeight / 2;\n\n\t\t// When force position is enabled, restrict max height\n\t\tif (this._forcePosition) {\n\t\t\tconst padding = (this._hoverPointer ? Constants.PointerSize : 0) + Constants.HoverBorderWidth;\n\t\t\tif (this._hoverPosition === HoverPosition.ABOVE) {\n\t\t\t\tmaxHeight = Math.min(maxHeight, target.top - padding);\n\t\t\t} else if (this._hoverPosition === HoverPosition.BELOW) {\n\t\t\t\tmaxHeight = Math.min(maxHeight, this._targetWindow.innerHeight - target.bottom - padding);\n\t\t\t}\n\t\t}\n\n\t\tthis._hover.containerDomNode.style.maxHeight = `${maxHeight}px`;\n\t\tif (this._hover.contentsDomNode.clientHeight < this._hover.contentsDomNode.scrollHeight) {\n\t\t\t// Add padding for a vertical scrollbar\n\t\t\tconst extraRightPadding = `${this._hover.scrollbar.options.verticalScrollbarSize}px`;\n\t\t\tif (this._hover.contentsDomNode.style.paddingRight !== extraRightPadding) {\n\t\t\t\tthis._hover.contentsDomNode.style.paddingRight = extraRightPadding;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate setHoverPointerPosition(target: TargetRect): void {\n\t\tif (!this._hoverPointer) {\n\t\t\treturn;\n\t\t}\n\n\t\tswitch (this._hoverPosition) {\n\t\t\tcase HoverPosition.LEFT:\n\t\t\tcase HoverPosition.RIGHT: {\n\t\t\t\tthis._hoverPointer.classList.add(this._hoverPosition === HoverPosition.LEFT ? 'right' : 'left');\n\t\t\t\tconst hoverHeight = this._hover.containerDomNode.clientHeight;\n\n\t\t\t\t// If hover is taller than target, then show the pointer at the center of target\n\t\t\t\tif (hoverHeight > target.height) {\n\t\t\t\t\tthis._hoverPointer.style.top = `${target.center.y - (this._y - hoverHeight) - Constants.PointerSize}px`;\n\t\t\t\t}\n\n\t\t\t\t// Otherwise show the pointer at the center of hover\n\t\t\t\telse {\n\t\t\t\t\tthis._hoverPointer.style.top = `${Math.round((hoverHeight / 2)) - Constants.PointerSize}px`;\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase HoverPosition.ABOVE:\n\t\t\tcase HoverPosition.BELOW: {\n\t\t\t\tthis._hoverPointer.classList.add(this._hoverPosition === HoverPosition.ABOVE ? 'bottom' : 'top');\n\t\t\t\tconst hoverWidth = this._hover.containerDomNode.clientWidth;\n\n\t\t\t\t// Position pointer at the center of the hover\n\t\t\t\tlet pointerLeftPosition = Math.round((hoverWidth / 2)) - Constants.PointerSize;\n\n\t\t\t\t// If pointer goes beyond target then position it at the center of the target\n\t\t\t\tconst pointerX = this._x + pointerLeftPosition;\n\t\t\t\tif (pointerX < target.left || pointerX > target.right) {\n\t\t\t\t\tpointerLeftPosition = target.center.x - this._x - Constants.PointerSize;\n\t\t\t\t}\n\n\t\t\t\tthis._hoverPointer.style.left = `${pointerLeftPosition}px`;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic focus() {\n\t\tthis._hover.containerDomNode.focus();\n\t}\n\n\tpublic override dispose(): void {\n\t\tif (!this._isDisposed) {\n\t\t\tthis._onDispose.fire();\n\t\t\tthis._hoverContainer.remove();\n\t\t\tthis._messageListeners.dispose();\n\t\t\tthis._target.dispose();\n\t\t\tsuper.dispose();\n\t\t}\n\t\tthis._isDisposed = true;\n\t}\n}\n\nclass CompositeMouseTracker extends Widget {\n\tprivate _isMouseIn: boolean = true;\n\tprivate _mouseTimeout: number | undefined;\n\n\tprivate readonly _onMouseOut = this._register(new Emitter());\n\tget onMouseOut(): Event { return this._onMouseOut.event; }\n\n\tget isMouseIn(): boolean { return this._isMouseIn; }\n\n\tconstructor(\n\t\tprivate _elements: HTMLElement[]\n\t) {\n\t\tsuper();\n\t\tthis._elements.forEach(n => this.onmouseover(n, () => this._onTargetMouseOver(n)));\n\t\tthis._elements.forEach(n => this.onmouseleave(n, () => this._onTargetMouseLeave(n)));\n\t}\n\n\tprivate _onTargetMouseOver(target: HTMLElement): void {\n\t\tthis._isMouseIn = true;\n\t\tthis._clearEvaluateMouseStateTimeout(target);\n\t}\n\n\tprivate _onTargetMouseLeave(target: HTMLElement): void {\n\t\tthis._isMouseIn = false;\n\t\tthis._evaluateMouseState(target);\n\t}\n\n\tprivate _evaluateMouseState(target: HTMLElement): void {\n\t\tthis._clearEvaluateMouseStateTimeout(target);\n\t\t// Evaluate whether the mouse is still outside asynchronously such that other mouse targets\n\t\t// have the opportunity to first their mouse in event.\n\t\tthis._mouseTimeout = dom.getWindow(target).setTimeout(() => this._fireIfMouseOutside(), 0);\n\t}\n\n\tprivate _clearEvaluateMouseStateTimeout(target: HTMLElement): void {\n\t\tif (this._mouseTimeout) {\n\t\t\tdom.getWindow(target).clearTimeout(this._mouseTimeout);\n\t\t\tthis._mouseTimeout = undefined;\n\t\t}\n\t}\n\n\tprivate _fireIfMouseOutside(): void {\n\t\tif (!this._isMouseIn) {\n\t\t\tthis._onMouseOut.fire();\n\t\t}\n\t}\n}\n\nclass ElementHoverTarget implements IHoverTarget {\n\treadonly targetElements: readonly HTMLElement[];\n\n\tconstructor(\n\t\tprivate _element: HTMLElement\n\t) {\n\t\tthis.targetElements = [this._element];\n\t}\n\n\tdispose(): void {\n\t}\n}\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\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle';\nimport * as strings from 'vs/base/common/strings';\nimport { ITextModel } from 'vs/editor/common/model';\nimport { DEFAULT_WORD_REGEXP, ensureValidWordDefinition } from 'vs/editor/common/core/wordHelper';\nimport { EnterAction, FoldingRules, IAutoClosingPair, IndentationRule, LanguageConfiguration, AutoClosingPairs, CharacterPair, ExplicitLanguageConfiguration } from 'vs/editor/common/languages/languageConfiguration';\nimport { createScopedLineTokens, ScopedLineTokens } from 'vs/editor/common/languages/supports';\nimport { CharacterPairSupport } from 'vs/editor/common/languages/supports/characterPair';\nimport { BracketElectricCharacterSupport } from 'vs/editor/common/languages/supports/electricCharacter';\nimport { IndentRulesSupport } from 'vs/editor/common/languages/supports/indentRules';\nimport { OnEnterSupport } from 'vs/editor/common/languages/supports/onEnter';\nimport { RichEditBrackets } from 'vs/editor/common/languages/supports/richEditBrackets';\nimport { EditorAutoIndentStrategy } from 'vs/editor/common/config/editorOptions';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\nimport { IConfigurationService } from 'vs/platform/configuration/common/configuration';\nimport { ILanguageService } from 'vs/editor/common/languages/language';\nimport { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions';\nimport { PLAINTEXT_LANGUAGE_ID } from 'vs/editor/common/languages/modesRegistry';\nimport { LanguageBracketsConfiguration } from 'vs/editor/common/languages/supports/languageBracketsConfiguration';\n\n/**\n * Interface used to support insertion of mode specific comments.\n */\nexport interface ICommentsConfiguration {\n\tlineCommentToken?: string;\n\tblockCommentStartToken?: string;\n\tblockCommentEndToken?: string;\n}\n\nexport interface ILanguageConfigurationService {\n\treadonly _serviceBrand: undefined;\n\n\tonDidChange: Event;\n\n\t/**\n\t * @param priority Use a higher number for higher priority\n\t */\n\tregister(languageId: string, configuration: LanguageConfiguration, priority?: number): IDisposable;\n\n\tgetLanguageConfiguration(languageId: string): ResolvedLanguageConfiguration;\n\n}\n\nexport class LanguageConfigurationServiceChangeEvent {\n\tconstructor(public readonly languageId: string | undefined) { }\n\n\tpublic affects(languageId: string): boolean {\n\t\treturn !this.languageId ? true : this.languageId === languageId;\n\t}\n}\n\nexport const ILanguageConfigurationService = createDecorator('languageConfigurationService');\n\nexport class LanguageConfigurationService extends Disposable implements ILanguageConfigurationService {\n\t_serviceBrand: undefined;\n\n\tprivate readonly _registry = this._register(new LanguageConfigurationRegistry());\n\n\tprivate readonly onDidChangeEmitter = this._register(new Emitter());\n\tpublic readonly onDidChange = this.onDidChangeEmitter.event;\n\n\tprivate readonly configurations = new Map();\n\n\tconstructor(\n\t\t@IConfigurationService private readonly configurationService: IConfigurationService,\n\t\t@ILanguageService private readonly languageService: ILanguageService\n\t) {\n\t\tsuper();\n\n\t\tconst languageConfigKeys = new Set(Object.values(customizedLanguageConfigKeys));\n\n\t\tthis._register(this.configurationService.onDidChangeConfiguration((e) => {\n\t\t\tconst globalConfigChanged = e.change.keys.some((k) =>\n\t\t\t\tlanguageConfigKeys.has(k)\n\t\t\t);\n\t\t\tconst localConfigChanged = e.change.overrides\n\t\t\t\t.filter(([overrideLangName, keys]) =>\n\t\t\t\t\tkeys.some((k) => languageConfigKeys.has(k))\n\t\t\t\t)\n\t\t\t\t.map(([overrideLangName]) => overrideLangName);\n\n\t\t\tif (globalConfigChanged) {\n\t\t\t\tthis.configurations.clear();\n\t\t\t\tthis.onDidChangeEmitter.fire(new LanguageConfigurationServiceChangeEvent(undefined));\n\t\t\t} else {\n\t\t\t\tfor (const languageId of localConfigChanged) {\n\t\t\t\t\tif (this.languageService.isRegisteredLanguageId(languageId)) {\n\t\t\t\t\t\tthis.configurations.delete(languageId);\n\t\t\t\t\t\tthis.onDidChangeEmitter.fire(new LanguageConfigurationServiceChangeEvent(languageId));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}));\n\n\t\tthis._register(this._registry.onDidChange((e) => {\n\t\t\tthis.configurations.delete(e.languageId);\n\t\t\tthis.onDidChangeEmitter.fire(new LanguageConfigurationServiceChangeEvent(e.languageId));\n\t\t}));\n\t}\n\n\tpublic register(languageId: string, configuration: LanguageConfiguration, priority?: number): IDisposable {\n\t\treturn this._registry.register(languageId, configuration, priority);\n\t}\n\n\tpublic getLanguageConfiguration(languageId: string): ResolvedLanguageConfiguration {\n\t\tlet result = this.configurations.get(languageId);\n\t\tif (!result) {\n\t\t\tresult = computeConfig(languageId, this._registry, this.configurationService, this.languageService);\n\t\t\tthis.configurations.set(languageId, result);\n\t\t}\n\t\treturn result;\n\t}\n}\n\nfunction computeConfig(\n\tlanguageId: string,\n\tregistry: LanguageConfigurationRegistry,\n\tconfigurationService: IConfigurationService,\n\tlanguageService: ILanguageService,\n): ResolvedLanguageConfiguration {\n\tlet languageConfig = registry.getLanguageConfiguration(languageId);\n\n\tif (!languageConfig) {\n\t\tif (!languageService.isRegisteredLanguageId(languageId)) {\n\t\t\t// this happens for the null language, which can be returned by monarch.\n\t\t\t// Instead of throwing an error, we just return a default config.\n\t\t\treturn new ResolvedLanguageConfiguration(languageId, {});\n\t\t}\n\t\tlanguageConfig = new ResolvedLanguageConfiguration(languageId, {});\n\t}\n\n\tconst customizedConfig = getCustomizedLanguageConfig(languageConfig.languageId, configurationService);\n\tconst data = combineLanguageConfigurations([languageConfig.underlyingConfig, customizedConfig]);\n\tconst config = new ResolvedLanguageConfiguration(languageConfig.languageId, data);\n\treturn config;\n}\n\nconst customizedLanguageConfigKeys = {\n\tbrackets: 'editor.language.brackets',\n\tcolorizedBracketPairs: 'editor.language.colorizedBracketPairs'\n};\n\nfunction getCustomizedLanguageConfig(languageId: string, configurationService: IConfigurationService): LanguageConfiguration {\n\tconst brackets = configurationService.getValue(customizedLanguageConfigKeys.brackets, {\n\t\toverrideIdentifier: languageId,\n\t});\n\n\tconst colorizedBracketPairs = configurationService.getValue(customizedLanguageConfigKeys.colorizedBracketPairs, {\n\t\toverrideIdentifier: languageId,\n\t});\n\n\treturn {\n\t\tbrackets: validateBracketPairs(brackets),\n\t\tcolorizedBracketPairs: validateBracketPairs(colorizedBracketPairs),\n\t};\n}\n\nfunction validateBracketPairs(data: unknown): CharacterPair[] | undefined {\n\tif (!Array.isArray(data)) {\n\t\treturn undefined;\n\t}\n\treturn data.map(pair => {\n\t\tif (!Array.isArray(pair) || pair.length !== 2) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn [pair[0], pair[1]] as CharacterPair;\n\t}).filter((p): p is CharacterPair => !!p);\n}\n\nexport function getIndentationAtPosition(model: ITextModel, lineNumber: number, column: number): string {\n\tconst lineText = model.getLineContent(lineNumber);\n\tlet indentation = strings.getLeadingWhitespace(lineText);\n\tif (indentation.length > column - 1) {\n\t\tindentation = indentation.substring(0, column - 1);\n\t}\n\treturn indentation;\n}\n\nexport function getScopedLineTokens(model: ITextModel, lineNumber: number, columnNumber?: number): ScopedLineTokens {\n\tmodel.tokenization.forceTokenization(lineNumber);\n\tconst lineTokens = model.tokenization.getLineTokens(lineNumber);\n\tconst column = (typeof columnNumber === 'undefined' ? model.getLineMaxColumn(lineNumber) - 1 : columnNumber - 1);\n\treturn createScopedLineTokens(lineTokens, column);\n}\n\nclass ComposedLanguageConfiguration {\n\tprivate readonly _entries: LanguageConfigurationContribution[];\n\tprivate _order: number;\n\tprivate _resolved: ResolvedLanguageConfiguration | null = null;\n\n\tconstructor(public readonly languageId: string) {\n\t\tthis._entries = [];\n\t\tthis._order = 0;\n\t\tthis._resolved = null;\n\t}\n\n\tpublic register(\n\t\tconfiguration: LanguageConfiguration,\n\t\tpriority: number\n\t): IDisposable {\n\t\tconst entry = new LanguageConfigurationContribution(\n\t\t\tconfiguration,\n\t\t\tpriority,\n\t\t\t++this._order\n\t\t);\n\t\tthis._entries.push(entry);\n\t\tthis._resolved = null;\n\t\treturn toDisposable(() => {\n\t\t\tfor (let i = 0; i < this._entries.length; i++) {\n\t\t\t\tif (this._entries[i] === entry) {\n\t\t\t\t\tthis._entries.splice(i, 1);\n\t\t\t\t\tthis._resolved = null;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n\n\tpublic getResolvedConfiguration(): ResolvedLanguageConfiguration | null {\n\t\tif (!this._resolved) {\n\t\t\tconst config = this._resolve();\n\t\t\tif (config) {\n\t\t\t\tthis._resolved = new ResolvedLanguageConfiguration(\n\t\t\t\t\tthis.languageId,\n\t\t\t\t\tconfig\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\treturn this._resolved;\n\t}\n\n\tprivate _resolve(): LanguageConfiguration | null {\n\t\tif (this._entries.length === 0) {\n\t\t\treturn null;\n\t\t}\n\t\tthis._entries.sort(LanguageConfigurationContribution.cmp);\n\t\treturn combineLanguageConfigurations(this._entries.map(e => e.configuration));\n\t}\n}\n\nfunction combineLanguageConfigurations(configs: LanguageConfiguration[]): LanguageConfiguration {\n\tlet result: ExplicitLanguageConfiguration = {\n\t\tcomments: undefined,\n\t\tbrackets: undefined,\n\t\twordPattern: undefined,\n\t\tindentationRules: undefined,\n\t\tonEnterRules: undefined,\n\t\tautoClosingPairs: undefined,\n\t\tsurroundingPairs: undefined,\n\t\tautoCloseBefore: undefined,\n\t\tfolding: undefined,\n\t\tcolorizedBracketPairs: undefined,\n\t\t__electricCharacterSupport: undefined,\n\t};\n\tfor (const entry of configs) {\n\t\tresult = {\n\t\t\tcomments: entry.comments || result.comments,\n\t\t\tbrackets: entry.brackets || result.brackets,\n\t\t\twordPattern: entry.wordPattern || result.wordPattern,\n\t\t\tindentationRules: entry.indentationRules || result.indentationRules,\n\t\t\tonEnterRules: entry.onEnterRules || result.onEnterRules,\n\t\t\tautoClosingPairs: entry.autoClosingPairs || result.autoClosingPairs,\n\t\t\tsurroundingPairs: entry.surroundingPairs || result.surroundingPairs,\n\t\t\tautoCloseBefore: entry.autoCloseBefore || result.autoCloseBefore,\n\t\t\tfolding: entry.folding || result.folding,\n\t\t\tcolorizedBracketPairs: entry.colorizedBracketPairs || result.colorizedBracketPairs,\n\t\t\t__electricCharacterSupport: entry.__electricCharacterSupport || result.__electricCharacterSupport,\n\t\t};\n\t}\n\n\treturn result;\n}\n\nclass LanguageConfigurationContribution {\n\tconstructor(\n\t\tpublic readonly configuration: LanguageConfiguration,\n\t\tpublic readonly priority: number,\n\t\tpublic readonly order: number\n\t) { }\n\n\tpublic static cmp(a: LanguageConfigurationContribution, b: LanguageConfigurationContribution) {\n\t\tif (a.priority === b.priority) {\n\t\t\t// higher order last\n\t\t\treturn a.order - b.order;\n\t\t}\n\t\t// higher priority last\n\t\treturn a.priority - b.priority;\n\t}\n}\n\nexport class LanguageConfigurationChangeEvent {\n\tconstructor(public readonly languageId: string) { }\n}\n\nexport class LanguageConfigurationRegistry extends Disposable {\n\tprivate readonly _entries = new Map();\n\n\tprivate readonly _onDidChange = this._register(new Emitter());\n\tpublic readonly onDidChange: Event = this._onDidChange.event;\n\n\tconstructor() {\n\t\tsuper();\n\t\tthis._register(this.register(PLAINTEXT_LANGUAGE_ID, {\n\t\t\tbrackets: [\n\t\t\t\t['(', ')'],\n\t\t\t\t['[', ']'],\n\t\t\t\t['{', '}'],\n\t\t\t],\n\t\t\tsurroundingPairs: [\n\t\t\t\t{ open: '{', close: '}' },\n\t\t\t\t{ open: '[', close: ']' },\n\t\t\t\t{ open: '(', close: ')' },\n\t\t\t\t{ open: '<', close: '>' },\n\t\t\t\t{ open: '\\\"', close: '\\\"' },\n\t\t\t\t{ open: '\\'', close: '\\'' },\n\t\t\t\t{ open: '`', close: '`' },\n\t\t\t],\n\t\t\tcolorizedBracketPairs: [],\n\t\t\tfolding: {\n\t\t\t\toffSide: true\n\t\t\t}\n\t\t}, 0));\n\t}\n\n\t/**\n\t * @param priority Use a higher number for higher priority\n\t */\n\tpublic register(languageId: string, configuration: LanguageConfiguration, priority: number = 0): IDisposable {\n\t\tlet entries = this._entries.get(languageId);\n\t\tif (!entries) {\n\t\t\tentries = new ComposedLanguageConfiguration(languageId);\n\t\t\tthis._entries.set(languageId, entries);\n\t\t}\n\n\t\tconst disposable = entries.register(configuration, priority);\n\t\tthis._onDidChange.fire(new LanguageConfigurationChangeEvent(languageId));\n\n\t\treturn toDisposable(() => {\n\t\t\tdisposable.dispose();\n\t\t\tthis._onDidChange.fire(new LanguageConfigurationChangeEvent(languageId));\n\t\t});\n\t}\n\n\tpublic getLanguageConfiguration(languageId: string): ResolvedLanguageConfiguration | null {\n\t\tconst entries = this._entries.get(languageId);\n\t\treturn entries?.getResolvedConfiguration() || null;\n\t}\n}\n\n/**\n * Immutable.\n*/\nexport class ResolvedLanguageConfiguration {\n\tprivate _brackets: RichEditBrackets | null;\n\tprivate _electricCharacter: BracketElectricCharacterSupport | null;\n\tprivate readonly _onEnterSupport: OnEnterSupport | null;\n\n\tpublic readonly comments: ICommentsConfiguration | null;\n\tpublic readonly characterPair: CharacterPairSupport;\n\tpublic readonly wordDefinition: RegExp;\n\tpublic readonly indentRulesSupport: IndentRulesSupport | null;\n\tpublic readonly indentationRules: IndentationRule | undefined;\n\tpublic readonly foldingRules: FoldingRules;\n\tpublic readonly bracketsNew: LanguageBracketsConfiguration;\n\n\tconstructor(\n\t\tpublic readonly languageId: string,\n\t\tpublic readonly underlyingConfig: LanguageConfiguration\n\t) {\n\t\tthis._brackets = null;\n\t\tthis._electricCharacter = null;\n\t\tthis._onEnterSupport =\n\t\t\tthis.underlyingConfig.brackets ||\n\t\t\t\tthis.underlyingConfig.indentationRules ||\n\t\t\t\tthis.underlyingConfig.onEnterRules\n\t\t\t\t? new OnEnterSupport(this.underlyingConfig)\n\t\t\t\t: null;\n\t\tthis.comments = ResolvedLanguageConfiguration._handleComments(this.underlyingConfig);\n\t\tthis.characterPair = new CharacterPairSupport(this.underlyingConfig);\n\n\t\tthis.wordDefinition = this.underlyingConfig.wordPattern || DEFAULT_WORD_REGEXP;\n\t\tthis.indentationRules = this.underlyingConfig.indentationRules;\n\t\tif (this.underlyingConfig.indentationRules) {\n\t\t\tthis.indentRulesSupport = new IndentRulesSupport(\n\t\t\t\tthis.underlyingConfig.indentationRules\n\t\t\t);\n\t\t} else {\n\t\t\tthis.indentRulesSupport = null;\n\t\t}\n\t\tthis.foldingRules = this.underlyingConfig.folding || {};\n\n\t\tthis.bracketsNew = new LanguageBracketsConfiguration(\n\t\t\tlanguageId,\n\t\t\tthis.underlyingConfig\n\t\t);\n\t}\n\n\tpublic getWordDefinition(): RegExp {\n\t\treturn ensureValidWordDefinition(this.wordDefinition);\n\t}\n\n\tpublic get brackets(): RichEditBrackets | null {\n\t\tif (!this._brackets && this.underlyingConfig.brackets) {\n\t\t\tthis._brackets = new RichEditBrackets(\n\t\t\t\tthis.languageId,\n\t\t\t\tthis.underlyingConfig.brackets\n\t\t\t);\n\t\t}\n\t\treturn this._brackets;\n\t}\n\n\tpublic get electricCharacter(): BracketElectricCharacterSupport | null {\n\t\tif (!this._electricCharacter) {\n\t\t\tthis._electricCharacter = new BracketElectricCharacterSupport(\n\t\t\t\tthis.brackets\n\t\t\t);\n\t\t}\n\t\treturn this._electricCharacter;\n\t}\n\n\tpublic onEnter(\n\t\tautoIndent: EditorAutoIndentStrategy,\n\t\tpreviousLineText: string,\n\t\tbeforeEnterText: string,\n\t\tafterEnterText: string\n\t): EnterAction | null {\n\t\tif (!this._onEnterSupport) {\n\t\t\treturn null;\n\t\t}\n\t\treturn this._onEnterSupport.onEnter(\n\t\t\tautoIndent,\n\t\t\tpreviousLineText,\n\t\t\tbeforeEnterText,\n\t\t\tafterEnterText\n\t\t);\n\t}\n\n\tpublic getAutoClosingPairs(): AutoClosingPairs {\n\t\treturn new AutoClosingPairs(this.characterPair.getAutoClosingPairs());\n\t}\n\n\tpublic getAutoCloseBeforeSet(forQuotes: boolean): string {\n\t\treturn this.characterPair.getAutoCloseBeforeSet(forQuotes);\n\t}\n\n\tpublic getSurroundingPairs(): IAutoClosingPair[] {\n\t\treturn this.characterPair.getSurroundingPairs();\n\t}\n\n\tprivate static _handleComments(\n\t\tconf: LanguageConfiguration\n\t): ICommentsConfiguration | null {\n\t\tconst commentRule = conf.comments;\n\t\tif (!commentRule) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// comment configuration\n\t\tconst comments: ICommentsConfiguration = {};\n\n\t\tif (commentRule.lineComment) {\n\t\t\tcomments.lineCommentToken = commentRule.lineComment;\n\t\t}\n\t\tif (commentRule.blockComment) {\n\t\t\tconst [blockStart, blockEnd] = commentRule.blockComment;\n\t\t\tcomments.blockCommentStartToken = blockStart;\n\t\t\tcomments.blockCommentEndToken = blockEnd;\n\t\t}\n\n\t\treturn comments;\n\t}\n}\n\nregisterSingleton(ILanguageConfigurationService, LanguageConfigurationService, InstantiationType.Delayed);\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\nimport { IntervalTimer, timeout } from 'vs/base/common/async';\nimport { Disposable, IDisposable, dispose, toDisposable, DisposableStore } from 'vs/base/common/lifecycle';\nimport { URI } from 'vs/base/common/uri';\nimport { SimpleWorkerClient, logOnceWebWorkerWarning, IWorkerClient } from 'vs/base/common/worker/simpleWorker';\nimport { DefaultWorkerFactory } from 'vs/base/browser/defaultWorkerFactory';\nimport { Position } from 'vs/editor/common/core/position';\nimport { IRange, Range } from 'vs/editor/common/core/range';\nimport { ITextModel } from 'vs/editor/common/model';\nimport * as languages from 'vs/editor/common/languages';\nimport { ILanguageConfigurationService } from 'vs/editor/common/languages/languageConfigurationRegistry';\nimport { EditorSimpleWorker } from 'vs/editor/common/services/editorSimpleWorker';\nimport { DiffAlgorithmName, IDiffComputationResult, IEditorWorkerService, ILineChange, IUnicodeHighlightsResult } from 'vs/editor/common/services/editorWorker';\nimport { IModelService } from 'vs/editor/common/services/model';\nimport { ITextResourceConfigurationService } from 'vs/editor/common/services/textResourceConfiguration';\nimport { isNonEmptyArray } from 'vs/base/common/arrays';\nimport { ILogService } from 'vs/platform/log/common/log';\nimport { StopWatch } from 'vs/base/common/stopwatch';\nimport { canceled } from 'vs/base/common/errors';\nimport { UnicodeHighlighterOptions } from 'vs/editor/common/services/unicodeTextModelHighlighter';\nimport { IEditorWorkerHost } from 'vs/editor/common/services/editorWorkerHost';\nimport { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';\nimport { IDocumentDiff, IDocumentDiffProviderOptions } from 'vs/editor/common/diff/documentDiffProvider';\nimport { MovedText } from 'vs/editor/common/diff/linesDiffComputer';\nimport { DetailedLineRangeMapping, RangeMapping, LineRangeMapping } from 'vs/editor/common/diff/rangeMapping';\nimport { LineRange } from 'vs/editor/common/core/lineRange';\nimport { SectionHeader, FindSectionHeaderOptions } from 'vs/editor/common/services/findSectionHeaders';\nimport { mainWindow } from 'vs/base/browser/window';\nimport { WindowIntervalTimer } from 'vs/base/browser/dom';\n\n/**\n * Stop syncing a model to the worker if it was not needed for 1 min.\n */\nconst STOP_SYNC_MODEL_DELTA_TIME_MS = 60 * 1000;\n\n/**\n * Stop the worker if it was not needed for 5 min.\n */\nconst STOP_WORKER_DELTA_TIME_MS = 5 * 60 * 1000;\n\nfunction canSyncModel(modelService: IModelService, resource: URI): boolean {\n\tconst model = modelService.getModel(resource);\n\tif (!model) {\n\t\treturn false;\n\t}\n\tif (model.isTooLargeForSyncing()) {\n\t\treturn false;\n\t}\n\treturn true;\n}\n\nexport class EditorWorkerService extends Disposable implements IEditorWorkerService {\n\n\tdeclare readonly _serviceBrand: undefined;\n\n\tprivate readonly _modelService: IModelService;\n\tprivate readonly _workerManager: WorkerManager;\n\tprivate readonly _logService: ILogService;\n\n\tconstructor(\n\t\t@IModelService modelService: IModelService,\n\t\t@ITextResourceConfigurationService configurationService: ITextResourceConfigurationService,\n\t\t@ILogService logService: ILogService,\n\t\t@ILanguageConfigurationService languageConfigurationService: ILanguageConfigurationService,\n\t\t@ILanguageFeaturesService languageFeaturesService: ILanguageFeaturesService,\n\t) {\n\t\tsuper();\n\t\tthis._modelService = modelService;\n\t\tthis._workerManager = this._register(new WorkerManager(this._modelService, languageConfigurationService));\n\t\tthis._logService = logService;\n\n\t\t// register default link-provider and default completions-provider\n\t\tthis._register(languageFeaturesService.linkProvider.register({ language: '*', hasAccessToAllModels: true }, {\n\t\t\tprovideLinks: (model, token) => {\n\t\t\t\tif (!canSyncModel(this._modelService, model.uri)) {\n\t\t\t\t\treturn Promise.resolve({ links: [] }); // File too large\n\t\t\t\t}\n\t\t\t\treturn this._workerManager.withWorker().then(client => client.computeLinks(model.uri)).then(links => {\n\t\t\t\t\treturn links && { links };\n\t\t\t\t});\n\t\t\t}\n\t\t}));\n\t\tthis._register(languageFeaturesService.completionProvider.register('*', new WordBasedCompletionItemProvider(this._workerManager, configurationService, this._modelService, languageConfigurationService)));\n\t}\n\n\tpublic override dispose(): void {\n\t\tsuper.dispose();\n\t}\n\n\tpublic canComputeUnicodeHighlights(uri: URI): boolean {\n\t\treturn canSyncModel(this._modelService, uri);\n\t}\n\n\tpublic computedUnicodeHighlights(uri: URI, options: UnicodeHighlighterOptions, range?: IRange): Promise {\n\t\treturn this._workerManager.withWorker().then(client => client.computedUnicodeHighlights(uri, options, range));\n\t}\n\n\tpublic async computeDiff(original: URI, modified: URI, options: IDocumentDiffProviderOptions, algorithm: DiffAlgorithmName): Promise {\n\t\tconst result = await this._workerManager.withWorker().then(client => client.computeDiff(original, modified, options, algorithm));\n\t\tif (!result) {\n\t\t\treturn null;\n\t\t}\n\t\t// Convert from space efficient JSON data to rich objects.\n\t\tconst diff: IDocumentDiff = {\n\t\t\tidentical: result.identical,\n\t\t\tquitEarly: result.quitEarly,\n\t\t\tchanges: toLineRangeMappings(result.changes),\n\t\t\tmoves: result.moves.map(m => new MovedText(\n\t\t\t\tnew LineRangeMapping(new LineRange(m[0], m[1]), new LineRange(m[2], m[3])),\n\t\t\t\ttoLineRangeMappings(m[4])\n\t\t\t))\n\t\t};\n\t\treturn diff;\n\n\t\tfunction toLineRangeMappings(changes: readonly ILineChange[]): readonly DetailedLineRangeMapping[] {\n\t\t\treturn changes.map(\n\t\t\t\t(c) => new DetailedLineRangeMapping(\n\t\t\t\t\tnew LineRange(c[0], c[1]),\n\t\t\t\t\tnew LineRange(c[2], c[3]),\n\t\t\t\t\tc[4]?.map(\n\t\t\t\t\t\t(c) => new RangeMapping(\n\t\t\t\t\t\t\tnew Range(c[0], c[1], c[2], c[3]),\n\t\t\t\t\t\t\tnew Range(c[4], c[5], c[6], c[7])\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}\n\t}\n\n\tpublic computeMoreMinimalEdits(resource: URI, edits: languages.TextEdit[] | null | undefined, pretty: boolean = false): Promise {\n\t\tif (isNonEmptyArray(edits)) {\n\t\t\tif (!canSyncModel(this._modelService, resource)) {\n\t\t\t\treturn Promise.resolve(edits); // File too large\n\t\t\t}\n\t\t\tconst sw = StopWatch.create();\n\t\t\tconst result = this._workerManager.withWorker().then(client => client.computeMoreMinimalEdits(resource, edits, pretty));\n\t\t\tresult.finally(() => this._logService.trace('FORMAT#computeMoreMinimalEdits', resource.toString(true), sw.elapsed()));\n\t\t\treturn Promise.race([result, timeout(1000).then(() => edits)]);\n\n\t\t} else {\n\t\t\treturn Promise.resolve(undefined);\n\t\t}\n\t}\n\n\tpublic canNavigateValueSet(resource: URI): boolean {\n\t\treturn (canSyncModel(this._modelService, resource));\n\t}\n\n\tpublic navigateValueSet(resource: URI, range: IRange, up: boolean): Promise {\n\t\treturn this._workerManager.withWorker().then(client => client.navigateValueSet(resource, range, up));\n\t}\n\n\tcanComputeWordRanges(resource: URI): boolean {\n\t\treturn canSyncModel(this._modelService, resource);\n\t}\n\n\tcomputeWordRanges(resource: URI, range: IRange): Promise<{ [word: string]: IRange[] } | null> {\n\t\treturn this._workerManager.withWorker().then(client => client.computeWordRanges(resource, range));\n\t}\n\n\tpublic findSectionHeaders(uri: URI, options: FindSectionHeaderOptions): Promise {\n\t\treturn this._workerManager.withWorker().then(client => client.findSectionHeaders(uri, options));\n\t}\n}\n\nclass WordBasedCompletionItemProvider implements languages.CompletionItemProvider {\n\n\tprivate readonly _workerManager: WorkerManager;\n\tprivate readonly _configurationService: ITextResourceConfigurationService;\n\tprivate readonly _modelService: IModelService;\n\n\treadonly _debugDisplayName = 'wordbasedCompletions';\n\n\tconstructor(\n\t\tworkerManager: WorkerManager,\n\t\tconfigurationService: ITextResourceConfigurationService,\n\t\tmodelService: IModelService,\n\t\tprivate readonly languageConfigurationService: ILanguageConfigurationService\n\t) {\n\t\tthis._workerManager = workerManager;\n\t\tthis._configurationService = configurationService;\n\t\tthis._modelService = modelService;\n\t}\n\n\tasync provideCompletionItems(model: ITextModel, position: Position): Promise {\n\t\ttype WordBasedSuggestionsConfig = {\n\t\t\twordBasedSuggestions?: 'off' | 'currentDocument' | 'matchingDocuments' | 'allDocuments';\n\t\t};\n\t\tconst config = this._configurationService.getValue(model.uri, position, 'editor');\n\t\tif (config.wordBasedSuggestions === 'off') {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst models: URI[] = [];\n\t\tif (config.wordBasedSuggestions === 'currentDocument') {\n\t\t\t// only current file and only if not too large\n\t\t\tif (canSyncModel(this._modelService, model.uri)) {\n\t\t\t\tmodels.push(model.uri);\n\t\t\t}\n\t\t} else {\n\t\t\t// either all files or files of same language\n\t\t\tfor (const candidate of this._modelService.getModels()) {\n\t\t\t\tif (!canSyncModel(this._modelService, candidate.uri)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (candidate === model) {\n\t\t\t\t\tmodels.unshift(candidate.uri);\n\n\t\t\t\t} else if (config.wordBasedSuggestions === 'allDocuments' || candidate.getLanguageId() === model.getLanguageId()) {\n\t\t\t\t\tmodels.push(candidate.uri);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (models.length === 0) {\n\t\t\treturn undefined; // File too large, no other files\n\t\t}\n\n\t\tconst wordDefRegExp = this.languageConfigurationService.getLanguageConfiguration(model.getLanguageId()).getWordDefinition();\n\t\tconst word = model.getWordAtPosition(position);\n\t\tconst replace = !word ? Range.fromPositions(position) : new Range(position.lineNumber, word.startColumn, position.lineNumber, word.endColumn);\n\t\tconst insert = replace.setEndPosition(position.lineNumber, position.column);\n\n\t\tconst client = await this._workerManager.withWorker();\n\t\tconst data = await client.textualSuggest(models, word?.word, wordDefRegExp);\n\t\tif (!data) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\treturn {\n\t\t\tduration: data.duration,\n\t\t\tsuggestions: data.words.map((word): languages.CompletionItem => {\n\t\t\t\treturn {\n\t\t\t\t\tkind: languages.CompletionItemKind.Text,\n\t\t\t\t\tlabel: word,\n\t\t\t\t\tinsertText: word,\n\t\t\t\t\trange: { insert, replace }\n\t\t\t\t};\n\t\t\t}),\n\t\t};\n\t}\n}\n\nclass WorkerManager extends Disposable {\n\n\tprivate readonly _modelService: IModelService;\n\tprivate _editorWorkerClient: EditorWorkerClient | null;\n\tprivate _lastWorkerUsedTime: number;\n\n\tconstructor(modelService: IModelService, private readonly languageConfigurationService: ILanguageConfigurationService) {\n\t\tsuper();\n\t\tthis._modelService = modelService;\n\t\tthis._editorWorkerClient = null;\n\t\tthis._lastWorkerUsedTime = (new Date()).getTime();\n\n\t\tconst stopWorkerInterval = this._register(new WindowIntervalTimer());\n\t\tstopWorkerInterval.cancelAndSet(() => this._checkStopIdleWorker(), Math.round(STOP_WORKER_DELTA_TIME_MS / 2), mainWindow);\n\n\t\tthis._register(this._modelService.onModelRemoved(_ => this._checkStopEmptyWorker()));\n\t}\n\n\tpublic override dispose(): void {\n\t\tif (this._editorWorkerClient) {\n\t\t\tthis._editorWorkerClient.dispose();\n\t\t\tthis._editorWorkerClient = null;\n\t\t}\n\t\tsuper.dispose();\n\t}\n\n\t/**\n\t * Check if the model service has no more models and stop the worker if that is the case.\n\t */\n\tprivate _checkStopEmptyWorker(): void {\n\t\tif (!this._editorWorkerClient) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst models = this._modelService.getModels();\n\t\tif (models.length === 0) {\n\t\t\t// There are no more models => nothing possible for me to do\n\t\t\tthis._editorWorkerClient.dispose();\n\t\t\tthis._editorWorkerClient = null;\n\t\t}\n\t}\n\n\t/**\n\t * Check if the worker has been idle for a while and then stop it.\n\t */\n\tprivate _checkStopIdleWorker(): void {\n\t\tif (!this._editorWorkerClient) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst timeSinceLastWorkerUsedTime = (new Date()).getTime() - this._lastWorkerUsedTime;\n\t\tif (timeSinceLastWorkerUsedTime > STOP_WORKER_DELTA_TIME_MS) {\n\t\t\tthis._editorWorkerClient.dispose();\n\t\t\tthis._editorWorkerClient = null;\n\t\t}\n\t}\n\n\tpublic withWorker(): Promise {\n\t\tthis._lastWorkerUsedTime = (new Date()).getTime();\n\t\tif (!this._editorWorkerClient) {\n\t\t\tthis._editorWorkerClient = new EditorWorkerClient(this._modelService, false, 'editorWorkerService', this.languageConfigurationService);\n\t\t}\n\t\treturn Promise.resolve(this._editorWorkerClient);\n\t}\n}\n\nclass EditorModelManager extends Disposable {\n\n\tprivate readonly _proxy: EditorSimpleWorker;\n\tprivate readonly _modelService: IModelService;\n\tprivate _syncedModels: { [modelUrl: string]: IDisposable } = Object.create(null);\n\tprivate _syncedModelsLastUsedTime: { [modelUrl: string]: number } = Object.create(null);\n\n\tconstructor(proxy: EditorSimpleWorker, modelService: IModelService, keepIdleModels: boolean) {\n\t\tsuper();\n\t\tthis._proxy = proxy;\n\t\tthis._modelService = modelService;\n\n\t\tif (!keepIdleModels) {\n\t\t\tconst timer = new IntervalTimer();\n\t\t\ttimer.cancelAndSet(() => this._checkStopModelSync(), Math.round(STOP_SYNC_MODEL_DELTA_TIME_MS / 2));\n\t\t\tthis._register(timer);\n\t\t}\n\t}\n\n\tpublic override dispose(): void {\n\t\tfor (const modelUrl in this._syncedModels) {\n\t\t\tdispose(this._syncedModels[modelUrl]);\n\t\t}\n\t\tthis._syncedModels = Object.create(null);\n\t\tthis._syncedModelsLastUsedTime = Object.create(null);\n\t\tsuper.dispose();\n\t}\n\n\tpublic ensureSyncedResources(resources: URI[], forceLargeModels: boolean): void {\n\t\tfor (const resource of resources) {\n\t\t\tconst resourceStr = resource.toString();\n\n\t\t\tif (!this._syncedModels[resourceStr]) {\n\t\t\t\tthis._beginModelSync(resource, forceLargeModels);\n\t\t\t}\n\t\t\tif (this._syncedModels[resourceStr]) {\n\t\t\t\tthis._syncedModelsLastUsedTime[resourceStr] = (new Date()).getTime();\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate _checkStopModelSync(): void {\n\t\tconst currentTime = (new Date()).getTime();\n\n\t\tconst toRemove: string[] = [];\n\t\tfor (const modelUrl in this._syncedModelsLastUsedTime) {\n\t\t\tconst elapsedTime = currentTime - this._syncedModelsLastUsedTime[modelUrl];\n\t\t\tif (elapsedTime > STOP_SYNC_MODEL_DELTA_TIME_MS) {\n\t\t\t\ttoRemove.push(modelUrl);\n\t\t\t}\n\t\t}\n\n\t\tfor (const e of toRemove) {\n\t\t\tthis._stopModelSync(e);\n\t\t}\n\t}\n\n\tprivate _beginModelSync(resource: URI, forceLargeModels: boolean): void {\n\t\tconst model = this._modelService.getModel(resource);\n\t\tif (!model) {\n\t\t\treturn;\n\t\t}\n\t\tif (!forceLargeModels && model.isTooLargeForSyncing()) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst modelUrl = resource.toString();\n\n\t\tthis._proxy.acceptNewModel({\n\t\t\turl: model.uri.toString(),\n\t\t\tlines: model.getLinesContent(),\n\t\t\tEOL: model.getEOL(),\n\t\t\tversionId: model.getVersionId()\n\t\t});\n\n\t\tconst toDispose = new DisposableStore();\n\t\ttoDispose.add(model.onDidChangeContent((e) => {\n\t\t\tthis._proxy.acceptModelChanged(modelUrl.toString(), e);\n\t\t}));\n\t\ttoDispose.add(model.onWillDispose(() => {\n\t\t\tthis._stopModelSync(modelUrl);\n\t\t}));\n\t\ttoDispose.add(toDisposable(() => {\n\t\t\tthis._proxy.acceptRemovedModel(modelUrl);\n\t\t}));\n\n\t\tthis._syncedModels[modelUrl] = toDispose;\n\t}\n\n\tprivate _stopModelSync(modelUrl: string): void {\n\t\tconst toDispose = this._syncedModels[modelUrl];\n\t\tdelete this._syncedModels[modelUrl];\n\t\tdelete this._syncedModelsLastUsedTime[modelUrl];\n\t\tdispose(toDispose);\n\t}\n}\n\nclass SynchronousWorkerClient implements IWorkerClient {\n\tprivate readonly _instance: T;\n\tprivate readonly _proxyObj: Promise;\n\n\tconstructor(instance: T) {\n\t\tthis._instance = instance;\n\t\tthis._proxyObj = Promise.resolve(this._instance);\n\t}\n\n\tpublic dispose(): void {\n\t\tthis._instance.dispose();\n\t}\n\n\tpublic getProxyObject(): Promise {\n\t\treturn this._proxyObj;\n\t}\n}\n\nexport interface IEditorWorkerClient {\n\tfhr(method: string, args: any[]): Promise;\n}\n\nexport class EditorWorkerHost implements IEditorWorkerHost {\n\n\tprivate readonly _workerClient: IEditorWorkerClient;\n\n\tconstructor(workerClient: IEditorWorkerClient) {\n\t\tthis._workerClient = workerClient;\n\t}\n\n\t// foreign host request\n\tpublic fhr(method: string, args: any[]): Promise {\n\t\treturn this._workerClient.fhr(method, args);\n\t}\n}\n\nexport class EditorWorkerClient extends Disposable implements IEditorWorkerClient {\n\n\tprivate readonly _modelService: IModelService;\n\tprivate readonly _keepIdleModels: boolean;\n\tprotected _worker: IWorkerClient | null;\n\tprotected readonly _workerFactory: DefaultWorkerFactory;\n\tprivate _modelManager: EditorModelManager | null;\n\tprivate _disposed = false;\n\n\tconstructor(\n\t\tmodelService: IModelService,\n\t\tkeepIdleModels: boolean,\n\t\tlabel: string | undefined,\n\t\tprivate readonly languageConfigurationService: ILanguageConfigurationService\n\t) {\n\t\tsuper();\n\t\tthis._modelService = modelService;\n\t\tthis._keepIdleModels = keepIdleModels;\n\t\tthis._workerFactory = new DefaultWorkerFactory(label);\n\t\tthis._worker = null;\n\t\tthis._modelManager = null;\n\t}\n\n\t// foreign host request\n\tpublic fhr(method: string, args: any[]): Promise {\n\t\tthrow new Error(`Not implemented!`);\n\t}\n\n\tprivate _getOrCreateWorker(): IWorkerClient {\n\t\tif (!this._worker) {\n\t\t\ttry {\n\t\t\t\tthis._worker = this._register(new SimpleWorkerClient(\n\t\t\t\t\tthis._workerFactory,\n\t\t\t\t\t'vs/editor/common/services/editorSimpleWorker',\n\t\t\t\t\tnew EditorWorkerHost(this)\n\t\t\t\t));\n\t\t\t} catch (err) {\n\t\t\t\tlogOnceWebWorkerWarning(err);\n\t\t\t\tthis._worker = new SynchronousWorkerClient(new EditorSimpleWorker(new EditorWorkerHost(this), null));\n\t\t\t}\n\t\t}\n\t\treturn this._worker;\n\t}\n\n\tprotected _getProxy(): Promise {\n\t\treturn this._getOrCreateWorker().getProxyObject().then(undefined, (err) => {\n\t\t\tlogOnceWebWorkerWarning(err);\n\t\t\tthis._worker = new SynchronousWorkerClient(new EditorSimpleWorker(new EditorWorkerHost(this), null));\n\t\t\treturn this._getOrCreateWorker().getProxyObject();\n\t\t});\n\t}\n\n\tprivate _getOrCreateModelManager(proxy: EditorSimpleWorker): EditorModelManager {\n\t\tif (!this._modelManager) {\n\t\t\tthis._modelManager = this._register(new EditorModelManager(proxy, this._modelService, this._keepIdleModels));\n\t\t}\n\t\treturn this._modelManager;\n\t}\n\n\tprotected async _withSyncedResources(resources: URI[], forceLargeModels: boolean = false): Promise {\n\t\tif (this._disposed) {\n\t\t\treturn Promise.reject(canceled());\n\t\t}\n\t\treturn this._getProxy().then((proxy) => {\n\t\t\tthis._getOrCreateModelManager(proxy).ensureSyncedResources(resources, forceLargeModels);\n\t\t\treturn proxy;\n\t\t});\n\t}\n\n\tpublic computedUnicodeHighlights(uri: URI, options: UnicodeHighlighterOptions, range?: IRange): Promise {\n\t\treturn this._withSyncedResources([uri]).then(proxy => {\n\t\t\treturn proxy.computeUnicodeHighlights(uri.toString(), options, range);\n\t\t});\n\t}\n\n\tpublic computeDiff(original: URI, modified: URI, options: IDocumentDiffProviderOptions, algorithm: DiffAlgorithmName): Promise {\n\t\treturn this._withSyncedResources([original, modified], /* forceLargeModels */true).then(proxy => {\n\t\t\treturn proxy.computeDiff(original.toString(), modified.toString(), options, algorithm);\n\t\t});\n\t}\n\n\tpublic computeMoreMinimalEdits(resource: URI, edits: languages.TextEdit[], pretty: boolean): Promise {\n\t\treturn this._withSyncedResources([resource]).then(proxy => {\n\t\t\treturn proxy.computeMoreMinimalEdits(resource.toString(), edits, pretty);\n\t\t});\n\t}\n\n\tpublic computeLinks(resource: URI): Promise {\n\t\treturn this._withSyncedResources([resource]).then(proxy => {\n\t\t\treturn proxy.computeLinks(resource.toString());\n\t\t});\n\t}\n\n\tpublic computeDefaultDocumentColors(resource: URI): Promise {\n\t\treturn this._withSyncedResources([resource]).then(proxy => {\n\t\t\treturn proxy.computeDefaultDocumentColors(resource.toString());\n\t\t});\n\t}\n\n\tpublic async textualSuggest(resources: URI[], leadingWord: string | undefined, wordDefRegExp: RegExp): Promise<{ words: string[]; duration: number } | null> {\n\t\tconst proxy = await this._withSyncedResources(resources);\n\t\tconst wordDef = wordDefRegExp.source;\n\t\tconst wordDefFlags = wordDefRegExp.flags;\n\t\treturn proxy.textualSuggest(resources.map(r => r.toString()), leadingWord, wordDef, wordDefFlags);\n\t}\n\n\tcomputeWordRanges(resource: URI, range: IRange): Promise<{ [word: string]: IRange[] } | null> {\n\t\treturn this._withSyncedResources([resource]).then(proxy => {\n\t\t\tconst model = this._modelService.getModel(resource);\n\t\t\tif (!model) {\n\t\t\t\treturn Promise.resolve(null);\n\t\t\t}\n\t\t\tconst wordDefRegExp = this.languageConfigurationService.getLanguageConfiguration(model.getLanguageId()).getWordDefinition();\n\t\t\tconst wordDef = wordDefRegExp.source;\n\t\t\tconst wordDefFlags = wordDefRegExp.flags;\n\t\t\treturn proxy.computeWordRanges(resource.toString(), range, wordDef, wordDefFlags);\n\t\t});\n\t}\n\n\tpublic navigateValueSet(resource: URI, range: IRange, up: boolean): Promise {\n\t\treturn this._withSyncedResources([resource]).then(proxy => {\n\t\t\tconst model = this._modelService.getModel(resource);\n\t\t\tif (!model) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst wordDefRegExp = this.languageConfigurationService.getLanguageConfiguration(model.getLanguageId()).getWordDefinition();\n\t\t\tconst wordDef = wordDefRegExp.source;\n\t\t\tconst wordDefFlags = wordDefRegExp.flags;\n\t\t\treturn proxy.navigateValueSet(resource.toString(), range, up, wordDef, wordDefFlags);\n\t\t});\n\t}\n\n\tpublic findSectionHeaders(uri: URI, options: FindSectionHeaderOptions): Promise {\n\t\treturn this._withSyncedResources([uri]).then(proxy => {\n\t\t\treturn proxy.findSectionHeaders(uri.toString(), options);\n\t\t});\n\t}\n\n\toverride dispose(): void {\n\t\tsuper.dispose();\n\t\tthis._disposed = true;\n\t}\n}\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\nimport { getAllMethodNames } from 'vs/base/common/objects';\nimport { URI } from 'vs/base/common/uri';\nimport { EditorWorkerClient } from 'vs/editor/browser/services/editorWorkerService';\nimport { ILanguageConfigurationService } from 'vs/editor/common/languages/languageConfigurationRegistry';\nimport { IModelService } from 'vs/editor/common/services/model';\n\n/**\n * Create a new web worker that has model syncing capabilities built in.\n * Specify an AMD module to load that will `create` an object that will be proxied.\n */\nexport function createWebWorker(modelService: IModelService, languageConfigurationService: ILanguageConfigurationService, opts: IWebWorkerOptions): MonacoWebWorker {\n\treturn new MonacoWebWorkerImpl(modelService, languageConfigurationService, opts);\n}\n\n/**\n * A web worker that can provide a proxy to an arbitrary file.\n */\nexport interface MonacoWebWorker {\n\t/**\n\t * Terminate the web worker, thus invalidating the returned proxy.\n\t */\n\tdispose(): void;\n\t/**\n\t * Get a proxy to the arbitrary loaded code.\n\t */\n\tgetProxy(): Promise;\n\t/**\n\t * Synchronize (send) the models at `resources` to the web worker,\n\t * making them available in the monaco.worker.getMirrorModels().\n\t */\n\twithSyncedResources(resources: URI[]): Promise;\n}\n\nexport interface IWebWorkerOptions {\n\t/**\n\t * The AMD moduleId to load.\n\t * It should export a function `create` that should return the exported proxy.\n\t */\n\tmoduleId: string;\n\t/**\n\t * The data to send over when calling create on the module.\n\t */\n\tcreateData?: any;\n\t/**\n\t * A label to be used to identify the web worker for debugging purposes.\n\t */\n\tlabel?: string;\n\t/**\n\t * An object that can be used by the web worker to make calls back to the main thread.\n\t */\n\thost?: any;\n\t/**\n\t * Keep idle models.\n\t * Defaults to false, which means that idle models will stop syncing after a while.\n\t */\n\tkeepIdleModels?: boolean;\n}\n\nclass MonacoWebWorkerImpl extends EditorWorkerClient implements MonacoWebWorker {\n\n\tprivate readonly _foreignModuleId: string;\n\tprivate readonly _foreignModuleHost: { [method: string]: Function } | null;\n\tprivate _foreignModuleCreateData: any | null;\n\tprivate _foreignProxy: Promise | null;\n\n\tconstructor(modelService: IModelService, languageConfigurationService: ILanguageConfigurationService, opts: IWebWorkerOptions) {\n\t\tsuper(modelService, opts.keepIdleModels || false, opts.label, languageConfigurationService);\n\t\tthis._foreignModuleId = opts.moduleId;\n\t\tthis._foreignModuleCreateData = opts.createData || null;\n\t\tthis._foreignModuleHost = opts.host || null;\n\t\tthis._foreignProxy = null;\n\t}\n\n\t// foreign host request\n\tpublic override fhr(method: string, args: any[]): Promise {\n\t\tif (!this._foreignModuleHost || typeof this._foreignModuleHost[method] !== 'function') {\n\t\t\treturn Promise.reject(new Error('Missing method ' + method + ' or missing main thread foreign host.'));\n\t\t}\n\n\t\ttry {\n\t\t\treturn Promise.resolve(this._foreignModuleHost[method].apply(this._foreignModuleHost, args));\n\t\t} catch (e) {\n\t\t\treturn Promise.reject(e);\n\t\t}\n\t}\n\n\tprivate _getForeignProxy(): Promise {\n\t\tif (!this._foreignProxy) {\n\t\t\tthis._foreignProxy = this._getProxy().then((proxy) => {\n\t\t\t\tconst foreignHostMethods = this._foreignModuleHost ? getAllMethodNames(this._foreignModuleHost) : [];\n\t\t\t\treturn proxy.loadForeignModule(this._foreignModuleId, this._foreignModuleCreateData, foreignHostMethods).then((foreignMethods) => {\n\t\t\t\t\tthis._foreignModuleCreateData = null;\n\n\t\t\t\t\tconst proxyMethodRequest = (method: string, args: any[]): Promise => {\n\t\t\t\t\t\treturn proxy.fmr(method, args);\n\t\t\t\t\t};\n\n\t\t\t\t\tconst createProxyMethod = (method: string, proxyMethodRequest: (method: string, args: any[]) => Promise): () => Promise => {\n\t\t\t\t\t\treturn function () {\n\t\t\t\t\t\t\tconst args = Array.prototype.slice.call(arguments, 0);\n\t\t\t\t\t\t\treturn proxyMethodRequest(method, args);\n\t\t\t\t\t\t};\n\t\t\t\t\t};\n\n\t\t\t\t\tconst foreignProxy = {} as T;\n\t\t\t\t\tfor (const foreignMethod of foreignMethods) {\n\t\t\t\t\t\t(foreignProxy)[foreignMethod] = createProxyMethod(foreignMethod, proxyMethodRequest);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn foreignProxy;\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\t\treturn this._foreignProxy;\n\t}\n\n\tpublic getProxy(): Promise {\n\t\treturn this._getForeignProxy();\n\t}\n\n\tpublic withSyncedResources(resources: URI[]): Promise {\n\t\treturn this._withSyncedResources(resources).then(_ => this.getProxy());\n\t}\n}\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\nimport * as strings from 'vs/base/common/strings';\nimport { Range } from 'vs/editor/common/core/range';\nimport { ITextModel } from 'vs/editor/common/model';\nimport { IndentAction } from 'vs/editor/common/languages/languageConfiguration';\nimport { createScopedLineTokens } from 'vs/editor/common/languages/supports';\nimport { IndentConsts, IndentRulesSupport } from 'vs/editor/common/languages/supports/indentRules';\nimport { EditorAutoIndentStrategy } from 'vs/editor/common/config/editorOptions';\nimport { getScopedLineTokens, ILanguageConfigurationService } from 'vs/editor/common/languages/languageConfigurationRegistry';\nimport { LineTokens } from 'vs/editor/common/tokens/lineTokens';\n\nexport interface IVirtualModel {\n\ttokenization: {\n\t\tgetLineTokens(lineNumber: number): LineTokens;\n\t\tgetLanguageId(): string;\n\t\tgetLanguageIdAtPosition(lineNumber: number, column: number): string;\n\t};\n\tgetLineContent(lineNumber: number): string;\n}\n\nexport interface IIndentConverter {\n\tshiftIndent(indentation: string): string;\n\tunshiftIndent(indentation: string): string;\n\tnormalizeIndentation?(indentation: string): string;\n}\n\n/**\n * Get nearest preceding line which doesn't match unIndentPattern or contains all whitespace.\n * Result:\n * -1: run into the boundary of embedded languages\n * 0: every line above are invalid\n * else: nearest preceding line of the same language\n */\nfunction getPrecedingValidLine(model: IVirtualModel, lineNumber: number, indentRulesSupport: IndentRulesSupport) {\n\tconst languageId = model.tokenization.getLanguageIdAtPosition(lineNumber, 0);\n\tif (lineNumber > 1) {\n\t\tlet lastLineNumber: number;\n\t\tlet resultLineNumber = -1;\n\n\t\tfor (lastLineNumber = lineNumber - 1; lastLineNumber >= 1; lastLineNumber--) {\n\t\t\tif (model.tokenization.getLanguageIdAtPosition(lastLineNumber, 0) !== languageId) {\n\t\t\t\treturn resultLineNumber;\n\t\t\t}\n\t\t\tconst text = model.getLineContent(lastLineNumber);\n\t\t\tif (indentRulesSupport.shouldIgnore(text) || /^\\s+$/.test(text) || text === '') {\n\t\t\t\tresultLineNumber = lastLineNumber;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\treturn lastLineNumber;\n\t\t}\n\t}\n\n\treturn -1;\n}\n\n/**\n * Get inherited indentation from above lines.\n * 1. Find the nearest preceding line which doesn't match unIndentedLinePattern.\n * 2. If this line matches indentNextLinePattern or increaseIndentPattern, it means that the indent level of `lineNumber` should be 1 greater than this line.\n * 3. If this line doesn't match any indent rules\n * a. check whether the line above it matches indentNextLinePattern\n * b. If not, the indent level of this line is the result\n * 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).\n * 4. Otherwise, we fail to get an inherited indent from aboves. Return null and we should not touch the indent of `lineNumber`\n *\n * This function only return the inherited indent based on above lines, it doesn't check whether current line should decrease or not.\n */\nexport function getInheritIndentForLine(\n\tautoIndent: EditorAutoIndentStrategy,\n\tmodel: IVirtualModel,\n\tlineNumber: number,\n\thonorIntentialIndent: boolean = true,\n\tlanguageConfigurationService: ILanguageConfigurationService\n): { indentation: string; action: IndentAction | null; line?: number } | null {\n\tif (autoIndent < EditorAutoIndentStrategy.Full) {\n\t\treturn null;\n\t}\n\n\tconst indentRulesSupport = languageConfigurationService.getLanguageConfiguration(model.tokenization.getLanguageId()).indentRulesSupport;\n\tif (!indentRulesSupport) {\n\t\treturn null;\n\t}\n\n\tif (lineNumber <= 1) {\n\t\treturn {\n\t\t\tindentation: '',\n\t\t\taction: null\n\t\t};\n\t}\n\n\t// Use no indent if this is the first non-blank line\n\tfor (let priorLineNumber = lineNumber - 1; priorLineNumber > 0; priorLineNumber--) {\n\t\tif (model.getLineContent(priorLineNumber) !== '') {\n\t\t\tbreak;\n\t\t}\n\t\tif (priorLineNumber === 1) {\n\t\t\treturn {\n\t\t\t\tindentation: '',\n\t\t\t\taction: null\n\t\t\t};\n\t\t}\n\t}\n\n\tconst precedingUnIgnoredLine = getPrecedingValidLine(model, lineNumber, indentRulesSupport);\n\tif (precedingUnIgnoredLine < 0) {\n\t\treturn null;\n\t} else if (precedingUnIgnoredLine < 1) {\n\t\treturn {\n\t\t\tindentation: '',\n\t\t\taction: null\n\t\t};\n\t}\n\n\tconst precedingUnIgnoredLineContent = model.getLineContent(precedingUnIgnoredLine);\n\tif (indentRulesSupport.shouldIncrease(precedingUnIgnoredLineContent) || indentRulesSupport.shouldIndentNextLine(precedingUnIgnoredLineContent)) {\n\t\treturn {\n\t\t\tindentation: strings.getLeadingWhitespace(precedingUnIgnoredLineContent),\n\t\t\taction: IndentAction.Indent,\n\t\t\tline: precedingUnIgnoredLine\n\t\t};\n\t} else if (indentRulesSupport.shouldDecrease(precedingUnIgnoredLineContent)) {\n\t\treturn {\n\t\t\tindentation: strings.getLeadingWhitespace(precedingUnIgnoredLineContent),\n\t\t\taction: null,\n\t\t\tline: precedingUnIgnoredLine\n\t\t};\n\t} else {\n\t\t// precedingUnIgnoredLine can not be ignored.\n\t\t// it doesn't increase indent of following lines\n\t\t// it doesn't increase just next line\n\t\t// so current line is not affect by precedingUnIgnoredLine\n\t\t// and then we should get a correct inheritted indentation from above lines\n\t\tif (precedingUnIgnoredLine === 1) {\n\t\t\treturn {\n\t\t\t\tindentation: strings.getLeadingWhitespace(model.getLineContent(precedingUnIgnoredLine)),\n\t\t\t\taction: null,\n\t\t\t\tline: precedingUnIgnoredLine\n\t\t\t};\n\t\t}\n\n\t\tconst previousLine = precedingUnIgnoredLine - 1;\n\n\t\tconst previousLineIndentMetadata = indentRulesSupport.getIndentMetadata(model.getLineContent(previousLine));\n\t\tif (!(previousLineIndentMetadata & (IndentConsts.INCREASE_MASK | IndentConsts.DECREASE_MASK)) &&\n\t\t\t(previousLineIndentMetadata & IndentConsts.INDENT_NEXTLINE_MASK)) {\n\t\t\tlet stopLine = 0;\n\t\t\tfor (let i = previousLine - 1; i > 0; i--) {\n\t\t\t\tif (indentRulesSupport.shouldIndentNextLine(model.getLineContent(i))) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tstopLine = i;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tindentation: strings.getLeadingWhitespace(model.getLineContent(stopLine + 1)),\n\t\t\t\taction: null,\n\t\t\t\tline: stopLine + 1\n\t\t\t};\n\t\t}\n\n\t\tif (honorIntentialIndent) {\n\t\t\treturn {\n\t\t\t\tindentation: strings.getLeadingWhitespace(model.getLineContent(precedingUnIgnoredLine)),\n\t\t\t\taction: null,\n\t\t\t\tline: precedingUnIgnoredLine\n\t\t\t};\n\t\t} else {\n\t\t\t// search from precedingUnIgnoredLine until we find one whose indent is not temporary\n\t\t\tfor (let i = precedingUnIgnoredLine; i > 0; i--) {\n\t\t\t\tconst lineContent = model.getLineContent(i);\n\t\t\t\tif (indentRulesSupport.shouldIncrease(lineContent)) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tindentation: strings.getLeadingWhitespace(lineContent),\n\t\t\t\t\t\taction: IndentAction.Indent,\n\t\t\t\t\t\tline: i\n\t\t\t\t\t};\n\t\t\t\t} else if (indentRulesSupport.shouldIndentNextLine(lineContent)) {\n\t\t\t\t\tlet stopLine = 0;\n\t\t\t\t\tfor (let j = i - 1; j > 0; j--) {\n\t\t\t\t\t\tif (indentRulesSupport.shouldIndentNextLine(model.getLineContent(i))) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tstopLine = j;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tindentation: strings.getLeadingWhitespace(model.getLineContent(stopLine + 1)),\n\t\t\t\t\t\taction: null,\n\t\t\t\t\t\tline: stopLine + 1\n\t\t\t\t\t};\n\t\t\t\t} else if (indentRulesSupport.shouldDecrease(lineContent)) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tindentation: strings.getLeadingWhitespace(lineContent),\n\t\t\t\t\t\taction: null,\n\t\t\t\t\t\tline: i\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tindentation: strings.getLeadingWhitespace(model.getLineContent(1)),\n\t\t\t\taction: null,\n\t\t\t\tline: 1\n\t\t\t};\n\t\t}\n\t}\n}\n\nexport function getGoodIndentForLine(\n\tautoIndent: EditorAutoIndentStrategy,\n\tvirtualModel: IVirtualModel,\n\tlanguageId: string,\n\tlineNumber: number,\n\tindentConverter: IIndentConverter,\n\tlanguageConfigurationService: ILanguageConfigurationService\n): string | null {\n\tif (autoIndent < EditorAutoIndentStrategy.Full) {\n\t\treturn null;\n\t}\n\n\tconst richEditSupport = languageConfigurationService.getLanguageConfiguration(languageId);\n\tif (!richEditSupport) {\n\t\treturn null;\n\t}\n\n\tconst indentRulesSupport = languageConfigurationService.getLanguageConfiguration(languageId).indentRulesSupport;\n\tif (!indentRulesSupport) {\n\t\treturn null;\n\t}\n\n\tconst indent = getInheritIndentForLine(autoIndent, virtualModel, lineNumber, undefined, languageConfigurationService);\n\tconst lineContent = virtualModel.getLineContent(lineNumber);\n\n\tif (indent) {\n\t\tconst inheritLine = indent.line;\n\t\tif (inheritLine !== undefined) {\n\t\t\t// Apply enter action as long as there are only whitespace lines between inherited line and this line.\n\t\t\tlet shouldApplyEnterRules = true;\n\t\t\tfor (let inBetweenLine = inheritLine; inBetweenLine < lineNumber - 1; inBetweenLine++) {\n\t\t\t\tif (!/^\\s*$/.test(virtualModel.getLineContent(inBetweenLine))) {\n\t\t\t\t\tshouldApplyEnterRules = false;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (shouldApplyEnterRules) {\n\t\t\t\tconst enterResult = richEditSupport.onEnter(autoIndent, '', virtualModel.getLineContent(inheritLine), '');\n\n\t\t\t\tif (enterResult) {\n\t\t\t\t\tlet indentation = strings.getLeadingWhitespace(virtualModel.getLineContent(inheritLine));\n\n\t\t\t\t\tif (enterResult.removeText) {\n\t\t\t\t\t\tindentation = indentation.substring(0, indentation.length - enterResult.removeText);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (\n\t\t\t\t\t\t(enterResult.indentAction === IndentAction.Indent) ||\n\t\t\t\t\t\t(enterResult.indentAction === IndentAction.IndentOutdent)\n\t\t\t\t\t) {\n\t\t\t\t\t\tindentation = indentConverter.shiftIndent(indentation);\n\t\t\t\t\t} else if (enterResult.indentAction === IndentAction.Outdent) {\n\t\t\t\t\t\tindentation = indentConverter.unshiftIndent(indentation);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (indentRulesSupport.shouldDecrease(lineContent)) {\n\t\t\t\t\t\tindentation = indentConverter.unshiftIndent(indentation);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (enterResult.appendText) {\n\t\t\t\t\t\tindentation += enterResult.appendText;\n\t\t\t\t\t}\n\n\t\t\t\t\treturn strings.getLeadingWhitespace(indentation);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (indentRulesSupport.shouldDecrease(lineContent)) {\n\t\t\tif (indent.action === IndentAction.Indent) {\n\t\t\t\treturn indent.indentation;\n\t\t\t} else {\n\t\t\t\treturn indentConverter.unshiftIndent(indent.indentation);\n\t\t\t}\n\t\t} else {\n\t\t\tif (indent.action === IndentAction.Indent) {\n\t\t\t\treturn indentConverter.shiftIndent(indent.indentation);\n\t\t\t} else {\n\t\t\t\treturn indent.indentation;\n\t\t\t}\n\t\t}\n\t}\n\treturn null;\n}\n\nexport function getIndentForEnter(\n\tautoIndent: EditorAutoIndentStrategy,\n\tmodel: ITextModel,\n\trange: Range,\n\tindentConverter: IIndentConverter,\n\tlanguageConfigurationService: ILanguageConfigurationService\n): { beforeEnter: string; afterEnter: string } | null {\n\tif (autoIndent < EditorAutoIndentStrategy.Full) {\n\t\treturn null;\n\t}\n\tmodel.tokenization.forceTokenization(range.startLineNumber);\n\tconst lineTokens = model.tokenization.getLineTokens(range.startLineNumber);\n\tconst scopedLineTokens = createScopedLineTokens(lineTokens, range.startColumn - 1);\n\tconst scopedLineText = scopedLineTokens.getLineContent();\n\n\tlet embeddedLanguage = false;\n\tlet beforeEnterText: string;\n\tif (scopedLineTokens.firstCharOffset > 0 && lineTokens.getLanguageId(0) !== scopedLineTokens.languageId) {\n\t\t// we are in the embeded language content\n\t\tembeddedLanguage = true; // if embeddedLanguage is true, then we don't touch the indentation of current line\n\t\tbeforeEnterText = scopedLineText.substr(0, range.startColumn - 1 - scopedLineTokens.firstCharOffset);\n\t} else {\n\t\tbeforeEnterText = lineTokens.getLineContent().substring(0, range.startColumn - 1);\n\t}\n\n\tlet afterEnterText: string;\n\tif (range.isEmpty()) {\n\t\tafterEnterText = scopedLineText.substr(range.startColumn - 1 - scopedLineTokens.firstCharOffset);\n\t} else {\n\t\tconst endScopedLineTokens = getScopedLineTokens(model, range.endLineNumber, range.endColumn);\n\t\tafterEnterText = endScopedLineTokens.getLineContent().substr(range.endColumn - 1 - scopedLineTokens.firstCharOffset);\n\t}\n\n\tconst indentRulesSupport = languageConfigurationService.getLanguageConfiguration(scopedLineTokens.languageId).indentRulesSupport;\n\tif (!indentRulesSupport) {\n\t\treturn null;\n\t}\n\n\tconst beforeEnterResult = beforeEnterText;\n\tconst beforeEnterIndent = strings.getLeadingWhitespace(beforeEnterText);\n\n\tconst virtualModel: IVirtualModel = {\n\t\ttokenization: {\n\t\t\tgetLineTokens: (lineNumber: number) => {\n\t\t\t\treturn model.tokenization.getLineTokens(lineNumber);\n\t\t\t},\n\t\t\tgetLanguageId: () => {\n\t\t\t\treturn model.getLanguageId();\n\t\t\t},\n\t\t\tgetLanguageIdAtPosition: (lineNumber: number, column: number) => {\n\t\t\t\treturn model.getLanguageIdAtPosition(lineNumber, column);\n\t\t\t},\n\t\t},\n\t\tgetLineContent: (lineNumber: number) => {\n\t\t\tif (lineNumber === range.startLineNumber) {\n\t\t\t\treturn beforeEnterResult;\n\t\t\t} else {\n\t\t\t\treturn model.getLineContent(lineNumber);\n\t\t\t}\n\t\t}\n\t};\n\n\tconst currentLineIndent = strings.getLeadingWhitespace(lineTokens.getLineContent());\n\tconst afterEnterAction = getInheritIndentForLine(autoIndent, virtualModel, range.startLineNumber + 1, undefined, languageConfigurationService);\n\tif (!afterEnterAction) {\n\t\tconst beforeEnter = embeddedLanguage ? currentLineIndent : beforeEnterIndent;\n\t\treturn {\n\t\t\tbeforeEnter: beforeEnter,\n\t\t\tafterEnter: beforeEnter\n\t\t};\n\t}\n\n\tlet afterEnterIndent = embeddedLanguage ? currentLineIndent : afterEnterAction.indentation;\n\n\tif (afterEnterAction.action === IndentAction.Indent) {\n\t\tafterEnterIndent = indentConverter.shiftIndent(afterEnterIndent);\n\t}\n\n\tif (indentRulesSupport.shouldDecrease(afterEnterText)) {\n\t\tafterEnterIndent = indentConverter.unshiftIndent(afterEnterIndent);\n\t}\n\n\treturn {\n\t\tbeforeEnter: embeddedLanguage ? currentLineIndent : beforeEnterIndent,\n\t\tafterEnter: afterEnterIndent\n\t};\n}\n\n/**\n * We should always allow intentional indentation. It means, if users change the indentation of `lineNumber` and the content of\n * this line doesn't match decreaseIndentPattern, we should not adjust the indentation.\n */\nexport function getIndentActionForType(\n\tautoIndent: EditorAutoIndentStrategy,\n\tmodel: ITextModel,\n\trange: Range,\n\tch: string,\n\tindentConverter: IIndentConverter,\n\tlanguageConfigurationService: ILanguageConfigurationService\n): string | null {\n\tif (autoIndent < EditorAutoIndentStrategy.Full) {\n\t\treturn null;\n\t}\n\tconst scopedLineTokens = getScopedLineTokens(model, range.startLineNumber, range.startColumn);\n\n\tif (scopedLineTokens.firstCharOffset) {\n\t\t// this line has mixed languages and indentation rules will not work\n\t\treturn null;\n\t}\n\n\tconst indentRulesSupport = languageConfigurationService.getLanguageConfiguration(scopedLineTokens.languageId).indentRulesSupport;\n\tif (!indentRulesSupport) {\n\t\treturn null;\n\t}\n\n\tconst scopedLineText = scopedLineTokens.getLineContent();\n\tconst beforeTypeText = scopedLineText.substr(0, range.startColumn - 1 - scopedLineTokens.firstCharOffset);\n\n\t// selection support\n\tlet afterTypeText: string;\n\tif (range.isEmpty()) {\n\t\tafterTypeText = scopedLineText.substr(range.startColumn - 1 - scopedLineTokens.firstCharOffset);\n\t} else {\n\t\tconst endScopedLineTokens = getScopedLineTokens(model, range.endLineNumber, range.endColumn);\n\t\tafterTypeText = endScopedLineTokens.getLineContent().substr(range.endColumn - 1 - scopedLineTokens.firstCharOffset);\n\t}\n\n\t// If previous content already matches decreaseIndentPattern, it means indentation of this line should already be adjusted\n\t// Users might change the indentation by purpose and we should honor that instead of readjusting.\n\tif (!indentRulesSupport.shouldDecrease(beforeTypeText + afterTypeText) && indentRulesSupport.shouldDecrease(beforeTypeText + ch + afterTypeText)) {\n\t\t// after typing `ch`, the content matches decreaseIndentPattern, we should adjust the indent to a good manner.\n\t\t// 1. Get inherited indent action\n\t\tconst r = getInheritIndentForLine(autoIndent, model, range.startLineNumber, false, languageConfigurationService);\n\t\tif (!r) {\n\t\t\treturn null;\n\t\t}\n\n\t\tlet indentation = r.indentation;\n\t\tif (r.action !== IndentAction.Indent) {\n\t\t\tindentation = indentConverter.unshiftIndent(indentation);\n\t\t}\n\n\t\treturn indentation;\n\t}\n\n\treturn null;\n}\n\nexport function getIndentMetadata(\n\tmodel: ITextModel,\n\tlineNumber: number,\n\tlanguageConfigurationService: ILanguageConfigurationService\n): number | null {\n\tconst indentRulesSupport = languageConfigurationService.getLanguageConfiguration(model.getLanguageId()).indentRulesSupport;\n\tif (!indentRulesSupport) {\n\t\treturn null;\n\t}\n\tif (lineNumber < 1 || lineNumber > model.getLineCount()) {\n\t\treturn null;\n\t}\n\treturn indentRulesSupport.getIndentMetadata(model.getLineContent(lineNumber));\n}\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\nimport { Range } from 'vs/editor/common/core/range';\nimport { ITextModel } from 'vs/editor/common/model';\nimport { IndentAction, CompleteEnterAction } from 'vs/editor/common/languages/languageConfiguration';\nimport { EditorAutoIndentStrategy } from 'vs/editor/common/config/editorOptions';\nimport { getIndentationAtPosition, getScopedLineTokens, ILanguageConfigurationService } from 'vs/editor/common/languages/languageConfigurationRegistry';\n\nexport function getEnterAction(\n\tautoIndent: EditorAutoIndentStrategy,\n\tmodel: ITextModel,\n\trange: Range,\n\tlanguageConfigurationService: ILanguageConfigurationService\n): CompleteEnterAction | null {\n\tconst scopedLineTokens = getScopedLineTokens(model, range.startLineNumber, range.startColumn);\n\tconst richEditSupport = languageConfigurationService.getLanguageConfiguration(scopedLineTokens.languageId);\n\tif (!richEditSupport) {\n\t\treturn null;\n\t}\n\n\tconst scopedLineText = scopedLineTokens.getLineContent();\n\tconst beforeEnterText = scopedLineText.substr(0, range.startColumn - 1 - scopedLineTokens.firstCharOffset);\n\n\t// selection support\n\tlet afterEnterText: string;\n\tif (range.isEmpty()) {\n\t\tafterEnterText = scopedLineText.substr(range.startColumn - 1 - scopedLineTokens.firstCharOffset);\n\t} else {\n\t\tconst endScopedLineTokens = getScopedLineTokens(model, range.endLineNumber, range.endColumn);\n\t\tafterEnterText = endScopedLineTokens.getLineContent().substr(range.endColumn - 1 - scopedLineTokens.firstCharOffset);\n\t}\n\n\tlet previousLineText = '';\n\tif (range.startLineNumber > 1 && scopedLineTokens.firstCharOffset === 0) {\n\t\t// This is not the first line and the entire line belongs to this mode\n\t\tconst oneLineAboveScopedLineTokens = getScopedLineTokens(model, range.startLineNumber - 1);\n\t\tif (oneLineAboveScopedLineTokens.languageId === scopedLineTokens.languageId) {\n\t\t\t// The line above ends with text belonging to the same mode\n\t\t\tpreviousLineText = oneLineAboveScopedLineTokens.getLineContent();\n\t\t}\n\t}\n\n\tconst enterResult = richEditSupport.onEnter(autoIndent, previousLineText, beforeEnterText, afterEnterText);\n\tif (!enterResult) {\n\t\treturn null;\n\t}\n\n\tconst indentAction = enterResult.indentAction;\n\tlet appendText = enterResult.appendText;\n\tconst removeText = enterResult.removeText || 0;\n\n\t// Here we add `\\t` to appendText first because enterAction is leveraging appendText and removeText to change indentation.\n\tif (!appendText) {\n\t\tif (\n\t\t\t(indentAction === IndentAction.Indent) ||\n\t\t\t(indentAction === IndentAction.IndentOutdent)\n\t\t) {\n\t\t\tappendText = '\\t';\n\t\t} else {\n\t\t\tappendText = '';\n\t\t}\n\t} else if (indentAction === IndentAction.Indent) {\n\t\tappendText = '\\t' + appendText;\n\t}\n\n\tlet indentation = getIndentationAtPosition(model, range.startLineNumber, range.startColumn);\n\tif (removeText) {\n\t\tindentation = indentation.substring(0, indentation.length - removeText);\n\t}\n\n\treturn {\n\t\tindentAction: indentAction,\n\t\tappendText: appendText,\n\t\tremoveText: removeText,\n\t\tindentation: indentation\n\t};\n}\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\nimport { CharCode } from 'vs/base/common/charCode';\nimport * as strings from 'vs/base/common/strings';\nimport { CursorColumns } from 'vs/editor/common/core/cursorColumns';\nimport { Range } from 'vs/editor/common/core/range';\nimport { Selection, SelectionDirection } from 'vs/editor/common/core/selection';\nimport { ICommand, ICursorStateComputerData, IEditOperationBuilder } from 'vs/editor/common/editorCommon';\nimport { ITextModel } from 'vs/editor/common/model';\nimport { EditorAutoIndentStrategy } from 'vs/editor/common/config/editorOptions';\nimport { getEnterAction } from 'vs/editor/common/languages/enterAction';\nimport { ILanguageConfigurationService } from 'vs/editor/common/languages/languageConfigurationRegistry';\n\nexport interface IShiftCommandOpts {\n\tisUnshift: boolean;\n\ttabSize: number;\n\tindentSize: number;\n\tinsertSpaces: boolean;\n\tuseTabStops: boolean;\n\tautoIndent: EditorAutoIndentStrategy;\n}\n\nconst repeatCache: { [str: string]: string[] } = Object.create(null);\nfunction cachedStringRepeat(str: string, count: number): string {\n\tif (count <= 0) {\n\t\treturn '';\n\t}\n\tif (!repeatCache[str]) {\n\t\trepeatCache[str] = ['', str];\n\t}\n\tconst cache = repeatCache[str];\n\tfor (let i = cache.length; i <= count; i++) {\n\t\tcache[i] = cache[i - 1] + str;\n\t}\n\treturn cache[count];\n}\n\nexport class ShiftCommand implements ICommand {\n\n\tpublic static unshiftIndent(line: string, column: number, tabSize: number, indentSize: number, insertSpaces: boolean): string {\n\t\t// Determine the visible column where the content starts\n\t\tconst contentStartVisibleColumn = CursorColumns.visibleColumnFromColumn(line, column, tabSize);\n\n\t\tif (insertSpaces) {\n\t\t\tconst indent = cachedStringRepeat(' ', indentSize);\n\t\t\tconst desiredTabStop = CursorColumns.prevIndentTabStop(contentStartVisibleColumn, indentSize);\n\t\t\tconst indentCount = desiredTabStop / indentSize; // will be an integer\n\t\t\treturn cachedStringRepeat(indent, indentCount);\n\t\t} else {\n\t\t\tconst indent = '\\t';\n\t\t\tconst desiredTabStop = CursorColumns.prevRenderTabStop(contentStartVisibleColumn, tabSize);\n\t\t\tconst indentCount = desiredTabStop / tabSize; // will be an integer\n\t\t\treturn cachedStringRepeat(indent, indentCount);\n\t\t}\n\t}\n\n\tpublic static shiftIndent(line: string, column: number, tabSize: number, indentSize: number, insertSpaces: boolean): string {\n\t\t// Determine the visible column where the content starts\n\t\tconst contentStartVisibleColumn = CursorColumns.visibleColumnFromColumn(line, column, tabSize);\n\n\t\tif (insertSpaces) {\n\t\t\tconst indent = cachedStringRepeat(' ', indentSize);\n\t\t\tconst desiredTabStop = CursorColumns.nextIndentTabStop(contentStartVisibleColumn, indentSize);\n\t\t\tconst indentCount = desiredTabStop / indentSize; // will be an integer\n\t\t\treturn cachedStringRepeat(indent, indentCount);\n\t\t} else {\n\t\t\tconst indent = '\\t';\n\t\t\tconst desiredTabStop = CursorColumns.nextRenderTabStop(contentStartVisibleColumn, tabSize);\n\t\t\tconst indentCount = desiredTabStop / tabSize; // will be an integer\n\t\t\treturn cachedStringRepeat(indent, indentCount);\n\t\t}\n\t}\n\n\tprivate readonly _opts: IShiftCommandOpts;\n\tprivate readonly _selection: Selection;\n\tprivate _selectionId: string | null;\n\tprivate _useLastEditRangeForCursorEndPosition: boolean;\n\tprivate _selectionStartColumnStaysPut: boolean;\n\n\tconstructor(\n\t\trange: Selection,\n\t\topts: IShiftCommandOpts,\n\t\t@ILanguageConfigurationService private readonly _languageConfigurationService: ILanguageConfigurationService\n\t) {\n\t\tthis._opts = opts;\n\t\tthis._selection = range;\n\t\tthis._selectionId = null;\n\t\tthis._useLastEditRangeForCursorEndPosition = false;\n\t\tthis._selectionStartColumnStaysPut = false;\n\t}\n\n\tprivate _addEditOperation(builder: IEditOperationBuilder, range: Range, text: string) {\n\t\tif (this._useLastEditRangeForCursorEndPosition) {\n\t\t\tbuilder.addTrackedEditOperation(range, text);\n\t\t} else {\n\t\t\tbuilder.addEditOperation(range, text);\n\t\t}\n\t}\n\n\tpublic getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {\n\t\tconst startLine = this._selection.startLineNumber;\n\n\t\tlet endLine = this._selection.endLineNumber;\n\t\tif (this._selection.endColumn === 1 && startLine !== endLine) {\n\t\t\tendLine = endLine - 1;\n\t\t}\n\n\t\tconst { tabSize, indentSize, insertSpaces } = this._opts;\n\t\tconst shouldIndentEmptyLines = (startLine === endLine);\n\n\t\tif (this._opts.useTabStops) {\n\t\t\t// if indenting or outdenting on a whitespace only line\n\t\t\tif (this._selection.isEmpty()) {\n\t\t\t\tif (/^\\s*$/.test(model.getLineContent(startLine))) {\n\t\t\t\t\tthis._useLastEditRangeForCursorEndPosition = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// keep track of previous line's \"miss-alignment\"\n\t\t\tlet previousLineExtraSpaces = 0, extraSpaces = 0;\n\t\t\tfor (let lineNumber = startLine; lineNumber <= endLine; lineNumber++, previousLineExtraSpaces = extraSpaces) {\n\t\t\t\textraSpaces = 0;\n\t\t\t\tconst lineText = model.getLineContent(lineNumber);\n\t\t\t\tlet indentationEndIndex = strings.firstNonWhitespaceIndex(lineText);\n\n\t\t\t\tif (this._opts.isUnshift && (lineText.length === 0 || indentationEndIndex === 0)) {\n\t\t\t\t\t// empty line or line with no leading whitespace => nothing to do\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (!shouldIndentEmptyLines && !this._opts.isUnshift && lineText.length === 0) {\n\t\t\t\t\t// do not indent empty lines => nothing to do\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (indentationEndIndex === -1) {\n\t\t\t\t\t// the entire line is whitespace\n\t\t\t\t\tindentationEndIndex = lineText.length;\n\t\t\t\t}\n\n\t\t\t\tif (lineNumber > 1) {\n\t\t\t\t\tconst contentStartVisibleColumn = CursorColumns.visibleColumnFromColumn(lineText, indentationEndIndex + 1, tabSize);\n\t\t\t\t\tif (contentStartVisibleColumn % indentSize !== 0) {\n\t\t\t\t\t\t// The current line is \"miss-aligned\", so let's see if this is expected...\n\t\t\t\t\t\t// This can only happen when it has trailing commas in the indent\n\t\t\t\t\t\tif (model.tokenization.isCheapToTokenize(lineNumber - 1)) {\n\t\t\t\t\t\t\tconst enterAction = getEnterAction(this._opts.autoIndent, model, new Range(lineNumber - 1, model.getLineMaxColumn(lineNumber - 1), lineNumber - 1, model.getLineMaxColumn(lineNumber - 1)), this._languageConfigurationService);\n\t\t\t\t\t\t\tif (enterAction) {\n\t\t\t\t\t\t\t\textraSpaces = previousLineExtraSpaces;\n\t\t\t\t\t\t\t\tif (enterAction.appendText) {\n\t\t\t\t\t\t\t\t\tfor (let j = 0, lenJ = enterAction.appendText.length; j < lenJ && extraSpaces < indentSize; j++) {\n\t\t\t\t\t\t\t\t\t\tif (enterAction.appendText.charCodeAt(j) === CharCode.Space) {\n\t\t\t\t\t\t\t\t\t\t\textraSpaces++;\n\t\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif (enterAction.removeText) {\n\t\t\t\t\t\t\t\t\textraSpaces = Math.max(0, extraSpaces - enterAction.removeText);\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// Act as if `prefixSpaces` is not part of the indentation\n\t\t\t\t\t\t\t\tfor (let j = 0; j < extraSpaces; j++) {\n\t\t\t\t\t\t\t\t\tif (indentationEndIndex === 0 || lineText.charCodeAt(indentationEndIndex - 1) !== CharCode.Space) {\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tindentationEndIndex--;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\n\t\t\t\tif (this._opts.isUnshift && indentationEndIndex === 0) {\n\t\t\t\t\t// line with no leading whitespace => nothing to do\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tlet desiredIndent: string;\n\t\t\t\tif (this._opts.isUnshift) {\n\t\t\t\t\tdesiredIndent = ShiftCommand.unshiftIndent(lineText, indentationEndIndex + 1, tabSize, indentSize, insertSpaces);\n\t\t\t\t} else {\n\t\t\t\t\tdesiredIndent = ShiftCommand.shiftIndent(lineText, indentationEndIndex + 1, tabSize, indentSize, insertSpaces);\n\t\t\t\t}\n\n\t\t\t\tthis._addEditOperation(builder, new Range(lineNumber, 1, lineNumber, indentationEndIndex + 1), desiredIndent);\n\t\t\t\tif (lineNumber === startLine && !this._selection.isEmpty()) {\n\t\t\t\t\t// Force the startColumn to stay put because we're inserting after it\n\t\t\t\t\tthis._selectionStartColumnStaysPut = (this._selection.startColumn <= indentationEndIndex + 1);\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\n\t\t\t// if indenting or outdenting on a whitespace only line\n\t\t\tif (!this._opts.isUnshift && this._selection.isEmpty() && model.getLineLength(startLine) === 0) {\n\t\t\t\tthis._useLastEditRangeForCursorEndPosition = true;\n\t\t\t}\n\n\t\t\tconst oneIndent = (insertSpaces ? cachedStringRepeat(' ', indentSize) : '\\t');\n\n\t\t\tfor (let lineNumber = startLine; lineNumber <= endLine; lineNumber++) {\n\t\t\t\tconst lineText = model.getLineContent(lineNumber);\n\t\t\t\tlet indentationEndIndex = strings.firstNonWhitespaceIndex(lineText);\n\n\t\t\t\tif (this._opts.isUnshift && (lineText.length === 0 || indentationEndIndex === 0)) {\n\t\t\t\t\t// empty line or line with no leading whitespace => nothing to do\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (!shouldIndentEmptyLines && !this._opts.isUnshift && lineText.length === 0) {\n\t\t\t\t\t// do not indent empty lines => nothing to do\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (indentationEndIndex === -1) {\n\t\t\t\t\t// the entire line is whitespace\n\t\t\t\t\tindentationEndIndex = lineText.length;\n\t\t\t\t}\n\n\t\t\t\tif (this._opts.isUnshift && indentationEndIndex === 0) {\n\t\t\t\t\t// line with no leading whitespace => nothing to do\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (this._opts.isUnshift) {\n\n\t\t\t\t\tindentationEndIndex = Math.min(indentationEndIndex, indentSize);\n\t\t\t\t\tfor (let i = 0; i < indentationEndIndex; i++) {\n\t\t\t\t\t\tconst chr = lineText.charCodeAt(i);\n\t\t\t\t\t\tif (chr === CharCode.Tab) {\n\t\t\t\t\t\t\tindentationEndIndex = i + 1;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tthis._addEditOperation(builder, new Range(lineNumber, 1, lineNumber, indentationEndIndex + 1), '');\n\t\t\t\t} else {\n\t\t\t\t\tthis._addEditOperation(builder, new Range(lineNumber, 1, lineNumber, 1), oneIndent);\n\t\t\t\t\tif (lineNumber === startLine && !this._selection.isEmpty()) {\n\t\t\t\t\t\t// Force the startColumn to stay put because we're inserting after it\n\t\t\t\t\t\tthis._selectionStartColumnStaysPut = (this._selection.startColumn === 1);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthis._selectionId = builder.trackSelection(this._selection);\n\t}\n\n\tpublic computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {\n\t\tif (this._useLastEditRangeForCursorEndPosition) {\n\t\t\tconst lastOp = helper.getInverseEditOperations()[0];\n\t\t\treturn new Selection(lastOp.range.endLineNumber, lastOp.range.endColumn, lastOp.range.endLineNumber, lastOp.range.endColumn);\n\t\t}\n\t\tconst result = helper.getTrackedSelection(this._selectionId!);\n\n\t\tif (this._selectionStartColumnStaysPut) {\n\t\t\t// The selection start should not move\n\t\t\tconst initialStartColumn = this._selection.startColumn;\n\t\t\tconst resultStartColumn = result.startColumn;\n\t\t\tif (resultStartColumn <= initialStartColumn) {\n\t\t\t\treturn result;\n\t\t\t}\n\n\t\t\tif (result.getDirection() === SelectionDirection.LTR) {\n\t\t\t\treturn new Selection(result.startLineNumber, initialStartColumn, result.endLineNumber, result.endColumn);\n\t\t\t}\n\t\t\treturn new Selection(result.endLineNumber, result.endColumn, result.startLineNumber, initialStartColumn);\n\t\t}\n\n\t\treturn result;\n\t}\n}\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\nimport { CharCode } from 'vs/base/common/charCode';\nimport { onUnexpectedError } from 'vs/base/common/errors';\nimport * as strings from 'vs/base/common/strings';\nimport { ReplaceCommand, ReplaceCommandWithOffsetCursorState, ReplaceCommandWithoutChangingPosition, ReplaceCommandThatPreservesSelection } from 'vs/editor/common/commands/replaceCommand';\nimport { ShiftCommand } from 'vs/editor/common/commands/shiftCommand';\nimport { CompositionSurroundSelectionCommand, SurroundSelectionCommand } from 'vs/editor/common/commands/surroundSelectionCommand';\nimport { CursorConfiguration, EditOperationResult, EditOperationType, ICursorSimpleModel, isQuote } from 'vs/editor/common/cursorCommon';\nimport { WordCharacterClass, getMapForWordSeparators } from 'vs/editor/common/core/wordCharacterClassifier';\nimport { Range } from 'vs/editor/common/core/range';\nimport { Selection } from 'vs/editor/common/core/selection';\nimport { Position } from 'vs/editor/common/core/position';\nimport { ICommand, ICursorStateComputerData } from 'vs/editor/common/editorCommon';\nimport { ITextModel } from 'vs/editor/common/model';\nimport { EnterAction, IndentAction, StandardAutoClosingPairConditional } from 'vs/editor/common/languages/languageConfiguration';\nimport { getIndentationAtPosition } from 'vs/editor/common/languages/languageConfigurationRegistry';\nimport { IElectricAction } from 'vs/editor/common/languages/supports/electricCharacter';\nimport { EditorAutoClosingStrategy, EditorAutoIndentStrategy } from 'vs/editor/common/config/editorOptions';\nimport { createScopedLineTokens } from 'vs/editor/common/languages/supports';\nimport { getIndentActionForType, getIndentForEnter, getInheritIndentForLine } from 'vs/editor/common/languages/autoIndent';\nimport { getEnterAction } from 'vs/editor/common/languages/enterAction';\n\nexport class TypeOperations {\n\n\tpublic static indent(config: CursorConfiguration, model: ICursorSimpleModel | null, selections: Selection[] | null): ICommand[] {\n\t\tif (model === null || selections === null) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst commands: ICommand[] = [];\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\n\t\t\tcommands[i] = new ShiftCommand(selections[i], {\n\t\t\t\tisUnshift: false,\n\t\t\t\ttabSize: config.tabSize,\n\t\t\t\tindentSize: config.indentSize,\n\t\t\t\tinsertSpaces: config.insertSpaces,\n\t\t\t\tuseTabStops: config.useTabStops,\n\t\t\t\tautoIndent: config.autoIndent\n\t\t\t}, config.languageConfigurationService);\n\t\t}\n\t\treturn commands;\n\t}\n\n\tpublic static outdent(config: CursorConfiguration, model: ICursorSimpleModel, selections: Selection[]): ICommand[] {\n\t\tconst commands: ICommand[] = [];\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\n\t\t\tcommands[i] = new ShiftCommand(selections[i], {\n\t\t\t\tisUnshift: true,\n\t\t\t\ttabSize: config.tabSize,\n\t\t\t\tindentSize: config.indentSize,\n\t\t\t\tinsertSpaces: config.insertSpaces,\n\t\t\t\tuseTabStops: config.useTabStops,\n\t\t\t\tautoIndent: config.autoIndent\n\t\t\t}, config.languageConfigurationService);\n\t\t}\n\t\treturn commands;\n\t}\n\n\tpublic static shiftIndent(config: CursorConfiguration, indentation: string, count?: number): string {\n\t\tcount = count || 1;\n\t\treturn ShiftCommand.shiftIndent(indentation, indentation.length + count, config.tabSize, config.indentSize, config.insertSpaces);\n\t}\n\n\tpublic static unshiftIndent(config: CursorConfiguration, indentation: string, count?: number): string {\n\t\tcount = count || 1;\n\t\treturn ShiftCommand.unshiftIndent(indentation, indentation.length + count, config.tabSize, config.indentSize, config.insertSpaces);\n\t}\n\n\tprivate static _distributedPaste(config: CursorConfiguration, model: ICursorSimpleModel, selections: Selection[], text: string[]): EditOperationResult {\n\t\tconst commands: ICommand[] = [];\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\n\t\t\tcommands[i] = new ReplaceCommand(selections[i], text[i]);\n\t\t}\n\t\treturn new EditOperationResult(EditOperationType.Other, commands, {\n\t\t\tshouldPushStackElementBefore: true,\n\t\t\tshouldPushStackElementAfter: true\n\t\t});\n\t}\n\n\tprivate static _simplePaste(config: CursorConfiguration, model: ICursorSimpleModel, selections: Selection[], text: string, pasteOnNewLine: boolean): EditOperationResult {\n\t\tconst commands: ICommand[] = [];\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\n\t\t\tconst selection = selections[i];\n\t\t\tconst position = selection.getPosition();\n\n\t\t\tif (pasteOnNewLine && !selection.isEmpty()) {\n\t\t\t\tpasteOnNewLine = false;\n\t\t\t}\n\t\t\tif (pasteOnNewLine && text.indexOf('\\n') !== text.length - 1) {\n\t\t\t\tpasteOnNewLine = false;\n\t\t\t}\n\n\t\t\tif (pasteOnNewLine) {\n\t\t\t\t// Paste entire line at the beginning of line\n\t\t\t\tconst typeSelection = new Range(position.lineNumber, 1, position.lineNumber, 1);\n\t\t\t\tcommands[i] = new ReplaceCommandThatPreservesSelection(typeSelection, text, selection, true);\n\t\t\t} else {\n\t\t\t\tcommands[i] = new ReplaceCommand(selection, text);\n\t\t\t}\n\t\t}\n\t\treturn new EditOperationResult(EditOperationType.Other, commands, {\n\t\t\tshouldPushStackElementBefore: true,\n\t\t\tshouldPushStackElementAfter: true\n\t\t});\n\t}\n\n\tprivate static _distributePasteToCursors(config: CursorConfiguration, selections: Selection[], text: string, pasteOnNewLine: boolean, multicursorText: string[]): string[] | null {\n\t\tif (pasteOnNewLine) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif (selections.length === 1) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif (multicursorText && multicursorText.length === selections.length) {\n\t\t\treturn multicursorText;\n\t\t}\n\n\t\tif (config.multiCursorPaste === 'spread') {\n\t\t\t// Try to spread the pasted text in case the line count matches the cursor count\n\t\t\t// Remove trailing \\n if present\n\t\t\tif (text.charCodeAt(text.length - 1) === CharCode.LineFeed) {\n\t\t\t\ttext = text.substr(0, text.length - 1);\n\t\t\t}\n\t\t\t// Remove trailing \\r if present\n\t\t\tif (text.charCodeAt(text.length - 1) === CharCode.CarriageReturn) {\n\t\t\t\ttext = text.substr(0, text.length - 1);\n\t\t\t}\n\t\t\tconst lines = strings.splitLines(text);\n\t\t\tif (lines.length === selections.length) {\n\t\t\t\treturn lines;\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tpublic static paste(config: CursorConfiguration, model: ICursorSimpleModel, selections: Selection[], text: string, pasteOnNewLine: boolean, multicursorText: string[]): EditOperationResult {\n\t\tconst distributedPaste = this._distributePasteToCursors(config, selections, text, pasteOnNewLine, multicursorText);\n\n\t\tif (distributedPaste) {\n\t\t\tselections = selections.sort(Range.compareRangesUsingStarts);\n\t\t\treturn this._distributedPaste(config, model, selections, distributedPaste);\n\t\t} else {\n\t\t\treturn this._simplePaste(config, model, selections, text, pasteOnNewLine);\n\t\t}\n\t}\n\n\tprivate static _goodIndentForLine(config: CursorConfiguration, model: ITextModel, lineNumber: number): string | null {\n\t\tlet action: IndentAction | EnterAction | null = null;\n\t\tlet indentation: string = '';\n\n\t\tconst expectedIndentAction = getInheritIndentForLine(config.autoIndent, model, lineNumber, false, config.languageConfigurationService);\n\t\tif (expectedIndentAction) {\n\t\t\taction = expectedIndentAction.action;\n\t\t\tindentation = expectedIndentAction.indentation;\n\t\t} else if (lineNumber > 1) {\n\t\t\tlet lastLineNumber: number;\n\t\t\tfor (lastLineNumber = lineNumber - 1; lastLineNumber >= 1; lastLineNumber--) {\n\t\t\t\tconst lineText = model.getLineContent(lastLineNumber);\n\t\t\t\tconst nonWhitespaceIdx = strings.lastNonWhitespaceIndex(lineText);\n\t\t\t\tif (nonWhitespaceIdx >= 0) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (lastLineNumber < 1) {\n\t\t\t\t// No previous line with content found\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst maxColumn = model.getLineMaxColumn(lastLineNumber);\n\t\t\tconst expectedEnterAction = getEnterAction(config.autoIndent, model, new Range(lastLineNumber, maxColumn, lastLineNumber, maxColumn), config.languageConfigurationService);\n\t\t\tif (expectedEnterAction) {\n\t\t\t\tindentation = expectedEnterAction.indentation + expectedEnterAction.appendText;\n\t\t\t}\n\t\t}\n\n\t\tif (action) {\n\t\t\tif (action === IndentAction.Indent) {\n\t\t\t\tindentation = TypeOperations.shiftIndent(config, indentation);\n\t\t\t}\n\n\t\t\tif (action === IndentAction.Outdent) {\n\t\t\t\tindentation = TypeOperations.unshiftIndent(config, indentation);\n\t\t\t}\n\n\t\t\tindentation = config.normalizeIndentation(indentation);\n\t\t}\n\n\t\tif (!indentation) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn indentation;\n\t}\n\n\tprivate static _replaceJumpToNextIndent(config: CursorConfiguration, model: ICursorSimpleModel, selection: Selection, insertsAutoWhitespace: boolean): ReplaceCommand {\n\t\tlet typeText = '';\n\n\t\tconst position = selection.getStartPosition();\n\t\tif (config.insertSpaces) {\n\t\t\tconst visibleColumnFromColumn = config.visibleColumnFromColumn(model, position);\n\t\t\tconst indentSize = config.indentSize;\n\t\t\tconst spacesCnt = indentSize - (visibleColumnFromColumn % indentSize);\n\t\t\tfor (let i = 0; i < spacesCnt; i++) {\n\t\t\t\ttypeText += ' ';\n\t\t\t}\n\t\t} else {\n\t\t\ttypeText = '\\t';\n\t\t}\n\n\t\treturn new ReplaceCommand(selection, typeText, insertsAutoWhitespace);\n\t}\n\n\tpublic static tab(config: CursorConfiguration, model: ITextModel, selections: Selection[]): ICommand[] {\n\t\tconst commands: ICommand[] = [];\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\n\t\t\tconst selection = selections[i];\n\n\t\t\tif (selection.isEmpty()) {\n\n\t\t\t\tconst lineText = model.getLineContent(selection.startLineNumber);\n\n\t\t\t\tif (/^\\s*$/.test(lineText) && model.tokenization.isCheapToTokenize(selection.startLineNumber)) {\n\t\t\t\t\tlet goodIndent = this._goodIndentForLine(config, model, selection.startLineNumber);\n\t\t\t\t\tgoodIndent = goodIndent || '\\t';\n\t\t\t\t\tconst possibleTypeText = config.normalizeIndentation(goodIndent);\n\t\t\t\t\tif (!lineText.startsWith(possibleTypeText)) {\n\t\t\t\t\t\tcommands[i] = new ReplaceCommand(new Range(selection.startLineNumber, 1, selection.startLineNumber, lineText.length + 1), possibleTypeText, true);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tcommands[i] = this._replaceJumpToNextIndent(config, model, selection, true);\n\t\t\t} else {\n\t\t\t\tif (selection.startLineNumber === selection.endLineNumber) {\n\t\t\t\t\tconst lineMaxColumn = model.getLineMaxColumn(selection.startLineNumber);\n\t\t\t\t\tif (selection.startColumn !== 1 || selection.endColumn !== lineMaxColumn) {\n\t\t\t\t\t\t// This is a single line selection that is not the entire line\n\t\t\t\t\t\tcommands[i] = this._replaceJumpToNextIndent(config, model, selection, false);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tcommands[i] = new ShiftCommand(selection, {\n\t\t\t\t\tisUnshift: false,\n\t\t\t\t\ttabSize: config.tabSize,\n\t\t\t\t\tindentSize: config.indentSize,\n\t\t\t\t\tinsertSpaces: config.insertSpaces,\n\t\t\t\t\tuseTabStops: config.useTabStops,\n\t\t\t\t\tautoIndent: config.autoIndent\n\t\t\t\t}, config.languageConfigurationService);\n\t\t\t}\n\t\t}\n\t\treturn commands;\n\t}\n\n\tpublic static compositionType(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITextModel, selections: Selection[], text: string, replacePrevCharCnt: number, replaceNextCharCnt: number, positionDelta: number): EditOperationResult {\n\t\tconst commands = selections.map(selection => this._compositionType(model, selection, text, replacePrevCharCnt, replaceNextCharCnt, positionDelta));\n\t\treturn new EditOperationResult(EditOperationType.TypingOther, commands, {\n\t\t\tshouldPushStackElementBefore: shouldPushStackElementBetween(prevEditOperationType, EditOperationType.TypingOther),\n\t\t\tshouldPushStackElementAfter: false\n\t\t});\n\t}\n\n\tprivate static _compositionType(model: ITextModel, selection: Selection, text: string, replacePrevCharCnt: number, replaceNextCharCnt: number, positionDelta: number): ICommand | null {\n\t\tif (!selection.isEmpty()) {\n\t\t\t// looks like https://github.com/microsoft/vscode/issues/2773\n\t\t\t// where a cursor operation occurred before a canceled composition\n\t\t\t// => ignore composition\n\t\t\treturn null;\n\t\t}\n\t\tconst pos = selection.getPosition();\n\t\tconst startColumn = Math.max(1, pos.column - replacePrevCharCnt);\n\t\tconst endColumn = Math.min(model.getLineMaxColumn(pos.lineNumber), pos.column + replaceNextCharCnt);\n\t\tconst range = new Range(pos.lineNumber, startColumn, pos.lineNumber, endColumn);\n\t\tconst oldText = model.getValueInRange(range);\n\t\tif (oldText === text && positionDelta === 0) {\n\t\t\t// => ignore composition that doesn't do anything\n\t\t\treturn null;\n\t\t}\n\t\treturn new ReplaceCommandWithOffsetCursorState(range, text, 0, positionDelta);\n\t}\n\n\tprivate static _typeCommand(range: Range, text: string, keepPosition: boolean): ICommand {\n\t\tif (keepPosition) {\n\t\t\treturn new ReplaceCommandWithoutChangingPosition(range, text, true);\n\t\t} else {\n\t\t\treturn new ReplaceCommand(range, text, true);\n\t\t}\n\t}\n\n\tprivate static _enter(config: CursorConfiguration, model: ITextModel, keepPosition: boolean, range: Range): ICommand {\n\t\tif (config.autoIndent === EditorAutoIndentStrategy.None) {\n\t\t\treturn TypeOperations._typeCommand(range, '\\n', keepPosition);\n\t\t}\n\t\tif (!model.tokenization.isCheapToTokenize(range.getStartPosition().lineNumber) || config.autoIndent === EditorAutoIndentStrategy.Keep) {\n\t\t\tconst lineText = model.getLineContent(range.startLineNumber);\n\t\t\tconst indentation = strings.getLeadingWhitespace(lineText).substring(0, range.startColumn - 1);\n\t\t\treturn TypeOperations._typeCommand(range, '\\n' + config.normalizeIndentation(indentation), keepPosition);\n\t\t}\n\n\t\tconst r = getEnterAction(config.autoIndent, model, range, config.languageConfigurationService);\n\t\tif (r) {\n\t\t\tif (r.indentAction === IndentAction.None) {\n\t\t\t\t// Nothing special\n\t\t\t\treturn TypeOperations._typeCommand(range, '\\n' + config.normalizeIndentation(r.indentation + r.appendText), keepPosition);\n\n\t\t\t} else if (r.indentAction === IndentAction.Indent) {\n\t\t\t\t// Indent once\n\t\t\t\treturn TypeOperations._typeCommand(range, '\\n' + config.normalizeIndentation(r.indentation + r.appendText), keepPosition);\n\n\t\t\t} else if (r.indentAction === IndentAction.IndentOutdent) {\n\t\t\t\t// Ultra special\n\t\t\t\tconst normalIndent = config.normalizeIndentation(r.indentation);\n\t\t\t\tconst increasedIndent = config.normalizeIndentation(r.indentation + r.appendText);\n\n\t\t\t\tconst typeText = '\\n' + increasedIndent + '\\n' + normalIndent;\n\n\t\t\t\tif (keepPosition) {\n\t\t\t\t\treturn new ReplaceCommandWithoutChangingPosition(range, typeText, true);\n\t\t\t\t} else {\n\t\t\t\t\treturn new ReplaceCommandWithOffsetCursorState(range, typeText, -1, increasedIndent.length - normalIndent.length, true);\n\t\t\t\t}\n\t\t\t} else if (r.indentAction === IndentAction.Outdent) {\n\t\t\t\tconst actualIndentation = TypeOperations.unshiftIndent(config, r.indentation);\n\t\t\t\treturn TypeOperations._typeCommand(range, '\\n' + config.normalizeIndentation(actualIndentation + r.appendText), keepPosition);\n\t\t\t}\n\t\t}\n\n\t\tconst lineText = model.getLineContent(range.startLineNumber);\n\t\tconst indentation = strings.getLeadingWhitespace(lineText).substring(0, range.startColumn - 1);\n\n\t\tif (config.autoIndent >= EditorAutoIndentStrategy.Full) {\n\t\t\tconst ir = getIndentForEnter(config.autoIndent, model, range, {\n\t\t\t\tunshiftIndent: (indent) => {\n\t\t\t\t\treturn TypeOperations.unshiftIndent(config, indent);\n\t\t\t\t},\n\t\t\t\tshiftIndent: (indent) => {\n\t\t\t\t\treturn TypeOperations.shiftIndent(config, indent);\n\t\t\t\t},\n\t\t\t\tnormalizeIndentation: (indent) => {\n\t\t\t\t\treturn config.normalizeIndentation(indent);\n\t\t\t\t}\n\t\t\t}, config.languageConfigurationService);\n\n\t\t\tif (ir) {\n\t\t\t\tlet oldEndViewColumn = config.visibleColumnFromColumn(model, range.getEndPosition());\n\t\t\t\tconst oldEndColumn = range.endColumn;\n\t\t\t\tconst newLineContent = model.getLineContent(range.endLineNumber);\n\t\t\t\tconst firstNonWhitespace = strings.firstNonWhitespaceIndex(newLineContent);\n\t\t\t\tif (firstNonWhitespace >= 0) {\n\t\t\t\t\trange = range.setEndPosition(range.endLineNumber, Math.max(range.endColumn, firstNonWhitespace + 1));\n\t\t\t\t} else {\n\t\t\t\t\trange = range.setEndPosition(range.endLineNumber, model.getLineMaxColumn(range.endLineNumber));\n\t\t\t\t}\n\n\t\t\t\tif (keepPosition) {\n\t\t\t\t\treturn new ReplaceCommandWithoutChangingPosition(range, '\\n' + config.normalizeIndentation(ir.afterEnter), true);\n\t\t\t\t} else {\n\t\t\t\t\tlet offset = 0;\n\t\t\t\t\tif (oldEndColumn <= firstNonWhitespace + 1) {\n\t\t\t\t\t\tif (!config.insertSpaces) {\n\t\t\t\t\t\t\toldEndViewColumn = Math.ceil(oldEndViewColumn / config.indentSize);\n\t\t\t\t\t\t}\n\t\t\t\t\t\toffset = Math.min(oldEndViewColumn + 1 - config.normalizeIndentation(ir.afterEnter).length - 1, 0);\n\t\t\t\t\t}\n\t\t\t\t\treturn new ReplaceCommandWithOffsetCursorState(range, '\\n' + config.normalizeIndentation(ir.afterEnter), 0, offset, true);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn TypeOperations._typeCommand(range, '\\n' + config.normalizeIndentation(indentation), keepPosition);\n\t}\n\n\tprivate static _isAutoIndentType(config: CursorConfiguration, model: ITextModel, selections: Selection[]): boolean {\n\t\tif (config.autoIndent < EditorAutoIndentStrategy.Full) {\n\t\t\treturn false;\n\t\t}\n\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\n\t\t\tif (!model.tokenization.isCheapToTokenize(selections[i].getEndPosition().lineNumber)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tprivate static _runAutoIndentType(config: CursorConfiguration, model: ITextModel, range: Range, ch: string): ICommand | null {\n\t\tconst currentIndentation = getIndentationAtPosition(model, range.startLineNumber, range.startColumn);\n\t\tconst actualIndentation = getIndentActionForType(config.autoIndent, model, range, ch, {\n\t\t\tshiftIndent: (indentation) => {\n\t\t\t\treturn TypeOperations.shiftIndent(config, indentation);\n\t\t\t},\n\t\t\tunshiftIndent: (indentation) => {\n\t\t\t\treturn TypeOperations.unshiftIndent(config, indentation);\n\t\t\t},\n\t\t}, config.languageConfigurationService);\n\n\t\tif (actualIndentation === null) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif (actualIndentation !== config.normalizeIndentation(currentIndentation)) {\n\t\t\tconst firstNonWhitespace = model.getLineFirstNonWhitespaceColumn(range.startLineNumber);\n\t\t\tif (firstNonWhitespace === 0) {\n\t\t\t\treturn TypeOperations._typeCommand(\n\t\t\t\t\tnew Range(range.startLineNumber, 1, range.endLineNumber, range.endColumn),\n\t\t\t\t\tconfig.normalizeIndentation(actualIndentation) + ch,\n\t\t\t\t\tfalse\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\treturn TypeOperations._typeCommand(\n\t\t\t\t\tnew Range(range.startLineNumber, 1, range.endLineNumber, range.endColumn),\n\t\t\t\t\tconfig.normalizeIndentation(actualIndentation) +\n\t\t\t\t\tmodel.getLineContent(range.startLineNumber).substring(firstNonWhitespace - 1, range.startColumn - 1) + ch,\n\t\t\t\t\tfalse\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tprivate static _isAutoClosingOvertype(config: CursorConfiguration, model: ITextModel, selections: Selection[], autoClosedCharacters: Range[], ch: string): boolean {\n\t\tif (config.autoClosingOvertype === 'never') {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (!config.autoClosingPairs.autoClosingPairsCloseSingleChar.has(ch)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\n\t\t\tconst selection = selections[i];\n\n\t\t\tif (!selection.isEmpty()) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tconst position = selection.getPosition();\n\t\t\tconst lineText = model.getLineContent(position.lineNumber);\n\t\t\tconst afterCharacter = lineText.charAt(position.column - 1);\n\n\t\t\tif (afterCharacter !== ch) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// Do not over-type quotes after a backslash\n\t\t\tconst chIsQuote = isQuote(ch);\n\t\t\tconst beforeCharacter = position.column > 2 ? lineText.charCodeAt(position.column - 2) : CharCode.Null;\n\t\t\tif (beforeCharacter === CharCode.Backslash && chIsQuote) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// Must over-type a closing character typed by the editor\n\t\t\tif (config.autoClosingOvertype === 'auto') {\n\t\t\t\tlet found = false;\n\t\t\t\tfor (let j = 0, lenJ = autoClosedCharacters.length; j < lenJ; j++) {\n\t\t\t\t\tconst autoClosedCharacter = autoClosedCharacters[j];\n\t\t\t\t\tif (position.lineNumber === autoClosedCharacter.startLineNumber && position.column === autoClosedCharacter.startColumn) {\n\t\t\t\t\t\tfound = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (!found) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tprivate static _runAutoClosingOvertype(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITextModel, selections: Selection[], ch: string): EditOperationResult {\n\t\tconst commands: ICommand[] = [];\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\n\t\t\tconst selection = selections[i];\n\t\t\tconst position = selection.getPosition();\n\t\t\tconst typeSelection = new Range(position.lineNumber, position.column, position.lineNumber, position.column + 1);\n\t\t\tcommands[i] = new ReplaceCommand(typeSelection, ch);\n\t\t}\n\t\treturn new EditOperationResult(EditOperationType.TypingOther, commands, {\n\t\t\tshouldPushStackElementBefore: shouldPushStackElementBetween(prevEditOperationType, EditOperationType.TypingOther),\n\t\t\tshouldPushStackElementAfter: false\n\t\t});\n\t}\n\n\tprivate static _isBeforeClosingBrace(config: CursorConfiguration, lineAfter: string) {\n\t\t// If the start of lineAfter can be interpretted as both a starting or ending brace, default to returning false\n\t\tconst nextChar = lineAfter.charAt(0);\n\t\tconst potentialStartingBraces = config.autoClosingPairs.autoClosingPairsOpenByStart.get(nextChar) || [];\n\t\tconst potentialClosingBraces = config.autoClosingPairs.autoClosingPairsCloseByStart.get(nextChar) || [];\n\n\t\tconst isBeforeStartingBrace = potentialStartingBraces.some(x => lineAfter.startsWith(x.open));\n\t\tconst isBeforeClosingBrace = potentialClosingBraces.some(x => lineAfter.startsWith(x.close));\n\n\t\treturn !isBeforeStartingBrace && isBeforeClosingBrace;\n\t}\n\n\t/**\n\t * Determine if typing `ch` at all `positions` in the `model` results in an\n\t * auto closing open sequence being typed.\n\t *\n\t * Auto closing open sequences can consist of multiple characters, which\n\t * can lead to ambiguities. In such a case, the longest auto-closing open\n\t * sequence is returned.\n\t */\n\tprivate static _findAutoClosingPairOpen(config: CursorConfiguration, model: ITextModel, positions: Position[], ch: string): StandardAutoClosingPairConditional | null {\n\t\tconst candidates = config.autoClosingPairs.autoClosingPairsOpenByEnd.get(ch);\n\t\tif (!candidates) {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Determine which auto-closing pair it is\n\t\tlet result: StandardAutoClosingPairConditional | null = null;\n\t\tfor (const candidate of candidates) {\n\t\t\tif (result === null || candidate.open.length > result.open.length) {\n\t\t\t\tlet candidateIsMatch = true;\n\t\t\t\tfor (const position of positions) {\n\t\t\t\t\tconst relevantText = model.getValueInRange(new Range(position.lineNumber, position.column - candidate.open.length + 1, position.lineNumber, position.column));\n\t\t\t\t\tif (relevantText + ch !== candidate.open) {\n\t\t\t\t\t\tcandidateIsMatch = false;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (candidateIsMatch) {\n\t\t\t\t\tresult = candidate;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Find another auto-closing pair that is contained by the one passed in.\n\t *\n\t * e.g. when having [(,)] and [(*,*)] as auto-closing pairs\n\t * this method will find [(,)] as a containment pair for [(*,*)]\n\t */\n\tprivate static _findContainedAutoClosingPair(config: CursorConfiguration, pair: StandardAutoClosingPairConditional): StandardAutoClosingPairConditional | null {\n\t\tif (pair.open.length <= 1) {\n\t\t\treturn null;\n\t\t}\n\t\tconst lastChar = pair.close.charAt(pair.close.length - 1);\n\t\t// get candidates with the same last character as close\n\t\tconst candidates = config.autoClosingPairs.autoClosingPairsCloseByEnd.get(lastChar) || [];\n\t\tlet result: StandardAutoClosingPairConditional | null = null;\n\t\tfor (const candidate of candidates) {\n\t\t\tif (candidate.open !== pair.open && pair.open.includes(candidate.open) && pair.close.endsWith(candidate.close)) {\n\t\t\t\tif (!result || candidate.open.length > result.open.length) {\n\t\t\t\t\tresult = candidate;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate static _getAutoClosingPairClose(config: CursorConfiguration, model: ITextModel, selections: Selection[], ch: string, chIsAlreadyTyped: boolean): string | null {\n\n\t\tfor (const selection of selections) {\n\t\t\tif (!selection.isEmpty()) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\n\t\t// This method is called both when typing (regularly) and when composition ends\n\t\t// This means that we need to work with a text buffer where sometimes `ch` is not\n\t\t// there (it is being typed right now) or with a text buffer where `ch` has already been typed\n\t\t//\n\t\t// In order to avoid adding checks for `chIsAlreadyTyped` in all places, we will work\n\t\t// with two conceptual positions, the position before `ch` and the position after `ch`\n\t\t//\n\t\tconst positions: { lineNumber: number; beforeColumn: number; afterColumn: number }[] = selections.map((s) => {\n\t\t\tconst position = s.getPosition();\n\t\t\tif (chIsAlreadyTyped) {\n\t\t\t\treturn { lineNumber: position.lineNumber, beforeColumn: position.column - ch.length, afterColumn: position.column };\n\t\t\t} else {\n\t\t\t\treturn { lineNumber: position.lineNumber, beforeColumn: position.column, afterColumn: position.column };\n\t\t\t}\n\t\t});\n\n\n\t\t// Find the longest auto-closing open pair in case of multiple ending in `ch`\n\t\t// e.g. when having [f\",\"] and [\",\"], it picks [f\",\"] if the character before is f\n\t\tconst pair = this._findAutoClosingPairOpen(config, model, positions.map(p => new Position(p.lineNumber, p.beforeColumn)), ch);\n\t\tif (!pair) {\n\t\t\treturn null;\n\t\t}\n\n\t\tlet autoCloseConfig: EditorAutoClosingStrategy;\n\t\tlet shouldAutoCloseBefore: (ch: string) => boolean;\n\n\t\tconst chIsQuote = isQuote(ch);\n\t\tif (chIsQuote) {\n\t\t\tautoCloseConfig = config.autoClosingQuotes;\n\t\t\tshouldAutoCloseBefore = config.shouldAutoCloseBefore.quote;\n\t\t} else {\n\t\t\tconst pairIsForComments = config.blockCommentStartToken ? pair.open.includes(config.blockCommentStartToken) : false;\n\t\t\tif (pairIsForComments) {\n\t\t\t\tautoCloseConfig = config.autoClosingComments;\n\t\t\t\tshouldAutoCloseBefore = config.shouldAutoCloseBefore.comment;\n\t\t\t} else {\n\t\t\t\tautoCloseConfig = config.autoClosingBrackets;\n\t\t\t\tshouldAutoCloseBefore = config.shouldAutoCloseBefore.bracket;\n\t\t\t}\n\t\t}\n\n\t\tif (autoCloseConfig === 'never') {\n\t\t\treturn null;\n\t\t}\n\n\t\t// Sometimes, it is possible to have two auto-closing pairs that have a containment relationship\n\t\t// e.g. when having [(,)] and [(*,*)]\n\t\t// - when typing (, the resulting state is (|)\n\t\t// - when typing *, the desired resulting state is (*|*), not (*|*))\n\t\tconst containedPair = this._findContainedAutoClosingPair(config, pair);\n\t\tconst containedPairClose = containedPair ? containedPair.close : '';\n\t\tlet isContainedPairPresent = true;\n\n\t\tfor (const position of positions) {\n\t\t\tconst { lineNumber, beforeColumn, afterColumn } = position;\n\t\t\tconst lineText = model.getLineContent(lineNumber);\n\t\t\tconst lineBefore = lineText.substring(0, beforeColumn - 1);\n\t\t\tconst lineAfter = lineText.substring(afterColumn - 1);\n\n\t\t\tif (!lineAfter.startsWith(containedPairClose)) {\n\t\t\t\tisContainedPairPresent = false;\n\t\t\t}\n\n\t\t\t// Only consider auto closing the pair if an allowed character follows or if another autoclosed pair closing brace follows\n\t\t\tif (lineAfter.length > 0) {\n\t\t\t\tconst characterAfter = lineAfter.charAt(0);\n\t\t\t\tconst isBeforeCloseBrace = TypeOperations._isBeforeClosingBrace(config, lineAfter);\n\n\t\t\t\tif (!isBeforeCloseBrace && !shouldAutoCloseBefore(characterAfter)) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Do not auto-close ' or \" after a word character\n\t\t\tif (pair.open.length === 1 && (ch === '\\'' || ch === '\"') && autoCloseConfig !== 'always') {\n\t\t\t\tconst wordSeparators = getMapForWordSeparators(config.wordSeparators, []);\n\t\t\t\tif (lineBefore.length > 0) {\n\t\t\t\t\tconst characterBefore = lineBefore.charCodeAt(lineBefore.length - 1);\n\t\t\t\t\tif (wordSeparators.get(characterBefore) === WordCharacterClass.Regular) {\n\t\t\t\t\t\treturn null;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!model.tokenization.isCheapToTokenize(lineNumber)) {\n\t\t\t\t// Do not force tokenization\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tmodel.tokenization.forceTokenization(lineNumber);\n\t\t\tconst lineTokens = model.tokenization.getLineTokens(lineNumber);\n\t\t\tconst scopedLineTokens = createScopedLineTokens(lineTokens, beforeColumn - 1);\n\t\t\tif (!pair.shouldAutoClose(scopedLineTokens, beforeColumn - scopedLineTokens.firstCharOffset)) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\t// Typing for example a quote could either start a new string, in which case auto-closing is desirable\n\t\t\t// or it could end a previously started string, in which case auto-closing is not desirable\n\t\t\t//\n\t\t\t// In certain cases, it is really not possible to look at the previous token to determine\n\t\t\t// what would happen. That's why we do something really unusual, we pretend to type a different\n\t\t\t// character and ask the tokenizer what the outcome of doing that is: after typing a neutral\n\t\t\t// character, are we in a string (i.e. the quote would most likely end a string) or not?\n\t\t\t//\n\t\t\tconst neutralCharacter = pair.findNeutralCharacter();\n\t\t\tif (neutralCharacter) {\n\t\t\t\tconst tokenType = model.tokenization.getTokenTypeIfInsertingCharacter(lineNumber, beforeColumn, neutralCharacter);\n\t\t\t\tif (!pair.isOK(tokenType)) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (isContainedPairPresent) {\n\t\t\treturn pair.close.substring(0, pair.close.length - containedPairClose.length);\n\t\t} else {\n\t\t\treturn pair.close;\n\t\t}\n\t}\n\n\tprivate static _runAutoClosingOpenCharType(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITextModel, selections: Selection[], ch: string, chIsAlreadyTyped: boolean, autoClosingPairClose: string): EditOperationResult {\n\t\tconst commands: ICommand[] = [];\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\n\t\t\tconst selection = selections[i];\n\t\t\tcommands[i] = new TypeWithAutoClosingCommand(selection, ch, !chIsAlreadyTyped, autoClosingPairClose);\n\t\t}\n\t\treturn new EditOperationResult(EditOperationType.TypingOther, commands, {\n\t\t\tshouldPushStackElementBefore: true,\n\t\t\tshouldPushStackElementAfter: false\n\t\t});\n\t}\n\n\tprivate static _shouldSurroundChar(config: CursorConfiguration, ch: string): boolean {\n\t\tif (isQuote(ch)) {\n\t\t\treturn (config.autoSurround === 'quotes' || config.autoSurround === 'languageDefined');\n\t\t} else {\n\t\t\t// Character is a bracket\n\t\t\treturn (config.autoSurround === 'brackets' || config.autoSurround === 'languageDefined');\n\t\t}\n\t}\n\n\tprivate static _isSurroundSelectionType(config: CursorConfiguration, model: ITextModel, selections: Selection[], ch: string): boolean {\n\t\tif (!TypeOperations._shouldSurroundChar(config, ch) || !config.surroundingPairs.hasOwnProperty(ch)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst isTypingAQuoteCharacter = isQuote(ch);\n\n\t\tfor (const selection of selections) {\n\n\t\t\tif (selection.isEmpty()) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tlet selectionContainsOnlyWhitespace = true;\n\n\t\t\tfor (let lineNumber = selection.startLineNumber; lineNumber <= selection.endLineNumber; lineNumber++) {\n\t\t\t\tconst lineText = model.getLineContent(lineNumber);\n\t\t\t\tconst startIndex = (lineNumber === selection.startLineNumber ? selection.startColumn - 1 : 0);\n\t\t\t\tconst endIndex = (lineNumber === selection.endLineNumber ? selection.endColumn - 1 : lineText.length);\n\t\t\t\tconst selectedText = lineText.substring(startIndex, endIndex);\n\t\t\t\tif (/[^ \\t]/.test(selectedText)) {\n\t\t\t\t\t// this selected text contains something other than whitespace\n\t\t\t\t\tselectionContainsOnlyWhitespace = false;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (selectionContainsOnlyWhitespace) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (isTypingAQuoteCharacter && selection.startLineNumber === selection.endLineNumber && selection.startColumn + 1 === selection.endColumn) {\n\t\t\t\tconst selectionText = model.getValueInRange(selection);\n\t\t\t\tif (isQuote(selectionText)) {\n\t\t\t\t\t// Typing a quote character on top of another quote character\n\t\t\t\t\t// => disable surround selection type\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tprivate static _runSurroundSelectionType(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITextModel, selections: Selection[], ch: string): EditOperationResult {\n\t\tconst commands: ICommand[] = [];\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\n\t\t\tconst selection = selections[i];\n\t\t\tconst closeCharacter = config.surroundingPairs[ch];\n\t\t\tcommands[i] = new SurroundSelectionCommand(selection, ch, closeCharacter);\n\t\t}\n\t\treturn new EditOperationResult(EditOperationType.Other, commands, {\n\t\t\tshouldPushStackElementBefore: true,\n\t\t\tshouldPushStackElementAfter: true\n\t\t});\n\t}\n\n\tprivate static _isTypeInterceptorElectricChar(config: CursorConfiguration, model: ITextModel, selections: Selection[]) {\n\t\tif (selections.length === 1 && model.tokenization.isCheapToTokenize(selections[0].getEndPosition().lineNumber)) {\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate static _typeInterceptorElectricChar(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITextModel, selection: Selection, ch: string): EditOperationResult | null {\n\t\tif (!config.electricChars.hasOwnProperty(ch) || !selection.isEmpty()) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst position = selection.getPosition();\n\t\tmodel.tokenization.forceTokenization(position.lineNumber);\n\t\tconst lineTokens = model.tokenization.getLineTokens(position.lineNumber);\n\n\t\tlet electricAction: IElectricAction | null;\n\t\ttry {\n\t\t\telectricAction = config.onElectricCharacter(ch, lineTokens, position.column);\n\t\t} catch (e) {\n\t\t\tonUnexpectedError(e);\n\t\t\treturn null;\n\t\t}\n\n\t\tif (!electricAction) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif (electricAction.matchOpenBracket) {\n\t\t\tconst endColumn = (lineTokens.getLineContent() + ch).lastIndexOf(electricAction.matchOpenBracket) + 1;\n\t\t\tconst match = model.bracketPairs.findMatchingBracketUp(electricAction.matchOpenBracket, {\n\t\t\t\tlineNumber: position.lineNumber,\n\t\t\t\tcolumn: endColumn\n\t\t\t}, 500 /* give at most 500ms to compute */);\n\n\t\t\tif (match) {\n\t\t\t\tif (match.startLineNumber === position.lineNumber) {\n\t\t\t\t\t// matched something on the same line => no change in indentation\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t\tconst matchLine = model.getLineContent(match.startLineNumber);\n\t\t\t\tconst matchLineIndentation = strings.getLeadingWhitespace(matchLine);\n\t\t\t\tconst newIndentation = config.normalizeIndentation(matchLineIndentation);\n\n\t\t\t\tconst lineText = model.getLineContent(position.lineNumber);\n\t\t\t\tconst lineFirstNonBlankColumn = model.getLineFirstNonWhitespaceColumn(position.lineNumber) || position.column;\n\n\t\t\t\tconst prefix = lineText.substring(lineFirstNonBlankColumn - 1, position.column - 1);\n\t\t\t\tconst typeText = newIndentation + prefix + ch;\n\n\t\t\t\tconst typeSelection = new Range(position.lineNumber, 1, position.lineNumber, position.column);\n\n\t\t\t\tconst command = new ReplaceCommand(typeSelection, typeText);\n\t\t\t\treturn new EditOperationResult(getTypingOperation(typeText, prevEditOperationType), [command], {\n\t\t\t\t\tshouldPushStackElementBefore: false,\n\t\t\t\t\tshouldPushStackElementAfter: true\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * This is very similar with typing, but the character is already in the text buffer!\n\t */\n\tpublic static compositionEndWithInterceptors(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITextModel, compositions: CompositionOutcome[] | null, selections: Selection[], autoClosedCharacters: Range[]): EditOperationResult | null {\n\t\tif (!compositions) {\n\t\t\t// could not deduce what the composition did\n\t\t\treturn null;\n\t\t}\n\n\t\tlet insertedText: string | null = null;\n\t\tfor (const composition of compositions) {\n\t\t\tif (insertedText === null) {\n\t\t\t\tinsertedText = composition.insertedText;\n\t\t\t} else if (insertedText !== composition.insertedText) {\n\t\t\t\t// not all selections agree on what was typed\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\n\t\tif (!insertedText || insertedText.length !== 1) {\n\t\t\t// we're only interested in the case where a single character was inserted\n\t\t\treturn null;\n\t\t}\n\n\t\tconst ch = insertedText;\n\n\t\tlet hasDeletion = false;\n\t\tfor (const composition of compositions) {\n\t\t\tif (composition.deletedText.length !== 0) {\n\t\t\t\thasDeletion = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (hasDeletion) {\n\t\t\t// Check if this could have been a surround selection\n\n\t\t\tif (!TypeOperations._shouldSurroundChar(config, ch) || !config.surroundingPairs.hasOwnProperty(ch)) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst isTypingAQuoteCharacter = isQuote(ch);\n\n\t\t\tfor (const composition of compositions) {\n\t\t\t\tif (composition.deletedSelectionStart !== 0 || composition.deletedSelectionEnd !== composition.deletedText.length) {\n\t\t\t\t\t// more text was deleted than was selected, so this could not have been a surround selection\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t\tif (/^[ \\t]+$/.test(composition.deletedText)) {\n\t\t\t\t\t// deleted text was only whitespace\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t\tif (isTypingAQuoteCharacter && isQuote(composition.deletedText)) {\n\t\t\t\t\t// deleted text was a quote\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst positions: Position[] = [];\n\t\t\tfor (const selection of selections) {\n\t\t\t\tif (!selection.isEmpty()) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t\tpositions.push(selection.getPosition());\n\t\t\t}\n\n\t\t\tif (positions.length !== compositions.length) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst commands: ICommand[] = [];\n\t\t\tfor (let i = 0, len = positions.length; i < len; i++) {\n\t\t\t\tcommands.push(new CompositionSurroundSelectionCommand(positions[i], compositions[i].deletedText, config.surroundingPairs[ch]));\n\t\t\t}\n\t\t\treturn new EditOperationResult(EditOperationType.TypingOther, commands, {\n\t\t\t\tshouldPushStackElementBefore: true,\n\t\t\t\tshouldPushStackElementAfter: false\n\t\t\t});\n\t\t}\n\n\t\tif (this._isAutoClosingOvertype(config, model, selections, autoClosedCharacters, ch)) {\n\t\t\t// Unfortunately, the close character is at this point \"doubled\", so we need to delete it...\n\t\t\tconst commands = selections.map(s => new ReplaceCommand(new Range(s.positionLineNumber, s.positionColumn, s.positionLineNumber, s.positionColumn + 1), '', false));\n\t\t\treturn new EditOperationResult(EditOperationType.TypingOther, commands, {\n\t\t\t\tshouldPushStackElementBefore: true,\n\t\t\t\tshouldPushStackElementAfter: false\n\t\t\t});\n\t\t}\n\n\t\tconst autoClosingPairClose = this._getAutoClosingPairClose(config, model, selections, ch, true);\n\t\tif (autoClosingPairClose !== null) {\n\t\t\treturn this._runAutoClosingOpenCharType(prevEditOperationType, config, model, selections, ch, true, autoClosingPairClose);\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tpublic static typeWithInterceptors(isDoingComposition: boolean, prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITextModel, selections: Selection[], autoClosedCharacters: Range[], ch: string): EditOperationResult {\n\n\t\tif (!isDoingComposition && ch === '\\n') {\n\t\t\tconst commands: ICommand[] = [];\n\t\t\tfor (let i = 0, len = selections.length; i < len; i++) {\n\t\t\t\tcommands[i] = TypeOperations._enter(config, model, false, selections[i]);\n\t\t\t}\n\t\t\treturn new EditOperationResult(EditOperationType.TypingOther, commands, {\n\t\t\t\tshouldPushStackElementBefore: true,\n\t\t\t\tshouldPushStackElementAfter: false,\n\t\t\t});\n\t\t}\n\n\t\tif (!isDoingComposition && this._isAutoIndentType(config, model, selections)) {\n\t\t\tconst commands: Array = [];\n\t\t\tlet autoIndentFails = false;\n\t\t\tfor (let i = 0, len = selections.length; i < len; i++) {\n\t\t\t\tcommands[i] = this._runAutoIndentType(config, model, selections[i], ch);\n\t\t\t\tif (!commands[i]) {\n\t\t\t\t\tautoIndentFails = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!autoIndentFails) {\n\t\t\t\treturn new EditOperationResult(EditOperationType.TypingOther, commands, {\n\t\t\t\t\tshouldPushStackElementBefore: true,\n\t\t\t\t\tshouldPushStackElementAfter: false,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tif (this._isAutoClosingOvertype(config, model, selections, autoClosedCharacters, ch)) {\n\t\t\treturn this._runAutoClosingOvertype(prevEditOperationType, config, model, selections, ch);\n\t\t}\n\n\t\tif (!isDoingComposition) {\n\t\t\tconst autoClosingPairClose = this._getAutoClosingPairClose(config, model, selections, ch, false);\n\t\t\tif (autoClosingPairClose) {\n\t\t\t\treturn this._runAutoClosingOpenCharType(prevEditOperationType, config, model, selections, ch, false, autoClosingPairClose);\n\t\t\t}\n\t\t}\n\n\t\tif (!isDoingComposition && this._isSurroundSelectionType(config, model, selections, ch)) {\n\t\t\treturn this._runSurroundSelectionType(prevEditOperationType, config, model, selections, ch);\n\t\t}\n\n\t\t// Electric characters make sense only when dealing with a single cursor,\n\t\t// as multiple cursors typing brackets for example would interfer with bracket matching\n\t\tif (!isDoingComposition && this._isTypeInterceptorElectricChar(config, model, selections)) {\n\t\t\tconst r = this._typeInterceptorElectricChar(prevEditOperationType, config, model, selections[0], ch);\n\t\t\tif (r) {\n\t\t\t\treturn r;\n\t\t\t}\n\t\t}\n\n\t\t// A simple character type\n\t\tconst commands: ICommand[] = [];\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\n\t\t\tcommands[i] = new ReplaceCommand(selections[i], ch);\n\t\t}\n\n\t\tconst opType = getTypingOperation(ch, prevEditOperationType);\n\t\treturn new EditOperationResult(opType, commands, {\n\t\t\tshouldPushStackElementBefore: shouldPushStackElementBetween(prevEditOperationType, opType),\n\t\t\tshouldPushStackElementAfter: false\n\t\t});\n\t}\n\n\tpublic static typeWithoutInterceptors(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITextModel, selections: Selection[], str: string): EditOperationResult {\n\t\tconst commands: ICommand[] = [];\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\n\t\t\tcommands[i] = new ReplaceCommand(selections[i], str);\n\t\t}\n\t\tconst opType = getTypingOperation(str, prevEditOperationType);\n\t\treturn new EditOperationResult(opType, commands, {\n\t\t\tshouldPushStackElementBefore: shouldPushStackElementBetween(prevEditOperationType, opType),\n\t\t\tshouldPushStackElementAfter: false\n\t\t});\n\t}\n\n\tpublic static lineInsertBefore(config: CursorConfiguration, model: ITextModel | null, selections: Selection[] | null): ICommand[] {\n\t\tif (model === null || selections === null) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst commands: ICommand[] = [];\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\n\t\t\tlet lineNumber = selections[i].positionLineNumber;\n\n\t\t\tif (lineNumber === 1) {\n\t\t\t\tcommands[i] = new ReplaceCommandWithoutChangingPosition(new Range(1, 1, 1, 1), '\\n');\n\t\t\t} else {\n\t\t\t\tlineNumber--;\n\t\t\t\tconst column = model.getLineMaxColumn(lineNumber);\n\n\t\t\t\tcommands[i] = this._enter(config, model, false, new Range(lineNumber, column, lineNumber, column));\n\t\t\t}\n\t\t}\n\t\treturn commands;\n\t}\n\n\tpublic static lineInsertAfter(config: CursorConfiguration, model: ITextModel | null, selections: Selection[] | null): ICommand[] {\n\t\tif (model === null || selections === null) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst commands: ICommand[] = [];\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\n\t\t\tconst lineNumber = selections[i].positionLineNumber;\n\t\t\tconst column = model.getLineMaxColumn(lineNumber);\n\t\t\tcommands[i] = this._enter(config, model, false, new Range(lineNumber, column, lineNumber, column));\n\t\t}\n\t\treturn commands;\n\t}\n\n\tpublic static lineBreakInsert(config: CursorConfiguration, model: ITextModel, selections: Selection[]): ICommand[] {\n\t\tconst commands: ICommand[] = [];\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\n\t\t\tcommands[i] = this._enter(config, model, true, selections[i]);\n\t\t}\n\t\treturn commands;\n\t}\n}\n\nexport class TypeWithAutoClosingCommand extends ReplaceCommandWithOffsetCursorState {\n\n\tprivate readonly _openCharacter: string;\n\tprivate readonly _closeCharacter: string;\n\tpublic closeCharacterRange: Range | null;\n\tpublic enclosingRange: Range | null;\n\n\tconstructor(selection: Selection, openCharacter: string, insertOpenCharacter: boolean, closeCharacter: string) {\n\t\tsuper(selection, (insertOpenCharacter ? openCharacter : '') + closeCharacter, 0, -closeCharacter.length);\n\t\tthis._openCharacter = openCharacter;\n\t\tthis._closeCharacter = closeCharacter;\n\t\tthis.closeCharacterRange = null;\n\t\tthis.enclosingRange = null;\n\t}\n\n\tpublic override computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {\n\t\tconst inverseEditOperations = helper.getInverseEditOperations();\n\t\tconst range = inverseEditOperations[0].range;\n\t\tthis.closeCharacterRange = new Range(range.startLineNumber, range.endColumn - this._closeCharacter.length, range.endLineNumber, range.endColumn);\n\t\tthis.enclosingRange = new Range(range.startLineNumber, range.endColumn - this._openCharacter.length - this._closeCharacter.length, range.endLineNumber, range.endColumn);\n\t\treturn super.computeCursorState(model, helper);\n\t}\n}\n\nexport class CompositionOutcome {\n\tconstructor(\n\t\tpublic readonly deletedText: string,\n\t\tpublic readonly deletedSelectionStart: number,\n\t\tpublic readonly deletedSelectionEnd: number,\n\t\tpublic readonly insertedText: string,\n\t\tpublic readonly insertedSelectionStart: number,\n\t\tpublic readonly insertedSelectionEnd: number,\n\t) { }\n}\n\nfunction getTypingOperation(typedText: string, previousTypingOperation: EditOperationType): EditOperationType {\n\tif (typedText === ' ') {\n\t\treturn previousTypingOperation === EditOperationType.TypingFirstSpace\n\t\t\t|| previousTypingOperation === EditOperationType.TypingConsecutiveSpace\n\t\t\t? EditOperationType.TypingConsecutiveSpace\n\t\t\t: EditOperationType.TypingFirstSpace;\n\t}\n\n\treturn EditOperationType.TypingOther;\n}\n\nfunction shouldPushStackElementBetween(previousTypingOperation: EditOperationType, typingOperation: EditOperationType): boolean {\n\tif (isTypingOperation(previousTypingOperation) && !isTypingOperation(typingOperation)) {\n\t\t// Always set an undo stop before non-type operations\n\t\treturn true;\n\t}\n\tif (previousTypingOperation === EditOperationType.TypingFirstSpace) {\n\t\t// `abc |d`: No undo stop\n\t\t// `abc |d`: Undo stop\n\t\treturn false;\n\t}\n\t// Insert undo stop between different operation types\n\treturn normalizeOperationType(previousTypingOperation) !== normalizeOperationType(typingOperation);\n}\n\nfunction normalizeOperationType(type: EditOperationType): EditOperationType | 'space' {\n\treturn (type === EditOperationType.TypingConsecutiveSpace || type === EditOperationType.TypingFirstSpace)\n\t\t? 'space'\n\t\t: type;\n}\n\nfunction isTypingOperation(type: EditOperationType): boolean {\n\treturn type === EditOperationType.TypingOther\n\t\t|| type === EditOperationType.TypingFirstSpace\n\t\t|| type === EditOperationType.TypingConsecutiveSpace;\n}\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\nimport { onUnexpectedError } from 'vs/base/common/errors';\nimport * as strings from 'vs/base/common/strings';\nimport { CursorCollection } from 'vs/editor/common/cursor/cursorCollection';\nimport { CursorConfiguration, CursorState, EditOperationResult, EditOperationType, IColumnSelectData, PartialCursorState, ICursorSimpleModel } from 'vs/editor/common/cursorCommon';\nimport { CursorContext } from 'vs/editor/common/cursor/cursorContext';\nimport { DeleteOperations } from 'vs/editor/common/cursor/cursorDeleteOperations';\nimport { CursorChangeReason } from 'vs/editor/common/cursorEvents';\nimport { CompositionOutcome, TypeOperations, TypeWithAutoClosingCommand } from 'vs/editor/common/cursor/cursorTypeOperations';\nimport { Position } from 'vs/editor/common/core/position';\nimport { Range, IRange } from 'vs/editor/common/core/range';\nimport { ISelection, Selection, SelectionDirection } from 'vs/editor/common/core/selection';\nimport * as editorCommon from 'vs/editor/common/editorCommon';\nimport { ITextModel, TrackedRangeStickiness, IModelDeltaDecoration, ICursorStateComputer, IIdentifiedSingleEditOperation, IValidEditOperation } from 'vs/editor/common/model';\nimport { RawContentChangedType, ModelInjectedTextChangedEvent, InternalModelContentChangeEvent } from 'vs/editor/common/textModelEvents';\nimport { VerticalRevealType, ViewCursorStateChangedEvent, ViewRevealRangeRequestEvent } from 'vs/editor/common/viewEvents';\nimport { dispose, Disposable } from 'vs/base/common/lifecycle';\nimport { ICoordinatesConverter } from 'vs/editor/common/viewModel';\nimport { CursorStateChangedEvent, ViewModelEventsCollector } from 'vs/editor/common/viewModelEventDispatcher';\n\nexport class CursorsController extends Disposable {\n\n\tprivate readonly _model: ITextModel;\n\tprivate _knownModelVersionId: number;\n\tprivate readonly _viewModel: ICursorSimpleModel;\n\tprivate readonly _coordinatesConverter: ICoordinatesConverter;\n\tpublic context: CursorContext;\n\tprivate _cursors: CursorCollection;\n\n\tprivate _hasFocus: boolean;\n\tprivate _isHandling: boolean;\n\tprivate _compositionState: CompositionState | null;\n\tprivate _columnSelectData: IColumnSelectData | null;\n\tprivate _autoClosedActions: AutoClosedAction[];\n\tprivate _prevEditOperationType: EditOperationType;\n\n\tconstructor(model: ITextModel, viewModel: ICursorSimpleModel, coordinatesConverter: ICoordinatesConverter, cursorConfig: CursorConfiguration) {\n\t\tsuper();\n\t\tthis._model = model;\n\t\tthis._knownModelVersionId = this._model.getVersionId();\n\t\tthis._viewModel = viewModel;\n\t\tthis._coordinatesConverter = coordinatesConverter;\n\t\tthis.context = new CursorContext(this._model, this._viewModel, this._coordinatesConverter, cursorConfig);\n\t\tthis._cursors = new CursorCollection(this.context);\n\n\t\tthis._hasFocus = false;\n\t\tthis._isHandling = false;\n\t\tthis._compositionState = null;\n\t\tthis._columnSelectData = null;\n\t\tthis._autoClosedActions = [];\n\t\tthis._prevEditOperationType = EditOperationType.Other;\n\t}\n\n\tpublic override dispose(): void {\n\t\tthis._cursors.dispose();\n\t\tthis._autoClosedActions = dispose(this._autoClosedActions);\n\t\tsuper.dispose();\n\t}\n\n\tpublic updateConfiguration(cursorConfig: CursorConfiguration): void {\n\t\tthis.context = new CursorContext(this._model, this._viewModel, this._coordinatesConverter, cursorConfig);\n\t\tthis._cursors.updateContext(this.context);\n\t}\n\n\tpublic onLineMappingChanged(eventsCollector: ViewModelEventsCollector): void {\n\t\tif (this._knownModelVersionId !== this._model.getVersionId()) {\n\t\t\t// There are model change events that I didn't yet receive.\n\t\t\t//\n\t\t\t// This can happen when editing the model, and the view model receives the change events first,\n\t\t\t// and the view model emits line mapping changed events, all before the cursor gets a chance to\n\t\t\t// recover from markers.\n\t\t\t//\n\t\t\t// The model change listener above will be called soon and we'll ensure a valid cursor state there.\n\t\t\treturn;\n\t\t}\n\t\t// Ensure valid state\n\t\tthis.setStates(eventsCollector, 'viewModel', CursorChangeReason.NotSet, this.getCursorStates());\n\t}\n\n\tpublic setHasFocus(hasFocus: boolean): void {\n\t\tthis._hasFocus = hasFocus;\n\t}\n\n\tprivate _validateAutoClosedActions(): void {\n\t\tif (this._autoClosedActions.length > 0) {\n\t\t\tconst selections: Range[] = this._cursors.getSelections();\n\t\t\tfor (let i = 0; i < this._autoClosedActions.length; i++) {\n\t\t\t\tconst autoClosedAction = this._autoClosedActions[i];\n\t\t\t\tif (!autoClosedAction.isValid(selections)) {\n\t\t\t\t\tautoClosedAction.dispose();\n\t\t\t\t\tthis._autoClosedActions.splice(i, 1);\n\t\t\t\t\ti--;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// ------ some getters/setters\n\n\tpublic getPrimaryCursorState(): CursorState {\n\t\treturn this._cursors.getPrimaryCursor();\n\t}\n\n\tpublic getLastAddedCursorIndex(): number {\n\t\treturn this._cursors.getLastAddedCursorIndex();\n\t}\n\n\tpublic getCursorStates(): CursorState[] {\n\t\treturn this._cursors.getAll();\n\t}\n\n\tpublic setStates(eventsCollector: ViewModelEventsCollector, source: string | null | undefined, reason: CursorChangeReason, states: PartialCursorState[] | null): boolean {\n\t\tlet reachedMaxCursorCount = false;\n\t\tconst multiCursorLimit = this.context.cursorConfig.multiCursorLimit;\n\t\tif (states !== null && states.length > multiCursorLimit) {\n\t\t\tstates = states.slice(0, multiCursorLimit);\n\t\t\treachedMaxCursorCount = true;\n\t\t}\n\n\t\tconst oldState = CursorModelState.from(this._model, this);\n\n\t\tthis._cursors.setStates(states);\n\t\tthis._cursors.normalize();\n\t\tthis._columnSelectData = null;\n\n\t\tthis._validateAutoClosedActions();\n\n\t\treturn this._emitStateChangedIfNecessary(eventsCollector, source, reason, oldState, reachedMaxCursorCount);\n\t}\n\n\tpublic setCursorColumnSelectData(columnSelectData: IColumnSelectData): void {\n\t\tthis._columnSelectData = columnSelectData;\n\t}\n\n\tpublic revealAll(eventsCollector: ViewModelEventsCollector, source: string | null | undefined, minimalReveal: boolean, verticalType: VerticalRevealType, revealHorizontal: boolean, scrollType: editorCommon.ScrollType): void {\n\t\tconst viewPositions = this._cursors.getViewPositions();\n\n\t\tlet revealViewRange: Range | null = null;\n\t\tlet revealViewSelections: Selection[] | null = null;\n\t\tif (viewPositions.length > 1) {\n\t\t\trevealViewSelections = this._cursors.getViewSelections();\n\t\t} else {\n\t\t\trevealViewRange = Range.fromPositions(viewPositions[0], viewPositions[0]);\n\t\t}\n\n\t\teventsCollector.emitViewEvent(new ViewRevealRangeRequestEvent(source, minimalReveal, revealViewRange, revealViewSelections, verticalType, revealHorizontal, scrollType));\n\t}\n\n\tpublic revealPrimary(eventsCollector: ViewModelEventsCollector, source: string | null | undefined, minimalReveal: boolean, verticalType: VerticalRevealType, revealHorizontal: boolean, scrollType: editorCommon.ScrollType): void {\n\t\tconst primaryCursor = this._cursors.getPrimaryCursor();\n\t\tconst revealViewSelections = [primaryCursor.viewState.selection];\n\t\teventsCollector.emitViewEvent(new ViewRevealRangeRequestEvent(source, minimalReveal, null, revealViewSelections, verticalType, revealHorizontal, scrollType));\n\t}\n\n\tpublic saveState(): editorCommon.ICursorState[] {\n\n\t\tconst result: editorCommon.ICursorState[] = [];\n\n\t\tconst selections = this._cursors.getSelections();\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\n\t\t\tconst selection = selections[i];\n\n\t\t\tresult.push({\n\t\t\t\tinSelectionMode: !selection.isEmpty(),\n\t\t\t\tselectionStart: {\n\t\t\t\t\tlineNumber: selection.selectionStartLineNumber,\n\t\t\t\t\tcolumn: selection.selectionStartColumn,\n\t\t\t\t},\n\t\t\t\tposition: {\n\t\t\t\t\tlineNumber: selection.positionLineNumber,\n\t\t\t\t\tcolumn: selection.positionColumn,\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic restoreState(eventsCollector: ViewModelEventsCollector, states: editorCommon.ICursorState[]): void {\n\n\t\tconst desiredSelections: ISelection[] = [];\n\n\t\tfor (let i = 0, len = states.length; i < len; i++) {\n\t\t\tconst state = states[i];\n\n\t\t\tlet positionLineNumber = 1;\n\t\t\tlet positionColumn = 1;\n\n\t\t\t// Avoid missing properties on the literal\n\t\t\tif (state.position && state.position.lineNumber) {\n\t\t\t\tpositionLineNumber = state.position.lineNumber;\n\t\t\t}\n\t\t\tif (state.position && state.position.column) {\n\t\t\t\tpositionColumn = state.position.column;\n\t\t\t}\n\n\t\t\tlet selectionStartLineNumber = positionLineNumber;\n\t\t\tlet selectionStartColumn = positionColumn;\n\n\t\t\t// Avoid missing properties on the literal\n\t\t\tif (state.selectionStart && state.selectionStart.lineNumber) {\n\t\t\t\tselectionStartLineNumber = state.selectionStart.lineNumber;\n\t\t\t}\n\t\t\tif (state.selectionStart && state.selectionStart.column) {\n\t\t\t\tselectionStartColumn = state.selectionStart.column;\n\t\t\t}\n\n\t\t\tdesiredSelections.push({\n\t\t\t\tselectionStartLineNumber: selectionStartLineNumber,\n\t\t\t\tselectionStartColumn: selectionStartColumn,\n\t\t\t\tpositionLineNumber: positionLineNumber,\n\t\t\t\tpositionColumn: positionColumn\n\t\t\t});\n\t\t}\n\n\t\tthis.setStates(eventsCollector, 'restoreState', CursorChangeReason.NotSet, CursorState.fromModelSelections(desiredSelections));\n\t\tthis.revealAll(eventsCollector, 'restoreState', false, VerticalRevealType.Simple, true, editorCommon.ScrollType.Immediate);\n\t}\n\n\tpublic onModelContentChanged(eventsCollector: ViewModelEventsCollector, event: InternalModelContentChangeEvent | ModelInjectedTextChangedEvent): void {\n\t\tif (event instanceof ModelInjectedTextChangedEvent) {\n\t\t\t// If injected texts change, the view positions of all cursors need to be updated.\n\t\t\tif (this._isHandling) {\n\t\t\t\t// The view positions will be updated when handling finishes\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// setStates might remove markers, which could trigger a decoration change.\n\t\t\t// If there are injected text decorations for that line, `onModelContentChanged` is emitted again\n\t\t\t// and an endless recursion happens.\n\t\t\t// _isHandling prevents that.\n\t\t\tthis._isHandling = true;\n\t\t\ttry {\n\t\t\t\tthis.setStates(eventsCollector, 'modelChange', CursorChangeReason.NotSet, this.getCursorStates());\n\t\t\t} finally {\n\t\t\t\tthis._isHandling = false;\n\t\t\t}\n\t\t} else {\n\t\t\tconst e = event.rawContentChangedEvent;\n\t\t\tthis._knownModelVersionId = e.versionId;\n\t\t\tif (this._isHandling) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst hadFlushEvent = e.containsEvent(RawContentChangedType.Flush);\n\t\t\tthis._prevEditOperationType = EditOperationType.Other;\n\n\t\t\tif (hadFlushEvent) {\n\t\t\t\t// a model.setValue() was called\n\t\t\t\tthis._cursors.dispose();\n\t\t\t\tthis._cursors = new CursorCollection(this.context);\n\t\t\t\tthis._validateAutoClosedActions();\n\t\t\t\tthis._emitStateChangedIfNecessary(eventsCollector, 'model', CursorChangeReason.ContentFlush, null, false);\n\t\t\t} else {\n\t\t\t\tif (this._hasFocus && e.resultingSelection && e.resultingSelection.length > 0) {\n\t\t\t\t\tconst cursorState = CursorState.fromModelSelections(e.resultingSelection);\n\t\t\t\t\tif (this.setStates(eventsCollector, 'modelChange', e.isUndoing ? CursorChangeReason.Undo : e.isRedoing ? CursorChangeReason.Redo : CursorChangeReason.RecoverFromMarkers, cursorState)) {\n\t\t\t\t\t\tthis.revealAll(eventsCollector, 'modelChange', false, VerticalRevealType.Simple, true, editorCommon.ScrollType.Smooth);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tconst selectionsFromMarkers = this._cursors.readSelectionFromMarkers();\n\t\t\t\t\tthis.setStates(eventsCollector, 'modelChange', CursorChangeReason.RecoverFromMarkers, CursorState.fromModelSelections(selectionsFromMarkers));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic getSelection(): Selection {\n\t\treturn this._cursors.getPrimaryCursor().modelState.selection;\n\t}\n\n\tpublic getTopMostViewPosition(): Position {\n\t\treturn this._cursors.getTopMostViewPosition();\n\t}\n\n\tpublic getBottomMostViewPosition(): Position {\n\t\treturn this._cursors.getBottomMostViewPosition();\n\t}\n\n\tpublic getCursorColumnSelectData(): IColumnSelectData {\n\t\tif (this._columnSelectData) {\n\t\t\treturn this._columnSelectData;\n\t\t}\n\t\tconst primaryCursor = this._cursors.getPrimaryCursor();\n\t\tconst viewSelectionStart = primaryCursor.viewState.selectionStart.getStartPosition();\n\t\tconst viewPosition = primaryCursor.viewState.position;\n\t\treturn {\n\t\t\tisReal: false,\n\t\t\tfromViewLineNumber: viewSelectionStart.lineNumber,\n\t\t\tfromViewVisualColumn: this.context.cursorConfig.visibleColumnFromColumn(this._viewModel, viewSelectionStart),\n\t\t\ttoViewLineNumber: viewPosition.lineNumber,\n\t\t\ttoViewVisualColumn: this.context.cursorConfig.visibleColumnFromColumn(this._viewModel, viewPosition),\n\t\t};\n\t}\n\n\tpublic getSelections(): Selection[] {\n\t\treturn this._cursors.getSelections();\n\t}\n\n\tpublic setSelections(eventsCollector: ViewModelEventsCollector, source: string | null | undefined, selections: readonly ISelection[], reason: CursorChangeReason): void {\n\t\tthis.setStates(eventsCollector, source, reason, CursorState.fromModelSelections(selections));\n\t}\n\n\tpublic getPrevEditOperationType(): EditOperationType {\n\t\treturn this._prevEditOperationType;\n\t}\n\n\tpublic setPrevEditOperationType(type: EditOperationType): void {\n\t\tthis._prevEditOperationType = type;\n\t}\n\n\t// ------ auxiliary handling logic\n\n\tprivate _pushAutoClosedAction(autoClosedCharactersRanges: Range[], autoClosedEnclosingRanges: Range[]): void {\n\t\tconst autoClosedCharactersDeltaDecorations: IModelDeltaDecoration[] = [];\n\t\tconst autoClosedEnclosingDeltaDecorations: IModelDeltaDecoration[] = [];\n\n\t\tfor (let i = 0, len = autoClosedCharactersRanges.length; i < len; i++) {\n\t\t\tautoClosedCharactersDeltaDecorations.push({\n\t\t\t\trange: autoClosedCharactersRanges[i],\n\t\t\t\toptions: {\n\t\t\t\t\tdescription: 'auto-closed-character',\n\t\t\t\t\tinlineClassName: 'auto-closed-character',\n\t\t\t\t\tstickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges\n\t\t\t\t}\n\t\t\t});\n\t\t\tautoClosedEnclosingDeltaDecorations.push({\n\t\t\t\trange: autoClosedEnclosingRanges[i],\n\t\t\t\toptions: {\n\t\t\t\t\tdescription: 'auto-closed-enclosing',\n\t\t\t\t\tstickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\tconst autoClosedCharactersDecorations = this._model.deltaDecorations([], autoClosedCharactersDeltaDecorations);\n\t\tconst autoClosedEnclosingDecorations = this._model.deltaDecorations([], autoClosedEnclosingDeltaDecorations);\n\t\tthis._autoClosedActions.push(new AutoClosedAction(this._model, autoClosedCharactersDecorations, autoClosedEnclosingDecorations));\n\t}\n\n\tprivate _executeEditOperation(opResult: EditOperationResult | null): void {\n\n\t\tif (!opResult) {\n\t\t\t// Nothing to execute\n\t\t\treturn;\n\t\t}\n\n\t\tif (opResult.shouldPushStackElementBefore) {\n\t\t\tthis._model.pushStackElement();\n\t\t}\n\n\t\tconst result = CommandExecutor.executeCommands(this._model, this._cursors.getSelections(), opResult.commands);\n\t\tif (result) {\n\t\t\t// The commands were applied correctly\n\t\t\tthis._interpretCommandResult(result);\n\n\t\t\t// Check for auto-closing closed characters\n\t\t\tconst autoClosedCharactersRanges: Range[] = [];\n\t\t\tconst autoClosedEnclosingRanges: Range[] = [];\n\n\t\t\tfor (let i = 0; i < opResult.commands.length; i++) {\n\t\t\t\tconst command = opResult.commands[i];\n\t\t\t\tif (command instanceof TypeWithAutoClosingCommand && command.enclosingRange && command.closeCharacterRange) {\n\t\t\t\t\tautoClosedCharactersRanges.push(command.closeCharacterRange);\n\t\t\t\t\tautoClosedEnclosingRanges.push(command.enclosingRange);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (autoClosedCharactersRanges.length > 0) {\n\t\t\t\tthis._pushAutoClosedAction(autoClosedCharactersRanges, autoClosedEnclosingRanges);\n\t\t\t}\n\n\t\t\tthis._prevEditOperationType = opResult.type;\n\t\t}\n\n\t\tif (opResult.shouldPushStackElementAfter) {\n\t\t\tthis._model.pushStackElement();\n\t\t}\n\t}\n\n\tprivate _interpretCommandResult(cursorState: Selection[] | null): void {\n\t\tif (!cursorState || cursorState.length === 0) {\n\t\t\tcursorState = this._cursors.readSelectionFromMarkers();\n\t\t}\n\n\t\tthis._columnSelectData = null;\n\t\tthis._cursors.setSelections(cursorState);\n\t\tthis._cursors.normalize();\n\t}\n\n\t// -----------------------------------------------------------------------------------------------------------\n\t// ----- emitting events\n\n\tprivate _emitStateChangedIfNecessary(eventsCollector: ViewModelEventsCollector, source: string | null | undefined, reason: CursorChangeReason, oldState: CursorModelState | null, reachedMaxCursorCount: boolean): boolean {\n\t\tconst newState = CursorModelState.from(this._model, this);\n\t\tif (newState.equals(oldState)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst selections = this._cursors.getSelections();\n\t\tconst viewSelections = this._cursors.getViewSelections();\n\n\t\t// Let the view get the event first.\n\t\teventsCollector.emitViewEvent(new ViewCursorStateChangedEvent(viewSelections, selections, reason));\n\n\t\t// Only after the view has been notified, let the rest of the world know...\n\t\tif (!oldState\n\t\t\t|| oldState.cursorState.length !== newState.cursorState.length\n\t\t\t|| newState.cursorState.some((newCursorState, i) => !newCursorState.modelState.equals(oldState.cursorState[i].modelState))\n\t\t) {\n\t\t\tconst oldSelections = oldState ? oldState.cursorState.map(s => s.modelState.selection) : null;\n\t\t\tconst oldModelVersionId = oldState ? oldState.modelVersionId : 0;\n\t\t\teventsCollector.emitOutgoingEvent(new CursorStateChangedEvent(oldSelections, selections, oldModelVersionId, newState.modelVersionId, source || 'keyboard', reason, reachedMaxCursorCount));\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t// -----------------------------------------------------------------------------------------------------------\n\t// ----- handlers beyond this point\n\n\tprivate _findAutoClosingPairs(edits: IIdentifiedSingleEditOperation[]): [number, number][] | null {\n\t\tif (!edits.length) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst indices: [number, number][] = [];\n\t\tfor (let i = 0, len = edits.length; i < len; i++) {\n\t\t\tconst edit = edits[i];\n\t\t\tif (!edit.text || edit.text.indexOf('\\n') >= 0) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst m = edit.text.match(/([)\\]}>'\"`])([^)\\]}>'\"`]*)$/);\n\t\t\tif (!m) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst closeChar = m[1];\n\n\t\t\tconst autoClosingPairsCandidates = this.context.cursorConfig.autoClosingPairs.autoClosingPairsCloseSingleChar.get(closeChar);\n\t\t\tif (!autoClosingPairsCandidates || autoClosingPairsCandidates.length !== 1) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst openChar = autoClosingPairsCandidates[0].open;\n\t\t\tconst closeCharIndex = edit.text.length - m[2].length - 1;\n\t\t\tconst openCharIndex = edit.text.lastIndexOf(openChar, closeCharIndex - 1);\n\t\t\tif (openCharIndex === -1) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tindices.push([openCharIndex, closeCharIndex]);\n\t\t}\n\n\t\treturn indices;\n\t}\n\n\tpublic executeEdits(eventsCollector: ViewModelEventsCollector, source: string | null | undefined, edits: IIdentifiedSingleEditOperation[], cursorStateComputer: ICursorStateComputer): void {\n\t\tlet autoClosingIndices: [number, number][] | null = null;\n\t\tif (source === 'snippet') {\n\t\t\tautoClosingIndices = this._findAutoClosingPairs(edits);\n\t\t}\n\n\t\tif (autoClosingIndices) {\n\t\t\tedits[0]._isTracked = true;\n\t\t}\n\t\tconst autoClosedCharactersRanges: Range[] = [];\n\t\tconst autoClosedEnclosingRanges: Range[] = [];\n\t\tconst selections = this._model.pushEditOperations(this.getSelections(), edits, (undoEdits) => {\n\t\t\tif (autoClosingIndices) {\n\t\t\t\tfor (let i = 0, len = autoClosingIndices.length; i < len; i++) {\n\t\t\t\t\tconst [openCharInnerIndex, closeCharInnerIndex] = autoClosingIndices[i];\n\t\t\t\t\tconst undoEdit = undoEdits[i];\n\t\t\t\t\tconst lineNumber = undoEdit.range.startLineNumber;\n\t\t\t\t\tconst openCharIndex = undoEdit.range.startColumn - 1 + openCharInnerIndex;\n\t\t\t\t\tconst closeCharIndex = undoEdit.range.startColumn - 1 + closeCharInnerIndex;\n\n\t\t\t\t\tautoClosedCharactersRanges.push(new Range(lineNumber, closeCharIndex + 1, lineNumber, closeCharIndex + 2));\n\t\t\t\t\tautoClosedEnclosingRanges.push(new Range(lineNumber, openCharIndex + 1, lineNumber, closeCharIndex + 2));\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst selections = cursorStateComputer(undoEdits);\n\t\t\tif (selections) {\n\t\t\t\t// Don't recover the selection from markers because\n\t\t\t\t// we know what it should be.\n\t\t\t\tthis._isHandling = true;\n\t\t\t}\n\n\t\t\treturn selections;\n\t\t});\n\t\tif (selections) {\n\t\t\tthis._isHandling = false;\n\t\t\tthis.setSelections(eventsCollector, source, selections, CursorChangeReason.NotSet);\n\t\t}\n\t\tif (autoClosedCharactersRanges.length > 0) {\n\t\t\tthis._pushAutoClosedAction(autoClosedCharactersRanges, autoClosedEnclosingRanges);\n\t\t}\n\t}\n\n\tprivate _executeEdit(callback: () => void, eventsCollector: ViewModelEventsCollector, source: string | null | undefined, cursorChangeReason: CursorChangeReason = CursorChangeReason.NotSet): void {\n\t\tif (this.context.cursorConfig.readOnly) {\n\t\t\t// we cannot edit when read only...\n\t\t\treturn;\n\t\t}\n\n\t\tconst oldState = CursorModelState.from(this._model, this);\n\t\tthis._cursors.stopTrackingSelections();\n\t\tthis._isHandling = true;\n\n\t\ttry {\n\t\t\tthis._cursors.ensureValidState();\n\t\t\tcallback();\n\t\t} catch (err) {\n\t\t\tonUnexpectedError(err);\n\t\t}\n\n\t\tthis._isHandling = false;\n\t\tthis._cursors.startTrackingSelections();\n\t\tthis._validateAutoClosedActions();\n\t\tif (this._emitStateChangedIfNecessary(eventsCollector, source, cursorChangeReason, oldState, false)) {\n\t\t\tthis.revealAll(eventsCollector, source, false, VerticalRevealType.Simple, true, editorCommon.ScrollType.Smooth);\n\t\t}\n\t}\n\n\tpublic getAutoClosedCharacters(): Range[] {\n\t\treturn AutoClosedAction.getAllAutoClosedCharacters(this._autoClosedActions);\n\t}\n\n\tpublic startComposition(eventsCollector: ViewModelEventsCollector): void {\n\t\tthis._compositionState = new CompositionState(this._model, this.getSelections());\n\t}\n\n\tpublic endComposition(eventsCollector: ViewModelEventsCollector, source?: string | null | undefined): void {\n\t\tconst compositionOutcome = this._compositionState ? this._compositionState.deduceOutcome(this._model, this.getSelections()) : null;\n\t\tthis._compositionState = null;\n\n\t\tthis._executeEdit(() => {\n\t\t\tif (source === 'keyboard') {\n\t\t\t\t// composition finishes, let's check if we need to auto complete if necessary.\n\t\t\t\tthis._executeEditOperation(TypeOperations.compositionEndWithInterceptors(this._prevEditOperationType, this.context.cursorConfig, this._model, compositionOutcome, this.getSelections(), this.getAutoClosedCharacters()));\n\t\t\t}\n\t\t}, eventsCollector, source);\n\t}\n\n\tpublic type(eventsCollector: ViewModelEventsCollector, text: string, source?: string | null | undefined): void {\n\t\tthis._executeEdit(() => {\n\t\t\tif (source === 'keyboard') {\n\t\t\t\t// If this event is coming straight from the keyboard, look for electric characters and enter\n\n\t\t\t\tconst len = text.length;\n\t\t\t\tlet offset = 0;\n\t\t\t\twhile (offset < len) {\n\t\t\t\t\tconst charLength = strings.nextCharLength(text, offset);\n\t\t\t\t\tconst chr = text.substr(offset, charLength);\n\n\t\t\t\t\t// Here we must interpret each typed character individually\n\t\t\t\t\tthis._executeEditOperation(TypeOperations.typeWithInterceptors(!!this._compositionState, this._prevEditOperationType, this.context.cursorConfig, this._model, this.getSelections(), this.getAutoClosedCharacters(), chr));\n\n\t\t\t\t\toffset += charLength;\n\t\t\t\t}\n\n\t\t\t} else {\n\t\t\t\tthis._executeEditOperation(TypeOperations.typeWithoutInterceptors(this._prevEditOperationType, this.context.cursorConfig, this._model, this.getSelections(), text));\n\t\t\t}\n\t\t}, eventsCollector, source);\n\t}\n\n\tpublic compositionType(eventsCollector: ViewModelEventsCollector, text: string, replacePrevCharCnt: number, replaceNextCharCnt: number, positionDelta: number, source?: string | null | undefined): void {\n\t\tif (text.length === 0 && replacePrevCharCnt === 0 && replaceNextCharCnt === 0) {\n\t\t\t// this edit is a no-op\n\t\t\tif (positionDelta !== 0) {\n\t\t\t\t// but it still wants to move the cursor\n\t\t\t\tconst newSelections = this.getSelections().map(selection => {\n\t\t\t\t\tconst position = selection.getPosition();\n\t\t\t\t\treturn new Selection(position.lineNumber, position.column + positionDelta, position.lineNumber, position.column + positionDelta);\n\t\t\t\t});\n\t\t\t\tthis.setSelections(eventsCollector, source, newSelections, CursorChangeReason.NotSet);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tthis._executeEdit(() => {\n\t\t\tthis._executeEditOperation(TypeOperations.compositionType(this._prevEditOperationType, this.context.cursorConfig, this._model, this.getSelections(), text, replacePrevCharCnt, replaceNextCharCnt, positionDelta));\n\t\t}, eventsCollector, source);\n\t}\n\n\tpublic paste(eventsCollector: ViewModelEventsCollector, text: string, pasteOnNewLine: boolean, multicursorText?: string[] | null | undefined, source?: string | null | undefined): void {\n\t\tthis._executeEdit(() => {\n\t\t\tthis._executeEditOperation(TypeOperations.paste(this.context.cursorConfig, this._model, this.getSelections(), text, pasteOnNewLine, multicursorText || []));\n\t\t}, eventsCollector, source, CursorChangeReason.Paste);\n\t}\n\n\tpublic cut(eventsCollector: ViewModelEventsCollector, source?: string | null | undefined): void {\n\t\tthis._executeEdit(() => {\n\t\t\tthis._executeEditOperation(DeleteOperations.cut(this.context.cursorConfig, this._model, this.getSelections()));\n\t\t}, eventsCollector, source);\n\t}\n\n\tpublic executeCommand(eventsCollector: ViewModelEventsCollector, command: editorCommon.ICommand, source?: string | null | undefined): void {\n\t\tthis._executeEdit(() => {\n\t\t\tthis._cursors.killSecondaryCursors();\n\n\t\t\tthis._executeEditOperation(new EditOperationResult(EditOperationType.Other, [command], {\n\t\t\t\tshouldPushStackElementBefore: false,\n\t\t\t\tshouldPushStackElementAfter: false\n\t\t\t}));\n\t\t}, eventsCollector, source);\n\t}\n\n\tpublic executeCommands(eventsCollector: ViewModelEventsCollector, commands: editorCommon.ICommand[], source?: string | null | undefined): void {\n\t\tthis._executeEdit(() => {\n\t\t\tthis._executeEditOperation(new EditOperationResult(EditOperationType.Other, commands, {\n\t\t\t\tshouldPushStackElementBefore: false,\n\t\t\t\tshouldPushStackElementAfter: false\n\t\t\t}));\n\t\t}, eventsCollector, source);\n\t}\n}\n\n/**\n * A snapshot of the cursor and the model state\n */\nclass CursorModelState {\n\tpublic static from(model: ITextModel, cursor: CursorsController): CursorModelState {\n\t\treturn new CursorModelState(model.getVersionId(), cursor.getCursorStates());\n\t}\n\n\tconstructor(\n\t\tpublic readonly modelVersionId: number,\n\t\tpublic readonly cursorState: CursorState[],\n\t) {\n\t}\n\n\tpublic equals(other: CursorModelState | null): boolean {\n\t\tif (!other) {\n\t\t\treturn false;\n\t\t}\n\t\tif (this.modelVersionId !== other.modelVersionId) {\n\t\t\treturn false;\n\t\t}\n\t\tif (this.cursorState.length !== other.cursorState.length) {\n\t\t\treturn false;\n\t\t}\n\t\tfor (let i = 0, len = this.cursorState.length; i < len; i++) {\n\t\t\tif (!this.cursorState[i].equals(other.cursorState[i])) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n}\n\nclass AutoClosedAction {\n\n\tpublic static getAllAutoClosedCharacters(autoClosedActions: AutoClosedAction[]): Range[] {\n\t\tlet autoClosedCharacters: Range[] = [];\n\t\tfor (const autoClosedAction of autoClosedActions) {\n\t\t\tautoClosedCharacters = autoClosedCharacters.concat(autoClosedAction.getAutoClosedCharactersRanges());\n\t\t}\n\t\treturn autoClosedCharacters;\n\t}\n\n\tprivate readonly _model: ITextModel;\n\n\tprivate _autoClosedCharactersDecorations: string[];\n\tprivate _autoClosedEnclosingDecorations: string[];\n\n\tconstructor(model: ITextModel, autoClosedCharactersDecorations: string[], autoClosedEnclosingDecorations: string[]) {\n\t\tthis._model = model;\n\t\tthis._autoClosedCharactersDecorations = autoClosedCharactersDecorations;\n\t\tthis._autoClosedEnclosingDecorations = autoClosedEnclosingDecorations;\n\t}\n\n\tpublic dispose(): void {\n\t\tthis._autoClosedCharactersDecorations = this._model.deltaDecorations(this._autoClosedCharactersDecorations, []);\n\t\tthis._autoClosedEnclosingDecorations = this._model.deltaDecorations(this._autoClosedEnclosingDecorations, []);\n\t}\n\n\tpublic getAutoClosedCharactersRanges(): Range[] {\n\t\tconst result: Range[] = [];\n\t\tfor (let i = 0; i < this._autoClosedCharactersDecorations.length; i++) {\n\t\t\tconst decorationRange = this._model.getDecorationRange(this._autoClosedCharactersDecorations[i]);\n\t\t\tif (decorationRange) {\n\t\t\t\tresult.push(decorationRange);\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tpublic isValid(selections: Range[]): boolean {\n\t\tconst enclosingRanges: Range[] = [];\n\t\tfor (let i = 0; i < this._autoClosedEnclosingDecorations.length; i++) {\n\t\t\tconst decorationRange = this._model.getDecorationRange(this._autoClosedEnclosingDecorations[i]);\n\t\t\tif (decorationRange) {\n\t\t\t\tenclosingRanges.push(decorationRange);\n\t\t\t\tif (decorationRange.startLineNumber !== decorationRange.endLineNumber) {\n\t\t\t\t\t// Stop tracking if the range becomes multiline...\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tenclosingRanges.sort(Range.compareRangesUsingStarts);\n\n\t\tselections.sort(Range.compareRangesUsingStarts);\n\n\t\tfor (let i = 0; i < selections.length; i++) {\n\t\t\tif (i >= enclosingRanges.length) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (!enclosingRanges[i].strictContainsRange(selections[i])) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n}\n\ninterface IExecContext {\n\treadonly model: ITextModel;\n\treadonly selectionsBefore: Selection[];\n\treadonly trackedRanges: string[];\n\treadonly trackedRangesDirection: SelectionDirection[];\n}\n\ninterface ICommandData {\n\toperations: IIdentifiedSingleEditOperation[];\n\thadTrackedEditOperation: boolean;\n}\n\ninterface ICommandsData {\n\toperations: IIdentifiedSingleEditOperation[];\n\thadTrackedEditOperation: boolean;\n}\n\nclass CommandExecutor {\n\n\tpublic static executeCommands(model: ITextModel, selectionsBefore: Selection[], commands: (editorCommon.ICommand | null)[]): Selection[] | null {\n\n\t\tconst ctx: IExecContext = {\n\t\t\tmodel: model,\n\t\t\tselectionsBefore: selectionsBefore,\n\t\t\ttrackedRanges: [],\n\t\t\ttrackedRangesDirection: []\n\t\t};\n\n\t\tconst result = this._innerExecuteCommands(ctx, commands);\n\n\t\tfor (let i = 0, len = ctx.trackedRanges.length; i < len; i++) {\n\t\t\tctx.model._setTrackedRange(ctx.trackedRanges[i], null, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges);\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tprivate static _innerExecuteCommands(ctx: IExecContext, commands: (editorCommon.ICommand | null)[]): Selection[] | null {\n\n\t\tif (this._arrayIsEmpty(commands)) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst commandsData = this._getEditOperations(ctx, commands);\n\t\tif (commandsData.operations.length === 0) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst rawOperations = commandsData.operations;\n\n\t\tconst loserCursorsMap = this._getLoserCursorMap(rawOperations);\n\t\tif (loserCursorsMap.hasOwnProperty('0')) {\n\t\t\t// These commands are very messed up\n\t\t\tconsole.warn('Ignoring commands');\n\t\t\treturn null;\n\t\t}\n\n\t\t// Remove operations belonging to losing cursors\n\t\tconst filteredOperations: IIdentifiedSingleEditOperation[] = [];\n\t\tfor (let i = 0, len = rawOperations.length; i < len; i++) {\n\t\t\tif (!loserCursorsMap.hasOwnProperty(rawOperations[i].identifier!.major.toString())) {\n\t\t\t\tfilteredOperations.push(rawOperations[i]);\n\t\t\t}\n\t\t}\n\n\t\t// TODO@Alex: find a better way to do this.\n\t\t// give the hint that edit operations are tracked to the model\n\t\tif (commandsData.hadTrackedEditOperation && filteredOperations.length > 0) {\n\t\t\tfilteredOperations[0]._isTracked = true;\n\t\t}\n\t\tlet selectionsAfter = ctx.model.pushEditOperations(ctx.selectionsBefore, filteredOperations, (inverseEditOperations: IValidEditOperation[]): Selection[] => {\n\t\t\tconst groupedInverseEditOperations: IValidEditOperation[][] = [];\n\t\t\tfor (let i = 0; i < ctx.selectionsBefore.length; i++) {\n\t\t\t\tgroupedInverseEditOperations[i] = [];\n\t\t\t}\n\t\t\tfor (const op of inverseEditOperations) {\n\t\t\t\tif (!op.identifier) {\n\t\t\t\t\t// perhaps auto whitespace trim edits\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tgroupedInverseEditOperations[op.identifier.major].push(op);\n\t\t\t}\n\t\t\tconst minorBasedSorter = (a: IValidEditOperation, b: IValidEditOperation) => {\n\t\t\t\treturn a.identifier!.minor - b.identifier!.minor;\n\t\t\t};\n\t\t\tconst cursorSelections: Selection[] = [];\n\t\t\tfor (let i = 0; i < ctx.selectionsBefore.length; i++) {\n\t\t\t\tif (groupedInverseEditOperations[i].length > 0) {\n\t\t\t\t\tgroupedInverseEditOperations[i].sort(minorBasedSorter);\n\t\t\t\t\tcursorSelections[i] = commands[i]!.computeCursorState(ctx.model, {\n\t\t\t\t\t\tgetInverseEditOperations: () => {\n\t\t\t\t\t\t\treturn groupedInverseEditOperations[i];\n\t\t\t\t\t\t},\n\n\t\t\t\t\t\tgetTrackedSelection: (id: string) => {\n\t\t\t\t\t\t\tconst idx = parseInt(id, 10);\n\t\t\t\t\t\t\tconst range = ctx.model._getTrackedRange(ctx.trackedRanges[idx])!;\n\t\t\t\t\t\t\tif (ctx.trackedRangesDirection[idx] === SelectionDirection.LTR) {\n\t\t\t\t\t\t\t\treturn new Selection(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn new Selection(range.endLineNumber, range.endColumn, range.startLineNumber, range.startColumn);\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\tcursorSelections[i] = ctx.selectionsBefore[i];\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn cursorSelections;\n\t\t});\n\t\tif (!selectionsAfter) {\n\t\t\tselectionsAfter = ctx.selectionsBefore;\n\t\t}\n\n\t\t// Extract losing cursors\n\t\tconst losingCursors: number[] = [];\n\t\tfor (const losingCursorIndex in loserCursorsMap) {\n\t\t\tif (loserCursorsMap.hasOwnProperty(losingCursorIndex)) {\n\t\t\t\tlosingCursors.push(parseInt(losingCursorIndex, 10));\n\t\t\t}\n\t\t}\n\n\t\t// Sort losing cursors descending\n\t\tlosingCursors.sort((a: number, b: number): number => {\n\t\t\treturn b - a;\n\t\t});\n\n\t\t// Remove losing cursors\n\t\tfor (const losingCursor of losingCursors) {\n\t\t\tselectionsAfter.splice(losingCursor, 1);\n\t\t}\n\n\t\treturn selectionsAfter;\n\t}\n\n\tprivate static _arrayIsEmpty(commands: (editorCommon.ICommand | null)[]): boolean {\n\t\tfor (let i = 0, len = commands.length; i < len; i++) {\n\t\t\tif (commands[i]) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\n\tprivate static _getEditOperations(ctx: IExecContext, commands: (editorCommon.ICommand | null)[]): ICommandsData {\n\t\tlet operations: IIdentifiedSingleEditOperation[] = [];\n\t\tlet hadTrackedEditOperation: boolean = false;\n\n\t\tfor (let i = 0, len = commands.length; i < len; i++) {\n\t\t\tconst command = commands[i];\n\t\t\tif (command) {\n\t\t\t\tconst r = this._getEditOperationsFromCommand(ctx, i, command);\n\t\t\t\toperations = operations.concat(r.operations);\n\t\t\t\thadTrackedEditOperation = hadTrackedEditOperation || r.hadTrackedEditOperation;\n\t\t\t}\n\t\t}\n\t\treturn {\n\t\t\toperations: operations,\n\t\t\thadTrackedEditOperation: hadTrackedEditOperation\n\t\t};\n\t}\n\n\tprivate static _getEditOperationsFromCommand(ctx: IExecContext, majorIdentifier: number, command: editorCommon.ICommand): ICommandData {\n\t\t// This method acts as a transaction, if the command fails\n\t\t// everything it has done is ignored\n\t\tconst operations: IIdentifiedSingleEditOperation[] = [];\n\t\tlet operationMinor = 0;\n\n\t\tconst addEditOperation = (range: IRange, text: string | null, forceMoveMarkers: boolean = false) => {\n\t\t\tif (Range.isEmpty(range) && text === '') {\n\t\t\t\t// This command wants to add a no-op => no thank you\n\t\t\t\treturn;\n\t\t\t}\n\t\t\toperations.push({\n\t\t\t\tidentifier: {\n\t\t\t\t\tmajor: majorIdentifier,\n\t\t\t\t\tminor: operationMinor++\n\t\t\t\t},\n\t\t\t\trange: range,\n\t\t\t\ttext: text,\n\t\t\t\tforceMoveMarkers: forceMoveMarkers,\n\t\t\t\tisAutoWhitespaceEdit: command.insertsAutoWhitespace\n\t\t\t});\n\t\t};\n\n\t\tlet hadTrackedEditOperation = false;\n\t\tconst addTrackedEditOperation = (selection: IRange, text: string | null, forceMoveMarkers?: boolean) => {\n\t\t\thadTrackedEditOperation = true;\n\t\t\taddEditOperation(selection, text, forceMoveMarkers);\n\t\t};\n\n\t\tconst trackSelection = (_selection: ISelection, trackPreviousOnEmpty?: boolean) => {\n\t\t\tconst selection = Selection.liftSelection(_selection);\n\t\t\tlet stickiness: TrackedRangeStickiness;\n\t\t\tif (selection.isEmpty()) {\n\t\t\t\tif (typeof trackPreviousOnEmpty === 'boolean') {\n\t\t\t\t\tif (trackPreviousOnEmpty) {\n\t\t\t\t\t\tstickiness = TrackedRangeStickiness.GrowsOnlyWhenTypingBefore;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tstickiness = TrackedRangeStickiness.GrowsOnlyWhenTypingAfter;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Try to lock it with surrounding text\n\t\t\t\t\tconst maxLineColumn = ctx.model.getLineMaxColumn(selection.startLineNumber);\n\t\t\t\t\tif (selection.startColumn === maxLineColumn) {\n\t\t\t\t\t\tstickiness = TrackedRangeStickiness.GrowsOnlyWhenTypingBefore;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tstickiness = TrackedRangeStickiness.GrowsOnlyWhenTypingAfter;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tstickiness = TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges;\n\t\t\t}\n\n\t\t\tconst l = ctx.trackedRanges.length;\n\t\t\tconst id = ctx.model._setTrackedRange(null, selection, stickiness);\n\t\t\tctx.trackedRanges[l] = id;\n\t\t\tctx.trackedRangesDirection[l] = selection.getDirection();\n\t\t\treturn l.toString();\n\t\t};\n\n\t\tconst editOperationBuilder: editorCommon.IEditOperationBuilder = {\n\t\t\taddEditOperation: addEditOperation,\n\t\t\taddTrackedEditOperation: addTrackedEditOperation,\n\t\t\ttrackSelection: trackSelection\n\t\t};\n\n\t\ttry {\n\t\t\tcommand.getEditOperations(ctx.model, editOperationBuilder);\n\t\t} catch (e) {\n\t\t\t// TODO@Alex use notification service if this should be user facing\n\t\t\t// e.friendlyMessage = nls.localize('corrupt.commands', \"Unexpected exception while executing command.\");\n\t\t\tonUnexpectedError(e);\n\t\t\treturn {\n\t\t\t\toperations: [],\n\t\t\t\thadTrackedEditOperation: false\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\toperations: operations,\n\t\t\thadTrackedEditOperation: hadTrackedEditOperation\n\t\t};\n\t}\n\n\tprivate static _getLoserCursorMap(operations: IIdentifiedSingleEditOperation[]): { [index: string]: boolean } {\n\t\t// This is destructive on the array\n\t\toperations = operations.slice(0);\n\n\t\t// Sort operations with last one first\n\t\toperations.sort((a: IIdentifiedSingleEditOperation, b: IIdentifiedSingleEditOperation): number => {\n\t\t\t// Note the minus!\n\t\t\treturn -(Range.compareRangesUsingEnds(a.range, b.range));\n\t\t});\n\n\t\t// Operations can not overlap!\n\t\tconst loserCursorsMap: { [index: string]: boolean } = {};\n\n\t\tfor (let i = 1; i < operations.length; i++) {\n\t\t\tconst previousOp = operations[i - 1];\n\t\t\tconst currentOp = operations[i];\n\n\t\t\tif (Range.getStartPosition(previousOp.range).isBefore(Range.getEndPosition(currentOp.range))) {\n\n\t\t\t\tlet loserMajor: number;\n\n\t\t\t\tif (previousOp.identifier!.major > currentOp.identifier!.major) {\n\t\t\t\t\t// previousOp loses the battle\n\t\t\t\t\tloserMajor = previousOp.identifier!.major;\n\t\t\t\t} else {\n\t\t\t\t\tloserMajor = currentOp.identifier!.major;\n\t\t\t\t}\n\n\t\t\t\tloserCursorsMap[loserMajor.toString()] = true;\n\n\t\t\t\tfor (let j = 0; j < operations.length; j++) {\n\t\t\t\t\tif (operations[j].identifier!.major === loserMajor) {\n\t\t\t\t\t\toperations.splice(j, 1);\n\t\t\t\t\t\tif (j < i) {\n\t\t\t\t\t\t\ti--;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tj--;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (i > 0) {\n\t\t\t\t\ti--;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn loserCursorsMap;\n\t}\n}\n\nclass CompositionLineState {\n\tconstructor(\n\t\tpublic readonly text: string,\n\t\tpublic readonly startSelection: number,\n\t\tpublic readonly endSelection: number\n\t) { }\n}\n\nclass CompositionState {\n\n\tprivate readonly _original: CompositionLineState[] | null;\n\n\tprivate static _capture(textModel: ITextModel, selections: Selection[]): CompositionLineState[] | null {\n\t\tconst result: CompositionLineState[] = [];\n\t\tfor (const selection of selections) {\n\t\t\tif (selection.startLineNumber !== selection.endLineNumber) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tresult.push(new CompositionLineState(\n\t\t\t\ttextModel.getLineContent(selection.startLineNumber),\n\t\t\t\tselection.startColumn - 1,\n\t\t\t\tselection.endColumn - 1\n\t\t\t));\n\t\t}\n\t\treturn result;\n\t}\n\n\tconstructor(textModel: ITextModel, selections: Selection[]) {\n\t\tthis._original = CompositionState._capture(textModel, selections);\n\t}\n\n\t/**\n\t * Returns the inserted text during this composition.\n\t * If the composition resulted in existing text being changed (i.e. not a pure insertion) it returns null.\n\t */\n\tdeduceOutcome(textModel: ITextModel, selections: Selection[]): CompositionOutcome[] | null {\n\t\tif (!this._original) {\n\t\t\treturn null;\n\t\t}\n\t\tconst current = CompositionState._capture(textModel, selections);\n\t\tif (!current) {\n\t\t\treturn null;\n\t\t}\n\t\tif (this._original.length !== current.length) {\n\t\t\treturn null;\n\t\t}\n\t\tconst result: CompositionOutcome[] = [];\n\t\tfor (let i = 0, len = this._original.length; i < len; i++) {\n\t\t\tresult.push(CompositionState._deduceOutcome(this._original[i], current[i]));\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate static _deduceOutcome(original: CompositionLineState, current: CompositionLineState): CompositionOutcome {\n\t\tconst commonPrefix = Math.min(\n\t\t\toriginal.startSelection,\n\t\t\tcurrent.startSelection,\n\t\t\tstrings.commonPrefixLength(original.text, current.text)\n\t\t);\n\t\tconst commonSuffix = Math.min(\n\t\t\toriginal.text.length - original.endSelection,\n\t\t\tcurrent.text.length - current.endSelection,\n\t\t\tstrings.commonSuffixLength(original.text, current.text)\n\t\t);\n\t\tconst deletedText = original.text.substring(commonPrefix, original.text.length - commonSuffix);\n\t\tconst insertedText = current.text.substring(commonPrefix, current.text.length - commonSuffix);\n\t\treturn new CompositionOutcome(\n\t\t\tdeletedText,\n\t\t\toriginal.startSelection - commonPrefix,\n\t\t\toriginal.endSelection - commonPrefix,\n\t\t\tinsertedText,\n\t\t\tcurrent.startSelection - commonPrefix,\n\t\t\tcurrent.endSelection - commonPrefix\n\t\t);\n\t}\n}\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\nimport { Schemas } from 'vs/base/common/network';\nimport { DataUri } from 'vs/base/common/resources';\nimport { URI, URI as uri } from 'vs/base/common/uri';\nimport { PLAINTEXT_LANGUAGE_ID } from 'vs/editor/common/languages/modesRegistry';\nimport { ILanguageService } from 'vs/editor/common/languages/language';\nimport { IModelService } from 'vs/editor/common/services/model';\nimport { FileKind } from 'vs/platform/files/common/files';\nimport { ThemeIcon } from 'vs/base/common/themables';\n\nconst fileIconDirectoryRegex = /(?:\\/|^)(?:([^\\/]+)\\/)?([^\\/]+)$/;\n\nexport function getIconClasses(modelService: IModelService, languageService: ILanguageService, resource: uri | undefined, fileKind?: FileKind, icon?: ThemeIcon | URI): string[] {\n\tif (ThemeIcon.isThemeIcon(icon)) {\n\t\treturn [`codicon-${icon.id}`, 'predefined-file-icon'];\n\t}\n\n\tif (URI.isUri(icon)) {\n\t\treturn [];\n\t}\n\n\t// we always set these base classes even if we do not have a path\n\tconst classes = fileKind === FileKind.ROOT_FOLDER ? ['rootfolder-icon'] : fileKind === FileKind.FOLDER ? ['folder-icon'] : ['file-icon'];\n\tif (resource) {\n\n\t\t// Get the path and name of the resource. For data-URIs, we need to parse specially\n\t\tlet name: string | undefined;\n\t\tif (resource.scheme === Schemas.data) {\n\t\t\tconst metadata = DataUri.parseMetaData(resource);\n\t\t\tname = metadata.get(DataUri.META_DATA_LABEL);\n\t\t} else {\n\t\t\tconst match = resource.path.match(fileIconDirectoryRegex);\n\t\t\tif (match) {\n\t\t\t\tname = cssEscape(match[2].toLowerCase());\n\t\t\t\tif (match[1]) {\n\t\t\t\t\tclasses.push(`${cssEscape(match[1].toLowerCase())}-name-dir-icon`); // parent directory\n\t\t\t\t}\n\n\t\t\t} else {\n\t\t\t\tname = cssEscape(resource.authority.toLowerCase());\n\t\t\t}\n\t\t}\n\n\t\t// Root Folders\n\t\tif (fileKind === FileKind.ROOT_FOLDER) {\n\t\t\tclasses.push(`${name}-root-name-folder-icon`);\n\t\t}\n\n\t\t// Folders\n\t\telse if (fileKind === FileKind.FOLDER) {\n\t\t\tclasses.push(`${name}-name-folder-icon`);\n\t\t}\n\n\t\t// Files\n\t\telse {\n\n\t\t\t// Name & Extension(s)\n\t\t\tif (name) {\n\t\t\t\tclasses.push(`${name}-name-file-icon`);\n\t\t\t\tclasses.push(`name-file-icon`); // extra segment to increase file-name score\n\t\t\t\t// Avoid doing an explosive combination of extensions for very long filenames\n\t\t\t\t// (most file systems do not allow files > 255 length) with lots of `.` characters\n\t\t\t\t// https://github.com/microsoft/vscode/issues/116199\n\t\t\t\tif (name.length <= 255) {\n\t\t\t\t\tconst dotSegments = name.split('.');\n\t\t\t\t\tfor (let i = 1; i < dotSegments.length; i++) {\n\t\t\t\t\t\tclasses.push(`${dotSegments.slice(i).join('.')}-ext-file-icon`); // add each combination of all found extensions if more than one\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tclasses.push(`ext-file-icon`); // extra segment to increase file-ext score\n\t\t\t}\n\n\t\t\t// Detected Mode\n\t\t\tconst detectedLanguageId = detectLanguageId(modelService, languageService, resource);\n\t\t\tif (detectedLanguageId) {\n\t\t\t\tclasses.push(`${cssEscape(detectedLanguageId)}-lang-file-icon`);\n\t\t\t}\n\t\t}\n\t}\n\treturn classes;\n}\n\nfunction detectLanguageId(modelService: IModelService, languageService: ILanguageService, resource: uri): string | null {\n\tif (!resource) {\n\t\treturn null; // we need a resource at least\n\t}\n\n\tlet languageId: string | null = null;\n\n\t// Data URI: check for encoded metadata\n\tif (resource.scheme === Schemas.data) {\n\t\tconst metadata = DataUri.parseMetaData(resource);\n\t\tconst mime = metadata.get(DataUri.META_DATA_MIME);\n\n\t\tif (mime) {\n\t\t\tlanguageId = languageService.getLanguageIdByMimeType(mime);\n\t\t}\n\t}\n\n\t// Any other URI: check for model if existing\n\telse {\n\t\tconst model = modelService.getModel(resource);\n\t\tif (model) {\n\t\t\tlanguageId = model.getLanguageId();\n\t\t}\n\t}\n\n\t// only take if the language id is specific (aka no just plain text)\n\tif (languageId && languageId !== PLAINTEXT_LANGUAGE_ID) {\n\t\treturn languageId;\n\t}\n\n\t// otherwise fallback to path based detection\n\treturn languageService.guessLanguageIdByFilepathOrFirstLine(resource);\n}\n\nfunction cssEscape(str: string): string {\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.\n}\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\nimport { ParsedPattern, parse } from 'vs/base/common/glob';\nimport { Mimes } from 'vs/base/common/mime';\nimport { Schemas } from 'vs/base/common/network';\nimport { basename, posix } from 'vs/base/common/path';\nimport { DataUri } from 'vs/base/common/resources';\nimport { startsWithUTF8BOM } from 'vs/base/common/strings';\nimport { URI } from 'vs/base/common/uri';\nimport { PLAINTEXT_LANGUAGE_ID } from 'vs/editor/common/languages/modesRegistry';\n\nexport interface ILanguageAssociation {\n\treadonly id: string;\n\treadonly mime: string;\n\treadonly filename?: string;\n\treadonly extension?: string;\n\treadonly filepattern?: string;\n\treadonly firstline?: RegExp;\n}\n\ninterface ILanguageAssociationItem extends ILanguageAssociation {\n\treadonly userConfigured: boolean;\n\treadonly filenameLowercase?: string;\n\treadonly extensionLowercase?: string;\n\treadonly filepatternLowercase?: ParsedPattern;\n\treadonly filepatternOnPath?: boolean;\n}\n\nlet registeredAssociations: ILanguageAssociationItem[] = [];\nlet nonUserRegisteredAssociations: ILanguageAssociationItem[] = [];\nlet userRegisteredAssociations: ILanguageAssociationItem[] = [];\n\n/**\n * Associate a language to the registry (platform).\n * * **NOTE**: This association will lose over associations registered using `registerConfiguredLanguageAssociation`.\n * * **NOTE**: Use `clearPlatformLanguageAssociations` to remove all associations registered using this function.\n */\nexport function registerPlatformLanguageAssociation(association: ILanguageAssociation, warnOnOverwrite = false): void {\n\t_registerLanguageAssociation(association, false, warnOnOverwrite);\n}\n\nfunction _registerLanguageAssociation(association: ILanguageAssociation, userConfigured: boolean, warnOnOverwrite: boolean): void {\n\n\t// Register\n\tconst associationItem = toLanguageAssociationItem(association, userConfigured);\n\tregisteredAssociations.push(associationItem);\n\tif (!associationItem.userConfigured) {\n\t\tnonUserRegisteredAssociations.push(associationItem);\n\t} else {\n\t\tuserRegisteredAssociations.push(associationItem);\n\t}\n\n\t// Check for conflicts unless this is a user configured association\n\tif (warnOnOverwrite && !associationItem.userConfigured) {\n\t\tregisteredAssociations.forEach(a => {\n\t\t\tif (a.mime === associationItem.mime || a.userConfigured) {\n\t\t\t\treturn; // same mime or userConfigured is ok\n\t\t\t}\n\n\t\t\tif (associationItem.extension && a.extension === associationItem.extension) {\n\t\t\t\tconsole.warn(`Overwriting extension <<${associationItem.extension}>> to now point to mime <<${associationItem.mime}>>`);\n\t\t\t}\n\n\t\t\tif (associationItem.filename && a.filename === associationItem.filename) {\n\t\t\t\tconsole.warn(`Overwriting filename <<${associationItem.filename}>> to now point to mime <<${associationItem.mime}>>`);\n\t\t\t}\n\n\t\t\tif (associationItem.filepattern && a.filepattern === associationItem.filepattern) {\n\t\t\t\tconsole.warn(`Overwriting filepattern <<${associationItem.filepattern}>> to now point to mime <<${associationItem.mime}>>`);\n\t\t\t}\n\n\t\t\tif (associationItem.firstline && a.firstline === associationItem.firstline) {\n\t\t\t\tconsole.warn(`Overwriting firstline <<${associationItem.firstline}>> to now point to mime <<${associationItem.mime}>>`);\n\t\t\t}\n\t\t});\n\t}\n}\n\nfunction toLanguageAssociationItem(association: ILanguageAssociation, userConfigured: boolean): ILanguageAssociationItem {\n\treturn {\n\t\tid: association.id,\n\t\tmime: association.mime,\n\t\tfilename: association.filename,\n\t\textension: association.extension,\n\t\tfilepattern: association.filepattern,\n\t\tfirstline: association.firstline,\n\t\tuserConfigured: userConfigured,\n\t\tfilenameLowercase: association.filename ? association.filename.toLowerCase() : undefined,\n\t\textensionLowercase: association.extension ? association.extension.toLowerCase() : undefined,\n\t\tfilepatternLowercase: association.filepattern ? parse(association.filepattern.toLowerCase()) : undefined,\n\t\tfilepatternOnPath: association.filepattern ? association.filepattern.indexOf(posix.sep) >= 0 : false\n\t};\n}\n\n/**\n * Clear language associations from the registry (platform).\n */\nexport function clearPlatformLanguageAssociations(): void {\n\tregisteredAssociations = registeredAssociations.filter(a => a.userConfigured);\n\tnonUserRegisteredAssociations = [];\n}\n\ninterface IdAndMime {\n\tid: string;\n\tmime: string;\n}\n\n/**\n * @see `getMimeTypes`\n */\nexport function getLanguageIds(resource: URI | null, firstLine?: string): string[] {\n\treturn getAssociations(resource, firstLine).map(item => item.id);\n}\n\nfunction getAssociations(resource: URI | null, firstLine?: string): IdAndMime[] {\n\tlet path: string | undefined;\n\tif (resource) {\n\t\tswitch (resource.scheme) {\n\t\t\tcase Schemas.file:\n\t\t\t\tpath = resource.fsPath;\n\t\t\t\tbreak;\n\t\t\tcase Schemas.data: {\n\t\t\t\tconst metadata = DataUri.parseMetaData(resource);\n\t\t\t\tpath = metadata.get(DataUri.META_DATA_LABEL);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase Schemas.vscodeNotebookCell:\n\t\t\t\t// File path not relevant for language detection of cell\n\t\t\t\tpath = undefined;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tpath = resource.path;\n\t\t}\n\t}\n\n\tif (!path) {\n\t\treturn [{ id: 'unknown', mime: Mimes.unknown }];\n\t}\n\n\tpath = path.toLowerCase();\n\n\tconst filename = basename(path);\n\n\t// 1.) User configured mappings have highest priority\n\tconst configuredLanguage = getAssociationByPath(path, filename, userRegisteredAssociations);\n\tif (configuredLanguage) {\n\t\treturn [configuredLanguage, { id: PLAINTEXT_LANGUAGE_ID, mime: Mimes.text }];\n\t}\n\n\t// 2.) Registered mappings have middle priority\n\tconst registeredLanguage = getAssociationByPath(path, filename, nonUserRegisteredAssociations);\n\tif (registeredLanguage) {\n\t\treturn [registeredLanguage, { id: PLAINTEXT_LANGUAGE_ID, mime: Mimes.text }];\n\t}\n\n\t// 3.) Firstline has lowest priority\n\tif (firstLine) {\n\t\tconst firstlineLanguage = getAssociationByFirstline(firstLine);\n\t\tif (firstlineLanguage) {\n\t\t\treturn [firstlineLanguage, { id: PLAINTEXT_LANGUAGE_ID, mime: Mimes.text }];\n\t\t}\n\t}\n\n\treturn [{ id: 'unknown', mime: Mimes.unknown }];\n}\n\nfunction getAssociationByPath(path: string, filename: string, associations: ILanguageAssociationItem[]): ILanguageAssociationItem | undefined {\n\tlet filenameMatch: ILanguageAssociationItem | undefined = undefined;\n\tlet patternMatch: ILanguageAssociationItem | undefined = undefined;\n\tlet extensionMatch: ILanguageAssociationItem | undefined = undefined;\n\n\t// We want to prioritize associations based on the order they are registered so that the last registered\n\t// association wins over all other. This is for https://github.com/microsoft/vscode/issues/20074\n\tfor (let i = associations.length - 1; i >= 0; i--) {\n\t\tconst association = associations[i];\n\n\t\t// First exact name match\n\t\tif (filename === association.filenameLowercase) {\n\t\t\tfilenameMatch = association;\n\t\t\tbreak; // take it!\n\t\t}\n\n\t\t// Longest pattern match\n\t\tif (association.filepattern) {\n\t\t\tif (!patternMatch || association.filepattern.length > patternMatch.filepattern!.length) {\n\t\t\t\tconst target = association.filepatternOnPath ? path : filename; // match on full path if pattern contains path separator\n\t\t\t\tif (association.filepatternLowercase?.(target)) {\n\t\t\t\t\tpatternMatch = association;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Longest extension match\n\t\tif (association.extension) {\n\t\t\tif (!extensionMatch || association.extension.length > extensionMatch.extension!.length) {\n\t\t\t\tif (filename.endsWith(association.extensionLowercase!)) {\n\t\t\t\t\textensionMatch = association;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// 1.) Exact name match has second highest priority\n\tif (filenameMatch) {\n\t\treturn filenameMatch;\n\t}\n\n\t// 2.) Match on pattern\n\tif (patternMatch) {\n\t\treturn patternMatch;\n\t}\n\n\t// 3.) Match on extension comes next\n\tif (extensionMatch) {\n\t\treturn extensionMatch;\n\t}\n\n\treturn undefined;\n}\n\nfunction getAssociationByFirstline(firstLine: string): ILanguageAssociationItem | undefined {\n\tif (startsWithUTF8BOM(firstLine)) {\n\t\tfirstLine = firstLine.substr(1);\n\t}\n\n\tif (firstLine.length > 0) {\n\n\t\t// We want to prioritize associations based on the order they are registered so that the last registered\n\t\t// association wins over all other. This is for https://github.com/microsoft/vscode/issues/20074\n\t\tfor (let i = registeredAssociations.length - 1; i >= 0; i--) {\n\t\t\tconst association = registeredAssociations[i];\n\t\t\tif (!association.firstline) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst matches = firstLine.match(association.firstline);\n\t\t\tif (matches && matches.length > 0) {\n\t\t\t\treturn association;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn undefined;\n}\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\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport { regExpLeadsToEndlessLoop } from 'vs/base/common/strings';\nimport { clearPlatformLanguageAssociations, getLanguageIds, registerPlatformLanguageAssociation } from 'vs/editor/common/services/languagesAssociations';\nimport { URI } from 'vs/base/common/uri';\nimport { ILanguageIdCodec } from 'vs/editor/common/languages';\nimport { LanguageId } from 'vs/editor/common/encodedTokenAttributes';\nimport { ModesRegistry, PLAINTEXT_LANGUAGE_ID } from 'vs/editor/common/languages/modesRegistry';\nimport { ILanguageExtensionPoint, ILanguageIcon } from 'vs/editor/common/languages/language';\nimport { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';\nimport { Registry } from 'vs/platform/registry/common/platform';\n\nconst hasOwnProperty = Object.prototype.hasOwnProperty;\nconst NULL_LANGUAGE_ID = 'vs.editor.nullLanguage';\n\ninterface IResolvedLanguage {\n\tidentifier: string;\n\tname: string | null;\n\tmimetypes: string[];\n\taliases: string[];\n\textensions: string[];\n\tfilenames: string[];\n\tconfigurationFiles: URI[];\n\ticons: ILanguageIcon[];\n}\n\nexport class LanguageIdCodec implements ILanguageIdCodec {\n\n\tprivate _nextLanguageId: number;\n\tprivate readonly _languageIdToLanguage: string[] = [];\n\tprivate readonly _languageToLanguageId = new Map();\n\n\tconstructor() {\n\t\tthis._register(NULL_LANGUAGE_ID, LanguageId.Null);\n\t\tthis._register(PLAINTEXT_LANGUAGE_ID, LanguageId.PlainText);\n\t\tthis._nextLanguageId = 2;\n\t}\n\n\tprivate _register(language: string, languageId: LanguageId): void {\n\t\tthis._languageIdToLanguage[languageId] = language;\n\t\tthis._languageToLanguageId.set(language, languageId);\n\t}\n\n\tpublic register(language: string): void {\n\t\tif (this._languageToLanguageId.has(language)) {\n\t\t\treturn;\n\t\t}\n\t\tconst languageId = this._nextLanguageId++;\n\t\tthis._register(language, languageId);\n\t}\n\n\tpublic encodeLanguageId(languageId: string): LanguageId {\n\t\treturn this._languageToLanguageId.get(languageId) || LanguageId.Null;\n\t}\n\n\tpublic decodeLanguageId(languageId: LanguageId): string {\n\t\treturn this._languageIdToLanguage[languageId] || NULL_LANGUAGE_ID;\n\t}\n}\n\nexport class LanguagesRegistry extends Disposable {\n\n\tstatic instanceCount = 0;\n\n\tprivate readonly _onDidChange: Emitter = this._register(new Emitter());\n\tpublic readonly onDidChange: Event = this._onDidChange.event;\n\n\tprivate readonly _warnOnOverwrite: boolean;\n\tpublic readonly languageIdCodec: LanguageIdCodec;\n\tprivate _dynamicLanguages: ILanguageExtensionPoint[];\n\tprivate _languages: { [id: string]: IResolvedLanguage };\n\tprivate _mimeTypesMap: { [mimeType: string]: string };\n\tprivate _nameMap: { [name: string]: string };\n\tprivate _lowercaseNameMap: { [name: string]: string };\n\n\tconstructor(useModesRegistry = true, warnOnOverwrite = false) {\n\t\tsuper();\n\t\tLanguagesRegistry.instanceCount++;\n\n\t\tthis._warnOnOverwrite = warnOnOverwrite;\n\t\tthis.languageIdCodec = new LanguageIdCodec();\n\t\tthis._dynamicLanguages = [];\n\t\tthis._languages = {};\n\t\tthis._mimeTypesMap = {};\n\t\tthis._nameMap = {};\n\t\tthis._lowercaseNameMap = {};\n\n\t\tif (useModesRegistry) {\n\t\t\tthis._initializeFromRegistry();\n\t\t\tthis._register(ModesRegistry.onDidChangeLanguages((m) => {\n\t\t\t\tthis._initializeFromRegistry();\n\t\t\t}));\n\t\t}\n\t}\n\n\toverride dispose() {\n\t\tLanguagesRegistry.instanceCount--;\n\t\tsuper.dispose();\n\t}\n\n\tprivate _initializeFromRegistry(): void {\n\t\tthis._languages = {};\n\t\tthis._mimeTypesMap = {};\n\t\tthis._nameMap = {};\n\t\tthis._lowercaseNameMap = {};\n\n\t\tclearPlatformLanguageAssociations();\n\t\tconst desc = ([]).concat(ModesRegistry.getLanguages()).concat(this._dynamicLanguages);\n\t\tthis._registerLanguages(desc);\n\t}\n\n\t_registerLanguages(desc: ILanguageExtensionPoint[]): void {\n\n\t\tfor (const d of desc) {\n\t\t\tthis._registerLanguage(d);\n\t\t}\n\n\t\t// Rebuild fast path maps\n\t\tthis._mimeTypesMap = {};\n\t\tthis._nameMap = {};\n\t\tthis._lowercaseNameMap = {};\n\t\tObject.keys(this._languages).forEach((langId) => {\n\t\t\tconst language = this._languages[langId];\n\t\t\tif (language.name) {\n\t\t\t\tthis._nameMap[language.name] = language.identifier;\n\t\t\t}\n\t\t\tlanguage.aliases.forEach((alias) => {\n\t\t\t\tthis._lowercaseNameMap[alias.toLowerCase()] = language.identifier;\n\t\t\t});\n\t\t\tlanguage.mimetypes.forEach((mimetype) => {\n\t\t\t\tthis._mimeTypesMap[mimetype] = language.identifier;\n\t\t\t});\n\t\t});\n\n\t\tRegistry.as(Extensions.Configuration).registerOverrideIdentifiers(this.getRegisteredLanguageIds());\n\n\t\tthis._onDidChange.fire();\n\t}\n\n\tprivate _registerLanguage(lang: ILanguageExtensionPoint): void {\n\t\tconst langId = lang.id;\n\n\t\tlet resolvedLanguage: IResolvedLanguage;\n\t\tif (hasOwnProperty.call(this._languages, langId)) {\n\t\t\tresolvedLanguage = this._languages[langId];\n\t\t} else {\n\t\t\tthis.languageIdCodec.register(langId);\n\t\t\tresolvedLanguage = {\n\t\t\t\tidentifier: langId,\n\t\t\t\tname: null,\n\t\t\t\tmimetypes: [],\n\t\t\t\taliases: [],\n\t\t\t\textensions: [],\n\t\t\t\tfilenames: [],\n\t\t\t\tconfigurationFiles: [],\n\t\t\t\ticons: []\n\t\t\t};\n\t\t\tthis._languages[langId] = resolvedLanguage;\n\t\t}\n\n\t\tthis._mergeLanguage(resolvedLanguage, lang);\n\t}\n\n\tprivate _mergeLanguage(resolvedLanguage: IResolvedLanguage, lang: ILanguageExtensionPoint): void {\n\t\tconst langId = lang.id;\n\n\t\tlet primaryMime: string | null = null;\n\n\t\tif (Array.isArray(lang.mimetypes) && lang.mimetypes.length > 0) {\n\t\t\tresolvedLanguage.mimetypes.push(...lang.mimetypes);\n\t\t\tprimaryMime = lang.mimetypes[0];\n\t\t}\n\n\t\tif (!primaryMime) {\n\t\t\tprimaryMime = `text/x-${langId}`;\n\t\t\tresolvedLanguage.mimetypes.push(primaryMime);\n\t\t}\n\n\t\tif (Array.isArray(lang.extensions)) {\n\t\t\tif (lang.configuration) {\n\t\t\t\t// insert first as this appears to be the 'primary' language definition\n\t\t\t\tresolvedLanguage.extensions = lang.extensions.concat(resolvedLanguage.extensions);\n\t\t\t} else {\n\t\t\t\tresolvedLanguage.extensions = resolvedLanguage.extensions.concat(lang.extensions);\n\t\t\t}\n\t\t\tfor (const extension of lang.extensions) {\n\t\t\t\tregisterPlatformLanguageAssociation({ id: langId, mime: primaryMime, extension: extension }, this._warnOnOverwrite);\n\t\t\t}\n\t\t}\n\n\t\tif (Array.isArray(lang.filenames)) {\n\t\t\tfor (const filename of lang.filenames) {\n\t\t\t\tregisterPlatformLanguageAssociation({ id: langId, mime: primaryMime, filename: filename }, this._warnOnOverwrite);\n\t\t\t\tresolvedLanguage.filenames.push(filename);\n\t\t\t}\n\t\t}\n\n\t\tif (Array.isArray(lang.filenamePatterns)) {\n\t\t\tfor (const filenamePattern of lang.filenamePatterns) {\n\t\t\t\tregisterPlatformLanguageAssociation({ id: langId, mime: primaryMime, filepattern: filenamePattern }, this._warnOnOverwrite);\n\t\t\t}\n\t\t}\n\n\t\tif (typeof lang.firstLine === 'string' && lang.firstLine.length > 0) {\n\t\t\tlet firstLineRegexStr = lang.firstLine;\n\t\t\tif (firstLineRegexStr.charAt(0) !== '^') {\n\t\t\t\tfirstLineRegexStr = '^' + firstLineRegexStr;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst firstLineRegex = new RegExp(firstLineRegexStr);\n\t\t\t\tif (!regExpLeadsToEndlessLoop(firstLineRegex)) {\n\t\t\t\t\tregisterPlatformLanguageAssociation({ id: langId, mime: primaryMime, firstline: firstLineRegex }, this._warnOnOverwrite);\n\t\t\t\t}\n\t\t\t} catch (err) {\n\t\t\t\t// Most likely, the regex was bad\n\t\t\t\tconsole.warn(`[${lang.id}]: Invalid regular expression \\`${firstLineRegexStr}\\`: `, err);\n\t\t\t}\n\t\t}\n\n\t\tresolvedLanguage.aliases.push(langId);\n\n\t\tlet langAliases: Array | null = null;\n\t\tif (typeof lang.aliases !== 'undefined' && Array.isArray(lang.aliases)) {\n\t\t\tif (lang.aliases.length === 0) {\n\t\t\t\t// signal that this language should not get a name\n\t\t\t\tlangAliases = [null];\n\t\t\t} else {\n\t\t\t\tlangAliases = lang.aliases;\n\t\t\t}\n\t\t}\n\n\t\tif (langAliases !== null) {\n\t\t\tfor (const langAlias of langAliases) {\n\t\t\t\tif (!langAlias || langAlias.length === 0) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tresolvedLanguage.aliases.push(langAlias);\n\t\t\t}\n\t\t}\n\n\t\tconst containsAliases = (langAliases !== null && langAliases.length > 0);\n\t\tif (containsAliases && langAliases![0] === null) {\n\t\t\t// signal that this language should not get a name\n\t\t} else {\n\t\t\tconst bestName = (containsAliases ? langAliases![0] : null) || langId;\n\t\t\tif (containsAliases || !resolvedLanguage.name) {\n\t\t\t\tresolvedLanguage.name = bestName;\n\t\t\t}\n\t\t}\n\n\t\tif (lang.configuration) {\n\t\t\tresolvedLanguage.configurationFiles.push(lang.configuration);\n\t\t}\n\n\t\tif (lang.icon) {\n\t\t\tresolvedLanguage.icons.push(lang.icon);\n\t\t}\n\t}\n\n\tpublic isRegisteredLanguageId(languageId: string | null | undefined): boolean {\n\t\tif (!languageId) {\n\t\t\treturn false;\n\t\t}\n\t\treturn hasOwnProperty.call(this._languages, languageId);\n\t}\n\n\tpublic getRegisteredLanguageIds(): string[] {\n\t\treturn Object.keys(this._languages);\n\t}\n\n\tpublic getLanguageIdByLanguageName(languageName: string): string | null {\n\t\tconst languageNameLower = languageName.toLowerCase();\n\t\tif (!hasOwnProperty.call(this._lowercaseNameMap, languageNameLower)) {\n\t\t\treturn null;\n\t\t}\n\t\treturn this._lowercaseNameMap[languageNameLower];\n\t}\n\n\tpublic getLanguageIdByMimeType(mimeType: string | null | undefined): string | null {\n\t\tif (!mimeType) {\n\t\t\treturn null;\n\t\t}\n\t\tif (hasOwnProperty.call(this._mimeTypesMap, mimeType)) {\n\t\t\treturn this._mimeTypesMap[mimeType];\n\t\t}\n\t\treturn null;\n\t}\n\n\tpublic guessLanguageIdByFilepathOrFirstLine(resource: URI | null, firstLine?: string): string[] {\n\t\tif (!resource && !firstLine) {\n\t\t\treturn [];\n\t\t}\n\t\treturn getLanguageIds(resource, firstLine);\n\t}\n}\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\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { Disposable, IDisposable } from 'vs/base/common/lifecycle';\nimport { URI } from 'vs/base/common/uri';\nimport { LanguagesRegistry } from 'vs/editor/common/services/languagesRegistry';\nimport { ILanguageSelection, ILanguageService } from 'vs/editor/common/languages/language';\nimport { firstOrDefault } from 'vs/base/common/arrays';\nimport { ILanguageIdCodec, TokenizationRegistry } from 'vs/editor/common/languages';\nimport { PLAINTEXT_LANGUAGE_ID } from 'vs/editor/common/languages/modesRegistry';\n\nexport class LanguageService extends Disposable implements ILanguageService {\n\tpublic _serviceBrand: undefined;\n\n\tstatic instanceCount = 0;\n\n\tprivate readonly _onDidRequestBasicLanguageFeatures = this._register(new Emitter());\n\tpublic readonly onDidRequestBasicLanguageFeatures = this._onDidRequestBasicLanguageFeatures.event;\n\n\tprivate readonly _onDidRequestRichLanguageFeatures = this._register(new Emitter());\n\tpublic readonly onDidRequestRichLanguageFeatures = this._onDidRequestRichLanguageFeatures.event;\n\n\tprotected readonly _onDidChange = this._register(new Emitter({ leakWarningThreshold: 200 /* https://github.com/microsoft/vscode/issues/119968 */ }));\n\tpublic readonly onDidChange: Event = this._onDidChange.event;\n\n\tprivate readonly _requestedBasicLanguages = new Set();\n\tprivate readonly _requestedRichLanguages = new Set();\n\n\tprotected readonly _registry: LanguagesRegistry;\n\tpublic readonly languageIdCodec: ILanguageIdCodec;\n\n\tconstructor(warnOnOverwrite = false) {\n\t\tsuper();\n\t\tLanguageService.instanceCount++;\n\t\tthis._registry = this._register(new LanguagesRegistry(true, warnOnOverwrite));\n\t\tthis.languageIdCodec = this._registry.languageIdCodec;\n\t\tthis._register(this._registry.onDidChange(() => this._onDidChange.fire()));\n\t}\n\n\tpublic override dispose(): void {\n\t\tLanguageService.instanceCount--;\n\t\tsuper.dispose();\n\t}\n\n\tpublic isRegisteredLanguageId(languageId: string | null | undefined): boolean {\n\t\treturn this._registry.isRegisteredLanguageId(languageId);\n\t}\n\n\tpublic getLanguageIdByLanguageName(languageName: string): string | null {\n\t\treturn this._registry.getLanguageIdByLanguageName(languageName);\n\t}\n\n\tpublic getLanguageIdByMimeType(mimeType: string | null | undefined): string | null {\n\t\treturn this._registry.getLanguageIdByMimeType(mimeType);\n\t}\n\n\tpublic guessLanguageIdByFilepathOrFirstLine(resource: URI | null, firstLine?: string): string | null {\n\t\tconst languageIds = this._registry.guessLanguageIdByFilepathOrFirstLine(resource, firstLine);\n\t\treturn firstOrDefault(languageIds, null);\n\t}\n\n\tpublic createById(languageId: string | null | undefined): ILanguageSelection {\n\t\treturn new LanguageSelection(this.onDidChange, () => {\n\t\t\treturn this._createAndGetLanguageIdentifier(languageId);\n\t\t});\n\t}\n\n\tpublic createByFilepathOrFirstLine(resource: URI | null, firstLine?: string): ILanguageSelection {\n\t\treturn new LanguageSelection(this.onDidChange, () => {\n\t\t\tconst languageId = this.guessLanguageIdByFilepathOrFirstLine(resource, firstLine);\n\t\t\treturn this._createAndGetLanguageIdentifier(languageId);\n\t\t});\n\t}\n\n\tprivate _createAndGetLanguageIdentifier(languageId: string | null | undefined): string {\n\t\tif (!languageId || !this.isRegisteredLanguageId(languageId)) {\n\t\t\t// Fall back to plain text if language is unknown\n\t\t\tlanguageId = PLAINTEXT_LANGUAGE_ID;\n\t\t}\n\n\t\treturn languageId;\n\t}\n\n\tpublic requestBasicLanguageFeatures(languageId: string): void {\n\t\tif (!this._requestedBasicLanguages.has(languageId)) {\n\t\t\tthis._requestedBasicLanguages.add(languageId);\n\t\t\tthis._onDidRequestBasicLanguageFeatures.fire(languageId);\n\t\t}\n\t}\n\n\tpublic requestRichLanguageFeatures(languageId: string): void {\n\t\tif (!this._requestedRichLanguages.has(languageId)) {\n\t\t\tthis._requestedRichLanguages.add(languageId);\n\n\t\t\t// Ensure basic features are requested\n\t\t\tthis.requestBasicLanguageFeatures(languageId);\n\n\t\t\t// Ensure tokenizers are created\n\t\t\tTokenizationRegistry.getOrCreate(languageId);\n\n\t\t\tthis._onDidRequestRichLanguageFeatures.fire(languageId);\n\t\t}\n\t}\n}\n\nclass LanguageSelection implements ILanguageSelection {\n\n\tpublic languageId: string;\n\n\tprivate _listener: IDisposable | null = null;\n\tprivate _emitter: Emitter | null = null;\n\n\tconstructor(\n\t\tprivate readonly _onDidChangeLanguages: Event,\n\t\tprivate readonly _selector: () => string\n\t) {\n\t\tthis.languageId = this._selector();\n\t}\n\n\tprivate _dispose(): void {\n\t\tif (this._listener) {\n\t\t\tthis._listener.dispose();\n\t\t\tthis._listener = null;\n\t\t}\n\t\tif (this._emitter) {\n\t\t\tthis._emitter.dispose();\n\t\t\tthis._emitter = null;\n\t\t}\n\t}\n\n\tpublic get onDidChange(): Event {\n\t\tif (!this._listener) {\n\t\t\tthis._listener = this._onDidChangeLanguages(() => this._evaluate());\n\t\t}\n\t\tif (!this._emitter) {\n\t\t\tthis._emitter = new Emitter({\n\t\t\t\tonDidRemoveLastListener: () => {\n\t\t\t\t\tthis._dispose();\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t\treturn this._emitter.event;\n\t}\n\n\tprivate _evaluate(): void {\n\t\tconst languageId = this._selector();\n\t\tif (languageId === this.languageId) {\n\t\t\t// no change\n\t\t\treturn;\n\t\t}\n\t\tthis.languageId = languageId;\n\t\tthis._emitter?.fire(this.languageId);\n\t}\n}\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\nimport { CancellationToken } from 'vs/base/common/cancellation';\nimport { Color, RGBA } from 'vs/base/common/color';\nimport { ITextModel } from 'vs/editor/common/model';\nimport { DocumentColorProvider, IColor, IColorInformation, IColorPresentation } from 'vs/editor/common/languages';\nimport { EditorWorkerClient } from 'vs/editor/browser/services/editorWorkerService';\nimport { IModelService } from 'vs/editor/common/services/model';\nimport { ILanguageConfigurationService } from 'vs/editor/common/languages/languageConfigurationRegistry';\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';\nimport { registerEditorFeature } from 'vs/editor/common/editorFeatures';\n\nexport class DefaultDocumentColorProvider implements DocumentColorProvider {\n\n\tprivate _editorWorkerClient: EditorWorkerClient;\n\n\tconstructor(\n\t\tmodelService: IModelService,\n\t\tlanguageConfigurationService: ILanguageConfigurationService,\n\t) {\n\t\tthis._editorWorkerClient = new EditorWorkerClient(modelService, false, 'editorWorkerService', languageConfigurationService);\n\t}\n\n\tasync provideDocumentColors(model: ITextModel, _token: CancellationToken): Promise {\n\t\treturn this._editorWorkerClient.computeDefaultDocumentColors(model.uri);\n\t}\n\n\tprovideColorPresentations(_model: ITextModel, colorInfo: IColorInformation, _token: CancellationToken): IColorPresentation[] {\n\t\tconst range = colorInfo.range;\n\t\tconst colorFromInfo: IColor = colorInfo.color;\n\t\tconst alpha = colorFromInfo.alpha;\n\t\tconst color = new Color(new RGBA(Math.round(255 * colorFromInfo.red), Math.round(255 * colorFromInfo.green), Math.round(255 * colorFromInfo.blue), alpha));\n\n\t\tconst rgb = alpha ? Color.Format.CSS.formatRGB(color) : Color.Format.CSS.formatRGBA(color);\n\t\tconst hsl = alpha ? Color.Format.CSS.formatHSL(color) : Color.Format.CSS.formatHSLA(color);\n\t\tconst hex = alpha ? Color.Format.CSS.formatHex(color) : Color.Format.CSS.formatHexA(color);\n\n\t\tconst colorPresentations: IColorPresentation[] = [];\n\t\tcolorPresentations.push({ label: rgb, textEdit: { range: range, text: rgb } });\n\t\tcolorPresentations.push({ label: hsl, textEdit: { range: range, text: hsl } });\n\t\tcolorPresentations.push({ label: hex, textEdit: { range: range, text: hex } });\n\t\treturn colorPresentations;\n\t}\n}\n\nclass DefaultDocumentColorProviderFeature extends Disposable {\n\tconstructor(\n\t\t@IModelService _modelService: IModelService,\n\t\t@ILanguageConfigurationService _languageConfigurationService: ILanguageConfigurationService,\n\t\t@ILanguageFeaturesService _languageFeaturesService: ILanguageFeaturesService,\n\t) {\n\t\tsuper();\n\t\tthis._register(_languageFeaturesService.colorProvider.register('*', new DefaultDocumentColorProvider(_modelService, _languageConfigurationService)));\n\t}\n}\n\nregisterEditorFeature(DefaultDocumentColorProviderFeature);\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\nimport { CancellationToken } from 'vs/base/common/cancellation';\nimport { illegalArgument, onUnexpectedExternalError } from 'vs/base/common/errors';\nimport { URI } from 'vs/base/common/uri';\nimport { IRange, Range } from 'vs/editor/common/core/range';\nimport { ITextModel } from 'vs/editor/common/model';\nimport { DocumentColorProvider, IColorInformation, IColorPresentation } from 'vs/editor/common/languages';\nimport { IModelService } from 'vs/editor/common/services/model';\nimport { CommandsRegistry } from 'vs/platform/commands/common/commands';\nimport { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';\nimport { LanguageFeatureRegistry } from 'vs/editor/common/languageFeatureRegistry';\nimport { DefaultDocumentColorProvider } from 'vs/editor/contrib/colorPicker/browser/defaultDocumentColorProvider';\nimport { IConfigurationService } from 'vs/platform/configuration/common/configuration';\nimport { ServicesAccessor } from 'vs/editor/browser/editorExtensions';\n\nexport async function getColors(colorProviderRegistry: LanguageFeatureRegistry, model: ITextModel, token: CancellationToken, isDefaultColorDecoratorsEnabled: boolean = true): Promise {\n\treturn _findColorData(new ColorDataCollector(), colorProviderRegistry, model, token, isDefaultColorDecoratorsEnabled);\n}\n\nexport function getColorPresentations(model: ITextModel, colorInfo: IColorInformation, provider: DocumentColorProvider, token: CancellationToken): Promise {\n\treturn Promise.resolve(provider.provideColorPresentations(model, colorInfo, token));\n}\n\nexport interface IColorData {\n\tcolorInfo: IColorInformation;\n\tprovider: DocumentColorProvider;\n}\n\ninterface IExtColorData { range: IRange; color: [number, number, number, number] }\n\ninterface DataCollector {\n\tcompute(provider: DocumentColorProvider, model: ITextModel, token: CancellationToken, result: T[]): Promise;\n}\n\nclass ColorDataCollector implements DataCollector {\n\tconstructor() { }\n\tasync compute(provider: DocumentColorProvider, model: ITextModel, token: CancellationToken, colors: IColorData[]): Promise {\n\t\tconst documentColors = await provider.provideDocumentColors(model, token);\n\t\tif (Array.isArray(documentColors)) {\n\t\t\tfor (const colorInfo of documentColors) {\n\t\t\t\tcolors.push({ colorInfo, provider });\n\t\t\t}\n\t\t}\n\t\treturn Array.isArray(documentColors);\n\t}\n}\n\nclass ExtColorDataCollector implements DataCollector {\n\tconstructor() { }\n\tasync compute(provider: DocumentColorProvider, model: ITextModel, token: CancellationToken, colors: IExtColorData[]): Promise {\n\t\tconst documentColors = await provider.provideDocumentColors(model, token);\n\t\tif (Array.isArray(documentColors)) {\n\t\t\tfor (const colorInfo of documentColors) {\n\t\t\t\tcolors.push({ range: colorInfo.range, color: [colorInfo.color.red, colorInfo.color.green, colorInfo.color.blue, colorInfo.color.alpha] });\n\t\t\t}\n\t\t}\n\t\treturn Array.isArray(documentColors);\n\t}\n\n}\n\nclass ColorPresentationsCollector implements DataCollector {\n\tconstructor(private colorInfo: IColorInformation) { }\n\tasync compute(provider: DocumentColorProvider, model: ITextModel, _token: CancellationToken, colors: IColorPresentation[]): Promise {\n\t\tconst documentColors = await provider.provideColorPresentations(model, this.colorInfo, CancellationToken.None);\n\t\tif (Array.isArray(documentColors)) {\n\t\t\tcolors.push(...documentColors);\n\t\t}\n\t\treturn Array.isArray(documentColors);\n\t}\n}\n\nasync function _findColorData(collector: DataCollector, colorProviderRegistry: LanguageFeatureRegistry, model: ITextModel, token: CancellationToken, isDefaultColorDecoratorsEnabled: boolean): Promise {\n\tlet validDocumentColorProviderFound = false;\n\tlet defaultProvider: DefaultDocumentColorProvider | undefined;\n\tconst colorData: T[] = [];\n\tconst documentColorProviders = colorProviderRegistry.ordered(model);\n\tfor (let i = documentColorProviders.length - 1; i >= 0; i--) {\n\t\tconst provider = documentColorProviders[i];\n\t\tif (provider instanceof DefaultDocumentColorProvider) {\n\t\t\tdefaultProvider = provider;\n\t\t} else {\n\t\t\ttry {\n\t\t\t\tif (await collector.compute(provider, model, token, colorData)) {\n\t\t\t\t\tvalidDocumentColorProviderFound = true;\n\t\t\t\t}\n\t\t\t} catch (e) {\n\t\t\t\tonUnexpectedExternalError(e);\n\t\t\t}\n\t\t}\n\t}\n\tif (validDocumentColorProviderFound) {\n\t\treturn colorData;\n\t}\n\tif (defaultProvider && isDefaultColorDecoratorsEnabled) {\n\t\tawait collector.compute(defaultProvider, model, token, colorData);\n\t\treturn colorData;\n\t}\n\treturn [];\n}\n\nfunction _setupColorCommand(accessor: ServicesAccessor, resource: URI): { model: ITextModel; colorProviderRegistry: LanguageFeatureRegistry; isDefaultColorDecoratorsEnabled: boolean } {\n\tconst { colorProvider: colorProviderRegistry } = accessor.get(ILanguageFeaturesService);\n\tconst model = accessor.get(IModelService).getModel(resource);\n\tif (!model) {\n\t\tthrow illegalArgument();\n\t}\n\tconst isDefaultColorDecoratorsEnabled = accessor.get(IConfigurationService).getValue('editor.defaultColorDecorators', { resource });\n\treturn { model, colorProviderRegistry, isDefaultColorDecoratorsEnabled };\n}\n\nCommandsRegistry.registerCommand('_executeDocumentColorProvider', function (accessor, ...args) {\n\tconst [resource] = args;\n\tif (!(resource instanceof URI)) {\n\t\tthrow illegalArgument();\n\t}\n\tconst { model, colorProviderRegistry, isDefaultColorDecoratorsEnabled } = _setupColorCommand(accessor, resource);\n\treturn _findColorData(new ExtColorDataCollector(), colorProviderRegistry, model, CancellationToken.None, isDefaultColorDecoratorsEnabled);\n});\n\nCommandsRegistry.registerCommand('_executeColorPresentationProvider', function (accessor, ...args) {\n\tconst [color, context] = args;\n\tconst { uri, range } = context;\n\tif (!(uri instanceof URI) || !Array.isArray(color) || color.length !== 4 || !Range.isIRange(range)) {\n\t\tthrow illegalArgument();\n\t}\n\tconst { model, colorProviderRegistry, isDefaultColorDecoratorsEnabled } = _setupColorCommand(accessor, uri);\n\tconst [red, green, blue, alpha] = color;\n\treturn _findColorData(new ColorPresentationsCollector({ range: range, color: { red, green, blue, alpha } }), colorProviderRegistry, model, CancellationToken.None, isDefaultColorDecoratorsEnabled);\n});\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\nimport * as dom from 'vs/base/browser/dom';\nimport { Disposable, DisposableStore } from 'vs/base/common/lifecycle';\nimport { MarkdownRenderer } from 'vs/editor/browser/widget/markdownRenderer/browser/markdownRenderer';\nimport { ICodeEditor, IEditorMouseEvent, IOverlayWidget, IOverlayWidgetPosition, MouseTargetType } from 'vs/editor/browser/editorBrowser';\nimport { ConfigurationChangedEvent, EditorOption } from 'vs/editor/common/config/editorOptions';\nimport { ILanguageService } from 'vs/editor/common/languages/language';\nimport { HoverOperation, HoverStartMode } from 'vs/editor/contrib/hover/browser/hoverOperation';\nimport { IOpenerService } from 'vs/platform/opener/common/opener';\nimport { HoverWidget } from 'vs/base/browser/ui/hover/hoverWidget';\nimport { IHoverWidget } from 'vs/editor/contrib/hover/browser/hoverTypes';\nimport { IHoverMessage, LaneOrLineNumber, MarginHoverComputer } from 'vs/editor/contrib/hover/browser/marginHoverComputer';\n\nconst $ = dom.$;\n\nexport class MarginHoverWidget extends Disposable implements IOverlayWidget, IHoverWidget {\n\n\tpublic static readonly ID = 'editor.contrib.modesGlyphHoverWidget';\n\n\tprivate readonly _editor: ICodeEditor;\n\tprivate readonly _hover: HoverWidget;\n\n\tprivate _isVisible: boolean;\n\tprivate _messages: IHoverMessage[];\n\n\tprivate readonly _markdownRenderer: MarkdownRenderer;\n\tprivate readonly _computer: MarginHoverComputer;\n\tprivate readonly _hoverOperation: HoverOperation;\n\tprivate readonly _renderDisposeables = this._register(new DisposableStore());\n\n\tconstructor(\n\t\teditor: ICodeEditor,\n\t\tlanguageService: ILanguageService,\n\t\topenerService: IOpenerService,\n\t) {\n\t\tsuper();\n\t\tthis._editor = editor;\n\n\t\tthis._isVisible = false;\n\t\tthis._messages = [];\n\n\t\tthis._hover = this._register(new HoverWidget());\n\t\tthis._hover.containerDomNode.classList.toggle('hidden', !this._isVisible);\n\n\t\tthis._markdownRenderer = this._register(new MarkdownRenderer({ editor: this._editor }, languageService, openerService));\n\t\tthis._computer = new MarginHoverComputer(this._editor);\n\t\tthis._hoverOperation = this._register(new HoverOperation(this._editor, this._computer));\n\t\tthis._register(this._hoverOperation.onResult((result) => {\n\t\t\tthis._withResult(result.value);\n\t\t}));\n\n\t\tthis._register(this._editor.onDidChangeModelDecorations(() => this._onModelDecorationsChanged()));\n\t\tthis._register(this._editor.onDidChangeConfiguration((e: ConfigurationChangedEvent) => {\n\t\t\tif (e.hasChanged(EditorOption.fontInfo)) {\n\t\t\t\tthis._updateFont();\n\t\t\t}\n\t\t}));\n\n\t\tthis._editor.addOverlayWidget(this);\n\t}\n\n\tpublic override dispose(): void {\n\t\tthis._editor.removeOverlayWidget(this);\n\t\tsuper.dispose();\n\t}\n\n\tpublic getId(): string {\n\t\treturn MarginHoverWidget.ID;\n\t}\n\n\tpublic getDomNode(): HTMLElement {\n\t\treturn this._hover.containerDomNode;\n\t}\n\n\tpublic getPosition(): IOverlayWidgetPosition | null {\n\t\treturn null;\n\t}\n\n\tprivate _updateFont(): void {\n\t\tconst codeClasses: HTMLElement[] = Array.prototype.slice.call(this._hover.contentsDomNode.getElementsByClassName('code'));\n\t\tcodeClasses.forEach(node => this._editor.applyFontInfo(node));\n\t}\n\n\tprivate _onModelDecorationsChanged(): void {\n\t\tif (this._isVisible) {\n\t\t\t// The decorations have changed and the hover is visible,\n\t\t\t// we need to recompute the displayed text\n\t\t\tthis._hoverOperation.cancel();\n\t\t\tthis._hoverOperation.start(HoverStartMode.Delayed);\n\t\t}\n\t}\n\n\tpublic showsOrWillShow(mouseEvent: IEditorMouseEvent): boolean {\n\t\tconst target = mouseEvent.target;\n\t\tif (target.type === MouseTargetType.GUTTER_GLYPH_MARGIN && target.detail.glyphMarginLane) {\n\t\t\tthis._startShowingAt(target.position.lineNumber, target.detail.glyphMarginLane);\n\t\t\treturn true;\n\t\t}\n\t\tif (target.type === MouseTargetType.GUTTER_LINE_NUMBERS) {\n\t\t\tthis._startShowingAt(target.position.lineNumber, 'lineNo');\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate _startShowingAt(lineNumber: number, laneOrLine: LaneOrLineNumber): void {\n\t\tif (this._computer.lineNumber === lineNumber && this._computer.lane === laneOrLine) {\n\t\t\t// We have to show the widget at the exact same line number as before, so no work is needed\n\t\t\treturn;\n\t\t}\n\n\t\tthis._hoverOperation.cancel();\n\n\t\tthis.hide();\n\n\t\tthis._computer.lineNumber = lineNumber;\n\t\tthis._computer.lane = laneOrLine;\n\t\tthis._hoverOperation.start(HoverStartMode.Delayed);\n\t}\n\n\tpublic hide(): void {\n\t\tthis._computer.lineNumber = -1;\n\t\tthis._hoverOperation.cancel();\n\t\tif (!this._isVisible) {\n\t\t\treturn;\n\t\t}\n\t\tthis._isVisible = false;\n\t\tthis._hover.containerDomNode.classList.toggle('hidden', !this._isVisible);\n\t}\n\n\tprivate _withResult(result: IHoverMessage[]): void {\n\t\tthis._messages = result;\n\n\t\tif (this._messages.length > 0) {\n\t\t\tthis._renderMessages(this._computer.lineNumber, this._messages);\n\t\t} else {\n\t\t\tthis.hide();\n\t\t}\n\t}\n\n\tprivate _renderMessages(lineNumber: number, messages: IHoverMessage[]): void {\n\t\tthis._renderDisposeables.clear();\n\n\t\tconst fragment = document.createDocumentFragment();\n\n\t\tfor (const msg of messages) {\n\t\t\tconst markdownHoverElement = $('div.hover-row.markdown-hover');\n\t\t\tconst hoverContentsElement = dom.append(markdownHoverElement, $('div.hover-contents'));\n\t\t\tconst renderedContents = this._renderDisposeables.add(this._markdownRenderer.render(msg.value));\n\t\t\thoverContentsElement.appendChild(renderedContents.element);\n\t\t\tfragment.appendChild(markdownHoverElement);\n\t\t}\n\n\t\tthis._updateContents(fragment);\n\t\tthis._showAt(lineNumber);\n\t}\n\n\tprivate _updateContents(node: Node): void {\n\t\tthis._hover.contentsDomNode.textContent = '';\n\t\tthis._hover.contentsDomNode.appendChild(node);\n\t\tthis._updateFont();\n\t}\n\n\tprivate _showAt(lineNumber: number): void {\n\t\tif (!this._isVisible) {\n\t\t\tthis._isVisible = true;\n\t\t\tthis._hover.containerDomNode.classList.toggle('hidden', !this._isVisible);\n\t\t}\n\n\t\tconst editorLayout = this._editor.getLayoutInfo();\n\t\tconst topForLineNumber = this._editor.getTopForLineNumber(lineNumber);\n\t\tconst editorScrollTop = this._editor.getScrollTop();\n\t\tconst lineHeight = this._editor.getOption(EditorOption.lineHeight);\n\t\tconst nodeHeight = this._hover.containerDomNode.clientHeight;\n\t\tconst top = topForLineNumber - editorScrollTop - ((nodeHeight - lineHeight) / 2);\n\t\tconst left = editorLayout.glyphMarginLeft + editorLayout.glyphMarginWidth + (this._computer.lane === 'lineNo' ? editorLayout.lineNumbersWidth : 0);\n\t\tthis._hover.containerDomNode.style.left = `${left}px`;\n\t\tthis._hover.containerDomNode.style.top = `${Math.max(Math.round(top), 0)}px`;\n\t}\n}\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\nimport * as strings from 'vs/base/common/strings';\nimport { ShiftCommand } from 'vs/editor/common/commands/shiftCommand';\nimport { EditOperation, ISingleEditOperation } from 'vs/editor/common/core/editOperation';\nimport { normalizeIndentation } from 'vs/editor/common/core/indentation';\nimport { Selection } from 'vs/editor/common/core/selection';\nimport { ILanguageConfigurationService } from 'vs/editor/common/languages/languageConfigurationRegistry';\nimport { ITextModel } from 'vs/editor/common/model';\n\nexport function getReindentEditOperations(model: ITextModel, languageConfigurationService: ILanguageConfigurationService, startLineNumber: number, endLineNumber: number, inheritedIndent?: string): ISingleEditOperation[] {\n\tif (model.getLineCount() === 1 && model.getLineMaxColumn(1) === 1) {\n\t\t// Model is empty\n\t\treturn [];\n\t}\n\n\tconst indentationRules = languageConfigurationService.getLanguageConfiguration(model.getLanguageId()).indentationRules;\n\tif (!indentationRules) {\n\t\treturn [];\n\t}\n\n\tendLineNumber = Math.min(endLineNumber, model.getLineCount());\n\n\t// Skip `unIndentedLinePattern` lines\n\twhile (startLineNumber <= endLineNumber) {\n\t\tif (!indentationRules.unIndentedLinePattern) {\n\t\t\tbreak;\n\t\t}\n\n\t\tconst text = model.getLineContent(startLineNumber);\n\t\tif (!indentationRules.unIndentedLinePattern.test(text)) {\n\t\t\tbreak;\n\t\t}\n\n\t\tstartLineNumber++;\n\t}\n\n\tif (startLineNumber > endLineNumber - 1) {\n\t\treturn [];\n\t}\n\n\tconst { tabSize, indentSize, insertSpaces } = model.getOptions();\n\tconst shiftIndent = (indentation: string, count?: number) => {\n\t\tcount = count || 1;\n\t\treturn ShiftCommand.shiftIndent(indentation, indentation.length + count, tabSize, indentSize, insertSpaces);\n\t};\n\tconst unshiftIndent = (indentation: string, count?: number) => {\n\t\tcount = count || 1;\n\t\treturn ShiftCommand.unshiftIndent(indentation, indentation.length + count, tabSize, indentSize, insertSpaces);\n\t};\n\tconst indentEdits: ISingleEditOperation[] = [];\n\n\t// indentation being passed to lines below\n\tlet globalIndent: string;\n\n\t// Calculate indentation for the first line\n\t// If there is no passed-in indentation, we use the indentation of the first line as base.\n\tconst currentLineText = model.getLineContent(startLineNumber);\n\tlet adjustedLineContent = currentLineText;\n\tif (inheritedIndent !== undefined && inheritedIndent !== null) {\n\t\tglobalIndent = inheritedIndent;\n\t\tconst oldIndentation = strings.getLeadingWhitespace(currentLineText);\n\n\t\tadjustedLineContent = globalIndent + currentLineText.substring(oldIndentation.length);\n\t\tif (indentationRules.decreaseIndentPattern && indentationRules.decreaseIndentPattern.test(adjustedLineContent)) {\n\t\t\tglobalIndent = unshiftIndent(globalIndent);\n\t\t\tadjustedLineContent = globalIndent + currentLineText.substring(oldIndentation.length);\n\n\t\t}\n\t\tif (currentLineText !== adjustedLineContent) {\n\t\t\tindentEdits.push(EditOperation.replaceMove(new Selection(startLineNumber, 1, startLineNumber, oldIndentation.length + 1), normalizeIndentation(globalIndent, indentSize, insertSpaces)));\n\t\t}\n\t} else {\n\t\tglobalIndent = strings.getLeadingWhitespace(currentLineText);\n\t}\n\n\t// idealIndentForNextLine doesn't equal globalIndent when there is a line matching `indentNextLinePattern`.\n\tlet idealIndentForNextLine: string = globalIndent;\n\n\tif (indentationRules.increaseIndentPattern && indentationRules.increaseIndentPattern.test(adjustedLineContent)) {\n\t\tidealIndentForNextLine = shiftIndent(idealIndentForNextLine);\n\t\tglobalIndent = shiftIndent(globalIndent);\n\t}\n\telse if (indentationRules.indentNextLinePattern && indentationRules.indentNextLinePattern.test(adjustedLineContent)) {\n\t\tidealIndentForNextLine = shiftIndent(idealIndentForNextLine);\n\t}\n\n\tstartLineNumber++;\n\n\t// Calculate indentation adjustment for all following lines\n\tfor (let lineNumber = startLineNumber; lineNumber <= endLineNumber; lineNumber++) {\n\t\tconst text = model.getLineContent(lineNumber);\n\t\tconst oldIndentation = strings.getLeadingWhitespace(text);\n\t\tconst adjustedLineContent = idealIndentForNextLine + text.substring(oldIndentation.length);\n\n\t\tif (indentationRules.decreaseIndentPattern && indentationRules.decreaseIndentPattern.test(adjustedLineContent)) {\n\t\t\tidealIndentForNextLine = unshiftIndent(idealIndentForNextLine);\n\t\t\tglobalIndent = unshiftIndent(globalIndent);\n\t\t}\n\n\t\tif (oldIndentation !== idealIndentForNextLine) {\n\t\t\tindentEdits.push(EditOperation.replaceMove(new Selection(lineNumber, 1, lineNumber, oldIndentation.length + 1), normalizeIndentation(idealIndentForNextLine, indentSize, insertSpaces)));\n\t\t}\n\n\t\t// calculate idealIndentForNextLine\n\t\tif (indentationRules.unIndentedLinePattern && indentationRules.unIndentedLinePattern.test(text)) {\n\t\t\t// In reindent phase, if the line matches `unIndentedLinePattern` we inherit indentation from above lines\n\t\t\t// but don't change globalIndent and idealIndentForNextLine.\n\t\t\tcontinue;\n\t\t} else if (indentationRules.increaseIndentPattern && indentationRules.increaseIndentPattern.test(adjustedLineContent)) {\n\t\t\tglobalIndent = shiftIndent(globalIndent);\n\t\t\tidealIndentForNextLine = globalIndent;\n\t\t} else if (indentationRules.indentNextLinePattern && indentationRules.indentNextLinePattern.test(adjustedLineContent)) {\n\t\t\tidealIndentForNextLine = shiftIndent(idealIndentForNextLine);\n\t\t} else {\n\t\t\tidealIndentForNextLine = globalIndent;\n\t\t}\n\t}\n\n\treturn indentEdits;\n}\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\nimport { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';\nimport { equalsIfDefined, itemEquals } from 'vs/base/common/equals';\nimport { matchesSubString } from 'vs/base/common/filters';\nimport { Disposable, IDisposable, MutableDisposable } from 'vs/base/common/lifecycle';\nimport { IObservable, IReader, ITransaction, derivedOpts, disposableObservableValue, transaction } from 'vs/base/common/observable';\nimport { Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\nimport { SingleTextEdit } from 'vs/editor/common/core/textEdit';\nimport { TextLength } from 'vs/editor/common/core/textLength';\nimport { InlineCompletionContext, InlineCompletionTriggerKind } from 'vs/editor/common/languages';\nimport { ILanguageConfigurationService } from 'vs/editor/common/languages/languageConfigurationRegistry';\nimport { EndOfLinePreference, ITextModel } from 'vs/editor/common/model';\nimport { IFeatureDebounceInformation } from 'vs/editor/common/services/languageFeatureDebounce';\nimport { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';\nimport { InlineCompletionItem, InlineCompletionProviderResult, provideInlineCompletions } from 'vs/editor/contrib/inlineCompletions/browser/provideInlineCompletions';\nimport { singleTextRemoveCommonPrefix } from 'vs/editor/contrib/inlineCompletions/browser/singleTextEdit';\n\nexport class InlineCompletionsSource extends Disposable {\n\tprivate readonly _updateOperation = this._register(new MutableDisposable());\n\tpublic readonly inlineCompletions = disposableObservableValue('inlineCompletions', undefined);\n\tpublic readonly suggestWidgetInlineCompletions = disposableObservableValue('suggestWidgetInlineCompletions', undefined);\n\n\tconstructor(\n\t\tprivate readonly textModel: ITextModel,\n\t\tprivate readonly versionId: IObservable,\n\t\tprivate readonly _debounceValue: IFeatureDebounceInformation,\n\t\t@ILanguageFeaturesService private readonly languageFeaturesService: ILanguageFeaturesService,\n\t\t@ILanguageConfigurationService private readonly languageConfigurationService: ILanguageConfigurationService,\n\t) {\n\t\tsuper();\n\n\t\tthis._register(this.textModel.onDidChangeContent(() => {\n\t\t\tthis._updateOperation.clear();\n\t\t}));\n\t}\n\n\tpublic fetch(position: Position, context: InlineCompletionContext, activeInlineCompletion: InlineCompletionWithUpdatedRange | undefined): Promise {\n\t\tconst request = new UpdateRequest(position, context, this.textModel.getVersionId());\n\n\t\tconst target = context.selectedSuggestionInfo ? this.suggestWidgetInlineCompletions : this.inlineCompletions;\n\n\t\tif (this._updateOperation.value?.request.satisfies(request)) {\n\t\t\treturn this._updateOperation.value.promise;\n\t\t} else if (target.get()?.request.satisfies(request)) {\n\t\t\treturn Promise.resolve(true);\n\t\t}\n\n\t\tconst updateOngoing = !!this._updateOperation.value;\n\t\tthis._updateOperation.clear();\n\n\t\tconst source = new CancellationTokenSource();\n\n\t\tconst promise = (async () => {\n\t\t\tconst shouldDebounce = updateOngoing || context.triggerKind === InlineCompletionTriggerKind.Automatic;\n\t\t\tif (shouldDebounce) {\n\t\t\t\t// This debounces the operation\n\t\t\t\tawait wait(this._debounceValue.get(this.textModel), source.token);\n\t\t\t}\n\n\t\t\tif (source.token.isCancellationRequested || this.textModel.getVersionId() !== request.versionId) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tconst startTime = new Date();\n\t\t\tconst updatedCompletions = await provideInlineCompletions(\n\t\t\t\tthis.languageFeaturesService.inlineCompletionsProvider,\n\t\t\t\tposition,\n\t\t\t\tthis.textModel,\n\t\t\t\tcontext,\n\t\t\t\tsource.token,\n\t\t\t\tthis.languageConfigurationService\n\t\t\t);\n\n\t\t\tif (source.token.isCancellationRequested || this.textModel.getVersionId() !== request.versionId) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tconst endTime = new Date();\n\t\t\tthis._debounceValue.update(this.textModel, endTime.getTime() - startTime.getTime());\n\n\t\t\tconst completions = new UpToDateInlineCompletions(updatedCompletions, request, this.textModel, this.versionId);\n\t\t\tif (activeInlineCompletion) {\n\t\t\t\tconst asInlineCompletion = activeInlineCompletion.toInlineCompletion(undefined);\n\t\t\t\tif (activeInlineCompletion.canBeReused(this.textModel, position) && !updatedCompletions.has(asInlineCompletion)) {\n\t\t\t\t\tcompletions.prepend(activeInlineCompletion.inlineCompletion, asInlineCompletion.range, true);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis._updateOperation.clear();\n\t\t\ttransaction(tx => {\n\t\t\t\t/** @description Update completions with provider result */\n\t\t\t\ttarget.set(completions, tx);\n\t\t\t});\n\n\t\t\treturn true;\n\t\t})();\n\n\t\tconst updateOperation = new UpdateOperation(request, source, promise);\n\t\tthis._updateOperation.value = updateOperation;\n\n\t\treturn promise;\n\t}\n\n\tpublic clear(tx: ITransaction): void {\n\t\tthis._updateOperation.clear();\n\t\tthis.inlineCompletions.set(undefined, tx);\n\t\tthis.suggestWidgetInlineCompletions.set(undefined, tx);\n\t}\n\n\tpublic clearSuggestWidgetInlineCompletions(tx: ITransaction): void {\n\t\tif (this._updateOperation.value?.request.context.selectedSuggestionInfo) {\n\t\t\tthis._updateOperation.clear();\n\t\t}\n\t\tthis.suggestWidgetInlineCompletions.set(undefined, tx);\n\t}\n\n\tpublic cancelUpdate(): void {\n\t\tthis._updateOperation.clear();\n\t}\n}\n\nfunction wait(ms: number, cancellationToken?: CancellationToken): Promise {\n\treturn new Promise(resolve => {\n\t\tlet d: IDisposable | undefined = undefined;\n\t\tconst handle = setTimeout(() => {\n\t\t\tif (d) { d.dispose(); }\n\t\t\tresolve();\n\t\t}, ms);\n\t\tif (cancellationToken) {\n\t\t\td = cancellationToken.onCancellationRequested(() => {\n\t\t\t\tclearTimeout(handle);\n\t\t\t\tif (d) { d.dispose(); }\n\t\t\t\tresolve();\n\t\t\t});\n\t\t}\n\t});\n}\n\nclass UpdateRequest {\n\tconstructor(\n\t\tpublic readonly position: Position,\n\t\tpublic readonly context: InlineCompletionContext,\n\t\tpublic readonly versionId: number,\n\t) {\n\t}\n\n\tpublic satisfies(other: UpdateRequest): boolean {\n\t\treturn this.position.equals(other.position)\n\t\t\t&& equalsIfDefined(this.context.selectedSuggestionInfo, other.context.selectedSuggestionInfo, itemEquals())\n\t\t\t&& (other.context.triggerKind === InlineCompletionTriggerKind.Automatic\n\t\t\t\t|| this.context.triggerKind === InlineCompletionTriggerKind.Explicit)\n\t\t\t&& this.versionId === other.versionId;\n\t}\n}\n\nclass UpdateOperation implements IDisposable {\n\tconstructor(\n\t\tpublic readonly request: UpdateRequest,\n\t\tpublic readonly cancellationTokenSource: CancellationTokenSource,\n\t\tpublic readonly promise: Promise,\n\t) {\n\t}\n\n\tdispose() {\n\t\tthis.cancellationTokenSource.cancel();\n\t}\n}\n\nexport class UpToDateInlineCompletions implements IDisposable {\n\tprivate readonly _inlineCompletions: InlineCompletionWithUpdatedRange[];\n\tpublic get inlineCompletions(): ReadonlyArray { return this._inlineCompletions; }\n\n\tprivate _refCount = 1;\n\tprivate readonly _prependedInlineCompletionItems: InlineCompletionItem[] = [];\n\n\tconstructor(\n\t\tprivate readonly inlineCompletionProviderResult: InlineCompletionProviderResult,\n\t\tpublic readonly request: UpdateRequest,\n\t\tprivate readonly _textModel: ITextModel,\n\t\tprivate readonly _versionId: IObservable,\n\t) {\n\t\tconst ids = _textModel.deltaDecorations([], inlineCompletionProviderResult.completions.map(i => ({\n\t\t\trange: i.range,\n\t\t\toptions: {\n\t\t\t\tdescription: 'inline-completion-tracking-range'\n\t\t\t},\n\t\t})));\n\n\t\tthis._inlineCompletions = inlineCompletionProviderResult.completions.map(\n\t\t\t(i, index) => new InlineCompletionWithUpdatedRange(i, ids[index], this._textModel, this._versionId)\n\t\t);\n\t}\n\n\tpublic clone(): this {\n\t\tthis._refCount++;\n\t\treturn this;\n\t}\n\n\tpublic dispose(): void {\n\t\tthis._refCount--;\n\t\tif (this._refCount === 0) {\n\t\t\tsetTimeout(() => {\n\t\t\t\t// To fix https://github.com/microsoft/vscode/issues/188348\n\t\t\t\tif (!this._textModel.isDisposed()) {\n\t\t\t\t\t// This is just cleanup. It's ok if it happens with a delay.\n\t\t\t\t\tthis._textModel.deltaDecorations(this._inlineCompletions.map(i => i.decorationId), []);\n\t\t\t\t}\n\t\t\t}, 0);\n\t\t\tthis.inlineCompletionProviderResult.dispose();\n\t\t\tfor (const i of this._prependedInlineCompletionItems) {\n\t\t\t\ti.source.removeRef();\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic prepend(inlineCompletion: InlineCompletionItem, range: Range, addRefToSource: boolean): void {\n\t\tif (addRefToSource) {\n\t\t\tinlineCompletion.source.addRef();\n\t\t}\n\n\t\tconst id = this._textModel.deltaDecorations([], [{\n\t\t\trange,\n\t\t\toptions: {\n\t\t\t\tdescription: 'inline-completion-tracking-range'\n\t\t\t},\n\t\t}])[0];\n\t\tthis._inlineCompletions.unshift(new InlineCompletionWithUpdatedRange(inlineCompletion, id, this._textModel, this._versionId));\n\t\tthis._prependedInlineCompletionItems.push(inlineCompletion);\n\t}\n}\n\nexport class InlineCompletionWithUpdatedRange {\n\tpublic readonly semanticId = JSON.stringify([\n\t\tthis.inlineCompletion.filterText,\n\t\tthis.inlineCompletion.insertText,\n\t\tthis.inlineCompletion.range.getStartPosition().toString()\n\t]);\n\n\tpublic get forwardStable() {\n\t\treturn this.inlineCompletion.source.inlineCompletions.enableForwardStability ?? false;\n\t}\n\n\tprivate readonly _updatedRange = derivedOpts({ owner: this, equalsFn: Range.equalsRange }, reader => {\n\t\tthis._modelVersion.read(reader);\n\t\treturn this._textModel.getDecorationRange(this.decorationId);\n\t});\n\n\tconstructor(\n\t\tpublic readonly inlineCompletion: InlineCompletionItem,\n\t\tpublic readonly decorationId: string,\n\t\tprivate readonly _textModel: ITextModel,\n\t\tprivate readonly _modelVersion: IObservable,\n\t) {\n\t}\n\n\tpublic toInlineCompletion(reader: IReader | undefined): InlineCompletionItem {\n\t\treturn this.inlineCompletion.withRange(this._updatedRange.read(reader) ?? emptyRange);\n\t}\n\n\tpublic toSingleTextEdit(reader: IReader | undefined): SingleTextEdit {\n\t\treturn new SingleTextEdit(this._updatedRange.read(reader) ?? emptyRange, this.inlineCompletion.insertText);\n\t}\n\n\tpublic isVisible(model: ITextModel, cursorPosition: Position, reader: IReader | undefined): boolean {\n\t\tconst minimizedReplacement = singleTextRemoveCommonPrefix(this._toFilterTextReplacement(reader), model);\n\t\tconst updatedRange = this._updatedRange.read(reader);\n\t\tif (\n\t\t\t!updatedRange\n\t\t\t|| !this.inlineCompletion.range.getStartPosition().equals(updatedRange.getStartPosition())\n\t\t\t|| cursorPosition.lineNumber !== minimizedReplacement.range.startLineNumber\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// We might consider comparing by .toLowerText, but this requires GhostTextReplacement\n\t\tconst originalValue = model.getValueInRange(minimizedReplacement.range, EndOfLinePreference.LF);\n\t\tconst filterText = minimizedReplacement.text;\n\n\t\tconst cursorPosIndex = Math.max(0, cursorPosition.column - minimizedReplacement.range.startColumn);\n\n\t\tlet filterTextBefore = filterText.substring(0, cursorPosIndex);\n\t\tlet filterTextAfter = filterText.substring(cursorPosIndex);\n\n\t\tlet originalValueBefore = originalValue.substring(0, cursorPosIndex);\n\t\tlet originalValueAfter = originalValue.substring(cursorPosIndex);\n\n\t\tconst originalValueIndent = model.getLineIndentColumn(minimizedReplacement.range.startLineNumber);\n\t\tif (minimizedReplacement.range.startColumn <= originalValueIndent) {\n\t\t\t// Remove indentation\n\t\t\toriginalValueBefore = originalValueBefore.trimStart();\n\t\t\tif (originalValueBefore.length === 0) {\n\t\t\t\toriginalValueAfter = originalValueAfter.trimStart();\n\t\t\t}\n\t\t\tfilterTextBefore = filterTextBefore.trimStart();\n\t\t\tif (filterTextBefore.length === 0) {\n\t\t\t\tfilterTextAfter = filterTextAfter.trimStart();\n\t\t\t}\n\t\t}\n\n\t\treturn filterTextBefore.startsWith(originalValueBefore)\n\t\t\t&& !!matchesSubString(originalValueAfter, filterTextAfter);\n\t}\n\n\tpublic canBeReused(model: ITextModel, position: Position): boolean {\n\t\tconst updatedRange = this._updatedRange.read(undefined);\n\t\tconst result = !!updatedRange\n\t\t\t&& updatedRange.containsPosition(position)\n\t\t\t&& this.isVisible(model, position, undefined)\n\t\t\t&& TextLength.ofRange(updatedRange).isGreaterThanOrEqualTo(TextLength.ofRange(this.inlineCompletion.range));\n\t\treturn result;\n\t}\n\n\tprivate _toFilterTextReplacement(reader: IReader | undefined): SingleTextEdit {\n\t\treturn new SingleTextEdit(this._updatedRange.read(reader) ?? emptyRange, this.inlineCompletion.filterText);\n\t}\n}\n\nconst emptyRange = new Range(1, 1, 1, 1);\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\nimport * as strings from 'vs/base/common/strings';\nimport { ShiftCommand } from 'vs/editor/common/commands/shiftCommand';\nimport { EditorAutoIndentStrategy } from 'vs/editor/common/config/editorOptions';\nimport { Range } from 'vs/editor/common/core/range';\nimport { Selection } from 'vs/editor/common/core/selection';\nimport { ICommand, ICursorStateComputerData, IEditOperationBuilder } from 'vs/editor/common/editorCommon';\nimport { ITextModel } from 'vs/editor/common/model';\nimport { CompleteEnterAction, IndentAction } from 'vs/editor/common/languages/languageConfiguration';\nimport { ILanguageConfigurationService } from 'vs/editor/common/languages/languageConfigurationRegistry';\nimport { IndentConsts } from 'vs/editor/common/languages/supports/indentRules';\nimport * as indentUtils from 'vs/editor/contrib/indentation/common/indentUtils';\nimport { getGoodIndentForLine, getIndentMetadata, IIndentConverter, IVirtualModel } from 'vs/editor/common/languages/autoIndent';\nimport { getEnterAction } from 'vs/editor/common/languages/enterAction';\n\nexport class MoveLinesCommand implements ICommand {\n\n\tprivate readonly _selection: Selection;\n\tprivate readonly _isMovingDown: boolean;\n\tprivate readonly _autoIndent: EditorAutoIndentStrategy;\n\n\tprivate _selectionId: string | null;\n\tprivate _moveEndPositionDown?: boolean;\n\tprivate _moveEndLineSelectionShrink: boolean;\n\n\tconstructor(\n\t\tselection: Selection,\n\t\tisMovingDown: boolean,\n\t\tautoIndent: EditorAutoIndentStrategy,\n\t\t@ILanguageConfigurationService private readonly _languageConfigurationService: ILanguageConfigurationService\n\t) {\n\t\tthis._selection = selection;\n\t\tthis._isMovingDown = isMovingDown;\n\t\tthis._autoIndent = autoIndent;\n\t\tthis._selectionId = null;\n\t\tthis._moveEndLineSelectionShrink = false;\n\t}\n\n\tpublic getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {\n\n\t\tconst modelLineCount = model.getLineCount();\n\n\t\tif (this._isMovingDown && this._selection.endLineNumber === modelLineCount) {\n\t\t\tthis._selectionId = builder.trackSelection(this._selection);\n\t\t\treturn;\n\t\t}\n\t\tif (!this._isMovingDown && this._selection.startLineNumber === 1) {\n\t\t\tthis._selectionId = builder.trackSelection(this._selection);\n\t\t\treturn;\n\t\t}\n\n\t\tthis._moveEndPositionDown = false;\n\t\tlet s = this._selection;\n\n\t\tif (s.startLineNumber < s.endLineNumber && s.endColumn === 1) {\n\t\t\tthis._moveEndPositionDown = true;\n\t\t\ts = s.setEndPosition(s.endLineNumber - 1, model.getLineMaxColumn(s.endLineNumber - 1));\n\t\t}\n\n\t\tconst { tabSize, indentSize, insertSpaces } = model.getOptions();\n\t\tconst indentConverter = this.buildIndentConverter(tabSize, indentSize, insertSpaces);\n\t\tconst virtualModel: IVirtualModel = {\n\t\t\ttokenization: {\n\t\t\t\tgetLineTokens: (lineNumber: number) => {\n\t\t\t\t\treturn model.tokenization.getLineTokens(lineNumber);\n\t\t\t\t},\n\t\t\t\tgetLanguageId: () => {\n\t\t\t\t\treturn model.getLanguageId();\n\t\t\t\t},\n\t\t\t\tgetLanguageIdAtPosition: (lineNumber: number, column: number) => {\n\t\t\t\t\treturn model.getLanguageIdAtPosition(lineNumber, column);\n\t\t\t\t},\n\t\t\t},\n\t\t\tgetLineContent: null as unknown as (lineNumber: number) => string,\n\t\t};\n\n\t\tif (s.startLineNumber === s.endLineNumber && model.getLineMaxColumn(s.startLineNumber) === 1) {\n\t\t\t// Current line is empty\n\t\t\tconst lineNumber = s.startLineNumber;\n\t\t\tconst otherLineNumber = (this._isMovingDown ? lineNumber + 1 : lineNumber - 1);\n\n\t\t\tif (model.getLineMaxColumn(otherLineNumber) === 1) {\n\t\t\t\t// Other line number is empty too, so no editing is needed\n\t\t\t\t// Add a no-op to force running by the model\n\t\t\t\tbuilder.addEditOperation(new Range(1, 1, 1, 1), null);\n\t\t\t} else {\n\t\t\t\t// Type content from other line number on line number\n\t\t\t\tbuilder.addEditOperation(new Range(lineNumber, 1, lineNumber, 1), model.getLineContent(otherLineNumber));\n\n\t\t\t\t// Remove content from other line number\n\t\t\t\tbuilder.addEditOperation(new Range(otherLineNumber, 1, otherLineNumber, model.getLineMaxColumn(otherLineNumber)), null);\n\t\t\t}\n\t\t\t// Track selection at the other line number\n\t\t\ts = new Selection(otherLineNumber, 1, otherLineNumber, 1);\n\n\t\t} else {\n\n\t\t\tlet movingLineNumber: number;\n\t\t\tlet movingLineText: string;\n\n\t\t\tif (this._isMovingDown) {\n\t\t\t\tmovingLineNumber = s.endLineNumber + 1;\n\t\t\t\tmovingLineText = model.getLineContent(movingLineNumber);\n\t\t\t\t// Delete line that needs to be moved\n\t\t\t\tbuilder.addEditOperation(new Range(movingLineNumber - 1, model.getLineMaxColumn(movingLineNumber - 1), movingLineNumber, model.getLineMaxColumn(movingLineNumber)), null);\n\n\t\t\t\tlet insertingText = movingLineText;\n\n\t\t\t\tif (this.shouldAutoIndent(model, s)) {\n\t\t\t\t\tconst movingLineMatchResult = this.matchEnterRule(model, indentConverter, tabSize, movingLineNumber, s.startLineNumber - 1);\n\t\t\t\t\t// if s.startLineNumber - 1 matches onEnter rule, we still honor that.\n\t\t\t\t\tif (movingLineMatchResult !== null) {\n\t\t\t\t\t\tconst oldIndentation = strings.getLeadingWhitespace(model.getLineContent(movingLineNumber));\n\t\t\t\t\t\tconst newSpaceCnt = movingLineMatchResult + indentUtils.getSpaceCnt(oldIndentation, tabSize);\n\t\t\t\t\t\tconst newIndentation = indentUtils.generateIndent(newSpaceCnt, tabSize, insertSpaces);\n\t\t\t\t\t\tinsertingText = newIndentation + this.trimStart(movingLineText);\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// no enter rule matches, let's check indentatin rules then.\n\t\t\t\t\t\tvirtualModel.getLineContent = (lineNumber: number) => {\n\t\t\t\t\t\t\tif (lineNumber === s.startLineNumber) {\n\t\t\t\t\t\t\t\treturn model.getLineContent(movingLineNumber);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\treturn model.getLineContent(lineNumber);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t};\n\t\t\t\t\t\tconst indentOfMovingLine = getGoodIndentForLine(\n\t\t\t\t\t\t\tthis._autoIndent,\n\t\t\t\t\t\t\tvirtualModel,\n\t\t\t\t\t\t\tmodel.getLanguageIdAtPosition(movingLineNumber, 1),\n\t\t\t\t\t\t\ts.startLineNumber,\n\t\t\t\t\t\t\tindentConverter,\n\t\t\t\t\t\t\tthis._languageConfigurationService\n\t\t\t\t\t\t);\n\t\t\t\t\t\tif (indentOfMovingLine !== null) {\n\t\t\t\t\t\t\tconst oldIndentation = strings.getLeadingWhitespace(model.getLineContent(movingLineNumber));\n\t\t\t\t\t\t\tconst newSpaceCnt = indentUtils.getSpaceCnt(indentOfMovingLine, tabSize);\n\t\t\t\t\t\t\tconst oldSpaceCnt = indentUtils.getSpaceCnt(oldIndentation, tabSize);\n\t\t\t\t\t\t\tif (newSpaceCnt !== oldSpaceCnt) {\n\t\t\t\t\t\t\t\tconst newIndentation = indentUtils.generateIndent(newSpaceCnt, tabSize, insertSpaces);\n\t\t\t\t\t\t\t\tinsertingText = newIndentation + this.trimStart(movingLineText);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// add edit operations for moving line first to make sure it's executed after we make indentation change\n\t\t\t\t\t// to s.startLineNumber\n\t\t\t\t\tbuilder.addEditOperation(new Range(s.startLineNumber, 1, s.startLineNumber, 1), insertingText + '\\n');\n\n\t\t\t\t\tconst ret = this.matchEnterRuleMovingDown(model, indentConverter, tabSize, s.startLineNumber, movingLineNumber, insertingText);\n\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.\n\t\t\t\t\tif (ret !== null) {\n\t\t\t\t\t\tif (ret !== 0) {\n\t\t\t\t\t\t\tthis.getIndentEditsOfMovingBlock(model, builder, s, tabSize, insertSpaces, ret);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// it doesn't match onEnter rules, let's check indentation rules then.\n\t\t\t\t\t\tvirtualModel.getLineContent = (lineNumber: number) => {\n\t\t\t\t\t\t\tif (lineNumber === s.startLineNumber) {\n\t\t\t\t\t\t\t\treturn insertingText;\n\t\t\t\t\t\t\t} else if (lineNumber >= s.startLineNumber + 1 && lineNumber <= s.endLineNumber + 1) {\n\t\t\t\t\t\t\t\treturn model.getLineContent(lineNumber - 1);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\treturn model.getLineContent(lineNumber);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tconst newIndentatOfMovingBlock = getGoodIndentForLine(\n\t\t\t\t\t\t\tthis._autoIndent,\n\t\t\t\t\t\t\tvirtualModel,\n\t\t\t\t\t\t\tmodel.getLanguageIdAtPosition(movingLineNumber, 1),\n\t\t\t\t\t\t\ts.startLineNumber + 1,\n\t\t\t\t\t\t\tindentConverter,\n\t\t\t\t\t\t\tthis._languageConfigurationService\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tif (newIndentatOfMovingBlock !== null) {\n\t\t\t\t\t\t\tconst oldIndentation = strings.getLeadingWhitespace(model.getLineContent(s.startLineNumber));\n\t\t\t\t\t\t\tconst newSpaceCnt = indentUtils.getSpaceCnt(newIndentatOfMovingBlock, tabSize);\n\t\t\t\t\t\t\tconst oldSpaceCnt = indentUtils.getSpaceCnt(oldIndentation, tabSize);\n\t\t\t\t\t\t\tif (newSpaceCnt !== oldSpaceCnt) {\n\t\t\t\t\t\t\t\tconst spaceCntOffset = newSpaceCnt - oldSpaceCnt;\n\n\t\t\t\t\t\t\t\tthis.getIndentEditsOfMovingBlock(model, builder, s, tabSize, insertSpaces, spaceCntOffset);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Insert line that needs to be moved before\n\t\t\t\t\tbuilder.addEditOperation(new Range(s.startLineNumber, 1, s.startLineNumber, 1), insertingText + '\\n');\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tmovingLineNumber = s.startLineNumber - 1;\n\t\t\t\tmovingLineText = model.getLineContent(movingLineNumber);\n\n\t\t\t\t// Delete line that needs to be moved\n\t\t\t\tbuilder.addEditOperation(new Range(movingLineNumber, 1, movingLineNumber + 1, 1), null);\n\n\t\t\t\t// Insert line that needs to be moved after\n\t\t\t\tbuilder.addEditOperation(new Range(s.endLineNumber, model.getLineMaxColumn(s.endLineNumber), s.endLineNumber, model.getLineMaxColumn(s.endLineNumber)), '\\n' + movingLineText);\n\n\t\t\t\tif (this.shouldAutoIndent(model, s)) {\n\t\t\t\t\tvirtualModel.getLineContent = (lineNumber: number) => {\n\t\t\t\t\t\tif (lineNumber === movingLineNumber) {\n\t\t\t\t\t\t\treturn model.getLineContent(s.startLineNumber);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\treturn model.getLineContent(lineNumber);\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\n\t\t\t\t\tconst ret = this.matchEnterRule(model, indentConverter, tabSize, s.startLineNumber, s.startLineNumber - 2);\n\t\t\t\t\t// check if s.startLineNumber - 2 matches onEnter rules, if so adjust the moving block by onEnter rules.\n\t\t\t\t\tif (ret !== null) {\n\t\t\t\t\t\tif (ret !== 0) {\n\t\t\t\t\t\t\tthis.getIndentEditsOfMovingBlock(model, builder, s, tabSize, insertSpaces, ret);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// it doesn't match any onEnter rule, let's check indentation rules then.\n\t\t\t\t\t\tconst indentOfFirstLine = getGoodIndentForLine(\n\t\t\t\t\t\t\tthis._autoIndent,\n\t\t\t\t\t\t\tvirtualModel,\n\t\t\t\t\t\t\tmodel.getLanguageIdAtPosition(s.startLineNumber, 1),\n\t\t\t\t\t\t\tmovingLineNumber,\n\t\t\t\t\t\t\tindentConverter,\n\t\t\t\t\t\t\tthis._languageConfigurationService\n\t\t\t\t\t\t);\n\t\t\t\t\t\tif (indentOfFirstLine !== null) {\n\t\t\t\t\t\t\t// adjust the indentation of the moving block\n\t\t\t\t\t\t\tconst oldIndent = strings.getLeadingWhitespace(model.getLineContent(s.startLineNumber));\n\t\t\t\t\t\t\tconst newSpaceCnt = indentUtils.getSpaceCnt(indentOfFirstLine, tabSize);\n\t\t\t\t\t\t\tconst oldSpaceCnt = indentUtils.getSpaceCnt(oldIndent, tabSize);\n\t\t\t\t\t\t\tif (newSpaceCnt !== oldSpaceCnt) {\n\t\t\t\t\t\t\t\tconst spaceCntOffset = newSpaceCnt - oldSpaceCnt;\n\n\t\t\t\t\t\t\t\tthis.getIndentEditsOfMovingBlock(model, builder, s, tabSize, insertSpaces, spaceCntOffset);\n\t\t\t\t\t\t\t}\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}\n\n\t\tthis._selectionId = builder.trackSelection(s);\n\t}\n\n\tprivate buildIndentConverter(tabSize: number, indentSize: number, insertSpaces: boolean): IIndentConverter {\n\t\treturn {\n\t\t\tshiftIndent: (indentation) => {\n\t\t\t\treturn ShiftCommand.shiftIndent(indentation, indentation.length + 1, tabSize, indentSize, insertSpaces);\n\t\t\t},\n\t\t\tunshiftIndent: (indentation) => {\n\t\t\t\treturn ShiftCommand.unshiftIndent(indentation, indentation.length + 1, tabSize, indentSize, insertSpaces);\n\t\t\t}\n\t\t};\n\t}\n\n\tprivate parseEnterResult(model: ITextModel, indentConverter: IIndentConverter, tabSize: number, line: number, enter: CompleteEnterAction | null) {\n\t\tif (enter) {\n\t\t\tlet enterPrefix = enter.indentation;\n\n\t\t\tif (enter.indentAction === IndentAction.None) {\n\t\t\t\tenterPrefix = enter.indentation + enter.appendText;\n\t\t\t} else if (enter.indentAction === IndentAction.Indent) {\n\t\t\t\tenterPrefix = enter.indentation + enter.appendText;\n\t\t\t} else if (enter.indentAction === IndentAction.IndentOutdent) {\n\t\t\t\tenterPrefix = enter.indentation;\n\t\t\t} else if (enter.indentAction === IndentAction.Outdent) {\n\t\t\t\tenterPrefix = indentConverter.unshiftIndent(enter.indentation) + enter.appendText;\n\t\t\t}\n\t\t\tconst movingLineText = model.getLineContent(line);\n\t\t\tif (this.trimStart(movingLineText).indexOf(this.trimStart(enterPrefix)) >= 0) {\n\t\t\t\tconst oldIndentation = strings.getLeadingWhitespace(model.getLineContent(line));\n\t\t\t\tlet newIndentation = strings.getLeadingWhitespace(enterPrefix);\n\t\t\t\tconst indentMetadataOfMovelingLine = getIndentMetadata(model, line, this._languageConfigurationService);\n\t\t\t\tif (indentMetadataOfMovelingLine !== null && indentMetadataOfMovelingLine & IndentConsts.DECREASE_MASK) {\n\t\t\t\t\tnewIndentation = indentConverter.unshiftIndent(newIndentation);\n\t\t\t\t}\n\t\t\t\tconst newSpaceCnt = indentUtils.getSpaceCnt(newIndentation, tabSize);\n\t\t\t\tconst oldSpaceCnt = indentUtils.getSpaceCnt(oldIndentation, tabSize);\n\t\t\t\treturn newSpaceCnt - oldSpaceCnt;\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t *\n\t * @param model\n\t * @param indentConverter\n\t * @param tabSize\n\t * @param line the line moving down\n\t * @param futureAboveLineNumber the line which will be at the `line` position\n\t * @param futureAboveLineText\n\t */\n\tprivate matchEnterRuleMovingDown(model: ITextModel, indentConverter: IIndentConverter, tabSize: number, line: number, futureAboveLineNumber: number, futureAboveLineText: string) {\n\t\tif (strings.lastNonWhitespaceIndex(futureAboveLineText) >= 0) {\n\t\t\t// break\n\t\t\tconst maxColumn = model.getLineMaxColumn(futureAboveLineNumber);\n\t\t\tconst enter = getEnterAction(this._autoIndent, model, new Range(futureAboveLineNumber, maxColumn, futureAboveLineNumber, maxColumn), this._languageConfigurationService);\n\t\t\treturn this.parseEnterResult(model, indentConverter, tabSize, line, enter);\n\t\t} else {\n\t\t\t// go upwards, starting from `line - 1`\n\t\t\tlet validPrecedingLine = line - 1;\n\t\t\twhile (validPrecedingLine >= 1) {\n\t\t\t\tconst lineContent = model.getLineContent(validPrecedingLine);\n\t\t\t\tconst nonWhitespaceIdx = strings.lastNonWhitespaceIndex(lineContent);\n\n\t\t\t\tif (nonWhitespaceIdx >= 0) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tvalidPrecedingLine--;\n\t\t\t}\n\n\t\t\tif (validPrecedingLine < 1 || line > model.getLineCount()) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst maxColumn = model.getLineMaxColumn(validPrecedingLine);\n\t\t\tconst enter = getEnterAction(this._autoIndent, model, new Range(validPrecedingLine, maxColumn, validPrecedingLine, maxColumn), this._languageConfigurationService);\n\t\t\treturn this.parseEnterResult(model, indentConverter, tabSize, line, enter);\n\t\t}\n\t}\n\n\tprivate matchEnterRule(model: ITextModel, indentConverter: IIndentConverter, tabSize: number, line: number, oneLineAbove: number, previousLineText?: string) {\n\t\tlet validPrecedingLine = oneLineAbove;\n\t\twhile (validPrecedingLine >= 1) {\n\t\t\t// ship empty lines as empty lines just inherit indentation\n\t\t\tlet lineContent;\n\t\t\tif (validPrecedingLine === oneLineAbove && previousLineText !== undefined) {\n\t\t\t\tlineContent = previousLineText;\n\t\t\t} else {\n\t\t\t\tlineContent = model.getLineContent(validPrecedingLine);\n\t\t\t}\n\n\t\t\tconst nonWhitespaceIdx = strings.lastNonWhitespaceIndex(lineContent);\n\t\t\tif (nonWhitespaceIdx >= 0) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tvalidPrecedingLine--;\n\t\t}\n\n\t\tif (validPrecedingLine < 1 || line > model.getLineCount()) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst maxColumn = model.getLineMaxColumn(validPrecedingLine);\n\t\tconst enter = getEnterAction(this._autoIndent, model, new Range(validPrecedingLine, maxColumn, validPrecedingLine, maxColumn), this._languageConfigurationService);\n\t\treturn this.parseEnterResult(model, indentConverter, tabSize, line, enter);\n\t}\n\n\tprivate trimStart(str: string) {\n\t\treturn str.replace(/^\\s+/, '');\n\t}\n\n\tprivate shouldAutoIndent(model: ITextModel, selection: Selection) {\n\t\tif (this._autoIndent < EditorAutoIndentStrategy.Full) {\n\t\t\treturn false;\n\t\t}\n\t\t// if it's not easy to tokenize, we stop auto indent.\n\t\tif (!model.tokenization.isCheapToTokenize(selection.startLineNumber)) {\n\t\t\treturn false;\n\t\t}\n\t\tconst languageAtSelectionStart = model.getLanguageIdAtPosition(selection.startLineNumber, 1);\n\t\tconst languageAtSelectionEnd = model.getLanguageIdAtPosition(selection.endLineNumber, 1);\n\n\t\tif (languageAtSelectionStart !== languageAtSelectionEnd) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (this._languageConfigurationService.getLanguageConfiguration(languageAtSelectionStart).indentRulesSupport === null) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tprivate getIndentEditsOfMovingBlock(model: ITextModel, builder: IEditOperationBuilder, s: Selection, tabSize: number, insertSpaces: boolean, offset: number) {\n\t\tfor (let i = s.startLineNumber; i <= s.endLineNumber; i++) {\n\t\t\tconst lineContent = model.getLineContent(i);\n\t\t\tconst originalIndent = strings.getLeadingWhitespace(lineContent);\n\t\t\tconst originalSpacesCnt = indentUtils.getSpaceCnt(originalIndent, tabSize);\n\t\t\tconst newSpacesCnt = originalSpacesCnt + offset;\n\t\t\tconst newIndent = indentUtils.generateIndent(newSpacesCnt, tabSize, insertSpaces);\n\n\t\t\tif (newIndent !== originalIndent) {\n\t\t\t\tbuilder.addEditOperation(new Range(i, 1, i, originalIndent.length + 1), newIndent);\n\n\t\t\t\tif (i === s.endLineNumber && s.endColumn <= originalIndent.length + 1 && newIndent === '') {\n\t\t\t\t\t// as users select part of the original indent white spaces\n\t\t\t\t\t// when we adjust the indentation of endLine, we should adjust the cursor position as well.\n\t\t\t\t\tthis._moveEndLineSelectionShrink = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\t}\n\n\tpublic computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {\n\t\tlet result = helper.getTrackedSelection(this._selectionId!);\n\n\t\tif (this._moveEndPositionDown) {\n\t\t\tresult = result.setEndPosition(result.endLineNumber + 1, 1);\n\t\t}\n\n\t\tif (this._moveEndLineSelectionShrink && result.startLineNumber < result.endLineNumber) {\n\t\t\tresult = result.setEndPosition(result.endLineNumber, 2);\n\t\t}\n\n\t\treturn result;\n\t}\n}\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\nimport * as dom from 'vs/base/browser/dom';\nimport { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';\nimport { Codicon } from 'vs/base/common/codicons';\nimport { ThemeIcon } from 'vs/base/common/themables';\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { MarkdownString } from 'vs/base/common/htmlContent';\nimport { DisposableStore } from 'vs/base/common/lifecycle';\nimport { MarkdownRenderer } from 'vs/editor/browser/widget/markdownRenderer/browser/markdownRenderer';\nimport { ICodeEditor, IOverlayWidget, IOverlayWidgetPosition } from 'vs/editor/browser/editorBrowser';\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\nimport { ResizableHTMLElement } from 'vs/base/browser/ui/resizable/resizable';\nimport * as nls from 'vs/nls';\nimport { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';\nimport { CompletionItem } from './suggest';\n\nexport function canExpandCompletionItem(item: CompletionItem | undefined): boolean {\n\treturn !!item && Boolean(item.completion.documentation || item.completion.detail && item.completion.detail !== item.completion.label);\n}\n\nexport class SuggestDetailsWidget {\n\n\treadonly domNode: HTMLDivElement;\n\n\tprivate readonly _onDidClose = new Emitter();\n\treadonly onDidClose: Event = this._onDidClose.event;\n\n\tprivate readonly _onDidChangeContents = new Emitter();\n\treadonly onDidChangeContents: Event = this._onDidChangeContents.event;\n\n\tprivate readonly _close: HTMLElement;\n\tprivate readonly _scrollbar: DomScrollableElement;\n\tprivate readonly _body: HTMLElement;\n\tprivate readonly _header: HTMLElement;\n\tprivate readonly _type: HTMLElement;\n\tprivate readonly _docs: HTMLElement;\n\tprivate readonly _disposables = new DisposableStore();\n\n\tprivate readonly _markdownRenderer: MarkdownRenderer;\n\tprivate readonly _renderDisposeable = new DisposableStore();\n\tprivate _borderWidth: number = 1;\n\tprivate _size = new dom.Dimension(330, 0);\n\n\tconstructor(\n\t\tprivate readonly _editor: ICodeEditor,\n\t\t@IInstantiationService instaService: IInstantiationService,\n\t) {\n\t\tthis.domNode = dom.$('.suggest-details');\n\t\tthis.domNode.classList.add('no-docs');\n\n\t\tthis._markdownRenderer = instaService.createInstance(MarkdownRenderer, { editor: _editor });\n\n\t\tthis._body = dom.$('.body');\n\n\t\tthis._scrollbar = new DomScrollableElement(this._body, {\n\t\t\talwaysConsumeMouseWheel: true,\n\t\t});\n\t\tdom.append(this.domNode, this._scrollbar.getDomNode());\n\t\tthis._disposables.add(this._scrollbar);\n\n\t\tthis._header = dom.append(this._body, dom.$('.header'));\n\t\tthis._close = dom.append(this._header, dom.$('span' + ThemeIcon.asCSSSelector(Codicon.close)));\n\t\tthis._close.title = nls.localize('details.close', \"Close\");\n\t\tthis._type = dom.append(this._header, dom.$('p.type'));\n\n\t\tthis._docs = dom.append(this._body, dom.$('p.docs'));\n\n\t\tthis._configureFont();\n\n\t\tthis._disposables.add(this._editor.onDidChangeConfiguration(e => {\n\t\t\tif (e.hasChanged(EditorOption.fontInfo)) {\n\t\t\t\tthis._configureFont();\n\t\t\t}\n\t\t}));\n\t}\n\n\tdispose(): void {\n\t\tthis._disposables.dispose();\n\t\tthis._renderDisposeable.dispose();\n\t}\n\n\tprivate _configureFont(): void {\n\t\tconst options = this._editor.getOptions();\n\t\tconst fontInfo = options.get(EditorOption.fontInfo);\n\t\tconst fontFamily = fontInfo.getMassagedFontFamily();\n\t\tconst fontSize = options.get(EditorOption.suggestFontSize) || fontInfo.fontSize;\n\t\tconst lineHeight = options.get(EditorOption.suggestLineHeight) || fontInfo.lineHeight;\n\t\tconst fontWeight = fontInfo.fontWeight;\n\t\tconst fontSizePx = `${fontSize}px`;\n\t\tconst lineHeightPx = `${lineHeight}px`;\n\n\t\tthis.domNode.style.fontSize = fontSizePx;\n\t\tthis.domNode.style.lineHeight = `${lineHeight / fontSize}`;\n\t\tthis.domNode.style.fontWeight = fontWeight;\n\t\tthis.domNode.style.fontFeatureSettings = fontInfo.fontFeatureSettings;\n\t\tthis._type.style.fontFamily = fontFamily;\n\t\tthis._close.style.height = lineHeightPx;\n\t\tthis._close.style.width = lineHeightPx;\n\t}\n\n\tgetLayoutInfo() {\n\t\tconst lineHeight = this._editor.getOption(EditorOption.suggestLineHeight) || this._editor.getOption(EditorOption.fontInfo).lineHeight;\n\t\tconst borderWidth = this._borderWidth;\n\t\tconst borderHeight = borderWidth * 2;\n\t\treturn {\n\t\t\tlineHeight,\n\t\t\tborderWidth,\n\t\t\tborderHeight,\n\t\t\tverticalPadding: 22,\n\t\t\thorizontalPadding: 14\n\t\t};\n\t}\n\n\n\trenderLoading(): void {\n\t\tthis._type.textContent = nls.localize('loading', \"Loading...\");\n\t\tthis._docs.textContent = '';\n\t\tthis.domNode.classList.remove('no-docs', 'no-type');\n\t\tthis.layout(this.size.width, this.getLayoutInfo().lineHeight * 2);\n\t\tthis._onDidChangeContents.fire(this);\n\t}\n\n\trenderItem(item: CompletionItem, explainMode: boolean): void {\n\t\tthis._renderDisposeable.clear();\n\n\t\tlet { detail, documentation } = item.completion;\n\n\t\tif (explainMode) {\n\t\t\tlet md = '';\n\t\t\tmd += `score: ${item.score[0]}\\n`;\n\t\t\tmd += `prefix: ${item.word ?? '(no prefix)'}\\n`;\n\t\t\tmd += `word: ${item.completion.filterText ? item.completion.filterText + ' (filterText)' : item.textLabel}\\n`;\n\t\t\tmd += `distance: ${item.distance} (localityBonus-setting)\\n`;\n\t\t\tmd += `index: ${item.idx}, based on ${item.completion.sortText && `sortText: \"${item.completion.sortText}\"` || 'label'}\\n`;\n\t\t\tmd += `commit_chars: ${item.completion.commitCharacters?.join('')}\\n`;\n\t\t\tdocumentation = new MarkdownString().appendCodeblock('empty', md);\n\t\t\tdetail = `Provider: ${item.provider._debugDisplayName}`;\n\t\t}\n\n\t\tif (!explainMode && !canExpandCompletionItem(item)) {\n\t\t\tthis.clearContents();\n\t\t\treturn;\n\t\t}\n\n\t\tthis.domNode.classList.remove('no-docs', 'no-type');\n\n\t\t// --- details\n\n\t\tif (detail) {\n\t\t\tconst cappedDetail = detail.length > 100000 ? `${detail.substr(0, 100000)}…` : detail;\n\t\t\tthis._type.textContent = cappedDetail;\n\t\t\tthis._type.title = cappedDetail;\n\t\t\tdom.show(this._type);\n\t\t\tthis._type.classList.toggle('auto-wrap', !/\\r?\\n^\\s+/gmi.test(cappedDetail));\n\t\t} else {\n\t\t\tdom.clearNode(this._type);\n\t\t\tthis._type.title = '';\n\t\t\tdom.hide(this._type);\n\t\t\tthis.domNode.classList.add('no-type');\n\t\t}\n\n\t\t// --- documentation\n\t\tdom.clearNode(this._docs);\n\t\tif (typeof documentation === 'string') {\n\t\t\tthis._docs.classList.remove('markdown-docs');\n\t\t\tthis._docs.textContent = documentation;\n\n\t\t} else if (documentation) {\n\t\t\tthis._docs.classList.add('markdown-docs');\n\t\t\tdom.clearNode(this._docs);\n\t\t\tconst renderedContents = this._markdownRenderer.render(documentation);\n\t\t\tthis._docs.appendChild(renderedContents.element);\n\t\t\tthis._renderDisposeable.add(renderedContents);\n\t\t\tthis._renderDisposeable.add(this._markdownRenderer.onDidRenderAsync(() => {\n\t\t\t\tthis.layout(this._size.width, this._type.clientHeight + this._docs.clientHeight);\n\t\t\t\tthis._onDidChangeContents.fire(this);\n\t\t\t}));\n\t\t}\n\n\t\tthis.domNode.style.userSelect = 'text';\n\t\tthis.domNode.tabIndex = -1;\n\n\t\tthis._close.onmousedown = e => {\n\t\t\te.preventDefault();\n\t\t\te.stopPropagation();\n\t\t};\n\t\tthis._close.onclick = e => {\n\t\t\te.preventDefault();\n\t\t\te.stopPropagation();\n\t\t\tthis._onDidClose.fire();\n\t\t};\n\n\t\tthis._body.scrollTop = 0;\n\n\t\tthis.layout(this._size.width, this._type.clientHeight + this._docs.clientHeight);\n\t\tthis._onDidChangeContents.fire(this);\n\t}\n\n\tclearContents() {\n\t\tthis.domNode.classList.add('no-docs');\n\t\tthis._type.textContent = '';\n\t\tthis._docs.textContent = '';\n\t}\n\n\tget isEmpty(): boolean {\n\t\treturn this.domNode.classList.contains('no-docs');\n\t}\n\n\tget size() {\n\t\treturn this._size;\n\t}\n\n\tlayout(width: number, height: number): void {\n\t\tconst newSize = new dom.Dimension(width, height);\n\t\tif (!dom.Dimension.equals(newSize, this._size)) {\n\t\t\tthis._size = newSize;\n\t\t\tdom.size(this.domNode, width, height);\n\t\t}\n\t\tthis._scrollbar.scanDomNode();\n\t}\n\n\tscrollDown(much = 8): void {\n\t\tthis._body.scrollTop += much;\n\t}\n\n\tscrollUp(much = 8): void {\n\t\tthis._body.scrollTop -= much;\n\t}\n\n\tscrollTop(): void {\n\t\tthis._body.scrollTop = 0;\n\t}\n\n\tscrollBottom(): void {\n\t\tthis._body.scrollTop = this._body.scrollHeight;\n\t}\n\n\tpageDown(): void {\n\t\tthis.scrollDown(80);\n\t}\n\n\tpageUp(): void {\n\t\tthis.scrollUp(80);\n\t}\n\n\tset borderWidth(width: number) {\n\t\tthis._borderWidth = width;\n\t}\n\n\tget borderWidth() {\n\t\treturn this._borderWidth;\n\t}\n}\n\ninterface TopLeftPosition {\n\ttop: number;\n\tleft: number;\n}\n\nexport class SuggestDetailsOverlay implements IOverlayWidget {\n\n\treadonly allowEditorOverflow = true;\n\n\tprivate readonly _disposables = new DisposableStore();\n\tprivate readonly _resizable: ResizableHTMLElement;\n\n\tprivate _added: boolean = false;\n\tprivate _anchorBox?: dom.IDomNodePagePosition;\n\tprivate _preferAlignAtTop: boolean = true;\n\tprivate _userSize?: dom.Dimension;\n\tprivate _topLeft?: TopLeftPosition;\n\n\tconstructor(\n\t\treadonly widget: SuggestDetailsWidget,\n\t\tprivate readonly _editor: ICodeEditor\n\t) {\n\n\t\tthis._resizable = new ResizableHTMLElement();\n\t\tthis._resizable.domNode.classList.add('suggest-details-container');\n\t\tthis._resizable.domNode.appendChild(widget.domNode);\n\t\tthis._resizable.enableSashes(false, true, true, false);\n\n\t\tlet topLeftNow: TopLeftPosition | undefined;\n\t\tlet sizeNow: dom.Dimension | undefined;\n\t\tlet deltaTop: number = 0;\n\t\tlet deltaLeft: number = 0;\n\t\tthis._disposables.add(this._resizable.onDidWillResize(() => {\n\t\t\ttopLeftNow = this._topLeft;\n\t\t\tsizeNow = this._resizable.size;\n\t\t}));\n\n\t\tthis._disposables.add(this._resizable.onDidResize(e => {\n\t\t\tif (topLeftNow && sizeNow) {\n\t\t\t\tthis.widget.layout(e.dimension.width, e.dimension.height);\n\n\t\t\t\tlet updateTopLeft = false;\n\t\t\t\tif (e.west) {\n\t\t\t\t\tdeltaLeft = sizeNow.width - e.dimension.width;\n\t\t\t\t\tupdateTopLeft = true;\n\t\t\t\t}\n\t\t\t\tif (e.north) {\n\t\t\t\t\tdeltaTop = sizeNow.height - e.dimension.height;\n\t\t\t\t\tupdateTopLeft = true;\n\t\t\t\t}\n\t\t\t\tif (updateTopLeft) {\n\t\t\t\t\tthis._applyTopLeft({\n\t\t\t\t\t\ttop: topLeftNow.top + deltaTop,\n\t\t\t\t\t\tleft: topLeftNow.left + deltaLeft,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (e.done) {\n\t\t\t\ttopLeftNow = undefined;\n\t\t\t\tsizeNow = undefined;\n\t\t\t\tdeltaTop = 0;\n\t\t\t\tdeltaLeft = 0;\n\t\t\t\tthis._userSize = e.dimension;\n\t\t\t}\n\t\t}));\n\n\t\tthis._disposables.add(this.widget.onDidChangeContents(() => {\n\t\t\tif (this._anchorBox) {\n\t\t\t\tthis._placeAtAnchor(this._anchorBox, this._userSize ?? this.widget.size, this._preferAlignAtTop);\n\t\t\t}\n\t\t}));\n\t}\n\n\tdispose(): void {\n\t\tthis._resizable.dispose();\n\t\tthis._disposables.dispose();\n\t\tthis.hide();\n\t}\n\n\tgetId(): string {\n\t\treturn 'suggest.details';\n\t}\n\n\tgetDomNode(): HTMLElement {\n\t\treturn this._resizable.domNode;\n\t}\n\n\tgetPosition(): IOverlayWidgetPosition | null {\n\t\treturn this._topLeft ? { preference: this._topLeft } : null;\n\t}\n\n\tshow(): void {\n\t\tif (!this._added) {\n\t\t\tthis._editor.addOverlayWidget(this);\n\t\t\tthis._added = true;\n\t\t}\n\t}\n\n\thide(sessionEnded: boolean = false): void {\n\t\tthis._resizable.clearSashHoverState();\n\n\t\tif (this._added) {\n\t\t\tthis._editor.removeOverlayWidget(this);\n\t\t\tthis._added = false;\n\t\t\tthis._anchorBox = undefined;\n\t\t\tthis._topLeft = undefined;\n\t\t}\n\t\tif (sessionEnded) {\n\t\t\tthis._userSize = undefined;\n\t\t\tthis.widget.clearContents();\n\t\t}\n\t}\n\n\tplaceAtAnchor(anchor: HTMLElement, preferAlignAtTop: boolean) {\n\t\tconst anchorBox = anchor.getBoundingClientRect();\n\t\tthis._anchorBox = anchorBox;\n\t\tthis._preferAlignAtTop = preferAlignAtTop;\n\t\tthis._placeAtAnchor(this._anchorBox, this._userSize ?? this.widget.size, preferAlignAtTop);\n\t}\n\n\t_placeAtAnchor(anchorBox: dom.IDomNodePagePosition, size: dom.Dimension, preferAlignAtTop: boolean) {\n\t\tconst bodyBox = dom.getClientArea(this.getDomNode().ownerDocument.body);\n\n\t\tconst info = this.widget.getLayoutInfo();\n\n\t\tconst defaultMinSize = new dom.Dimension(220, 2 * info.lineHeight);\n\t\tconst defaultTop = anchorBox.top;\n\n\t\ttype Placement = { top: number; left: number; fit: number; maxSizeTop: dom.Dimension; maxSizeBottom: dom.Dimension; minSize: dom.Dimension };\n\n\t\t// EAST\n\t\tconst eastPlacement: Placement = (function () {\n\t\t\tconst width = bodyBox.width - (anchorBox.left + anchorBox.width + info.borderWidth + info.horizontalPadding);\n\t\t\tconst left = -info.borderWidth + anchorBox.left + anchorBox.width;\n\t\t\tconst maxSizeTop = new dom.Dimension(width, bodyBox.height - anchorBox.top - info.borderHeight - info.verticalPadding);\n\t\t\tconst maxSizeBottom = maxSizeTop.with(undefined, anchorBox.top + anchorBox.height - info.borderHeight - info.verticalPadding);\n\t\t\treturn { top: defaultTop, left, fit: width - size.width, maxSizeTop, maxSizeBottom, minSize: defaultMinSize.with(Math.min(width, defaultMinSize.width)) };\n\t\t})();\n\n\t\t// WEST\n\t\tconst westPlacement: Placement = (function () {\n\t\t\tconst width = anchorBox.left - info.borderWidth - info.horizontalPadding;\n\t\t\tconst left = Math.max(info.horizontalPadding, anchorBox.left - size.width - info.borderWidth);\n\t\t\tconst maxSizeTop = new dom.Dimension(width, bodyBox.height - anchorBox.top - info.borderHeight - info.verticalPadding);\n\t\t\tconst maxSizeBottom = maxSizeTop.with(undefined, anchorBox.top + anchorBox.height - info.borderHeight - info.verticalPadding);\n\t\t\treturn { top: defaultTop, left, fit: width - size.width, maxSizeTop, maxSizeBottom, minSize: defaultMinSize.with(Math.min(width, defaultMinSize.width)) };\n\t\t})();\n\n\t\t// SOUTH\n\t\tconst southPacement: Placement = (function () {\n\t\t\tconst left = anchorBox.left;\n\t\t\tconst top = -info.borderWidth + anchorBox.top + anchorBox.height;\n\t\t\tconst maxSizeBottom = new dom.Dimension(anchorBox.width - info.borderHeight, bodyBox.height - anchorBox.top - anchorBox.height - info.verticalPadding);\n\t\t\treturn { top, left, fit: maxSizeBottom.height - size.height, maxSizeBottom, maxSizeTop: maxSizeBottom, minSize: defaultMinSize.with(maxSizeBottom.width) };\n\t\t})();\n\n\t\t// take first placement that fits or the first with \"least bad\" fit\n\t\tconst placements = [eastPlacement, westPlacement, southPacement];\n\t\tconst placement = placements.find(p => p.fit >= 0) ?? placements.sort((a, b) => b.fit - a.fit)[0];\n\n\t\t// top/bottom placement\n\t\tconst bottom = anchorBox.top + anchorBox.height - info.borderHeight;\n\t\tlet alignAtTop: boolean;\n\t\tlet height = size.height;\n\t\tconst maxHeight = Math.max(placement.maxSizeTop.height, placement.maxSizeBottom.height);\n\t\tif (height > maxHeight) {\n\t\t\theight = maxHeight;\n\t\t}\n\t\tlet maxSize: dom.Dimension;\n\t\tif (preferAlignAtTop) {\n\t\t\tif (height <= placement.maxSizeTop.height) {\n\t\t\t\talignAtTop = true;\n\t\t\t\tmaxSize = placement.maxSizeTop;\n\t\t\t} else {\n\t\t\t\talignAtTop = false;\n\t\t\t\tmaxSize = placement.maxSizeBottom;\n\t\t\t}\n\t\t} else {\n\t\t\tif (height <= placement.maxSizeBottom.height) {\n\t\t\t\talignAtTop = false;\n\t\t\t\tmaxSize = placement.maxSizeBottom;\n\t\t\t} else {\n\t\t\t\talignAtTop = true;\n\t\t\t\tmaxSize = placement.maxSizeTop;\n\t\t\t}\n\t\t}\n\n\t\tlet { top, left } = placement;\n\t\tif (!alignAtTop && height > anchorBox.height) {\n\t\t\ttop = bottom - height;\n\t\t}\n\t\tconst editorDomNode = this._editor.getDomNode();\n\t\tif (editorDomNode) {\n\t\t\t// get bounding rectangle of the suggest widget relative to the editor\n\t\t\tconst editorBoundingBox = editorDomNode.getBoundingClientRect();\n\t\t\ttop -= editorBoundingBox.top;\n\t\t\tleft -= editorBoundingBox.left;\n\t\t}\n\t\tthis._applyTopLeft({ left, top });\n\n\t\tthis._resizable.enableSashes(!alignAtTop, placement === eastPlacement, alignAtTop, placement !== eastPlacement);\n\n\t\tthis._resizable.minSize = placement.minSize;\n\t\tthis._resizable.maxSize = maxSize;\n\t\tthis._resizable.layout(height, Math.min(maxSize.width, size.width));\n\t\tthis.widget.layout(this._resizable.size.width, this._resizable.size.height);\n\t}\n\n\tprivate _applyTopLeft(topLeft: TopLeftPosition): void {\n\t\tthis._topLeft = topLeft;\n\t\tthis._editor.layoutOverlayWidget(this);\n\t}\n}\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\nimport * as arrays from 'vs/base/common/arrays';\nimport { IStringDictionary } from 'vs/base/common/collections';\nimport { ResourceMap } from 'vs/base/common/map';\nimport * as objects from 'vs/base/common/objects';\nimport * as types from 'vs/base/common/types';\nimport { URI, UriComponents } from 'vs/base/common/uri';\nimport { addToValueTree, ConfigurationTarget, getConfigurationValue, IConfigurationChange, IConfigurationChangeEvent, IConfigurationData, IConfigurationModel, IConfigurationOverrides, IConfigurationUpdateOverrides, IConfigurationValue, IInspectValue, IOverrides, removeFromValueTree, toValuesTree } from 'vs/platform/configuration/common/configuration';\nimport { ConfigurationScope, Extensions, IConfigurationPropertySchema, IConfigurationRegistry, overrideIdentifiersFromKey, OVERRIDE_PROPERTY_REGEX } from 'vs/platform/configuration/common/configurationRegistry';\nimport { ILogService } from 'vs/platform/log/common/log';\nimport { Registry } from 'vs/platform/registry/common/platform';\nimport { Workspace } from 'vs/platform/workspace/common/workspace';\n\nfunction freeze(data: T): T {\n\treturn Object.isFrozen(data) ? data : objects.deepFreeze(data);\n}\n\ntype InspectValue = IInspectValue & { merged?: V };\n\nexport class ConfigurationModel implements IConfigurationModel {\n\n\tstatic createEmptyModel(logService: ILogService): ConfigurationModel {\n\t\treturn new ConfigurationModel({}, [], [], undefined, logService);\n\t}\n\n\tprivate readonly overrideConfigurations = new Map();\n\n\tconstructor(\n\t\tprivate readonly _contents: any,\n\t\tprivate readonly _keys: string[],\n\t\tprivate readonly _overrides: IOverrides[],\n\t\treadonly raw: ReadonlyArray | ConfigurationModel> | undefined,\n\t\tprivate readonly logService: ILogService\n\t) {\n\t}\n\n\tprivate _rawConfiguration: ConfigurationModel | undefined;\n\tget rawConfiguration(): ConfigurationModel {\n\t\tif (!this._rawConfiguration) {\n\t\t\tif (this.raw?.length) {\n\t\t\t\tconst rawConfigurationModels = this.raw.map(raw => {\n\t\t\t\t\tif (raw instanceof ConfigurationModel) {\n\t\t\t\t\t\treturn raw;\n\t\t\t\t\t}\n\t\t\t\t\tconst parser = new ConfigurationModelParser('', this.logService);\n\t\t\t\t\tparser.parseRaw(raw);\n\t\t\t\t\treturn parser.configurationModel;\n\t\t\t\t});\n\t\t\t\tthis._rawConfiguration = rawConfigurationModels.reduce((previous, current) => current === previous ? current : previous.merge(current), rawConfigurationModels[0]);\n\t\t\t} else {\n\t\t\t\t// raw is same as current\n\t\t\t\tthis._rawConfiguration = this;\n\t\t\t}\n\t\t}\n\t\treturn this._rawConfiguration;\n\t}\n\n\tget contents(): any {\n\t\treturn this._contents;\n\t}\n\n\tget overrides(): IOverrides[] {\n\t\treturn this._overrides;\n\t}\n\n\tget keys(): string[] {\n\t\treturn this._keys;\n\t}\n\n\tisEmpty(): boolean {\n\t\treturn this._keys.length === 0 && Object.keys(this._contents).length === 0 && this._overrides.length === 0;\n\t}\n\n\tgetValue(section: string | undefined): V {\n\t\treturn section ? getConfigurationValue(this.contents, section) : this.contents;\n\t}\n\n\tinspect(section: string | undefined, overrideIdentifier?: string | null): InspectValue {\n\t\tconst that = this;\n\t\treturn {\n\t\t\tget value() {\n\t\t\t\treturn freeze(that.rawConfiguration.getValue(section));\n\t\t\t},\n\t\t\tget override() {\n\t\t\t\treturn overrideIdentifier ? freeze(that.rawConfiguration.getOverrideValue(section, overrideIdentifier)) : undefined;\n\t\t\t},\n\t\t\tget merged() {\n\t\t\t\treturn freeze(overrideIdentifier ? that.rawConfiguration.override(overrideIdentifier).getValue(section) : that.rawConfiguration.getValue(section));\n\t\t\t},\n\t\t\tget overrides() {\n\t\t\t\tconst overrides: { readonly identifiers: string[]; readonly value: V }[] = [];\n\t\t\t\tfor (const { contents, identifiers, keys } of that.rawConfiguration.overrides) {\n\t\t\t\t\tconst value = new ConfigurationModel(contents, keys, [], undefined, that.logService).getValue(section);\n\t\t\t\t\tif (value !== undefined) {\n\t\t\t\t\t\toverrides.push({ identifiers, value });\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn overrides.length ? freeze(overrides) : undefined;\n\t\t\t}\n\t\t};\n\t}\n\n\tgetOverrideValue(section: string | undefined, overrideIdentifier: string): V | undefined {\n\t\tconst overrideContents = this.getContentsForOverrideIdentifer(overrideIdentifier);\n\t\treturn overrideContents\n\t\t\t? section ? getConfigurationValue(overrideContents, section) : overrideContents\n\t\t\t: undefined;\n\t}\n\n\toverride(identifier: string): ConfigurationModel {\n\t\tlet overrideConfigurationModel = this.overrideConfigurations.get(identifier);\n\t\tif (!overrideConfigurationModel) {\n\t\t\toverrideConfigurationModel = this.createOverrideConfigurationModel(identifier);\n\t\t\tthis.overrideConfigurations.set(identifier, overrideConfigurationModel);\n\t\t}\n\t\treturn overrideConfigurationModel;\n\t}\n\n\tmerge(...others: ConfigurationModel[]): ConfigurationModel {\n\t\tconst contents = objects.deepClone(this.contents);\n\t\tconst overrides = objects.deepClone(this.overrides);\n\t\tconst keys = [...this.keys];\n\t\tconst raws = this.raw?.length ? [...this.raw] : [this];\n\n\t\tfor (const other of others) {\n\t\t\traws.push(...(other.raw?.length ? other.raw : [other]));\n\t\t\tif (other.isEmpty()) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tthis.mergeContents(contents, other.contents);\n\n\t\t\tfor (const otherOverride of other.overrides) {\n\t\t\t\tconst [override] = overrides.filter(o => arrays.equals(o.identifiers, otherOverride.identifiers));\n\t\t\t\tif (override) {\n\t\t\t\t\tthis.mergeContents(override.contents, otherOverride.contents);\n\t\t\t\t\toverride.keys.push(...otherOverride.keys);\n\t\t\t\t\toverride.keys = arrays.distinct(override.keys);\n\t\t\t\t} else {\n\t\t\t\t\toverrides.push(objects.deepClone(otherOverride));\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (const key of other.keys) {\n\t\t\t\tif (keys.indexOf(key) === -1) {\n\t\t\t\t\tkeys.push(key);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn new ConfigurationModel(contents, keys, overrides, raws.every(raw => raw instanceof ConfigurationModel) ? undefined : raws, this.logService);\n\t}\n\n\tprivate createOverrideConfigurationModel(identifier: string): ConfigurationModel {\n\t\tconst overrideContents = this.getContentsForOverrideIdentifer(identifier);\n\n\t\tif (!overrideContents || typeof overrideContents !== 'object' || !Object.keys(overrideContents).length) {\n\t\t\t// If there are no valid overrides, return self\n\t\t\treturn this;\n\t\t}\n\n\t\tconst contents: any = {};\n\t\tfor (const key of arrays.distinct([...Object.keys(this.contents), ...Object.keys(overrideContents)])) {\n\n\t\t\tlet contentsForKey = this.contents[key];\n\t\t\tconst overrideContentsForKey = overrideContents[key];\n\n\t\t\t// If there are override contents for the key, clone and merge otherwise use base contents\n\t\t\tif (overrideContentsForKey) {\n\t\t\t\t// Clone and merge only if base contents and override contents are of type object otherwise just override\n\t\t\t\tif (typeof contentsForKey === 'object' && typeof overrideContentsForKey === 'object') {\n\t\t\t\t\tcontentsForKey = objects.deepClone(contentsForKey);\n\t\t\t\t\tthis.mergeContents(contentsForKey, overrideContentsForKey);\n\t\t\t\t} else {\n\t\t\t\t\tcontentsForKey = overrideContentsForKey;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tcontents[key] = contentsForKey;\n\t\t}\n\n\t\treturn new ConfigurationModel(contents, this.keys, this.overrides, undefined, this.logService);\n\t}\n\n\tprivate mergeContents(source: any, target: any): void {\n\t\tfor (const key of Object.keys(target)) {\n\t\t\tif (key in source) {\n\t\t\t\tif (types.isObject(source[key]) && types.isObject(target[key])) {\n\t\t\t\t\tthis.mergeContents(source[key], target[key]);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\tsource[key] = objects.deepClone(target[key]);\n\t\t}\n\t}\n\n\tprivate getContentsForOverrideIdentifer(identifier: string): any {\n\t\tlet contentsForIdentifierOnly: IStringDictionary | null = null;\n\t\tlet contents: IStringDictionary | null = null;\n\t\tconst mergeContents = (contentsToMerge: any) => {\n\t\t\tif (contentsToMerge) {\n\t\t\t\tif (contents) {\n\t\t\t\t\tthis.mergeContents(contents, contentsToMerge);\n\t\t\t\t} else {\n\t\t\t\t\tcontents = objects.deepClone(contentsToMerge);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\tfor (const override of this.overrides) {\n\t\t\tif (override.identifiers.length === 1 && override.identifiers[0] === identifier) {\n\t\t\t\tcontentsForIdentifierOnly = override.contents;\n\t\t\t} else if (override.identifiers.includes(identifier)) {\n\t\t\t\tmergeContents(override.contents);\n\t\t\t}\n\t\t}\n\t\t// Merge contents of the identifier only at the end to take precedence.\n\t\tmergeContents(contentsForIdentifierOnly);\n\t\treturn contents;\n\t}\n\n\ttoJSON(): IConfigurationModel {\n\t\treturn {\n\t\t\tcontents: this.contents,\n\t\t\toverrides: this.overrides,\n\t\t\tkeys: this.keys\n\t\t};\n\t}\n\n\t// Update methods\n\n\tpublic addValue(key: string, value: any): void {\n\t\tthis.updateValue(key, value, true);\n\t}\n\n\tpublic setValue(key: string, value: any): void {\n\t\tthis.updateValue(key, value, false);\n\t}\n\n\tpublic removeValue(key: string): void {\n\t\tconst index = this.keys.indexOf(key);\n\t\tif (index === -1) {\n\t\t\treturn;\n\t\t}\n\t\tthis.keys.splice(index, 1);\n\t\tremoveFromValueTree(this.contents, key);\n\t\tif (OVERRIDE_PROPERTY_REGEX.test(key)) {\n\t\t\tthis.overrides.splice(this.overrides.findIndex(o => arrays.equals(o.identifiers, overrideIdentifiersFromKey(key))), 1);\n\t\t}\n\t}\n\n\tprivate updateValue(key: string, value: any, add: boolean): void {\n\t\taddToValueTree(this.contents, key, value, e => this.logService.error(e));\n\t\tadd = add || this.keys.indexOf(key) === -1;\n\t\tif (add) {\n\t\t\tthis.keys.push(key);\n\t\t}\n\t\tif (OVERRIDE_PROPERTY_REGEX.test(key)) {\n\t\t\tthis.overrides.push({\n\t\t\t\tidentifiers: overrideIdentifiersFromKey(key),\n\t\t\t\tkeys: Object.keys(this.contents[key]),\n\t\t\t\tcontents: toValuesTree(this.contents[key], message => this.logService.error(message)),\n\t\t\t});\n\t\t}\n\t}\n}\n\nexport interface ConfigurationParseOptions {\n\tscopes?: ConfigurationScope[];\n\tskipRestricted?: boolean;\n\tinclude?: string[];\n\texclude?: string[];\n}\n\nexport class ConfigurationModelParser {\n\n\tprivate _raw: any = null;\n\tprivate _configurationModel: ConfigurationModel | null = null;\n\tprivate _restrictedConfigurations: string[] = [];\n\n\tconstructor(\n\t\tprotected readonly _name: string,\n\t\tprotected readonly logService: ILogService\n\t) { }\n\n\tget configurationModel(): ConfigurationModel {\n\t\treturn this._configurationModel || ConfigurationModel.createEmptyModel(this.logService);\n\t}\n\n\tpublic parseRaw(raw: any, options?: ConfigurationParseOptions): void {\n\t\tthis._raw = raw;\n\t\tconst { contents, keys, overrides, restricted, hasExcludedProperties } = this.doParseRaw(raw, options);\n\t\tthis._configurationModel = new ConfigurationModel(contents, keys, overrides, hasExcludedProperties ? [raw] : undefined /* raw has not changed */, this.logService);\n\t\tthis._restrictedConfigurations = restricted || [];\n\t}\n\n\tprotected doParseRaw(raw: any, options?: ConfigurationParseOptions): IConfigurationModel & { restricted?: string[]; hasExcludedProperties?: boolean } {\n\t\tconst configurationProperties = Registry.as(Extensions.Configuration).getConfigurationProperties();\n\t\tconst filtered = this.filter(raw, configurationProperties, true, options);\n\t\traw = filtered.raw;\n\t\tconst contents = toValuesTree(raw, message => this.logService.error(`Conflict in settings file ${this._name}: ${message}`));\n\t\tconst keys = Object.keys(raw);\n\t\tconst overrides = this.toOverrides(raw, message => this.logService.error(`Conflict in settings file ${this._name}: ${message}`));\n\t\treturn { contents, keys, overrides, restricted: filtered.restricted, hasExcludedProperties: filtered.hasExcludedProperties };\n\t}\n\n\tprivate filter(properties: any, configurationProperties: { [qualifiedKey: string]: IConfigurationPropertySchema | undefined }, filterOverriddenProperties: boolean, options?: ConfigurationParseOptions): { raw: {}; restricted: string[]; hasExcludedProperties: boolean } {\n\t\tlet hasExcludedProperties = false;\n\t\tif (!options?.scopes && !options?.skipRestricted && !options?.exclude?.length) {\n\t\t\treturn { raw: properties, restricted: [], hasExcludedProperties };\n\t\t}\n\t\tconst raw: any = {};\n\t\tconst restricted: string[] = [];\n\t\tfor (const key in properties) {\n\t\t\tif (OVERRIDE_PROPERTY_REGEX.test(key) && filterOverriddenProperties) {\n\t\t\t\tconst result = this.filter(properties[key], configurationProperties, false, options);\n\t\t\t\traw[key] = result.raw;\n\t\t\t\thasExcludedProperties = hasExcludedProperties || result.hasExcludedProperties;\n\t\t\t\trestricted.push(...result.restricted);\n\t\t\t} else {\n\t\t\t\tconst propertySchema = configurationProperties[key];\n\t\t\t\tconst scope = propertySchema ? typeof propertySchema.scope !== 'undefined' ? propertySchema.scope : ConfigurationScope.WINDOW : undefined;\n\t\t\t\tif (propertySchema?.restricted) {\n\t\t\t\t\trestricted.push(key);\n\t\t\t\t}\n\t\t\t\tif (!options.exclude?.includes(key) /* Check exclude */\n\t\t\t\t\t&& (options.include?.includes(key) /* Check include */\n\t\t\t\t\t\t|| ((scope === undefined || options.scopes === undefined || options.scopes.includes(scope)) /* Check scopes */\n\t\t\t\t\t\t\t&& !(options.skipRestricted && propertySchema?.restricted)))) /* Check restricted */ {\n\t\t\t\t\traw[key] = properties[key];\n\t\t\t\t} else {\n\t\t\t\t\thasExcludedProperties = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn { raw, restricted, hasExcludedProperties };\n\t}\n\n\tprivate toOverrides(raw: any, conflictReporter: (message: string) => void): IOverrides[] {\n\t\tconst overrides: IOverrides[] = [];\n\t\tfor (const key of Object.keys(raw)) {\n\t\t\tif (OVERRIDE_PROPERTY_REGEX.test(key)) {\n\t\t\t\tconst overrideRaw: any = {};\n\t\t\t\tfor (const keyInOverrideRaw in raw[key]) {\n\t\t\t\t\toverrideRaw[keyInOverrideRaw] = raw[key][keyInOverrideRaw];\n\t\t\t\t}\n\t\t\t\toverrides.push({\n\t\t\t\t\tidentifiers: overrideIdentifiersFromKey(key),\n\t\t\t\t\tkeys: Object.keys(overrideRaw),\n\t\t\t\t\tcontents: toValuesTree(overrideRaw, conflictReporter)\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\treturn overrides;\n\t}\n\n}\n\nclass ConfigurationInspectValue implements IConfigurationValue {\n\n\tconstructor(\n\t\tprivate readonly key: string,\n\t\tprivate readonly overrides: IConfigurationOverrides,\n\t\tprivate readonly _value: V | undefined,\n\t\treadonly overrideIdentifiers: string[] | undefined,\n\t\tprivate readonly defaultConfiguration: ConfigurationModel,\n\t\tprivate readonly policyConfiguration: ConfigurationModel | undefined,\n\t\tprivate readonly applicationConfiguration: ConfigurationModel | undefined,\n\t\tprivate readonly userConfiguration: ConfigurationModel,\n\t\tprivate readonly localUserConfiguration: ConfigurationModel,\n\t\tprivate readonly remoteUserConfiguration: ConfigurationModel,\n\t\tprivate readonly workspaceConfiguration: ConfigurationModel | undefined,\n\t\tprivate readonly folderConfigurationModel: ConfigurationModel | undefined,\n\t\tprivate readonly memoryConfigurationModel: ConfigurationModel\n\t) {\n\t}\n\n\tprivate toInspectValue(inspectValue: IInspectValue | undefined | null): IInspectValue | undefined {\n\t\treturn inspectValue?.value !== undefined || inspectValue?.override !== undefined || inspectValue?.overrides !== undefined ? inspectValue : undefined;\n\t}\n\n\tprivate _userInspectValue: InspectValue | undefined;\n\tprivate get userInspectValue(): InspectValue {\n\t\tif (!this._userInspectValue) {\n\t\t\tthis._userInspectValue = this.userConfiguration.inspect(this.key, this.overrides.overrideIdentifier);\n\t\t}\n\t\treturn this._userInspectValue;\n\t}\n\n\tget user(): IInspectValue | undefined {\n\t\treturn this.toInspectValue(this.userInspectValue);\n\t}\n\n}\n\nexport class Configuration {\n\n\tprivate _workspaceConsolidatedConfiguration: ConfigurationModel | null = null;\n\tprivate _foldersConsolidatedConfigurations = new ResourceMap();\n\n\tconstructor(\n\t\tprivate _defaultConfiguration: ConfigurationModel,\n\t\tprivate _policyConfiguration: ConfigurationModel,\n\t\tprivate _applicationConfiguration: ConfigurationModel,\n\t\tprivate _localUserConfiguration: ConfigurationModel,\n\t\tprivate _remoteUserConfiguration: ConfigurationModel,\n\t\tprivate _workspaceConfiguration: ConfigurationModel,\n\t\tprivate _folderConfigurations: ResourceMap,\n\t\tprivate _memoryConfiguration: ConfigurationModel,\n\t\tprivate _memoryConfigurationByResource: ResourceMap,\n\t\tprivate readonly logService: ILogService\n\t) {\n\t}\n\n\tgetValue(section: string | undefined, overrides: IConfigurationOverrides, workspace: Workspace | undefined): any {\n\t\tconst consolidateConfigurationModel = this.getConsolidatedConfigurationModel(section, overrides, workspace);\n\t\treturn consolidateConfigurationModel.getValue(section);\n\t}\n\n\tupdateValue(key: string, value: any, overrides: IConfigurationUpdateOverrides = {}): void {\n\t\tlet memoryConfiguration: ConfigurationModel | undefined;\n\t\tif (overrides.resource) {\n\t\t\tmemoryConfiguration = this._memoryConfigurationByResource.get(overrides.resource);\n\t\t\tif (!memoryConfiguration) {\n\t\t\t\tmemoryConfiguration = ConfigurationModel.createEmptyModel(this.logService);\n\t\t\t\tthis._memoryConfigurationByResource.set(overrides.resource, memoryConfiguration);\n\t\t\t}\n\t\t} else {\n\t\t\tmemoryConfiguration = this._memoryConfiguration;\n\t\t}\n\n\t\tif (value === undefined) {\n\t\t\tmemoryConfiguration.removeValue(key);\n\t\t} else {\n\t\t\tmemoryConfiguration.setValue(key, value);\n\t\t}\n\n\t\tif (!overrides.resource) {\n\t\t\tthis._workspaceConsolidatedConfiguration = null;\n\t\t}\n\t}\n\n\tinspect(key: string, overrides: IConfigurationOverrides, workspace: Workspace | undefined): IConfigurationValue {\n\t\tconst consolidateConfigurationModel = this.getConsolidatedConfigurationModel(key, overrides, workspace);\n\t\tconst folderConfigurationModel = this.getFolderConfigurationModelForResource(overrides.resource, workspace);\n\t\tconst memoryConfigurationModel = overrides.resource ? this._memoryConfigurationByResource.get(overrides.resource) || this._memoryConfiguration : this._memoryConfiguration;\n\t\tconst overrideIdentifiers = new Set();\n\t\tfor (const override of consolidateConfigurationModel.overrides) {\n\t\t\tfor (const overrideIdentifier of override.identifiers) {\n\t\t\t\tif (consolidateConfigurationModel.getOverrideValue(key, overrideIdentifier) !== undefined) {\n\t\t\t\t\toverrideIdentifiers.add(overrideIdentifier);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn new ConfigurationInspectValue(\n\t\t\tkey,\n\t\t\toverrides,\n\t\t\tconsolidateConfigurationModel.getValue(key),\n\t\t\toverrideIdentifiers.size ? [...overrideIdentifiers] : undefined,\n\t\t\tthis._defaultConfiguration,\n\t\t\tthis._policyConfiguration.isEmpty() ? undefined : this._policyConfiguration,\n\t\t\tthis.applicationConfiguration.isEmpty() ? undefined : this.applicationConfiguration,\n\t\t\tthis.userConfiguration,\n\t\t\tthis.localUserConfiguration,\n\t\t\tthis.remoteUserConfiguration,\n\t\t\tworkspace ? this._workspaceConfiguration : undefined,\n\t\t\tfolderConfigurationModel ? folderConfigurationModel : undefined,\n\t\t\tmemoryConfigurationModel\n\t\t);\n\n\t}\n\n\tget applicationConfiguration(): ConfigurationModel {\n\t\treturn this._applicationConfiguration;\n\t}\n\n\tprivate _userConfiguration: ConfigurationModel | null = null;\n\tget userConfiguration(): ConfigurationModel {\n\t\tif (!this._userConfiguration) {\n\t\t\tthis._userConfiguration = this._remoteUserConfiguration.isEmpty() ? this._localUserConfiguration : this._localUserConfiguration.merge(this._remoteUserConfiguration);\n\t\t}\n\t\treturn this._userConfiguration;\n\t}\n\n\tget localUserConfiguration(): ConfigurationModel {\n\t\treturn this._localUserConfiguration;\n\t}\n\n\tget remoteUserConfiguration(): ConfigurationModel {\n\t\treturn this._remoteUserConfiguration;\n\t}\n\n\tprivate getConsolidatedConfigurationModel(section: string | undefined, overrides: IConfigurationOverrides, workspace: Workspace | undefined): ConfigurationModel {\n\t\tlet configurationModel = this.getConsolidatedConfigurationModelForResource(overrides, workspace);\n\t\tif (overrides.overrideIdentifier) {\n\t\t\tconfigurationModel = configurationModel.override(overrides.overrideIdentifier);\n\t\t}\n\t\tif (!this._policyConfiguration.isEmpty() && this._policyConfiguration.getValue(section) !== undefined) {\n\t\t\tconfigurationModel = configurationModel.merge(this._policyConfiguration);\n\t\t}\n\t\treturn configurationModel;\n\t}\n\n\tprivate getConsolidatedConfigurationModelForResource({ resource }: IConfigurationOverrides, workspace: Workspace | undefined): ConfigurationModel {\n\t\tlet consolidateConfiguration = this.getWorkspaceConsolidatedConfiguration();\n\n\t\tif (workspace && resource) {\n\t\t\tconst root = workspace.getFolder(resource);\n\t\t\tif (root) {\n\t\t\t\tconsolidateConfiguration = this.getFolderConsolidatedConfiguration(root.uri) || consolidateConfiguration;\n\t\t\t}\n\t\t\tconst memoryConfigurationForResource = this._memoryConfigurationByResource.get(resource);\n\t\t\tif (memoryConfigurationForResource) {\n\t\t\t\tconsolidateConfiguration = consolidateConfiguration.merge(memoryConfigurationForResource);\n\t\t\t}\n\t\t}\n\n\t\treturn consolidateConfiguration;\n\t}\n\n\tprivate getWorkspaceConsolidatedConfiguration(): ConfigurationModel {\n\t\tif (!this._workspaceConsolidatedConfiguration) {\n\t\t\tthis._workspaceConsolidatedConfiguration = this._defaultConfiguration.merge(this.applicationConfiguration, this.userConfiguration, this._workspaceConfiguration, this._memoryConfiguration);\n\t\t}\n\t\treturn this._workspaceConsolidatedConfiguration;\n\t}\n\n\tprivate getFolderConsolidatedConfiguration(folder: URI): ConfigurationModel {\n\t\tlet folderConsolidatedConfiguration = this._foldersConsolidatedConfigurations.get(folder);\n\t\tif (!folderConsolidatedConfiguration) {\n\t\t\tconst workspaceConsolidateConfiguration = this.getWorkspaceConsolidatedConfiguration();\n\t\t\tconst folderConfiguration = this._folderConfigurations.get(folder);\n\t\t\tif (folderConfiguration) {\n\t\t\t\tfolderConsolidatedConfiguration = workspaceConsolidateConfiguration.merge(folderConfiguration);\n\t\t\t\tthis._foldersConsolidatedConfigurations.set(folder, folderConsolidatedConfiguration);\n\t\t\t} else {\n\t\t\t\tfolderConsolidatedConfiguration = workspaceConsolidateConfiguration;\n\t\t\t}\n\t\t}\n\t\treturn folderConsolidatedConfiguration;\n\t}\n\n\tprivate getFolderConfigurationModelForResource(resource: URI | null | undefined, workspace: Workspace | undefined): ConfigurationModel | undefined {\n\t\tif (workspace && resource) {\n\t\t\tconst root = workspace.getFolder(resource);\n\t\t\tif (root) {\n\t\t\t\treturn this._folderConfigurations.get(root.uri);\n\t\t\t}\n\t\t}\n\t\treturn undefined;\n\t}\n\n\ttoData(): IConfigurationData {\n\t\treturn {\n\t\t\tdefaults: {\n\t\t\t\tcontents: this._defaultConfiguration.contents,\n\t\t\t\toverrides: this._defaultConfiguration.overrides,\n\t\t\t\tkeys: this._defaultConfiguration.keys\n\t\t\t},\n\t\t\tpolicy: {\n\t\t\t\tcontents: this._policyConfiguration.contents,\n\t\t\t\toverrides: this._policyConfiguration.overrides,\n\t\t\t\tkeys: this._policyConfiguration.keys\n\t\t\t},\n\t\t\tapplication: {\n\t\t\t\tcontents: this.applicationConfiguration.contents,\n\t\t\t\toverrides: this.applicationConfiguration.overrides,\n\t\t\t\tkeys: this.applicationConfiguration.keys\n\t\t\t},\n\t\t\tuser: {\n\t\t\t\tcontents: this.userConfiguration.contents,\n\t\t\t\toverrides: this.userConfiguration.overrides,\n\t\t\t\tkeys: this.userConfiguration.keys\n\t\t\t},\n\t\t\tworkspace: {\n\t\t\t\tcontents: this._workspaceConfiguration.contents,\n\t\t\t\toverrides: this._workspaceConfiguration.overrides,\n\t\t\t\tkeys: this._workspaceConfiguration.keys\n\t\t\t},\n\t\t\tfolders: [...this._folderConfigurations.keys()].reduce<[UriComponents, IConfigurationModel][]>((result, folder) => {\n\t\t\t\tconst { contents, overrides, keys } = this._folderConfigurations.get(folder)!;\n\t\t\t\tresult.push([folder, { contents, overrides, keys }]);\n\t\t\t\treturn result;\n\t\t\t}, [])\n\t\t};\n\t}\n\n\tstatic parse(data: IConfigurationData, logService: ILogService): Configuration {\n\t\tconst defaultConfiguration = this.parseConfigurationModel(data.defaults, logService);\n\t\tconst policyConfiguration = this.parseConfigurationModel(data.policy, logService);\n\t\tconst applicationConfiguration = this.parseConfigurationModel(data.application, logService);\n\t\tconst userConfiguration = this.parseConfigurationModel(data.user, logService);\n\t\tconst workspaceConfiguration = this.parseConfigurationModel(data.workspace, logService);\n\t\tconst folders: ResourceMap = data.folders.reduce((result, value) => {\n\t\t\tresult.set(URI.revive(value[0]), this.parseConfigurationModel(value[1], logService));\n\t\t\treturn result;\n\t\t}, new ResourceMap());\n\t\treturn new Configuration(\n\t\t\tdefaultConfiguration,\n\t\t\tpolicyConfiguration,\n\t\t\tapplicationConfiguration,\n\t\t\tuserConfiguration,\n\t\t\tConfigurationModel.createEmptyModel(logService),\n\t\t\tworkspaceConfiguration,\n\t\t\tfolders,\n\t\t\tConfigurationModel.createEmptyModel(logService),\n\t\t\tnew ResourceMap(),\n\t\t\tlogService\n\t\t);\n\t}\n\n\tprivate static parseConfigurationModel(model: IConfigurationModel, logService: ILogService): ConfigurationModel {\n\t\treturn new ConfigurationModel(model.contents, model.keys, model.overrides, undefined, logService);\n\t}\n\n}\n\nexport class ConfigurationChangeEvent implements IConfigurationChangeEvent {\n\n\tprivate readonly _marker = '\\n';\n\tprivate readonly _markerCode1 = this._marker.charCodeAt(0);\n\tprivate readonly _markerCode2 = '.'.charCodeAt(0);\n\tprivate readonly _affectsConfigStr: string;\n\n\treadonly affectedKeys = new Set();\n\tsource!: ConfigurationTarget;\n\n\tconstructor(\n\t\treadonly change: IConfigurationChange,\n\t\tprivate readonly previous: { workspace?: Workspace; data: IConfigurationData } | undefined,\n\t\tprivate readonly currentConfiguraiton: Configuration,\n\t\tprivate readonly currentWorkspace: Workspace | undefined,\n\t\tprivate readonly logService: ILogService\n\t) {\n\t\tfor (const key of change.keys) {\n\t\t\tthis.affectedKeys.add(key);\n\t\t}\n\t\tfor (const [, keys] of change.overrides) {\n\t\t\tfor (const key of keys) {\n\t\t\t\tthis.affectedKeys.add(key);\n\t\t\t}\n\t\t}\n\n\t\t// Example: '\\nfoo.bar\\nabc.def\\n'\n\t\tthis._affectsConfigStr = this._marker;\n\t\tfor (const key of this.affectedKeys) {\n\t\t\tthis._affectsConfigStr += key + this._marker;\n\t\t}\n\t}\n\n\tprivate _previousConfiguration: Configuration | undefined = undefined;\n\tget previousConfiguration(): Configuration | undefined {\n\t\tif (!this._previousConfiguration && this.previous) {\n\t\t\tthis._previousConfiguration = Configuration.parse(this.previous.data, this.logService);\n\t\t}\n\t\treturn this._previousConfiguration;\n\t}\n\n\taffectsConfiguration(section: string, overrides?: IConfigurationOverrides): boolean {\n\t\t// we have one large string with all keys that have changed. we pad (marker) the section\n\t\t// and check that either find it padded or before a segment character\n\t\tconst needle = this._marker + section;\n\t\tconst idx = this._affectsConfigStr.indexOf(needle);\n\t\tif (idx < 0) {\n\t\t\t// NOT: (marker + section)\n\t\t\treturn false;\n\t\t}\n\t\tconst pos = idx + needle.length;\n\t\tif (pos >= this._affectsConfigStr.length) {\n\t\t\treturn false;\n\t\t}\n\t\tconst code = this._affectsConfigStr.charCodeAt(pos);\n\t\tif (code !== this._markerCode1 && code !== this._markerCode2) {\n\t\t\t// NOT: section + (marker | segment)\n\t\t\treturn false;\n\t\t}\n\t\tif (overrides) {\n\t\t\tconst value1 = this.previousConfiguration ? this.previousConfiguration.getValue(section, overrides, this.previous?.workspace) : undefined;\n\t\t\tconst value2 = this.currentConfiguraiton.getValue(section, overrides, this.currentWorkspace);\n\t\t\treturn !objects.equals(value1, value2);\n\t\t}\n\t\treturn true;\n\t}\n}\n","\nimport { IStringDictionary } from 'vs/base/common/collections';\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport { ConfigurationModel } from 'vs/platform/configuration/common/configurationModels';\nimport { Extensions, IConfigurationRegistry, IRegisteredConfigurationPropertySchema } from 'vs/platform/configuration/common/configurationRegistry';\nimport { ILogService } from 'vs/platform/log/common/log';\nimport { Registry } from 'vs/platform/registry/common/platform';\n\nexport class DefaultConfiguration extends Disposable {\n\n\tprivate _configurationModel = ConfigurationModel.createEmptyModel(this.logService);\n\tget configurationModel(): ConfigurationModel {\n\t\treturn this._configurationModel;\n\t}\n\n\tconstructor(private readonly logService: ILogService) {\n\t\tsuper();\n\t}\n\n\treload(): ConfigurationModel {\n\t\tthis.resetConfigurationModel();\n\t\treturn this.configurationModel;\n\t}\n\n\tprotected getConfigurationDefaultOverrides(): IStringDictionary {\n\t\treturn {};\n\t}\n\n\tprivate resetConfigurationModel(): void {\n\t\tthis._configurationModel = ConfigurationModel.createEmptyModel(this.logService);\n\t\tconst properties = Registry.as(Extensions.Configuration).getConfigurationProperties();\n\t\tthis.updateConfigurationModel(Object.keys(properties), properties);\n\t}\n\n\tprivate updateConfigurationModel(properties: string[], configurationProperties: IStringDictionary): void {\n\t\tconst configurationDefaultsOverrides = this.getConfigurationDefaultOverrides();\n\t\tfor (const key of properties) {\n\t\t\tconst defaultOverrideValue = configurationDefaultsOverrides[key];\n\t\t\tconst propertySchema = configurationProperties[key];\n\t\t\tif (defaultOverrideValue !== undefined) {\n\t\t\t\tthis._configurationModel.addValue(key, defaultOverrideValue);\n\t\t\t} else if (propertySchema) {\n\t\t\t\tthis._configurationModel.addValue(key, propertySchema.default);\n\t\t\t} else {\n\t\t\t\tthis._configurationModel.removeValue(key);\n\t\t\t}\n\t\t}\n\t}\n\n}\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\nimport { decodeKeybinding, Keybinding } from 'vs/base/common/keybindings';\nimport { OperatingSystem, OS } from 'vs/base/common/platform';\nimport { CommandsRegistry, ICommandHandler, ICommandMetadata } from 'vs/platform/commands/common/commands';\nimport { ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey';\nimport { Registry } from 'vs/platform/registry/common/platform';\nimport { combinedDisposable, DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle';\nimport { LinkedList } from 'vs/base/common/linkedList';\n\nexport interface IKeybindingItem {\n\tkeybinding: Keybinding | null;\n\tcommand: string | null;\n\tcommandArgs?: any;\n\twhen: ContextKeyExpression | null | undefined;\n\tweight1: number;\n\tweight2: number;\n\textensionId: string | null;\n\tisBuiltinExtension: boolean;\n}\n\nexport interface IKeybindings {\n\tprimary?: number;\n\tsecondary?: number[];\n\twin?: {\n\t\tprimary: number;\n\t\tsecondary?: number[];\n\t};\n\tlinux?: {\n\t\tprimary: number;\n\t\tsecondary?: number[];\n\t};\n\tmac?: {\n\t\tprimary: number;\n\t\tsecondary?: number[];\n\t};\n}\n\nexport interface IKeybindingRule extends IKeybindings {\n\tid: string;\n\tweight: number;\n\targs?: any;\n\t/**\n\t * Keybinding is disabled if expression returns false.\n\t */\n\twhen?: ContextKeyExpression | null | undefined;\n}\n\nexport const enum KeybindingWeight {\n\tEditorCore = 0,\n\tEditorContrib = 100,\n\tWorkbenchContrib = 200,\n\tBuiltinExtension = 300,\n\tExternalExtension = 400\n}\n\nexport interface ICommandAndKeybindingRule extends IKeybindingRule {\n\thandler: ICommandHandler;\n\tmetadata?: ICommandMetadata | null;\n}\n\nexport interface IKeybindingsRegistry {\n\tregisterKeybindingRule(rule: IKeybindingRule): IDisposable;\n\tregisterCommandAndKeybindingRule(desc: ICommandAndKeybindingRule): IDisposable;\n\tgetDefaultKeybindings(): IKeybindingItem[];\n}\n\n/**\n * Stores all built-in and extension-provided keybindings (but not ones that user defines themselves)\n */\nclass KeybindingsRegistryImpl implements IKeybindingsRegistry {\n\n\tprivate _coreKeybindings: LinkedList;\n\tprivate _extensionKeybindings: IKeybindingItem[];\n\tprivate _cachedMergedKeybindings: IKeybindingItem[] | null;\n\n\tconstructor() {\n\t\tthis._coreKeybindings = new LinkedList();\n\t\tthis._extensionKeybindings = [];\n\t\tthis._cachedMergedKeybindings = null;\n\t}\n\n\t/**\n\t * Take current platform into account and reduce to primary & secondary.\n\t */\n\tprivate static bindToCurrentPlatform(kb: IKeybindings): { primary?: number; secondary?: number[] } {\n\t\tif (OS === OperatingSystem.Windows) {\n\t\t\tif (kb && kb.win) {\n\t\t\t\treturn kb.win;\n\t\t\t}\n\t\t} else if (OS === OperatingSystem.Macintosh) {\n\t\t\tif (kb && kb.mac) {\n\t\t\t\treturn kb.mac;\n\t\t\t}\n\t\t} else {\n\t\t\tif (kb && kb.linux) {\n\t\t\t\treturn kb.linux;\n\t\t\t}\n\t\t}\n\n\t\treturn kb;\n\t}\n\n\tpublic registerKeybindingRule(rule: IKeybindingRule): IDisposable {\n\t\tconst actualKb = KeybindingsRegistryImpl.bindToCurrentPlatform(rule);\n\t\tconst result = new DisposableStore();\n\n\t\tif (actualKb && actualKb.primary) {\n\t\t\tconst kk = decodeKeybinding(actualKb.primary, OS);\n\t\t\tif (kk) {\n\t\t\t\tresult.add(this._registerDefaultKeybinding(kk, rule.id, rule.args, rule.weight, 0, rule.when));\n\t\t\t}\n\t\t}\n\n\t\tif (actualKb && Array.isArray(actualKb.secondary)) {\n\t\t\tfor (let i = 0, len = actualKb.secondary.length; i < len; i++) {\n\t\t\t\tconst k = actualKb.secondary[i];\n\t\t\t\tconst kk = decodeKeybinding(k, OS);\n\t\t\t\tif (kk) {\n\t\t\t\t\tresult.add(this._registerDefaultKeybinding(kk, rule.id, rule.args, rule.weight, -i - 1, rule.when));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tpublic registerCommandAndKeybindingRule(desc: ICommandAndKeybindingRule): IDisposable {\n\t\treturn combinedDisposable(\n\t\t\tthis.registerKeybindingRule(desc),\n\t\t\tCommandsRegistry.registerCommand(desc)\n\t\t);\n\t}\n\n\tprivate _registerDefaultKeybinding(keybinding: Keybinding, commandId: string, commandArgs: any, weight1: number, weight2: number, when: ContextKeyExpression | null | undefined): IDisposable {\n\t\tconst remove = this._coreKeybindings.push({\n\t\t\tkeybinding: keybinding,\n\t\t\tcommand: commandId,\n\t\t\tcommandArgs: commandArgs,\n\t\t\twhen: when,\n\t\t\tweight1: weight1,\n\t\t\tweight2: weight2,\n\t\t\textensionId: null,\n\t\t\tisBuiltinExtension: false\n\t\t});\n\t\tthis._cachedMergedKeybindings = null;\n\n\t\treturn toDisposable(() => {\n\t\t\tremove();\n\t\t\tthis._cachedMergedKeybindings = null;\n\t\t});\n\t}\n\n\tpublic getDefaultKeybindings(): IKeybindingItem[] {\n\t\tif (!this._cachedMergedKeybindings) {\n\t\t\tthis._cachedMergedKeybindings = Array.from(this._coreKeybindings).concat(this._extensionKeybindings);\n\t\t\tthis._cachedMergedKeybindings.sort(sorter);\n\t\t}\n\t\treturn this._cachedMergedKeybindings.slice(0);\n\t}\n}\nexport const KeybindingsRegistry: IKeybindingsRegistry = new KeybindingsRegistryImpl();\n\n// Define extension point ids\nexport const Extensions = {\n\tEditorModes: 'platform.keybindingsRegistry'\n};\nRegistry.add(Extensions.EditorModes, KeybindingsRegistry);\n\nfunction sorter(a: IKeybindingItem, b: IKeybindingItem): number {\n\tif (a.weight1 !== b.weight1) {\n\t\treturn a.weight1 - b.weight1;\n\t}\n\tif (a.command && b.command) {\n\t\tif (a.command < b.command) {\n\t\t\treturn -1;\n\t\t}\n\t\tif (a.command > b.command) {\n\t\t\treturn 1;\n\t\t}\n\t}\n\treturn a.weight2 - b.weight2;\n}\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\nimport { IAction, SubmenuAction } from 'vs/base/common/actions';\nimport { ThemeIcon } from 'vs/base/common/themables';\nimport { Event, MicrotaskEmitter } from 'vs/base/common/event';\nimport { DisposableStore, dispose, IDisposable, toDisposable } from 'vs/base/common/lifecycle';\nimport { LinkedList } from 'vs/base/common/linkedList';\nimport { ICommandAction, ICommandActionTitle, Icon, ILocalizedString } from 'vs/platform/action/common/action';\nimport { Categories } from 'vs/platform/action/common/actionCommonCategories';\nimport { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands';\nimport { ContextKeyExpr, ContextKeyExpression, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';\nimport { createDecorator, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';\nimport { IKeybindingRule, KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry';\n\nexport interface IMenuItem {\n\tcommand: ICommandAction;\n\talt?: ICommandAction;\n\t/**\n\t * Menu item is hidden if this expression returns false.\n\t */\n\twhen?: ContextKeyExpression;\n\tgroup?: 'navigation' | string;\n\torder?: number;\n\tisHiddenByDefault?: boolean;\n}\n\nexport interface ISubmenuItem {\n\ttitle: string | ICommandActionTitle;\n\tsubmenu: MenuId;\n\ticon?: Icon;\n\twhen?: ContextKeyExpression;\n\tgroup?: 'navigation' | string;\n\torder?: number;\n\tisSelection?: boolean;\n\trememberDefaultAction?: boolean;\t// for dropdown menu: if true the last executed action is remembered as the default action\n}\n\nexport function isIMenuItem(item: any): item is IMenuItem {\n\treturn (item as IMenuItem).command !== undefined;\n}\n\nexport function isISubmenuItem(item: any): item is ISubmenuItem {\n\treturn (item as ISubmenuItem).submenu !== undefined;\n}\n\nexport class MenuId {\n\n\tprivate static readonly _instances = new Map();\n\n\tstatic readonly CommandPalette = new MenuId('CommandPalette');\n\tstatic readonly DebugBreakpointsContext = new MenuId('DebugBreakpointsContext');\n\tstatic readonly DebugCallStackContext = new MenuId('DebugCallStackContext');\n\tstatic readonly DebugConsoleContext = new MenuId('DebugConsoleContext');\n\tstatic readonly DebugVariablesContext = new MenuId('DebugVariablesContext');\n\tstatic readonly NotebookVariablesContext = new MenuId('NotebookVariablesContext');\n\tstatic readonly DebugHoverContext = new MenuId('DebugHoverContext');\n\tstatic readonly DebugWatchContext = new MenuId('DebugWatchContext');\n\tstatic readonly DebugToolBar = new MenuId('DebugToolBar');\n\tstatic readonly DebugToolBarStop = new MenuId('DebugToolBarStop');\n\tstatic readonly EditorContext = new MenuId('EditorContext');\n\tstatic readonly SimpleEditorContext = new MenuId('SimpleEditorContext');\n\tstatic readonly EditorContent = new MenuId('EditorContent');\n\tstatic readonly EditorLineNumberContext = new MenuId('EditorLineNumberContext');\n\tstatic readonly EditorContextCopy = new MenuId('EditorContextCopy');\n\tstatic readonly EditorContextPeek = new MenuId('EditorContextPeek');\n\tstatic readonly EditorContextShare = new MenuId('EditorContextShare');\n\tstatic readonly EditorTitle = new MenuId('EditorTitle');\n\tstatic readonly EditorTitleRun = new MenuId('EditorTitleRun');\n\tstatic readonly EditorTitleContext = new MenuId('EditorTitleContext');\n\tstatic readonly EditorTitleContextShare = new MenuId('EditorTitleContextShare');\n\tstatic readonly EmptyEditorGroup = new MenuId('EmptyEditorGroup');\n\tstatic readonly EmptyEditorGroupContext = new MenuId('EmptyEditorGroupContext');\n\tstatic readonly EditorTabsBarContext = new MenuId('EditorTabsBarContext');\n\tstatic readonly EditorTabsBarShowTabsSubmenu = new MenuId('EditorTabsBarShowTabsSubmenu');\n\tstatic readonly EditorTabsBarShowTabsZenModeSubmenu = new MenuId('EditorTabsBarShowTabsZenModeSubmenu');\n\tstatic readonly EditorActionsPositionSubmenu = new MenuId('EditorActionsPositionSubmenu');\n\tstatic readonly ExplorerContext = new MenuId('ExplorerContext');\n\tstatic readonly ExplorerContextShare = new MenuId('ExplorerContextShare');\n\tstatic readonly ExtensionContext = new MenuId('ExtensionContext');\n\tstatic readonly GlobalActivity = new MenuId('GlobalActivity');\n\tstatic readonly CommandCenter = new MenuId('CommandCenter');\n\tstatic readonly CommandCenterCenter = new MenuId('CommandCenterCenter');\n\tstatic readonly LayoutControlMenuSubmenu = new MenuId('LayoutControlMenuSubmenu');\n\tstatic readonly LayoutControlMenu = new MenuId('LayoutControlMenu');\n\tstatic readonly MenubarMainMenu = new MenuId('MenubarMainMenu');\n\tstatic readonly MenubarAppearanceMenu = new MenuId('MenubarAppearanceMenu');\n\tstatic readonly MenubarDebugMenu = new MenuId('MenubarDebugMenu');\n\tstatic readonly MenubarEditMenu = new MenuId('MenubarEditMenu');\n\tstatic readonly MenubarCopy = new MenuId('MenubarCopy');\n\tstatic readonly MenubarFileMenu = new MenuId('MenubarFileMenu');\n\tstatic readonly MenubarGoMenu = new MenuId('MenubarGoMenu');\n\tstatic readonly MenubarHelpMenu = new MenuId('MenubarHelpMenu');\n\tstatic readonly MenubarLayoutMenu = new MenuId('MenubarLayoutMenu');\n\tstatic readonly MenubarNewBreakpointMenu = new MenuId('MenubarNewBreakpointMenu');\n\tstatic readonly PanelAlignmentMenu = new MenuId('PanelAlignmentMenu');\n\tstatic readonly PanelPositionMenu = new MenuId('PanelPositionMenu');\n\tstatic readonly ActivityBarPositionMenu = new MenuId('ActivityBarPositionMenu');\n\tstatic readonly MenubarPreferencesMenu = new MenuId('MenubarPreferencesMenu');\n\tstatic readonly MenubarRecentMenu = new MenuId('MenubarRecentMenu');\n\tstatic readonly MenubarSelectionMenu = new MenuId('MenubarSelectionMenu');\n\tstatic readonly MenubarShare = new MenuId('MenubarShare');\n\tstatic readonly MenubarSwitchEditorMenu = new MenuId('MenubarSwitchEditorMenu');\n\tstatic readonly MenubarSwitchGroupMenu = new MenuId('MenubarSwitchGroupMenu');\n\tstatic readonly MenubarTerminalMenu = new MenuId('MenubarTerminalMenu');\n\tstatic readonly MenubarViewMenu = new MenuId('MenubarViewMenu');\n\tstatic readonly MenubarHomeMenu = new MenuId('MenubarHomeMenu');\n\tstatic readonly OpenEditorsContext = new MenuId('OpenEditorsContext');\n\tstatic readonly OpenEditorsContextShare = new MenuId('OpenEditorsContextShare');\n\tstatic readonly ProblemsPanelContext = new MenuId('ProblemsPanelContext');\n\tstatic readonly SCMInputBox = new MenuId('SCMInputBox');\n\tstatic readonly SCMChangesSeparator = new MenuId('SCMChangesSeparator');\n\tstatic readonly SCMIncomingChanges = new MenuId('SCMIncomingChanges');\n\tstatic readonly SCMIncomingChangesContext = new MenuId('SCMIncomingChangesContext');\n\tstatic readonly SCMIncomingChangesSetting = new MenuId('SCMIncomingChangesSetting');\n\tstatic readonly SCMOutgoingChanges = new MenuId('SCMOutgoingChanges');\n\tstatic readonly SCMOutgoingChangesContext = new MenuId('SCMOutgoingChangesContext');\n\tstatic readonly SCMOutgoingChangesSetting = new MenuId('SCMOutgoingChangesSetting');\n\tstatic readonly SCMIncomingChangesAllChangesContext = new MenuId('SCMIncomingChangesAllChangesContext');\n\tstatic readonly SCMIncomingChangesHistoryItemContext = new MenuId('SCMIncomingChangesHistoryItemContext');\n\tstatic readonly SCMOutgoingChangesAllChangesContext = new MenuId('SCMOutgoingChangesAllChangesContext');\n\tstatic readonly SCMOutgoingChangesHistoryItemContext = new MenuId('SCMOutgoingChangesHistoryItemContext');\n\tstatic readonly SCMChangeContext = new MenuId('SCMChangeContext');\n\tstatic readonly SCMResourceContext = new MenuId('SCMResourceContext');\n\tstatic readonly SCMResourceContextShare = new MenuId('SCMResourceContextShare');\n\tstatic readonly SCMResourceFolderContext = new MenuId('SCMResourceFolderContext');\n\tstatic readonly SCMResourceGroupContext = new MenuId('SCMResourceGroupContext');\n\tstatic readonly SCMSourceControl = new MenuId('SCMSourceControl');\n\tstatic readonly SCMSourceControlInline = new MenuId('SCMSourceControlInline');\n\tstatic readonly SCMSourceControlTitle = new MenuId('SCMSourceControlTitle');\n\tstatic readonly SCMTitle = new MenuId('SCMTitle');\n\tstatic readonly SearchContext = new MenuId('SearchContext');\n\tstatic readonly SearchActionMenu = new MenuId('SearchActionContext');\n\tstatic readonly StatusBarWindowIndicatorMenu = new MenuId('StatusBarWindowIndicatorMenu');\n\tstatic readonly StatusBarRemoteIndicatorMenu = new MenuId('StatusBarRemoteIndicatorMenu');\n\tstatic readonly StickyScrollContext = new MenuId('StickyScrollContext');\n\tstatic readonly TestItem = new MenuId('TestItem');\n\tstatic readonly TestItemGutter = new MenuId('TestItemGutter');\n\tstatic readonly TestMessageContext = new MenuId('TestMessageContext');\n\tstatic readonly TestMessageContent = new MenuId('TestMessageContent');\n\tstatic readonly TestPeekElement = new MenuId('TestPeekElement');\n\tstatic readonly TestPeekTitle = new MenuId('TestPeekTitle');\n\tstatic readonly TouchBarContext = new MenuId('TouchBarContext');\n\tstatic readonly TitleBarContext = new MenuId('TitleBarContext');\n\tstatic readonly TitleBarTitleContext = new MenuId('TitleBarTitleContext');\n\tstatic readonly TunnelContext = new MenuId('TunnelContext');\n\tstatic readonly TunnelPrivacy = new MenuId('TunnelPrivacy');\n\tstatic readonly TunnelProtocol = new MenuId('TunnelProtocol');\n\tstatic readonly TunnelPortInline = new MenuId('TunnelInline');\n\tstatic readonly TunnelTitle = new MenuId('TunnelTitle');\n\tstatic readonly TunnelLocalAddressInline = new MenuId('TunnelLocalAddressInline');\n\tstatic readonly TunnelOriginInline = new MenuId('TunnelOriginInline');\n\tstatic readonly ViewItemContext = new MenuId('ViewItemContext');\n\tstatic readonly ViewContainerTitle = new MenuId('ViewContainerTitle');\n\tstatic readonly ViewContainerTitleContext = new MenuId('ViewContainerTitleContext');\n\tstatic readonly ViewTitle = new MenuId('ViewTitle');\n\tstatic readonly ViewTitleContext = new MenuId('ViewTitleContext');\n\tstatic readonly CommentEditorActions = new MenuId('CommentEditorActions');\n\tstatic readonly CommentThreadTitle = new MenuId('CommentThreadTitle');\n\tstatic readonly CommentThreadActions = new MenuId('CommentThreadActions');\n\tstatic readonly CommentThreadAdditionalActions = new MenuId('CommentThreadAdditionalActions');\n\tstatic readonly CommentThreadTitleContext = new MenuId('CommentThreadTitleContext');\n\tstatic readonly CommentThreadCommentContext = new MenuId('CommentThreadCommentContext');\n\tstatic readonly CommentTitle = new MenuId('CommentTitle');\n\tstatic readonly CommentActions = new MenuId('CommentActions');\n\tstatic readonly CommentsViewThreadActions = new MenuId('CommentsViewThreadActions');\n\tstatic readonly InteractiveToolbar = new MenuId('InteractiveToolbar');\n\tstatic readonly InteractiveCellTitle = new MenuId('InteractiveCellTitle');\n\tstatic readonly InteractiveCellDelete = new MenuId('InteractiveCellDelete');\n\tstatic readonly InteractiveCellExecute = new MenuId('InteractiveCellExecute');\n\tstatic readonly InteractiveInputExecute = new MenuId('InteractiveInputExecute');\n\tstatic readonly IssueReporter = new MenuId('IssueReporter');\n\tstatic readonly NotebookToolbar = new MenuId('NotebookToolbar');\n\tstatic readonly NotebookStickyScrollContext = new MenuId('NotebookStickyScrollContext');\n\tstatic readonly NotebookCellTitle = new MenuId('NotebookCellTitle');\n\tstatic readonly NotebookCellDelete = new MenuId('NotebookCellDelete');\n\tstatic readonly NotebookCellInsert = new MenuId('NotebookCellInsert');\n\tstatic readonly NotebookCellBetween = new MenuId('NotebookCellBetween');\n\tstatic readonly NotebookCellListTop = new MenuId('NotebookCellTop');\n\tstatic readonly NotebookCellExecute = new MenuId('NotebookCellExecute');\n\tstatic readonly NotebookCellExecuteGoTo = new MenuId('NotebookCellExecuteGoTo');\n\tstatic readonly NotebookCellExecutePrimary = new MenuId('NotebookCellExecutePrimary');\n\tstatic readonly NotebookDiffCellInputTitle = new MenuId('NotebookDiffCellInputTitle');\n\tstatic readonly NotebookDiffCellMetadataTitle = new MenuId('NotebookDiffCellMetadataTitle');\n\tstatic readonly NotebookDiffCellOutputsTitle = new MenuId('NotebookDiffCellOutputsTitle');\n\tstatic readonly NotebookOutputToolbar = new MenuId('NotebookOutputToolbar');\n\tstatic readonly NotebookOutlineFilter = new MenuId('NotebookOutlineFilter');\n\tstatic readonly NotebookOutlineActionMenu = new MenuId('NotebookOutlineActionMenu');\n\tstatic readonly NotebookEditorLayoutConfigure = new MenuId('NotebookEditorLayoutConfigure');\n\tstatic readonly NotebookKernelSource = new MenuId('NotebookKernelSource');\n\tstatic readonly BulkEditTitle = new MenuId('BulkEditTitle');\n\tstatic readonly BulkEditContext = new MenuId('BulkEditContext');\n\tstatic readonly TimelineItemContext = new MenuId('TimelineItemContext');\n\tstatic readonly TimelineTitle = new MenuId('TimelineTitle');\n\tstatic readonly TimelineTitleContext = new MenuId('TimelineTitleContext');\n\tstatic readonly TimelineFilterSubMenu = new MenuId('TimelineFilterSubMenu');\n\tstatic readonly AccountsContext = new MenuId('AccountsContext');\n\tstatic readonly SidebarTitle = new MenuId('SidebarTitle');\n\tstatic readonly PanelTitle = new MenuId('PanelTitle');\n\tstatic readonly AuxiliaryBarTitle = new MenuId('AuxiliaryBarTitle');\n\tstatic readonly AuxiliaryBarHeader = new MenuId('AuxiliaryBarHeader');\n\tstatic readonly TerminalInstanceContext = new MenuId('TerminalInstanceContext');\n\tstatic readonly TerminalEditorInstanceContext = new MenuId('TerminalEditorInstanceContext');\n\tstatic readonly TerminalNewDropdownContext = new MenuId('TerminalNewDropdownContext');\n\tstatic readonly TerminalTabContext = new MenuId('TerminalTabContext');\n\tstatic readonly TerminalTabEmptyAreaContext = new MenuId('TerminalTabEmptyAreaContext');\n\tstatic readonly TerminalStickyScrollContext = new MenuId('TerminalStickyScrollContext');\n\tstatic readonly WebviewContext = new MenuId('WebviewContext');\n\tstatic readonly InlineCompletionsActions = new MenuId('InlineCompletionsActions');\n\tstatic readonly InlineEditActions = new MenuId('InlineEditActions');\n\tstatic readonly NewFile = new MenuId('NewFile');\n\tstatic readonly MergeInput1Toolbar = new MenuId('MergeToolbar1Toolbar');\n\tstatic readonly MergeInput2Toolbar = new MenuId('MergeToolbar2Toolbar');\n\tstatic readonly MergeBaseToolbar = new MenuId('MergeBaseToolbar');\n\tstatic readonly MergeInputResultToolbar = new MenuId('MergeToolbarResultToolbar');\n\tstatic readonly InlineSuggestionToolbar = new MenuId('InlineSuggestionToolbar');\n\tstatic readonly InlineEditToolbar = new MenuId('InlineEditToolbar');\n\tstatic readonly ChatContext = new MenuId('ChatContext');\n\tstatic readonly ChatCodeBlock = new MenuId('ChatCodeblock');\n\tstatic readonly ChatCompareBlock = new MenuId('ChatCompareBlock');\n\tstatic readonly ChatMessageTitle = new MenuId('ChatMessageTitle');\n\tstatic readonly ChatExecute = new MenuId('ChatExecute');\n\tstatic readonly ChatExecuteSecondary = new MenuId('ChatExecuteSecondary');\n\tstatic readonly ChatInputSide = new MenuId('ChatInputSide');\n\tstatic readonly AccessibleView = new MenuId('AccessibleView');\n\tstatic readonly MultiDiffEditorFileToolbar = new MenuId('MultiDiffEditorFileToolbar');\n\tstatic readonly DiffEditorHunkToolbar = new MenuId('DiffEditorHunkToolbar');\n\tstatic readonly DiffEditorSelectionToolbar = new MenuId('DiffEditorSelectionToolbar');\n\n\treadonly id: string;\n\n\t/**\n\t * Create a new `MenuId` with the unique identifier. Will throw if a menu\n\t * with the identifier already exists, use `MenuId.for(ident)` or a unique\n\t * identifier\n\t */\n\tconstructor(identifier: string) {\n\t\tif (MenuId._instances.has(identifier)) {\n\t\t\tthrow new TypeError(`MenuId with identifier '${identifier}' already exists. Use MenuId.for(ident) or a unique identifier`);\n\t\t}\n\t\tMenuId._instances.set(identifier, this);\n\t\tthis.id = identifier;\n\t}\n}\n\nexport interface IMenuActionOptions {\n\targ?: any;\n\tshouldForwardArgs?: boolean;\n\trenderShortTitle?: boolean;\n}\n\nexport interface IMenuChangeEvent {\n\treadonly menu: IMenu;\n\treadonly isStructuralChange: boolean;\n\treadonly isToggleChange: boolean;\n\treadonly isEnablementChange: boolean;\n}\n\nexport interface IMenu extends IDisposable {\n\treadonly onDidChange: Event;\n\tgetActions(options?: IMenuActionOptions): [string, Array][];\n}\n\nexport const IMenuService = createDecorator('menuService');\n\nexport interface IMenuCreateOptions {\n\temitEventsForSubmenuChanges?: boolean;\n\teventDebounceDelay?: number;\n}\n\nexport interface IMenuService {\n\n\treadonly _serviceBrand: undefined;\n\n\t/**\n\t * Create a new menu for the given menu identifier. A menu sends events when it's entries\n\t * have changed (placement, enablement, checked-state). By default it does not send events for\n\t * submenu entries. That is more expensive and must be explicitly enabled with the\n\t * `emitEventsForSubmenuChanges` flag.\n\t */\n\tcreateMenu(id: MenuId, contextKeyService: IContextKeyService, options?: IMenuCreateOptions): IMenu;\n\n\t/**\n\t * Reset **all** menu item hidden states.\n\t */\n\tresetHiddenStates(): void;\n\n\t/**\n\t * Reset the menu's hidden states.\n\t */\n\tresetHiddenStates(menuIds: readonly MenuId[] | undefined): void;\n}\n\ntype ICommandsMap = Map;\n\nexport interface IMenuRegistryChangeEvent {\n\thas(id: MenuId): boolean;\n}\n\nclass MenuRegistryChangeEvent {\n\n\tprivate static _all = new Map();\n\n\tstatic for(id: MenuId): MenuRegistryChangeEvent {\n\t\tlet value = this._all.get(id);\n\t\tif (!value) {\n\t\t\tvalue = new MenuRegistryChangeEvent(id);\n\t\t\tthis._all.set(id, value);\n\t\t}\n\t\treturn value;\n\t}\n\n\tstatic merge(events: IMenuRegistryChangeEvent[]): IMenuRegistryChangeEvent {\n\t\tconst ids = new Set();\n\t\tfor (const item of events) {\n\t\t\tif (item instanceof MenuRegistryChangeEvent) {\n\t\t\t\tids.add(item.id);\n\t\t\t}\n\t\t}\n\t\treturn ids;\n\t}\n\n\treadonly has: (id: MenuId) => boolean;\n\n\tprivate constructor(private readonly id: MenuId) {\n\t\tthis.has = candidate => candidate === id;\n\t}\n}\n\nexport interface IMenuRegistry {\n\treadonly onDidChangeMenu: Event;\n\taddCommand(userCommand: ICommandAction): IDisposable;\n\tappendMenuItem(menu: MenuId, item: IMenuItem | ISubmenuItem): IDisposable;\n\tgetMenuItems(loc: MenuId): Array;\n}\n\nexport const MenuRegistry: IMenuRegistry = new class implements IMenuRegistry {\n\n\tprivate readonly _commands = new Map();\n\tprivate readonly _menuItems = new Map>();\n\tprivate readonly _onDidChangeMenu = new MicrotaskEmitter({\n\t\tmerge: MenuRegistryChangeEvent.merge\n\t});\n\n\treadonly onDidChangeMenu: Event = this._onDidChangeMenu.event;\n\n\taddCommand(command: ICommandAction): IDisposable {\n\t\tthis._commands.set(command.id, command);\n\t\tthis._onDidChangeMenu.fire(MenuRegistryChangeEvent.for(MenuId.CommandPalette));\n\n\t\treturn toDisposable(() => {\n\t\t\tif (this._commands.delete(command.id)) {\n\t\t\t\tthis._onDidChangeMenu.fire(MenuRegistryChangeEvent.for(MenuId.CommandPalette));\n\t\t\t}\n\t\t});\n\t}\n\n\tgetCommand(id: string): ICommandAction | undefined {\n\t\treturn this._commands.get(id);\n\t}\n\n\tgetCommands(): ICommandsMap {\n\t\tconst map = new Map();\n\t\tthis._commands.forEach((value, key) => map.set(key, value));\n\t\treturn map;\n\t}\n\n\tappendMenuItem(id: MenuId, item: IMenuItem | ISubmenuItem): IDisposable {\n\t\tlet list = this._menuItems.get(id);\n\t\tif (!list) {\n\t\t\tlist = new LinkedList();\n\t\t\tthis._menuItems.set(id, list);\n\t\t}\n\t\tconst rm = list.push(item);\n\t\tthis._onDidChangeMenu.fire(MenuRegistryChangeEvent.for(id));\n\t\treturn toDisposable(() => {\n\t\t\trm();\n\t\t\tthis._onDidChangeMenu.fire(MenuRegistryChangeEvent.for(id));\n\t\t});\n\t}\n\n\tappendMenuItems(items: Iterable<{ id: MenuId; item: IMenuItem | ISubmenuItem }>): IDisposable {\n\t\tconst result = new DisposableStore();\n\t\tfor (const { id, item } of items) {\n\t\t\tresult.add(this.appendMenuItem(id, item));\n\t\t}\n\t\treturn result;\n\t}\n\n\tgetMenuItems(id: MenuId): Array {\n\t\tlet result: Array;\n\t\tif (this._menuItems.has(id)) {\n\t\t\tresult = [...this._menuItems.get(id)!];\n\t\t} else {\n\t\t\tresult = [];\n\t\t}\n\t\tif (id === MenuId.CommandPalette) {\n\t\t\t// CommandPalette is special because it shows\n\t\t\t// all commands by default\n\t\t\tthis._appendImplicitItems(result);\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate _appendImplicitItems(result: Array) {\n\t\tconst set = new Set();\n\n\t\tfor (const item of result) {\n\t\t\tif (isIMenuItem(item)) {\n\t\t\t\tset.add(item.command.id);\n\t\t\t\tif (item.alt) {\n\t\t\t\t\tset.add(item.alt.id);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tthis._commands.forEach((command, id) => {\n\t\t\tif (!set.has(id)) {\n\t\t\t\tresult.push({ command });\n\t\t\t}\n\t\t});\n\t}\n};\n\nexport class SubmenuItemAction extends SubmenuAction {\n\n\tconstructor(\n\t\treadonly item: ISubmenuItem,\n\t\treadonly hideActions: IMenuItemHide | undefined,\n\t\tactions: IAction[],\n\t) {\n\t\tsuper(`submenuitem.${item.submenu.id}`, typeof item.title === 'string' ? item.title : item.title.value, actions, 'submenu');\n\t}\n}\n\nexport interface IMenuItemHide {\n\treadonly isHidden: boolean;\n\treadonly hide: IAction;\n\treadonly toggle: IAction;\n}\n\n// implements IAction, does NOT extend Action, so that no one\n// subscribes to events of Action or modified properties\nexport class MenuItemAction implements IAction {\n\n\tstatic label(action: ICommandAction, options?: IMenuActionOptions): string {\n\t\treturn options?.renderShortTitle && action.shortTitle\n\t\t\t? (typeof action.shortTitle === 'string' ? action.shortTitle : action.shortTitle.value)\n\t\t\t: (typeof action.title === 'string' ? action.title : action.title.value);\n\t}\n\n\treadonly item: ICommandAction;\n\treadonly alt: MenuItemAction | undefined;\n\n\tprivate readonly _options: IMenuActionOptions | undefined;\n\n\treadonly id: string;\n\treadonly label: string;\n\treadonly tooltip: string;\n\treadonly class: string | undefined;\n\treadonly enabled: boolean;\n\treadonly checked?: boolean;\n\n\tconstructor(\n\t\titem: ICommandAction,\n\t\talt: ICommandAction | undefined,\n\t\toptions: IMenuActionOptions | undefined,\n\t\treadonly hideActions: IMenuItemHide | undefined,\n\t\treadonly menuKeybinding: IAction | undefined,\n\t\t@IContextKeyService contextKeyService: IContextKeyService,\n\t\t@ICommandService private _commandService: ICommandService\n\t) {\n\t\tthis.id = item.id;\n\t\tthis.label = MenuItemAction.label(item, options);\n\t\tthis.tooltip = (typeof item.tooltip === 'string' ? item.tooltip : item.tooltip?.value) ?? '';\n\t\tthis.enabled = !item.precondition || contextKeyService.contextMatchesRules(item.precondition);\n\t\tthis.checked = undefined;\n\n\t\tlet icon: ThemeIcon | undefined;\n\n\t\tif (item.toggled) {\n\t\t\tconst toggled = ((item.toggled as { condition: ContextKeyExpression }).condition ? item.toggled : { condition: item.toggled }) as {\n\t\t\t\tcondition: ContextKeyExpression; icon?: Icon; tooltip?: string | ILocalizedString; title?: string | ILocalizedString;\n\t\t\t};\n\t\t\tthis.checked = contextKeyService.contextMatchesRules(toggled.condition);\n\t\t\tif (this.checked && toggled.tooltip) {\n\t\t\t\tthis.tooltip = typeof toggled.tooltip === 'string' ? toggled.tooltip : toggled.tooltip.value;\n\t\t\t}\n\n\t\t\tif (this.checked && ThemeIcon.isThemeIcon(toggled.icon)) {\n\t\t\t\ticon = toggled.icon;\n\t\t\t}\n\n\t\t\tif (this.checked && toggled.title) {\n\t\t\t\tthis.label = typeof toggled.title === 'string' ? toggled.title : toggled.title.value;\n\t\t\t}\n\t\t}\n\n\t\tif (!icon) {\n\t\t\ticon = ThemeIcon.isThemeIcon(item.icon) ? item.icon : undefined;\n\t\t}\n\n\t\tthis.item = item;\n\t\tthis.alt = alt ? new MenuItemAction(alt, undefined, options, hideActions, undefined, contextKeyService, _commandService) : undefined;\n\t\tthis._options = options;\n\t\tthis.class = icon && ThemeIcon.asClassName(icon);\n\n\t}\n\n\trun(...args: any[]): Promise {\n\t\tlet runArgs: any[] = [];\n\n\t\tif (this._options?.arg) {\n\t\t\trunArgs = [...runArgs, this._options.arg];\n\t\t}\n\n\t\tif (this._options?.shouldForwardArgs) {\n\t\t\trunArgs = [...runArgs, ...args];\n\t\t}\n\n\t\treturn this._commandService.executeCommand(this.id, ...runArgs);\n\t}\n}\n\n//#region --- IAction2\n\ntype OneOrN = T | T[];\n\ninterface IAction2CommonOptions extends ICommandAction {\n\t/**\n\t * One or many menu items.\n\t */\n\tmenu?: OneOrN<{ id: MenuId; precondition?: null } & Omit>;\n\n\t/**\n\t * One keybinding.\n\t */\n\tkeybinding?: OneOrN>;\n}\n\ninterface IBaseAction2Options extends IAction2CommonOptions {\n\n\t/**\n\t * This type is used when an action is not going to show up in the command palette.\n\t * In that case, it's able to use a string for the `title` and `category` properties.\n\t */\n\tf1?: false;\n}\n\ninterface ICommandPaletteOptions extends IAction2CommonOptions {\n\n\t/**\n\t * The title of the command that will be displayed in the command palette after the category.\n\t * This overrides {@link ICommandAction.title} to ensure a string isn't used so that the title\n\t * includes the localized value and the original value for users using language packs.\n\t */\n\ttitle: ICommandActionTitle;\n\n\t/**\n\t * The category of the command that will be displayed in the command palette before the title suffixed.\n\t * with a colon This overrides {@link ICommandAction.title} to ensure a string isn't used so that\n\t * the title includes the localized value and the original value for users using language packs.\n\t */\n\tcategory?: keyof typeof Categories | ILocalizedString;\n\n\t/**\n\t * Shorthand to add this command to the command palette. Note: this is not the only way to declare that\n\t * a command should be in the command palette... however, enforcing ILocalizedString in the other scenarios\n\t * is much more challenging and this gets us most of the way there.\n\t */\n\tf1: true;\n}\n\nexport type IAction2Options = ICommandPaletteOptions | IBaseAction2Options;\n\nexport interface IAction2F1RequiredOptions {\n\ttitle: ICommandActionTitle;\n}\n\nexport abstract class Action2 {\n\tconstructor(readonly desc: Readonly) { }\n\tabstract run(accessor: ServicesAccessor, ...args: any[]): void;\n}\n\nexport function registerAction2(ctor: { new(): Action2 }): IDisposable {\n\tconst disposables: IDisposable[] = []; // not using `DisposableStore` to reduce startup perf cost\n\tconst action = new ctor();\n\n\tconst { f1, menu, keybinding, ...command } = action.desc;\n\n\tif (CommandsRegistry.getCommand(command.id)) {\n\t\tthrow new Error(`Cannot register two commands with the same id: ${command.id}`);\n\t}\n\n\t// command\n\tdisposables.push(CommandsRegistry.registerCommand({\n\t\tid: command.id,\n\t\thandler: (accessor, ...args) => action.run(accessor, ...args),\n\t\tmetadata: command.metadata,\n\t}));\n\n\t// menu\n\tif (Array.isArray(menu)) {\n\t\tfor (const item of menu) {\n\t\t\tdisposables.push(MenuRegistry.appendMenuItem(item.id, { command: { ...command, precondition: item.precondition === null ? undefined : command.precondition }, ...item }));\n\t\t}\n\n\t} else if (menu) {\n\t\tdisposables.push(MenuRegistry.appendMenuItem(menu.id, { command: { ...command, precondition: menu.precondition === null ? undefined : command.precondition }, ...menu }));\n\t}\n\tif (f1) {\n\t\tdisposables.push(MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command, when: command.precondition }));\n\t\tdisposables.push(MenuRegistry.addCommand(command));\n\t}\n\n\t// keybinding\n\tif (Array.isArray(keybinding)) {\n\t\tfor (const item of keybinding) {\n\t\t\tdisposables.push(KeybindingsRegistry.registerKeybindingRule({\n\t\t\t\t...item,\n\t\t\t\tid: command.id,\n\t\t\t\twhen: command.precondition ? ContextKeyExpr.and(command.precondition, item.when) : item.when\n\t\t\t}));\n\t\t}\n\t} else if (keybinding) {\n\t\tdisposables.push(KeybindingsRegistry.registerKeybindingRule({\n\t\t\t...keybinding,\n\t\t\tid: command.id,\n\t\t\twhen: command.precondition ? ContextKeyExpr.and(command.precondition, keybinding.when) : keybinding.when\n\t\t}));\n\t}\n\n\treturn {\n\t\tdispose() {\n\t\t\tdispose(disposables);\n\t\t}\n\t};\n}\n//#endregion\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\nimport { alert } from 'vs/base/browser/ui/aria/aria';\nimport { KeyCode, KeyMod } from 'vs/base/common/keyCodes';\nimport { TabFocus } from 'vs/editor/browser/config/tabFocus';\nimport * as nls from 'vs/nls';\nimport { Action2, registerAction2 } from 'vs/platform/actions/common/actions';\nimport { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';\n\nexport class ToggleTabFocusModeAction extends Action2 {\n\n\tpublic static readonly ID = 'editor.action.toggleTabFocusMode';\n\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: ToggleTabFocusModeAction.ID,\n\t\t\ttitle: nls.localize2({ key: 'toggle.tabMovesFocus', comment: ['Turn on/off use of tab key for moving focus around VS Code'] }, 'Toggle Tab Key Moves Focus'),\n\t\t\tprecondition: undefined,\n\t\t\tkeybinding: {\n\t\t\t\tprimary: KeyMod.CtrlCmd | KeyCode.KeyM,\n\t\t\t\tmac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.KeyM },\n\t\t\t\tweight: KeybindingWeight.EditorContrib\n\t\t\t},\n\t\t\tmetadata: {\n\t\t\t\tdescription: nls.localize2('tabMovesFocusDescriptions', \"Determines whether the tab key moves focus around the workbench or inserts the tab character in the current editor. This is also called tab trapping, tab navigation, or tab focus mode.\"),\n\t\t\t},\n\t\t\tf1: true\n\t\t});\n\t}\n\n\tpublic run(): void {\n\t\tconst oldValue = TabFocus.getTabFocusMode();\n\t\tconst newValue = !oldValue;\n\t\tTabFocus.setTabFocusMode(newValue);\n\t\tif (newValue) {\n\t\t\talert(nls.localize('toggle.tabMovesFocus.on', \"Pressing Tab will now move focus to the next focusable element\"));\n\t\t} else {\n\t\t\talert(nls.localize('toggle.tabMovesFocus.off', \"Pressing Tab will now insert the tab character\"));\n\t\t}\n\t}\n}\n\nregisterAction2(ToggleTabFocusModeAction);\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\nimport { IHistoryNavigationWidget } from 'vs/base/browser/history';\nimport { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview';\nimport { FindInput, IFindInputOptions } from 'vs/base/browser/ui/findinput/findInput';\nimport { IReplaceInputOptions, ReplaceInput } from 'vs/base/browser/ui/findinput/replaceInput';\nimport { KeyCode, KeyMod } from 'vs/base/common/keyCodes';\nimport { ContextKeyExpr, IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';\nimport { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';\nimport { localize } from 'vs/nls';\nimport { DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle';\nimport { isActiveElement } from 'vs/base/browser/dom';\n\nexport const historyNavigationVisible = new RawContextKey('suggestWidgetVisible', false, localize('suggestWidgetVisible', \"Whether suggestion are visible\"));\n\nconst HistoryNavigationWidgetFocusContext = 'historyNavigationWidgetFocus';\nconst HistoryNavigationForwardsEnablementContext = 'historyNavigationForwardsEnabled';\nconst HistoryNavigationBackwardsEnablementContext = 'historyNavigationBackwardsEnabled';\n\nexport interface IHistoryNavigationContext extends IDisposable {\n\thistoryNavigationForwardsEnablement: IContextKey;\n\thistoryNavigationBackwardsEnablement: IContextKey;\n}\n\nlet lastFocusedWidget: IHistoryNavigationWidget | undefined = undefined;\nconst widgets: IHistoryNavigationWidget[] = [];\n\nexport function registerAndCreateHistoryNavigationContext(scopedContextKeyService: IContextKeyService, widget: IHistoryNavigationWidget): IHistoryNavigationContext {\n\tif (widgets.includes(widget)) {\n\t\tthrow new Error('Cannot register the same widget multiple times');\n\t}\n\n\twidgets.push(widget);\n\tconst disposableStore = new DisposableStore();\n\tconst historyNavigationWidgetFocus = new RawContextKey(HistoryNavigationWidgetFocusContext, false).bindTo(scopedContextKeyService);\n\tconst historyNavigationForwardsEnablement = new RawContextKey(HistoryNavigationForwardsEnablementContext, true).bindTo(scopedContextKeyService);\n\tconst historyNavigationBackwardsEnablement = new RawContextKey(HistoryNavigationBackwardsEnablementContext, true).bindTo(scopedContextKeyService);\n\n\tconst onDidFocus = () => {\n\t\thistoryNavigationWidgetFocus.set(true);\n\t\tlastFocusedWidget = widget;\n\t};\n\n\tconst onDidBlur = () => {\n\t\thistoryNavigationWidgetFocus.set(false);\n\t\tif (lastFocusedWidget === widget) {\n\t\t\tlastFocusedWidget = undefined;\n\t\t}\n\t};\n\n\t// Check for currently being focused\n\tif (isActiveElement(widget.element)) {\n\t\tonDidFocus();\n\t}\n\n\tdisposableStore.add(widget.onDidFocus(() => onDidFocus()));\n\tdisposableStore.add(widget.onDidBlur(() => onDidBlur()));\n\tdisposableStore.add(toDisposable(() => {\n\t\twidgets.splice(widgets.indexOf(widget), 1);\n\t\tonDidBlur();\n\t}));\n\n\treturn {\n\t\thistoryNavigationForwardsEnablement,\n\t\thistoryNavigationBackwardsEnablement,\n\t\tdispose() {\n\t\t\tdisposableStore.dispose();\n\t\t}\n\t};\n}\n\nexport class ContextScopedFindInput extends FindInput {\n\n\tconstructor(container: HTMLElement | null, contextViewProvider: IContextViewProvider, options: IFindInputOptions,\n\t\t@IContextKeyService contextKeyService: IContextKeyService\n\t) {\n\t\tsuper(container, contextViewProvider, options);\n\t\tconst scopedContextKeyService = this._register(contextKeyService.createScoped(this.inputBox.element));\n\t\tthis._register(registerAndCreateHistoryNavigationContext(scopedContextKeyService, this.inputBox));\n\t}\n}\n\nexport class ContextScopedReplaceInput extends ReplaceInput {\n\n\tconstructor(container: HTMLElement | null, contextViewProvider: IContextViewProvider | undefined, options: IReplaceInputOptions,\n\t\t@IContextKeyService contextKeyService: IContextKeyService, showReplaceOptions: boolean = false\n\t) {\n\t\tsuper(container, contextViewProvider, showReplaceOptions, options);\n\t\tconst scopedContextKeyService = this._register(contextKeyService.createScoped(this.inputBox.element));\n\t\tthis._register(registerAndCreateHistoryNavigationContext(scopedContextKeyService, this.inputBox));\n\t}\n\n}\n\nKeybindingsRegistry.registerCommandAndKeybindingRule({\n\tid: 'history.showPrevious',\n\tweight: KeybindingWeight.WorkbenchContrib,\n\twhen: ContextKeyExpr.and(\n\t\tContextKeyExpr.has(HistoryNavigationWidgetFocusContext),\n\t\tContextKeyExpr.equals(HistoryNavigationBackwardsEnablementContext, true),\n\t\tContextKeyExpr.not('isComposing'),\n\t\thistoryNavigationVisible.isEqualTo(false),\n\t),\n\tprimary: KeyCode.UpArrow,\n\tsecondary: [KeyMod.Alt | KeyCode.UpArrow],\n\thandler: (accessor) => {\n\t\tlastFocusedWidget?.showPreviousValue();\n\t}\n});\n\nKeybindingsRegistry.registerCommandAndKeybindingRule({\n\tid: 'history.showNext',\n\tweight: KeybindingWeight.WorkbenchContrib,\n\twhen: ContextKeyExpr.and(\n\t\tContextKeyExpr.has(HistoryNavigationWidgetFocusContext),\n\t\tContextKeyExpr.equals(HistoryNavigationForwardsEnablementContext, true),\n\t\tContextKeyExpr.not('isComposing'),\n\t\thistoryNavigationVisible.isEqualTo(false),\n\t),\n\tprimary: KeyCode.DownArrow,\n\tsecondary: [KeyMod.Alt | KeyCode.DownArrow],\n\thandler: (accessor) => {\n\t\tlastFocusedWidget?.showNextValue();\n\t}\n});\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\nimport { CancellationToken } from 'vs/base/common/cancellation';\nimport { CancellationError, isCancellationError, onUnexpectedExternalError } from 'vs/base/common/errors';\nimport { FuzzyScore } from 'vs/base/common/filters';\nimport { DisposableStore, IDisposable, isDisposable } from 'vs/base/common/lifecycle';\nimport { StopWatch } from 'vs/base/common/stopwatch';\nimport { assertType } from 'vs/base/common/types';\nimport { URI } from 'vs/base/common/uri';\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\nimport { IPosition, Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\nimport { IEditorContribution } from 'vs/editor/common/editorCommon';\nimport { ITextModel } from 'vs/editor/common/model';\nimport * as languages from 'vs/editor/common/languages';\nimport { ITextModelService } from 'vs/editor/common/services/resolverService';\nimport { SnippetParser } from 'vs/editor/contrib/snippet/browser/snippetParser';\nimport { localize } from 'vs/nls';\nimport { MenuId } from 'vs/platform/actions/common/actions';\nimport { CommandsRegistry } from 'vs/platform/commands/common/commands';\nimport { RawContextKey } from 'vs/platform/contextkey/common/contextkey';\nimport { LanguageFeatureRegistry } from 'vs/editor/common/languageFeatureRegistry';\nimport { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';\nimport { historyNavigationVisible } from 'vs/platform/history/browser/contextScopedHistoryWidget';\nimport { InternalQuickSuggestionsOptions, QuickSuggestionsValue } from 'vs/editor/common/config/editorOptions';\nimport { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';\nimport { StandardTokenType } from 'vs/editor/common/encodedTokenAttributes';\n\nexport const Context = {\n\tVisible: historyNavigationVisible,\n\tHasFocusedSuggestion: new RawContextKey('suggestWidgetHasFocusedSuggestion', false, localize('suggestWidgetHasSelection', \"Whether any suggestion is focused\")),\n\tDetailsVisible: new RawContextKey('suggestWidgetDetailsVisible', false, localize('suggestWidgetDetailsVisible', \"Whether suggestion details are visible\")),\n\tMultipleSuggestions: new RawContextKey('suggestWidgetMultipleSuggestions', false, localize('suggestWidgetMultipleSuggestions', \"Whether there are multiple suggestions to pick from\")),\n\tMakesTextEdit: new RawContextKey('suggestionMakesTextEdit', true, localize('suggestionMakesTextEdit', \"Whether inserting the current suggestion yields in a change or has everything already been typed\")),\n\tAcceptSuggestionsOnEnter: new RawContextKey('acceptSuggestionOnEnter', true, localize('acceptSuggestionOnEnter', \"Whether suggestions are inserted when pressing Enter\")),\n\tHasInsertAndReplaceRange: new RawContextKey('suggestionHasInsertAndReplaceRange', false, localize('suggestionHasInsertAndReplaceRange', \"Whether the current suggestion has insert and replace behaviour\")),\n\tInsertMode: new RawContextKey<'insert' | 'replace'>('suggestionInsertMode', undefined, { type: 'string', description: localize('suggestionInsertMode', \"Whether the default behaviour is to insert or replace\") }),\n\tCanResolve: new RawContextKey('suggestionCanResolve', false, localize('suggestionCanResolve', \"Whether the current suggestion supports to resolve further details\")),\n};\n\nexport const suggestWidgetStatusbarMenu = new MenuId('suggestWidgetStatusBar');\n\nexport class CompletionItem {\n\n\t//\n\treadonly editStart: IPosition;\n\treadonly editInsertEnd: IPosition;\n\treadonly editReplaceEnd: IPosition;\n\n\t//\n\treadonly textLabel: string;\n\n\t// perf\n\treadonly labelLow: string;\n\treadonly sortTextLow?: string;\n\treadonly filterTextLow?: string;\n\n\t// validation\n\treadonly isInvalid: boolean = false;\n\n\t// sorting, filtering\n\tscore: FuzzyScore = FuzzyScore.Default;\n\tdistance: number = 0;\n\tidx?: number;\n\tword?: string;\n\n\t// instrumentation\n\treadonly extensionId?: ExtensionIdentifier;\n\n\t// resolving\n\tprivate _resolveDuration?: number;\n\tprivate _resolveCache?: Promise;\n\n\tconstructor(\n\t\treadonly position: IPosition,\n\t\treadonly completion: languages.CompletionItem,\n\t\treadonly container: languages.CompletionList,\n\t\treadonly provider: languages.CompletionItemProvider,\n\t) {\n\t\tthis.textLabel = typeof completion.label === 'string'\n\t\t\t? completion.label\n\t\t\t: completion.label?.label;\n\n\t\t// ensure lower-variants (perf)\n\t\tthis.labelLow = this.textLabel.toLowerCase();\n\n\t\t// validate label\n\t\tthis.isInvalid = !this.textLabel;\n\n\t\tthis.sortTextLow = completion.sortText && completion.sortText.toLowerCase();\n\t\tthis.filterTextLow = completion.filterText && completion.filterText.toLowerCase();\n\n\t\tthis.extensionId = completion.extensionId;\n\n\t\t// normalize ranges\n\t\tif (Range.isIRange(completion.range)) {\n\t\t\tthis.editStart = new Position(completion.range.startLineNumber, completion.range.startColumn);\n\t\t\tthis.editInsertEnd = new Position(completion.range.endLineNumber, completion.range.endColumn);\n\t\t\tthis.editReplaceEnd = new Position(completion.range.endLineNumber, completion.range.endColumn);\n\n\t\t\t// validate range\n\t\t\tthis.isInvalid = this.isInvalid\n\t\t\t\t|| Range.spansMultipleLines(completion.range) || completion.range.startLineNumber !== position.lineNumber;\n\n\t\t} else {\n\t\t\tthis.editStart = new Position(completion.range.insert.startLineNumber, completion.range.insert.startColumn);\n\t\t\tthis.editInsertEnd = new Position(completion.range.insert.endLineNumber, completion.range.insert.endColumn);\n\t\t\tthis.editReplaceEnd = new Position(completion.range.replace.endLineNumber, completion.range.replace.endColumn);\n\n\t\t\t// validate ranges\n\t\t\tthis.isInvalid = this.isInvalid\n\t\t\t\t|| Range.spansMultipleLines(completion.range.insert) || Range.spansMultipleLines(completion.range.replace)\n\t\t\t\t|| completion.range.insert.startLineNumber !== position.lineNumber || completion.range.replace.startLineNumber !== position.lineNumber\n\t\t\t\t|| completion.range.insert.startColumn !== completion.range.replace.startColumn;\n\t\t}\n\n\t\t// create the suggestion resolver\n\t\tif (typeof provider.resolveCompletionItem !== 'function') {\n\t\t\tthis._resolveCache = Promise.resolve();\n\t\t\tthis._resolveDuration = 0;\n\t\t}\n\t}\n\n\t// ---- resolving\n\n\tget isResolved(): boolean {\n\t\treturn this._resolveDuration !== undefined;\n\t}\n\n\tget resolveDuration(): number {\n\t\treturn this._resolveDuration !== undefined ? this._resolveDuration : -1;\n\t}\n\n\tasync resolve(token: CancellationToken) {\n\t\tif (!this._resolveCache) {\n\t\t\tconst sub = token.onCancellationRequested(() => {\n\t\t\t\tthis._resolveCache = undefined;\n\t\t\t\tthis._resolveDuration = undefined;\n\t\t\t});\n\t\t\tconst sw = new StopWatch(true);\n\t\t\tthis._resolveCache = Promise.resolve(this.provider.resolveCompletionItem!(this.completion, token)).then(value => {\n\t\t\t\tObject.assign(this.completion, value);\n\t\t\t\tthis._resolveDuration = sw.elapsed();\n\t\t\t}, err => {\n\t\t\t\tif (isCancellationError(err)) {\n\t\t\t\t\t// the IPC queue will reject the request with the\n\t\t\t\t\t// cancellation error -> reset cached\n\t\t\t\t\tthis._resolveCache = undefined;\n\t\t\t\t\tthis._resolveDuration = undefined;\n\t\t\t\t}\n\t\t\t}).finally(() => {\n\t\t\t\tsub.dispose();\n\t\t\t});\n\t\t}\n\t\treturn this._resolveCache;\n\t}\n}\n\nexport const enum SnippetSortOrder {\n\tTop, Inline, Bottom\n}\n\nexport class CompletionOptions {\n\n\tstatic readonly default = new CompletionOptions();\n\n\tconstructor(\n\t\treadonly snippetSortOrder = SnippetSortOrder.Bottom,\n\t\treadonly kindFilter = new Set(),\n\t\treadonly providerFilter = new Set(),\n\t\treadonly providerItemsToReuse: ReadonlyMap = new Map(),\n\t\treadonly showDeprecated = true\n\t) { }\n}\n\nlet _snippetSuggestSupport: languages.CompletionItemProvider;\n\nexport function getSnippetSuggestSupport(): languages.CompletionItemProvider {\n\treturn _snippetSuggestSupport;\n}\n\nexport interface CompletionDurationEntry {\n\treadonly providerName: string;\n\treadonly elapsedProvider: number;\n\treadonly elapsedOverall: number;\n}\n\nexport interface CompletionDurations {\n\treadonly entries: readonly CompletionDurationEntry[];\n\treadonly elapsed: number;\n}\n\nexport class CompletionItemModel {\n\tconstructor(\n\t\treadonly items: CompletionItem[],\n\t\treadonly needsClipboard: boolean,\n\t\treadonly durations: CompletionDurations,\n\t\treadonly disposable: IDisposable,\n\t) { }\n}\n\nexport async function provideSuggestionItems(\n\tregistry: LanguageFeatureRegistry,\n\tmodel: ITextModel,\n\tposition: Position,\n\toptions: CompletionOptions = CompletionOptions.default,\n\tcontext: languages.CompletionContext = { triggerKind: languages.CompletionTriggerKind.Invoke },\n\ttoken: CancellationToken = CancellationToken.None\n): Promise {\n\n\tconst sw = new StopWatch();\n\tposition = position.clone();\n\n\tconst word = model.getWordAtPosition(position);\n\tconst defaultReplaceRange = word ? new Range(position.lineNumber, word.startColumn, position.lineNumber, word.endColumn) : Range.fromPositions(position);\n\tconst defaultRange = { replace: defaultReplaceRange, insert: defaultReplaceRange.setEndPosition(position.lineNumber, position.column) };\n\n\tconst result: CompletionItem[] = [];\n\tconst disposables = new DisposableStore();\n\tconst durations: CompletionDurationEntry[] = [];\n\tlet needsClipboard = false;\n\n\tconst onCompletionList = (provider: languages.CompletionItemProvider, container: languages.CompletionList | null | undefined, sw: StopWatch): boolean => {\n\t\tlet didAddResult = false;\n\t\tif (!container) {\n\t\t\treturn didAddResult;\n\t\t}\n\t\tfor (const suggestion of container.suggestions) {\n\t\t\tif (!options.kindFilter.has(suggestion.kind)) {\n\t\t\t\t// skip if not showing deprecated suggestions\n\t\t\t\tif (!options.showDeprecated && suggestion?.tags?.includes(languages.CompletionItemTag.Deprecated)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t// fill in default range when missing\n\t\t\t\tif (!suggestion.range) {\n\t\t\t\t\tsuggestion.range = defaultRange;\n\t\t\t\t}\n\t\t\t\t// fill in default sortText when missing\n\t\t\t\tif (!suggestion.sortText) {\n\t\t\t\t\tsuggestion.sortText = typeof suggestion.label === 'string' ? suggestion.label : suggestion.label.label;\n\t\t\t\t}\n\t\t\t\tif (!needsClipboard && suggestion.insertTextRules && suggestion.insertTextRules & languages.CompletionItemInsertTextRule.InsertAsSnippet) {\n\t\t\t\t\tneedsClipboard = SnippetParser.guessNeedsClipboard(suggestion.insertText);\n\t\t\t\t}\n\t\t\t\tresult.push(new CompletionItem(position, suggestion, container, provider));\n\t\t\t\tdidAddResult = true;\n\t\t\t}\n\t\t}\n\t\tif (isDisposable(container)) {\n\t\t\tdisposables.add(container);\n\t\t}\n\t\tdurations.push({\n\t\t\tproviderName: provider._debugDisplayName ?? 'unknown_provider', elapsedProvider: container.duration ?? -1, elapsedOverall: sw.elapsed()\n\t\t});\n\t\treturn didAddResult;\n\t};\n\n\t// ask for snippets in parallel to asking \"real\" providers. Only do something if configured to\n\t// do so - no snippet filter, no special-providers-only request\n\tconst snippetCompletions = (async () => {\n\t\tif (!_snippetSuggestSupport || options.kindFilter.has(languages.CompletionItemKind.Snippet)) {\n\t\t\treturn;\n\t\t}\n\t\t// we have items from a previous session that we can reuse\n\t\tconst reuseItems = options.providerItemsToReuse.get(_snippetSuggestSupport);\n\t\tif (reuseItems) {\n\t\t\treuseItems.forEach(item => result.push(item));\n\t\t\treturn;\n\t\t}\n\t\tif (options.providerFilter.size > 0 && !options.providerFilter.has(_snippetSuggestSupport)) {\n\t\t\treturn;\n\t\t}\n\t\tconst sw = new StopWatch();\n\t\tconst list = await _snippetSuggestSupport.provideCompletionItems(model, position, context, token);\n\t\tonCompletionList(_snippetSuggestSupport, list, sw);\n\t})();\n\n\t// add suggestions from contributed providers - providers are ordered in groups of\n\t// equal score and once a group produces a result the process stops\n\t// get provider groups, always add snippet suggestion provider\n\tfor (const providerGroup of registry.orderedGroups(model)) {\n\n\t\t// for each support in the group ask for suggestions\n\t\tlet didAddResult = false;\n\t\tawait Promise.all(providerGroup.map(async provider => {\n\t\t\t// we have items from a previous session that we can reuse\n\t\t\tif (options.providerItemsToReuse.has(provider)) {\n\t\t\t\tconst items = options.providerItemsToReuse.get(provider)!;\n\t\t\t\titems.forEach(item => result.push(item));\n\t\t\t\tdidAddResult = didAddResult || items.length > 0;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// check if this provider is filtered out\n\t\t\tif (options.providerFilter.size > 0 && !options.providerFilter.has(provider)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst sw = new StopWatch();\n\t\t\t\tconst list = await provider.provideCompletionItems(model, position, context, token);\n\t\t\t\tdidAddResult = onCompletionList(provider, list, sw) || didAddResult;\n\t\t\t} catch (err) {\n\t\t\t\tonUnexpectedExternalError(err);\n\t\t\t}\n\t\t}));\n\n\t\tif (didAddResult || token.isCancellationRequested) {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tawait snippetCompletions;\n\n\tif (token.isCancellationRequested) {\n\t\tdisposables.dispose();\n\t\treturn Promise.reject(new CancellationError());\n\t}\n\n\treturn new CompletionItemModel(\n\t\tresult.sort(getSuggestionComparator(options.snippetSortOrder)),\n\t\tneedsClipboard,\n\t\t{ entries: durations, elapsed: sw.elapsed() },\n\t\tdisposables,\n\t);\n}\n\n\nfunction defaultComparator(a: CompletionItem, b: CompletionItem): number {\n\t// check with 'sortText'\n\tif (a.sortTextLow && b.sortTextLow) {\n\t\tif (a.sortTextLow < b.sortTextLow) {\n\t\t\treturn -1;\n\t\t} else if (a.sortTextLow > b.sortTextLow) {\n\t\t\treturn 1;\n\t\t}\n\t}\n\t// check with 'label'\n\tif (a.textLabel < b.textLabel) {\n\t\treturn -1;\n\t} else if (a.textLabel > b.textLabel) {\n\t\treturn 1;\n\t}\n\t// check with 'type'\n\treturn a.completion.kind - b.completion.kind;\n}\n\nfunction snippetUpComparator(a: CompletionItem, b: CompletionItem): number {\n\tif (a.completion.kind !== b.completion.kind) {\n\t\tif (a.completion.kind === languages.CompletionItemKind.Snippet) {\n\t\t\treturn -1;\n\t\t} else if (b.completion.kind === languages.CompletionItemKind.Snippet) {\n\t\t\treturn 1;\n\t\t}\n\t}\n\treturn defaultComparator(a, b);\n}\n\nfunction snippetDownComparator(a: CompletionItem, b: CompletionItem): number {\n\tif (a.completion.kind !== b.completion.kind) {\n\t\tif (a.completion.kind === languages.CompletionItemKind.Snippet) {\n\t\t\treturn 1;\n\t\t} else if (b.completion.kind === languages.CompletionItemKind.Snippet) {\n\t\t\treturn -1;\n\t\t}\n\t}\n\treturn defaultComparator(a, b);\n}\n\ninterface Comparator { (a: T, b: T): number }\nconst _snippetComparators = new Map>();\n_snippetComparators.set(SnippetSortOrder.Top, snippetUpComparator);\n_snippetComparators.set(SnippetSortOrder.Bottom, snippetDownComparator);\n_snippetComparators.set(SnippetSortOrder.Inline, defaultComparator);\n\nexport function getSuggestionComparator(snippetConfig: SnippetSortOrder): (a: CompletionItem, b: CompletionItem) => number {\n\treturn _snippetComparators.get(snippetConfig)!;\n}\n\nCommandsRegistry.registerCommand('_executeCompletionItemProvider', async (accessor, ...args: [URI, IPosition, string?, number?]) => {\n\tconst [uri, position, triggerCharacter, maxItemsToResolve] = args;\n\tassertType(URI.isUri(uri));\n\tassertType(Position.isIPosition(position));\n\tassertType(typeof triggerCharacter === 'string' || !triggerCharacter);\n\tassertType(typeof maxItemsToResolve === 'number' || !maxItemsToResolve);\n\n\tconst { completionProvider } = accessor.get(ILanguageFeaturesService);\n\tconst ref = await accessor.get(ITextModelService).createModelReference(uri);\n\ttry {\n\n\t\tconst result: languages.CompletionList = {\n\t\t\tincomplete: false,\n\t\t\tsuggestions: []\n\t\t};\n\n\t\tconst resolving: Promise[] = [];\n\t\tconst actualPosition = ref.object.textEditorModel.validatePosition(position);\n\t\tconst completions = await provideSuggestionItems(completionProvider, ref.object.textEditorModel, actualPosition, undefined, { triggerCharacter: triggerCharacter ?? undefined, triggerKind: triggerCharacter ? languages.CompletionTriggerKind.TriggerCharacter : languages.CompletionTriggerKind.Invoke });\n\t\tfor (const item of completions.items) {\n\t\t\tif (resolving.length < (maxItemsToResolve ?? 0)) {\n\t\t\t\tresolving.push(item.resolve(CancellationToken.None));\n\t\t\t}\n\t\t\tresult.incomplete = result.incomplete || item.container.incomplete;\n\t\t\tresult.suggestions.push(item.completion);\n\t\t}\n\n\t\ttry {\n\t\t\tawait Promise.all(resolving);\n\t\t\treturn result;\n\t\t} finally {\n\t\t\tsetTimeout(() => completions.disposable.dispose(), 100);\n\t\t}\n\n\t} finally {\n\t\tref.dispose();\n\t}\n\n});\n\ninterface SuggestController extends IEditorContribution {\n\ttriggerSuggest(onlyFrom?: Set, auto?: boolean, noFilter?: boolean): void;\n}\n\nexport function showSimpleSuggestions(editor: ICodeEditor, provider: languages.CompletionItemProvider) {\n\teditor.getContribution('editor.contrib.suggestController')?.triggerSuggest(\n\t\tnew Set().add(provider), undefined, true\n\t);\n}\n\nexport interface ISuggestItemPreselector {\n\t/**\n\t * The preselector with highest priority is asked first.\n\t*/\n\treadonly priority: number;\n\n\t/**\n\t * Is called to preselect a suggest item.\n\t * When -1 is returned, item preselectors with lower priority are asked.\n\t*/\n\tselect(model: ITextModel, pos: IPosition, items: CompletionItem[]): number | -1;\n}\n\n\nexport abstract class QuickSuggestionsOptions {\n\n\tstatic isAllOff(config: InternalQuickSuggestionsOptions): boolean {\n\t\treturn config.other === 'off' && config.comments === 'off' && config.strings === 'off';\n\t}\n\n\tstatic isAllOn(config: InternalQuickSuggestionsOptions): boolean {\n\t\treturn config.other === 'on' && config.comments === 'on' && config.strings === 'on';\n\t}\n\n\tstatic valueFor(config: InternalQuickSuggestionsOptions, tokenType: StandardTokenType): QuickSuggestionsValue {\n\t\tswitch (tokenType) {\n\t\t\tcase StandardTokenType.Comment: return config.comments;\n\t\t\tcase StandardTokenType.String: return config.strings;\n\t\t\tdefault: return config.other;\n\t\t}\n\t}\n}\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\nimport { KeyCode, KeyMod } from 'vs/base/common/keyCodes';\nimport { isMacintosh } from 'vs/base/common/platform';\nimport { PartialExcept } from 'vs/base/common/types';\nimport { localize } from 'vs/nls';\nimport { ICommandHandler } from 'vs/platform/commands/common/commands';\nimport { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';\nimport { InputFocusedContext } from 'vs/platform/contextkey/common/contextkeys';\nimport { ICommandAndKeybindingRule, KeybindingWeight, KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry';\nimport { endOfQuickInputBoxContext, inQuickInputContext, quickInputTypeContextKeyValue } from 'vs/platform/quickinput/browser/quickInput';\nimport { IQuickInputService, IQuickPick, QuickInputType, QuickPickFocus } from 'vs/platform/quickinput/common/quickInput';\n\nconst defaultCommandAndKeybindingRule = {\n\tweight: KeybindingWeight.WorkbenchContrib,\n\twhen: ContextKeyExpr.and(ContextKeyExpr.equals(quickInputTypeContextKeyValue, QuickInputType.QuickPick), inQuickInputContext),\n\tmetadata: { description: localize('quickPick', \"Used while in the context of the quick pick. If you change one keybinding for this command, you should change all of the other keybindings (modifier variants) of this command as well.\") }\n};\nfunction registerQuickPickCommandAndKeybindingRule(rule: PartialExcept, options: { withAltMod?: boolean; withCtrlMod?: boolean; withCmdMod?: boolean } = {}) {\n\tKeybindingsRegistry.registerCommandAndKeybindingRule({\n\t\t...defaultCommandAndKeybindingRule,\n\t\t...rule,\n\t\tsecondary: getSecondary(rule.primary!, rule.secondary ?? [], options)\n\t});\n}\n\n// This function will generate all the combinations of keybindings for the given primary keybinding\nfunction getSecondary(primary: number, secondary: number[], options: { withAltMod?: boolean; withCtrlMod?: boolean; withCmdMod?: boolean } = {}): number[] {\n\tif (options.withAltMod) {\n\t\tsecondary.push(KeyMod.Alt + primary);\n\t}\n\tconst ctrlKeyMod = isMacintosh ? KeyMod.WinCtrl : KeyMod.CtrlCmd;\n\tif (options.withCtrlMod) {\n\t\tsecondary.push(ctrlKeyMod + primary);\n\t\tif (options.withAltMod) {\n\t\t\tsecondary.push(KeyMod.Alt + ctrlKeyMod + primary);\n\t\t}\n\t}\n\n\tif (options.withCmdMod && isMacintosh) {\n\t\tsecondary.push(KeyMod.CtrlCmd + primary);\n\t\tif (options.withCtrlMod) {\n\t\t\tsecondary.push(KeyMod.CtrlCmd + KeyMod.WinCtrl + primary);\n\t\t}\n\t\tif (options.withAltMod) {\n\t\t\tsecondary.push(KeyMod.CtrlCmd + KeyMod.Alt + primary);\n\t\t\tif (options.withCtrlMod) {\n\t\t\t\tsecondary.push(KeyMod.CtrlCmd + KeyMod.Alt + KeyMod.WinCtrl + primary);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn secondary;\n}\n\n//#region Navigation\n\nfunction focusHandler(focus: QuickPickFocus, focusOnQuickNatigate?: QuickPickFocus): ICommandHandler {\n\treturn accessor => {\n\t\t// Assuming this is a quick pick due to above when clause\n\t\tconst currentQuickPick = accessor.get(IQuickInputService).currentQuickInput as IQuickPick | undefined;\n\t\tif (!currentQuickPick) {\n\t\t\treturn;\n\t\t}\n\t\tif (focusOnQuickNatigate && currentQuickPick.quickNavigate) {\n\t\t\treturn currentQuickPick.focus(focusOnQuickNatigate);\n\t\t}\n\t\treturn currentQuickPick.focus(focus);\n\t};\n}\n\nregisterQuickPickCommandAndKeybindingRule(\n\t{ id: 'quickInput.pageNext', primary: KeyCode.PageDown, handler: focusHandler(QuickPickFocus.NextPage) },\n\t{ withAltMod: true, withCtrlMod: true, withCmdMod: true }\n);\nregisterQuickPickCommandAndKeybindingRule(\n\t{ id: 'quickInput.pagePrevious', primary: KeyCode.PageUp, handler: focusHandler(QuickPickFocus.PreviousPage) },\n\t{ withAltMod: true, withCtrlMod: true, withCmdMod: true }\n);\nregisterQuickPickCommandAndKeybindingRule(\n\t{ id: 'quickInput.first', primary: KeyCode.Home, handler: focusHandler(QuickPickFocus.First) },\n\t{ withAltMod: true, withCtrlMod: true, withCmdMod: true }\n);\nregisterQuickPickCommandAndKeybindingRule(\n\t{ id: 'quickInput.last', primary: KeyCode.End, handler: focusHandler(QuickPickFocus.Last) },\n\t{ withAltMod: true, withCtrlMod: true, withCmdMod: true }\n);\nregisterQuickPickCommandAndKeybindingRule(\n\t{ id: 'quickInput.next', primary: KeyCode.DownArrow, handler: focusHandler(QuickPickFocus.Next) },\n\t{ withCtrlMod: true }\n);\nregisterQuickPickCommandAndKeybindingRule(\n\t{ id: 'quickInput.previous', primary: KeyCode.UpArrow, handler: focusHandler(QuickPickFocus.Previous) },\n\t{ withCtrlMod: true }\n);\n\n// The next & previous separator commands are interesting because if we are in quick access mode, we are already holding a modifier key down.\n// In this case, we want that modifier key+up/down to navigate to the next/previous item, not the next/previous separator.\n// To handle this, we have a separate command for navigating to the next/previous separator when we are not in quick access mode.\n// If, however, we are in quick access mode, and you hold down an additional modifier key, we will navigate to the next/previous separator.\n\nconst nextSeparatorFallbackDesc = localize('quickInput.nextSeparatorWithQuickAccessFallback', \"If we're in quick access mode, this will navigate to the next item. If we are not in quick access mode, this will navigate to the next separator.\");\nconst prevSeparatorFallbackDesc = localize('quickInput.previousSeparatorWithQuickAccessFallback', \"If we're in quick access mode, this will navigate to the previous item. If we are not in quick access mode, this will navigate to the previous separator.\");\nif (isMacintosh) {\n\tregisterQuickPickCommandAndKeybindingRule(\n\t\t{\n\t\t\tid: 'quickInput.nextSeparatorWithQuickAccessFallback',\n\t\t\tprimary: KeyMod.CtrlCmd + KeyCode.DownArrow,\n\t\t\thandler: focusHandler(QuickPickFocus.NextSeparator, QuickPickFocus.Next),\n\t\t\tmetadata: { description: nextSeparatorFallbackDesc }\n\t\t},\n\t);\n\tregisterQuickPickCommandAndKeybindingRule(\n\t\t{\n\t\t\tid: 'quickInput.nextSeparator',\n\t\t\tprimary: KeyMod.CtrlCmd + KeyMod.Alt + KeyCode.DownArrow,\n\t\t\t// Since macOS has the cmd key as the primary modifier, we need to add this additional\n\t\t\t// keybinding to capture cmd+ctrl+upArrow\n\t\t\tsecondary: [KeyMod.CtrlCmd + KeyMod.WinCtrl + KeyCode.DownArrow],\n\t\t\thandler: focusHandler(QuickPickFocus.NextSeparator)\n\t\t},\n\t\t{ withCtrlMod: true }\n\t);\n\n\tregisterQuickPickCommandAndKeybindingRule(\n\t\t{\n\t\t\tid: 'quickInput.previousSeparatorWithQuickAccessFallback',\n\t\t\tprimary: KeyMod.CtrlCmd + KeyCode.UpArrow,\n\t\t\thandler: focusHandler(QuickPickFocus.PreviousSeparator, QuickPickFocus.Previous),\n\t\t\tmetadata: { description: prevSeparatorFallbackDesc }\n\t\t},\n\t);\n\tregisterQuickPickCommandAndKeybindingRule(\n\t\t{\n\t\t\tid: 'quickInput.previousSeparator',\n\t\t\tprimary: KeyMod.CtrlCmd + KeyMod.Alt + KeyCode.UpArrow,\n\t\t\t// Since macOS has the cmd key as the primary modifier, we need to add this additional\n\t\t\t// keybinding to capture cmd+ctrl+upArrow\n\t\t\tsecondary: [KeyMod.CtrlCmd + KeyMod.WinCtrl + KeyCode.UpArrow],\n\t\t\thandler: focusHandler(QuickPickFocus.PreviousSeparator)\n\t\t},\n\t\t{ withCtrlMod: true }\n\t);\n} else {\n\tregisterQuickPickCommandAndKeybindingRule(\n\t\t{\n\t\t\tid: 'quickInput.nextSeparatorWithQuickAccessFallback',\n\t\t\tprimary: KeyMod.Alt + KeyCode.DownArrow,\n\t\t\thandler: focusHandler(QuickPickFocus.NextSeparator, QuickPickFocus.Next),\n\t\t\tmetadata: { description: nextSeparatorFallbackDesc }\n\t\t},\n\t);\n\tregisterQuickPickCommandAndKeybindingRule(\n\t\t{\n\t\t\tid: 'quickInput.nextSeparator',\n\t\t\tprimary: KeyMod.CtrlCmd + KeyMod.Alt + KeyCode.DownArrow,\n\t\t\thandler: focusHandler(QuickPickFocus.NextSeparator)\n\t\t},\n\t);\n\n\tregisterQuickPickCommandAndKeybindingRule(\n\t\t{\n\t\t\tid: 'quickInput.previousSeparatorWithQuickAccessFallback',\n\t\t\tprimary: KeyMod.Alt + KeyCode.UpArrow,\n\t\t\thandler: focusHandler(QuickPickFocus.PreviousSeparator, QuickPickFocus.Previous),\n\t\t\tmetadata: { description: prevSeparatorFallbackDesc }\n\t\t},\n\t);\n\tregisterQuickPickCommandAndKeybindingRule(\n\t\t{\n\t\t\tid: 'quickInput.previousSeparator',\n\t\t\tprimary: KeyMod.CtrlCmd + KeyMod.Alt + KeyCode.UpArrow,\n\t\t\thandler: focusHandler(QuickPickFocus.PreviousSeparator)\n\t\t},\n\t);\n}\n\n//#endregion\n\n//#region Accept\n\nregisterQuickPickCommandAndKeybindingRule(\n\t{\n\t\tid: 'quickInput.acceptInBackground',\n\t\t// If we are in the quick pick but the input box is not focused or our cursor is at the end of the input box\n\t\twhen: ContextKeyExpr.and(defaultCommandAndKeybindingRule.when, ContextKeyExpr.or(InputFocusedContext.negate(), endOfQuickInputBoxContext)),\n\t\tprimary: KeyCode.RightArrow,\n\t\t// Need a little extra weight to ensure this keybinding is preferred over the default cmd+alt+right arrow keybinding\n\t\t// https://github.com/microsoft/vscode/blob/1451e4fbbbf074a4355cc537c35b547b80ce1c52/src/vs/workbench/browser/parts/editor/editorActions.ts#L1178-L1195\n\t\tweight: KeybindingWeight.WorkbenchContrib + 50,\n\t\thandler: (accessor) => {\n\t\t\tconst currentQuickPick = accessor.get(IQuickInputService).currentQuickInput as IQuickPick;\n\t\t\tcurrentQuickPick?.accept(true);\n\t\t},\n\t},\n\t{ withAltMod: true, withCtrlMod: true, withCmdMod: true }\n);\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\nimport { coalesce } from 'vs/base/common/arrays';\nimport { CancellationToken } from 'vs/base/common/cancellation';\nimport { IDisposable, toDisposable } from 'vs/base/common/lifecycle';\nimport { ItemActivation, IQuickNavigateConfiguration, IQuickPick, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';\nimport { Registry } from 'vs/platform/registry/common/platform';\n\n/**\n * Provider specific options for this particular showing of the\n * quick access.\n */\nexport interface IQuickAccessProviderRunOptions {\n\treadonly from?: string;\n\t/**\n\t * A handler to invoke when an item is accepted for\n\t * this particular showing of the quick access.\n\t * @param item The item that was accepted.\n\t */\n\treadonly handleAccept?: (item: IQuickPickItem) => void;\n}\n\nexport interface IQuickAccessOptions {\n\n\t/**\n\t * Allows to enable quick navigate support in quick input.\n\t */\n\treadonly quickNavigateConfiguration?: IQuickNavigateConfiguration;\n\n\t/**\n\t * Allows to configure a different item activation strategy.\n\t * By default the first item in the list will get activated.\n\t */\n\treadonly itemActivation?: ItemActivation;\n\n\t/**\n\t * Whether to take the input value as is and not restore it\n\t * from any existing value if quick access is visible.\n\t */\n\treadonly preserveValue?: boolean;\n\n\t/**\n\t * Provider specific options for this particular showing of the\n\t * quick access.\n\t */\n\treadonly providerOptions?: IQuickAccessProviderRunOptions;\n\n\t/**\n\t * An array of provider prefixes to enable for this\n\t * particular showing of the quick access.\n\t */\n\treadonly enabledProviderPrefixes?: string[];\n\n\t/**\n\t * A placeholder to use for this particular showing of the quick access.\n\t*/\n\treadonly placeholder?: string;\n}\n\nexport interface IQuickAccessController {\n\n\t/**\n\t * Open the quick access picker with the optional value prefilled.\n\t */\n\tshow(value?: string, options?: IQuickAccessOptions): void;\n}\n\nexport enum DefaultQuickAccessFilterValue {\n\n\t/**\n\t * Keep the value as it is given to quick access.\n\t */\n\tPRESERVE = 0,\n\n\t/**\n\t * Use the value that was used last time something was accepted from the picker.\n\t */\n\tLAST = 1\n}\n\nexport interface IQuickAccessProvider {\n\n\t/**\n\t * Allows to set a default filter value when the provider opens. This can be:\n\t * - `undefined` to not specify any default value\n\t * - `DefaultFilterValues.PRESERVE` to use the value that was last typed\n\t * - `string` for the actual value to use\n\t *\n\t * Note: the default filter will only be used if quick access was opened with\n\t * the exact prefix of the provider. Otherwise the filter value is preserved.\n\t */\n\treadonly defaultFilterValue?: string | DefaultQuickAccessFilterValue;\n\n\t/**\n\t * Called whenever a prefix was typed into quick pick that matches the provider.\n\t *\n\t * @param picker the picker to use for showing provider results. The picker is\n\t * automatically shown after the method returns, no need to call `show()`.\n\t * @param token providers have to check the cancellation token everytime after\n\t * a long running operation or from event handlers because it could be that the\n\t * picker has been closed or changed meanwhile. The token can be used to find out\n\t * that the picker was closed without picking an entry (e.g. was canceled by the user).\n\t * @param options additional configuration specific for this provider that will\n\t * influence what picks will be shown.\n\t * @return a disposable that will automatically be disposed when the picker\n\t * closes or is replaced by another picker.\n\t */\n\tprovide(picker: IQuickPick, token: CancellationToken, options?: IQuickAccessProviderRunOptions): IDisposable;\n}\n\nexport interface IQuickAccessProviderHelp {\n\n\t/**\n\t * The prefix to show for the help entry. If not provided,\n\t * the prefix used for registration will be taken.\n\t */\n\treadonly prefix?: string;\n\n\t/**\n\t * A description text to help understand the intent of the provider.\n\t */\n\treadonly description: string;\n\n\t/**\n\t * The command to bring up this quick access provider.\n\t */\n\treadonly commandId?: string;\n}\n\nexport interface IQuickAccessProviderDescriptor {\n\n\t/**\n\t * The actual provider that will be instantiated as needed.\n\t */\n\treadonly ctor: { new(...services: any /* TS BrandedService but no clue how to type this properly */[]): IQuickAccessProvider };\n\n\t/**\n\t * The prefix for quick access picker to use the provider for.\n\t */\n\treadonly prefix: string;\n\n\t/**\n\t * A placeholder to use for the input field when the provider is active.\n\t * This will also be read out by screen readers and thus helps for\n\t * accessibility.\n\t */\n\treadonly placeholder?: string;\n\n\t/**\n\t * Documentation for the provider in the quick access help.\n\t */\n\treadonly helpEntries: IQuickAccessProviderHelp[];\n\n\t/**\n\t * A context key that will be set automatically when the\n\t * picker for the provider is showing.\n\t */\n\treadonly contextKey?: string;\n}\n\nexport const Extensions = {\n\tQuickaccess: 'workbench.contributions.quickaccess'\n};\n\nexport interface IQuickAccessRegistry {\n\n\t/**\n\t * Registers a quick access provider to the platform.\n\t */\n\tregisterQuickAccessProvider(provider: IQuickAccessProviderDescriptor): IDisposable;\n\n\t/**\n\t * Get all registered quick access providers.\n\t */\n\tgetQuickAccessProviders(): IQuickAccessProviderDescriptor[];\n\n\t/**\n\t * Get a specific quick access provider for a given prefix.\n\t */\n\tgetQuickAccessProvider(prefix: string): IQuickAccessProviderDescriptor | undefined;\n}\n\nexport class QuickAccessRegistry implements IQuickAccessRegistry {\n\n\tprivate providers: IQuickAccessProviderDescriptor[] = [];\n\tprivate defaultProvider: IQuickAccessProviderDescriptor | undefined = undefined;\n\n\tregisterQuickAccessProvider(provider: IQuickAccessProviderDescriptor): IDisposable {\n\n\t\t// Extract the default provider when no prefix is present\n\t\tif (provider.prefix.length === 0) {\n\t\t\tthis.defaultProvider = provider;\n\t\t} else {\n\t\t\tthis.providers.push(provider);\n\t\t}\n\n\t\t// sort the providers by decreasing prefix length, such that longer\n\t\t// prefixes take priority: 'ext' vs 'ext install' - the latter should win\n\t\tthis.providers.sort((providerA, providerB) => providerB.prefix.length - providerA.prefix.length);\n\n\t\treturn toDisposable(() => {\n\t\t\tthis.providers.splice(this.providers.indexOf(provider), 1);\n\n\t\t\tif (this.defaultProvider === provider) {\n\t\t\t\tthis.defaultProvider = undefined;\n\t\t\t}\n\t\t});\n\t}\n\n\tgetQuickAccessProviders(): IQuickAccessProviderDescriptor[] {\n\t\treturn coalesce([this.defaultProvider, ...this.providers]);\n\t}\n\n\tgetQuickAccessProvider(prefix: string): IQuickAccessProviderDescriptor | undefined {\n\t\tconst result = prefix ? (this.providers.find(provider => prefix.startsWith(provider.prefix)) || undefined) : undefined;\n\n\t\treturn result || this.defaultProvider;\n\t}\n}\n\nRegistry.add(Extensions.Quickaccess, new QuickAccessRegistry());\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\nimport { localize } from 'vs/nls';\nimport { Registry } from 'vs/platform/registry/common/platform';\nimport { DisposableStore, IDisposable } from 'vs/base/common/lifecycle';\nimport { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';\nimport { Extensions, IQuickAccessProvider, IQuickAccessProviderDescriptor, IQuickAccessRegistry } from 'vs/platform/quickinput/common/quickAccess';\nimport { IQuickInputService, IQuickPick, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';\n\ninterface IHelpQuickAccessPickItem extends IQuickPickItem {\n\treadonly prefix: string;\n}\n\nexport class HelpQuickAccessProvider implements IQuickAccessProvider {\n\n\tstatic PREFIX = '?';\n\n\tprivate readonly registry = Registry.as(Extensions.Quickaccess);\n\n\tconstructor(\n\t\t@IQuickInputService private readonly quickInputService: IQuickInputService,\n\t\t@IKeybindingService private readonly keybindingService: IKeybindingService\n\t) { }\n\n\tprovide(picker: IQuickPick): IDisposable {\n\t\tconst disposables = new DisposableStore();\n\n\t\t// Open a picker with the selected value if picked\n\t\tdisposables.add(picker.onDidAccept(() => {\n\t\t\tconst [item] = picker.selectedItems;\n\t\t\tif (item) {\n\t\t\t\tthis.quickInputService.quickAccess.show(item.prefix, { preserveValue: true });\n\t\t\t}\n\t\t}));\n\n\t\t// Also open a picker when we detect the user typed the exact\n\t\t// name of a provider (e.g. `?term` for terminals)\n\t\tdisposables.add(picker.onDidChangeValue(value => {\n\t\t\tconst providerDescriptor = this.registry.getQuickAccessProvider(value.substr(HelpQuickAccessProvider.PREFIX.length));\n\t\t\tif (providerDescriptor && providerDescriptor.prefix && providerDescriptor.prefix !== HelpQuickAccessProvider.PREFIX) {\n\t\t\t\tthis.quickInputService.quickAccess.show(providerDescriptor.prefix, { preserveValue: true });\n\t\t\t}\n\t\t}));\n\n\t\t// Fill in all providers\n\t\tpicker.items = this.getQuickAccessProviders().filter(p => p.prefix !== HelpQuickAccessProvider.PREFIX);\n\n\t\treturn disposables;\n\t}\n\n\tgetQuickAccessProviders(): IHelpQuickAccessPickItem[] {\n\t\tconst providers: IHelpQuickAccessPickItem[] = this.registry\n\t\t\t.getQuickAccessProviders()\n\t\t\t.sort((providerA, providerB) => providerA.prefix.localeCompare(providerB.prefix))\n\t\t\t.flatMap(provider => this.createPicks(provider));\n\n\t\treturn providers;\n\t}\n\n\tprivate createPicks(provider: IQuickAccessProviderDescriptor): IHelpQuickAccessPickItem[] {\n\t\treturn provider.helpEntries.map(helpEntry => {\n\t\t\tconst prefix = helpEntry.prefix || provider.prefix;\n\t\t\tconst label = prefix || '\\u2026' /* ... */;\n\n\t\t\treturn {\n\t\t\t\tprefix,\n\t\t\t\tlabel,\n\t\t\t\tkeybinding: helpEntry.commandId ? this.keybindingService.lookupKeybinding(helpEntry.commandId) : undefined,\n\t\t\t\tariaLabel: localize('helpPickAriaLabel', \"{0}, {1}\", label, helpEntry.description),\n\t\t\t\tdescription: helpEntry.description\n\t\t\t};\n\t\t});\n\t}\n}\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\nimport { Registry } from 'vs/platform/registry/common/platform';\nimport { IQuickAccessRegistry, Extensions } from 'vs/platform/quickinput/common/quickAccess';\nimport { QuickHelpNLS } from 'vs/editor/common/standaloneStrings';\nimport { HelpQuickAccessProvider } from 'vs/platform/quickinput/browser/helpQuickAccess';\n\nRegistry.as(Extensions.Quickaccess).registerQuickAccessProvider({\n\tctor: HelpQuickAccessProvider,\n\tprefix: '',\n\thelpEntries: [{ description: QuickHelpNLS.helpQuickAccessActionLabel }]\n});\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\nimport { DeferredPromise } from 'vs/base/common/async';\nimport { CancellationTokenSource } from 'vs/base/common/cancellation';\nimport { Event } from 'vs/base/common/event';\nimport { Disposable, DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle';\nimport { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';\nimport { DefaultQuickAccessFilterValue, Extensions, IQuickAccessController, IQuickAccessOptions, IQuickAccessProvider, IQuickAccessProviderDescriptor, IQuickAccessRegistry } from 'vs/platform/quickinput/common/quickAccess';\nimport { IQuickInputService, IQuickPick, IQuickPickItem, ItemActivation } from 'vs/platform/quickinput/common/quickInput';\nimport { Registry } from 'vs/platform/registry/common/platform';\n\nexport class QuickAccessController extends Disposable implements IQuickAccessController {\n\n\tprivate readonly registry = Registry.as(Extensions.Quickaccess);\n\tprivate readonly mapProviderToDescriptor = new Map();\n\n\tprivate readonly lastAcceptedPickerValues = new Map();\n\n\tprivate visibleQuickAccess: {\n\t\treadonly picker: IQuickPick;\n\t\treadonly descriptor: IQuickAccessProviderDescriptor | undefined;\n\t\treadonly value: string;\n\t} | undefined = undefined;\n\n\tconstructor(\n\t\t@IQuickInputService private readonly quickInputService: IQuickInputService,\n\t\t@IInstantiationService private readonly instantiationService: IInstantiationService\n\t) {\n\t\tsuper();\n\t}\n\n\tshow(value = '', options?: IQuickAccessOptions): void {\n\t\tthis.doShowOrPick(value, false, options);\n\t}\n\n\tprivate doShowOrPick(value: string, pick: true, options?: IQuickAccessOptions): Promise;\n\tprivate doShowOrPick(value: string, pick: false, options?: IQuickAccessOptions): void;\n\tprivate doShowOrPick(value: string, pick: boolean, options?: IQuickAccessOptions): Promise | void {\n\n\t\t// Find provider for the value to show\n\t\tconst [provider, descriptor] = this.getOrInstantiateProvider(value, options?.enabledProviderPrefixes);\n\n\t\t// Return early if quick access is already showing on that same prefix\n\t\tconst visibleQuickAccess = this.visibleQuickAccess;\n\t\tconst visibleDescriptor = visibleQuickAccess?.descriptor;\n\t\tif (visibleQuickAccess && descriptor && visibleDescriptor === descriptor) {\n\n\t\t\t// Apply value only if it is more specific than the prefix\n\t\t\t// from the provider and we are not instructed to preserve\n\t\t\tif (value !== descriptor.prefix && !options?.preserveValue) {\n\t\t\t\tvisibleQuickAccess.picker.value = value;\n\t\t\t}\n\n\t\t\t// Always adjust selection\n\t\t\tthis.adjustValueSelection(visibleQuickAccess.picker, descriptor, options);\n\n\t\t\treturn;\n\t\t}\n\n\t\t// Rewrite the filter value based on certain rules unless disabled\n\t\tif (descriptor && !options?.preserveValue) {\n\t\t\tlet newValue: string | undefined = undefined;\n\n\t\t\t// If we have a visible provider with a value, take it's filter value but\n\t\t\t// rewrite to new provider prefix in case they differ\n\t\t\tif (visibleQuickAccess && visibleDescriptor && visibleDescriptor !== descriptor) {\n\t\t\t\tconst newValueCandidateWithoutPrefix = visibleQuickAccess.value.substr(visibleDescriptor.prefix.length);\n\t\t\t\tif (newValueCandidateWithoutPrefix) {\n\t\t\t\t\tnewValue = `${descriptor.prefix}${newValueCandidateWithoutPrefix}`;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Otherwise, take a default value as instructed\n\t\t\tif (!newValue) {\n\t\t\t\tconst defaultFilterValue = provider?.defaultFilterValue;\n\t\t\t\tif (defaultFilterValue === DefaultQuickAccessFilterValue.LAST) {\n\t\t\t\t\tnewValue = this.lastAcceptedPickerValues.get(descriptor);\n\t\t\t\t} else if (typeof defaultFilterValue === 'string') {\n\t\t\t\t\tnewValue = `${descriptor.prefix}${defaultFilterValue}`;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (typeof newValue === 'string') {\n\t\t\t\tvalue = newValue;\n\t\t\t}\n\t\t}\n\n\t\t// Store the existing selection if there was one.\n\t\tconst visibleSelection = visibleQuickAccess?.picker?.valueSelection;\n\t\tconst visibleValue = visibleQuickAccess?.picker?.value;\n\n\t\t// Create a picker for the provider to use with the initial value\n\t\t// and adjust the filtering to exclude the prefix from filtering\n\t\tconst disposables = new DisposableStore();\n\t\tconst picker = disposables.add(this.quickInputService.createQuickPick());\n\t\tpicker.value = value;\n\t\tthis.adjustValueSelection(picker, descriptor, options);\n\t\tpicker.placeholder = options?.placeholder ?? descriptor?.placeholder;\n\t\tpicker.quickNavigate = options?.quickNavigateConfiguration;\n\t\tpicker.hideInput = !!picker.quickNavigate && !visibleQuickAccess; // only hide input if there was no picker opened already\n\t\tif (typeof options?.itemActivation === 'number' || options?.quickNavigateConfiguration) {\n\t\t\tpicker.itemActivation = options?.itemActivation ?? ItemActivation.SECOND /* quick nav is always second */;\n\t\t}\n\t\tpicker.contextKey = descriptor?.contextKey;\n\t\tpicker.filterValue = (value: string) => value.substring(descriptor ? descriptor.prefix.length : 0);\n\n\t\t// Pick mode: setup a promise that can be resolved\n\t\t// with the selected items and prevent execution\n\t\tlet pickPromise: DeferredPromise | undefined = undefined;\n\t\tif (pick) {\n\t\t\tpickPromise = new DeferredPromise();\n\t\t\tdisposables.add(Event.once(picker.onWillAccept)(e => {\n\t\t\t\te.veto();\n\t\t\t\tpicker.hide();\n\t\t\t}));\n\t\t}\n\n\t\t// Register listeners\n\t\tdisposables.add(this.registerPickerListeners(picker, provider, descriptor, value, options));\n\n\t\t// Ask provider to fill the picker as needed if we have one\n\t\t// and pass over a cancellation token that will indicate when\n\t\t// the picker is hiding without a pick being made.\n\t\tconst cts = disposables.add(new CancellationTokenSource());\n\t\tif (provider) {\n\t\t\tdisposables.add(provider.provide(picker, cts.token, options?.providerOptions));\n\t\t}\n\n\t\t// Finally, trigger disposal and cancellation when the picker\n\t\t// hides depending on items selected or not.\n\t\tEvent.once(picker.onDidHide)(() => {\n\t\t\tif (picker.selectedItems.length === 0) {\n\t\t\t\tcts.cancel();\n\t\t\t}\n\n\t\t\t// Start to dispose once picker hides\n\t\t\tdisposables.dispose();\n\n\t\t\t// Resolve pick promise with selected items\n\t\t\tpickPromise?.complete(picker.selectedItems.slice(0));\n\t\t});\n\n\t\t// Finally, show the picker. This is important because a provider\n\t\t// may not call this and then our disposables would leak that rely\n\t\t// on the onDidHide event.\n\t\tpicker.show();\n\n\t\t// If the previous picker had a selection and the value is unchanged, we should set that in the new picker.\n\t\tif (visibleSelection && visibleValue === value) {\n\t\t\tpicker.valueSelection = visibleSelection;\n\t\t}\n\n\t\t// Pick mode: return with promise\n\t\tif (pick) {\n\t\t\treturn pickPromise?.p;\n\t\t}\n\t}\n\n\tprivate adjustValueSelection(picker: IQuickPick, descriptor?: IQuickAccessProviderDescriptor, options?: IQuickAccessOptions): void {\n\t\tlet valueSelection: [number, number];\n\n\t\t// Preserve: just always put the cursor at the end\n\t\tif (options?.preserveValue) {\n\t\t\tvalueSelection = [picker.value.length, picker.value.length];\n\t\t}\n\n\t\t// Otherwise: select the value up until the prefix\n\t\telse {\n\t\t\tvalueSelection = [descriptor?.prefix.length ?? 0, picker.value.length];\n\t\t}\n\n\t\tpicker.valueSelection = valueSelection;\n\t}\n\n\tprivate registerPickerListeners(\n\t\tpicker: IQuickPick,\n\t\tprovider: IQuickAccessProvider | undefined,\n\t\tdescriptor: IQuickAccessProviderDescriptor | undefined,\n\t\tvalue: string,\n\t\toptions?: IQuickAccessOptions\n\t): IDisposable {\n\t\tconst disposables = new DisposableStore();\n\n\t\t// Remember as last visible picker and clean up once picker get's disposed\n\t\tconst visibleQuickAccess = this.visibleQuickAccess = { picker, descriptor, value };\n\t\tdisposables.add(toDisposable(() => {\n\t\t\tif (visibleQuickAccess === this.visibleQuickAccess) {\n\t\t\t\tthis.visibleQuickAccess = undefined;\n\t\t\t}\n\t\t}));\n\n\t\t// Whenever the value changes, check if the provider has\n\t\t// changed and if so - re-create the picker from the beginning\n\t\tdisposables.add(picker.onDidChangeValue(value => {\n\t\t\tconst [providerForValue] = this.getOrInstantiateProvider(value, options?.enabledProviderPrefixes);\n\t\t\tif (providerForValue !== provider) {\n\t\t\t\tthis.show(value, {\n\t\t\t\t\tenabledProviderPrefixes: options?.enabledProviderPrefixes,\n\t\t\t\t\t// do not rewrite value from user typing!\n\t\t\t\t\tpreserveValue: true,\n\t\t\t\t\t// persist the value of the providerOptions from the original showing\n\t\t\t\t\tproviderOptions: options?.providerOptions\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tvisibleQuickAccess.value = value; // remember the value in our visible one\n\t\t\t}\n\t\t}));\n\n\t\t// Remember picker input for future use when accepting\n\t\tif (descriptor) {\n\t\t\tdisposables.add(picker.onDidAccept(() => {\n\t\t\t\tthis.lastAcceptedPickerValues.set(descriptor, picker.value);\n\t\t\t}));\n\t\t}\n\n\t\treturn disposables;\n\t}\n\n\tprivate getOrInstantiateProvider(value: string, enabledProviderPrefixes?: string[]): [IQuickAccessProvider | undefined, IQuickAccessProviderDescriptor | undefined] {\n\t\tconst providerDescriptor = this.registry.getQuickAccessProvider(value);\n\t\tif (!providerDescriptor || enabledProviderPrefixes && !enabledProviderPrefixes?.includes(providerDescriptor.prefix)) {\n\t\t\treturn [undefined, undefined];\n\t\t}\n\n\t\tlet provider = this.mapProviderToDescriptor.get(providerDescriptor);\n\t\tif (!provider) {\n\t\t\tprovider = this.instantiationService.createInstance(providerDescriptor.ctor);\n\t\t\tthis.mapProviderToDescriptor.set(providerDescriptor, provider);\n\t\t}\n\n\t\treturn [provider, providerDescriptor];\n\t}\n}\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\nimport 'vs/css!./media/severityIcon';\nimport { Codicon } from 'vs/base/common/codicons';\nimport { ThemeIcon } from 'vs/base/common/themables';\nimport Severity from 'vs/base/common/severity';\n\nexport namespace SeverityIcon {\n\n\texport function className(severity: Severity): string {\n\t\tswitch (severity) {\n\t\t\tcase Severity.Ignore:\n\t\t\t\treturn 'severity-ignore ' + ThemeIcon.asClassName(Codicon.info);\n\t\t\tcase Severity.Info:\n\t\t\t\treturn ThemeIcon.asClassName(Codicon.info);\n\t\t\tcase Severity.Warning:\n\t\t\t\treturn ThemeIcon.asClassName(Codicon.warning);\n\t\t\tcase Severity.Error:\n\t\t\t\treturn ThemeIcon.asClassName(Codicon.error);\n\t\t\tdefault:\n\t\t\t\treturn '';\n\t\t}\n\t}\n}\n","\nimport { Emitter, Event, PauseableEmitter } from 'vs/base/common/event';\nimport { Disposable, DisposableStore } from 'vs/base/common/lifecycle';\nimport { isUndefinedOrNull } from 'vs/base/common/types';\nimport { InMemoryStorageDatabase, IStorage, IStorageChangeEvent, Storage, StorageHint, StorageValue } from 'vs/base/parts/storage/common/storage';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\nexport const TARGET_KEY = '__$__targetStorageMarker';\n\nexport const IStorageService = createDecorator('storageService');\n\nexport enum WillSaveStateReason {\n\n\t/**\n\t * No specific reason to save state.\n\t */\n\tNONE,\n\n\t/**\n\t * A hint that the workbench is about to shutdown.\n\t */\n\tSHUTDOWN\n}\n\nexport interface IWillSaveStateEvent {\n\treadonly reason: WillSaveStateReason;\n}\n\nexport interface IWorkspaceStorageValueChangeEvent extends IStorageValueChangeEvent {\n}\n\nexport interface IProfileStorageValueChangeEvent extends IStorageValueChangeEvent {\n}\n\nexport interface IApplicationStorageValueChangeEvent extends IStorageValueChangeEvent {\n}\n\nexport interface IStorageService {\n\n\treadonly _serviceBrand: undefined;\n\n\t/**\n\t * Emitted whenever data is updated or deleted on the given\n\t * scope and optional key.\n\t *\n\t * @param scope the `StorageScope` to listen to changes\n\t * @param key the optional key to filter for or all keys of\n\t * the scope if `undefined`\n\t */\n\tonDidChangeValue(scope: StorageScope.WORKSPACE, key: string | undefined, disposable: DisposableStore): Event;\n\tonDidChangeValue(scope: StorageScope.PROFILE, key: string | undefined, disposable: DisposableStore): Event;\n\tonDidChangeValue(scope: StorageScope.APPLICATION, key: string | undefined, disposable: DisposableStore): Event;\n\tonDidChangeValue(scope: StorageScope, key: string | undefined, disposable: DisposableStore): Event;\n\n\t/**\n\t * Emitted when the storage is about to persist. This is the right time\n\t * to persist data to ensure it is stored before the application shuts\n\t * down.\n\t *\n\t * The will save state event allows to optionally ask for the reason of\n\t * saving the state, e.g. to find out if the state is saved due to a\n\t * shutdown.\n\t *\n\t * Note: this event may be fired many times, not only on shutdown to prevent\n\t * loss of state in situations where the shutdown is not sufficient to\n\t * persist the data properly.\n\t */\n\treadonly onWillSaveState: Event;\n\n\t/**\n\t * Retrieve an element stored with the given key from storage. Use\n\t * the provided `defaultValue` if the element is `null` or `undefined`.\n\t *\n\t * @param scope allows to define the scope of the storage operation\n\t * to either the current workspace only, all workspaces or all profiles.\n\t */\n\tget(key: string, scope: StorageScope, fallbackValue: string): string;\n\tget(key: string, scope: StorageScope, fallbackValue?: string): string | undefined;\n\n\t/**\n\t * Retrieve an element stored with the given key from storage. Use\n\t * the provided `defaultValue` if the element is `null` or `undefined`.\n\t * The element will be converted to a `boolean`.\n\t *\n\t * @param scope allows to define the scope of the storage operation\n\t * to either the current workspace only, all workspaces or all profiles.\n\t */\n\tgetBoolean(key: string, scope: StorageScope, fallbackValue: boolean): boolean;\n\tgetBoolean(key: string, scope: StorageScope, fallbackValue?: boolean): boolean | undefined;\n\n\t/**\n\t * Retrieve an element stored with the given key from storage. Use\n\t * the provided `defaultValue` if the element is `null` or `undefined`.\n\t * The element will be converted to a `number` using `parseInt` with a\n\t * base of `10`.\n\t *\n\t * @param scope allows to define the scope of the storage operation\n\t * to either the current workspace only, all workspaces or all profiles.\n\t */\n\tgetNumber(key: string, scope: StorageScope, fallbackValue: number): number;\n\tgetNumber(key: string, scope: StorageScope, fallbackValue?: number): number | undefined;\n\n\t/**\n\t * Store a value under the given key to storage. The value will be\n\t * converted to a `string`. Storing either `undefined` or `null` will\n\t * remove the entry under the key.\n\t *\n\t * @param scope allows to define the scope of the storage operation\n\t * to either the current workspace only, all workspaces or all profiles.\n\t *\n\t * @param target allows to define the target of the storage operation\n\t * to either the current machine or user.\n\t */\n\tstore(key: string, value: StorageValue, scope: StorageScope, target: StorageTarget): void;\n\n\t/**\n\t * Delete an element stored under the provided key from storage.\n\t *\n\t * The scope argument allows to define the scope of the storage\n\t * operation to either the current workspace only, all workspaces\n\t * or all profiles.\n\t */\n\tremove(key: string, scope: StorageScope): void;\n}\n\nexport const enum StorageScope {\n\n\t/**\n\t * The stored data will be scoped to all workspaces across all profiles.\n\t */\n\tAPPLICATION = -1,\n\n\t/**\n\t * The stored data will be scoped to all workspaces of the same profile.\n\t */\n\tPROFILE = 0,\n\n\t/**\n\t * The stored data will be scoped to the current workspace.\n\t */\n\tWORKSPACE = 1\n}\n\nexport const enum StorageTarget {\n\n\t/**\n\t * The stored data is user specific and applies across machines.\n\t */\n\tUSER,\n\n\t/**\n\t * The stored data is machine specific.\n\t */\n\tMACHINE\n}\n\nexport interface IStorageValueChangeEvent {\n\n\t/**\n\t * The scope for the storage entry that changed\n\t * or was removed.\n\t */\n\treadonly scope: StorageScope;\n\n\t/**\n\t * The `key` of the storage entry that was changed\n\t * or was removed.\n\t */\n\treadonly key: string;\n\n\t/**\n\t * The `target` can be `undefined` if a key is being\n\t * removed.\n\t */\n\treadonly target: StorageTarget | undefined;\n\n\t/**\n\t * A hint how the storage change event was triggered. If\n\t * `true`, the storage change was triggered by an external\n\t * source, such as:\n\t * - another process (for example another window)\n\t * - operations such as settings sync or profiles change\n\t */\n\treadonly external?: boolean;\n}\n\nexport interface IStorageTargetChangeEvent {\n\n\t/**\n\t * The scope for the target that changed. Listeners\n\t * should use `keys(scope, target)` to get an updated\n\t * list of keys for the given `scope` and `target`.\n\t */\n\treadonly scope: StorageScope;\n}\n\ninterface IKeyTargets {\n\t[key: string]: StorageTarget;\n}\n\nexport interface IStorageServiceOptions {\n\treadonly flushInterval: number;\n}\n\nexport function loadKeyTargets(storage: IStorage): IKeyTargets {\n\tconst keysRaw = storage.get(TARGET_KEY);\n\tif (keysRaw) {\n\t\ttry {\n\t\t\treturn JSON.parse(keysRaw);\n\t\t} catch (error) {\n\t\t\t// Fail gracefully\n\t\t}\n\t}\n\n\treturn Object.create(null);\n}\n\nexport abstract class AbstractStorageService extends Disposable implements IStorageService {\n\n\tdeclare readonly _serviceBrand: undefined;\n\n\tprivate static DEFAULT_FLUSH_INTERVAL = 60 * 1000; // every minute\n\n\tprivate readonly _onDidChangeValue = this._register(new PauseableEmitter());\n\n\tprivate readonly _onDidChangeTarget = this._register(new PauseableEmitter());\n\n\tprivate readonly _onWillSaveState = this._register(new Emitter());\n\treadonly onWillSaveState = this._onWillSaveState.event;\n\n\tconstructor(private readonly options: IStorageServiceOptions = { flushInterval: AbstractStorageService.DEFAULT_FLUSH_INTERVAL }) {\n\t\tsuper();\n\t}\n\n\tonDidChangeValue(scope: StorageScope.WORKSPACE, key: string | undefined, disposable: DisposableStore): Event;\n\tonDidChangeValue(scope: StorageScope.PROFILE, key: string | undefined, disposable: DisposableStore): Event;\n\tonDidChangeValue(scope: StorageScope.APPLICATION, key: string | undefined, disposable: DisposableStore): Event;\n\tonDidChangeValue(scope: StorageScope, key: string | undefined, disposable: DisposableStore): Event {\n\t\treturn Event.filter(this._onDidChangeValue.event, e => e.scope === scope && (key === undefined || e.key === key), disposable);\n\t}\n\n\tprotected emitDidChangeValue(scope: StorageScope, event: IStorageChangeEvent): void {\n\t\tconst { key, external } = event;\n\n\t\t// Specially handle `TARGET_KEY`\n\t\tif (key === TARGET_KEY) {\n\n\t\t\t// Clear our cached version which is now out of date\n\t\t\tswitch (scope) {\n\t\t\t\tcase StorageScope.APPLICATION:\n\t\t\t\t\tthis._applicationKeyTargets = undefined;\n\t\t\t\t\tbreak;\n\t\t\t\tcase StorageScope.PROFILE:\n\t\t\t\t\tthis._profileKeyTargets = undefined;\n\t\t\t\t\tbreak;\n\t\t\t\tcase StorageScope.WORKSPACE:\n\t\t\t\t\tthis._workspaceKeyTargets = undefined;\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// Emit as `didChangeTarget` event\n\t\t\tthis._onDidChangeTarget.fire({ scope });\n\t\t}\n\n\t\t// Emit any other key to outside\n\t\telse {\n\t\t\tthis._onDidChangeValue.fire({ scope, key, target: this.getKeyTargets(scope)[key], external });\n\t\t}\n\t}\n\n\tget(key: string, scope: StorageScope, fallbackValue: string): string;\n\tget(key: string, scope: StorageScope): string | undefined;\n\tget(key: string, scope: StorageScope, fallbackValue?: string): string | undefined {\n\t\treturn this.getStorage(scope)?.get(key, fallbackValue);\n\t}\n\n\tgetBoolean(key: string, scope: StorageScope, fallbackValue: boolean): boolean;\n\tgetBoolean(key: string, scope: StorageScope): boolean | undefined;\n\tgetBoolean(key: string, scope: StorageScope, fallbackValue?: boolean): boolean | undefined {\n\t\treturn this.getStorage(scope)?.getBoolean(key, fallbackValue);\n\t}\n\n\tgetNumber(key: string, scope: StorageScope, fallbackValue: number): number;\n\tgetNumber(key: string, scope: StorageScope): number | undefined;\n\tgetNumber(key: string, scope: StorageScope, fallbackValue?: number): number | undefined {\n\t\treturn this.getStorage(scope)?.getNumber(key, fallbackValue);\n\t}\n\n\tstore(key: string, value: StorageValue, scope: StorageScope, target: StorageTarget, external = false): void {\n\n\t\t// We remove the key for undefined/null values\n\t\tif (isUndefinedOrNull(value)) {\n\t\t\tthis.remove(key, scope, external);\n\t\t\treturn;\n\t\t}\n\n\t\t// Update our datastructures but send events only after\n\t\tthis.withPausedEmitters(() => {\n\n\t\t\t// Update key-target map\n\t\t\tthis.updateKeyTarget(key, scope, target);\n\n\t\t\t// Store actual value\n\t\t\tthis.getStorage(scope)?.set(key, value, external);\n\t\t});\n\t}\n\n\tremove(key: string, scope: StorageScope, external = false): void {\n\n\t\t// Update our datastructures but send events only after\n\t\tthis.withPausedEmitters(() => {\n\n\t\t\t// Update key-target map\n\t\t\tthis.updateKeyTarget(key, scope, undefined);\n\n\t\t\t// Remove actual key\n\t\t\tthis.getStorage(scope)?.delete(key, external);\n\t\t});\n\t}\n\n\tprivate withPausedEmitters(fn: Function): void {\n\n\t\t// Pause emitters\n\t\tthis._onDidChangeValue.pause();\n\t\tthis._onDidChangeTarget.pause();\n\n\t\ttry {\n\t\t\tfn();\n\t\t} finally {\n\n\t\t\t// Resume emitters\n\t\t\tthis._onDidChangeValue.resume();\n\t\t\tthis._onDidChangeTarget.resume();\n\t\t}\n\t}\n\n\tprivate updateKeyTarget(key: string, scope: StorageScope, target: StorageTarget | undefined, external = false): void {\n\n\t\t// Add\n\t\tconst keyTargets = this.getKeyTargets(scope);\n\t\tif (typeof target === 'number') {\n\t\t\tif (keyTargets[key] !== target) {\n\t\t\t\tkeyTargets[key] = target;\n\t\t\t\tthis.getStorage(scope)?.set(TARGET_KEY, JSON.stringify(keyTargets), external);\n\t\t\t}\n\t\t}\n\n\t\t// Remove\n\t\telse {\n\t\t\tif (typeof keyTargets[key] === 'number') {\n\t\t\t\tdelete keyTargets[key];\n\t\t\t\tthis.getStorage(scope)?.set(TARGET_KEY, JSON.stringify(keyTargets), external);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate _workspaceKeyTargets: IKeyTargets | undefined = undefined;\n\tprivate get workspaceKeyTargets(): IKeyTargets {\n\t\tif (!this._workspaceKeyTargets) {\n\t\t\tthis._workspaceKeyTargets = this.loadKeyTargets(StorageScope.WORKSPACE);\n\t\t}\n\n\t\treturn this._workspaceKeyTargets;\n\t}\n\n\tprivate _profileKeyTargets: IKeyTargets | undefined = undefined;\n\tprivate get profileKeyTargets(): IKeyTargets {\n\t\tif (!this._profileKeyTargets) {\n\t\t\tthis._profileKeyTargets = this.loadKeyTargets(StorageScope.PROFILE);\n\t\t}\n\n\t\treturn this._profileKeyTargets;\n\t}\n\n\tprivate _applicationKeyTargets: IKeyTargets | undefined = undefined;\n\tprivate get applicationKeyTargets(): IKeyTargets {\n\t\tif (!this._applicationKeyTargets) {\n\t\t\tthis._applicationKeyTargets = this.loadKeyTargets(StorageScope.APPLICATION);\n\t\t}\n\n\t\treturn this._applicationKeyTargets;\n\t}\n\n\tprivate getKeyTargets(scope: StorageScope): IKeyTargets {\n\t\tswitch (scope) {\n\t\t\tcase StorageScope.APPLICATION:\n\t\t\t\treturn this.applicationKeyTargets;\n\t\t\tcase StorageScope.PROFILE:\n\t\t\t\treturn this.profileKeyTargets;\n\t\t\tdefault:\n\t\t\t\treturn this.workspaceKeyTargets;\n\t\t}\n\t}\n\n\tprivate loadKeyTargets(scope: StorageScope): { [key: string]: StorageTarget } {\n\t\tconst storage = this.getStorage(scope);\n\n\t\treturn storage ? loadKeyTargets(storage) : Object.create(null);\n\t}\n\n\tprotected abstract getStorage(scope: StorageScope): IStorage | undefined;\n}\n\nexport class InMemoryStorageService extends AbstractStorageService {\n\n\tprivate readonly applicationStorage = this._register(new Storage(new InMemoryStorageDatabase(), { hint: StorageHint.STORAGE_IN_MEMORY }));\n\tprivate readonly profileStorage = this._register(new Storage(new InMemoryStorageDatabase(), { hint: StorageHint.STORAGE_IN_MEMORY }));\n\tprivate readonly workspaceStorage = this._register(new Storage(new InMemoryStorageDatabase(), { hint: StorageHint.STORAGE_IN_MEMORY }));\n\n\tconstructor() {\n\t\tsuper();\n\n\t\tthis._register(this.workspaceStorage.onDidChangeStorage(e => this.emitDidChangeValue(StorageScope.WORKSPACE, e)));\n\t\tthis._register(this.profileStorage.onDidChangeStorage(e => this.emitDidChangeValue(StorageScope.PROFILE, e)));\n\t\tthis._register(this.applicationStorage.onDidChangeStorage(e => this.emitDidChangeValue(StorageScope.APPLICATION, e)));\n\t}\n\n\tprotected getStorage(scope: StorageScope): IStorage {\n\t\tswitch (scope) {\n\t\t\tcase StorageScope.APPLICATION:\n\t\t\t\treturn this.applicationStorage;\n\t\t\tcase StorageScope.PROFILE:\n\t\t\t\treturn this.profileStorage;\n\t\t\tdefault:\n\t\t\t\treturn this.workspaceStorage;\n\t\t}\n\t}\n}\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\nimport { Event } from 'vs/base/common/event';\nimport { LRUCache } from 'vs/base/common/map';\nimport { Range } from 'vs/editor/common/core/range';\nimport { ITextModel } from 'vs/editor/common/model';\nimport { CodeLens, CodeLensList, CodeLensProvider } from 'vs/editor/common/languages';\nimport { CodeLensModel } from 'vs/editor/contrib/codelens/browser/codelens';\nimport { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\nimport { IStorageService, StorageScope, StorageTarget, WillSaveStateReason } from 'vs/platform/storage/common/storage';\nimport { mainWindow } from 'vs/base/browser/window';\nimport { runWhenWindowIdle } from 'vs/base/browser/dom';\n\nexport const ICodeLensCache = createDecorator('ICodeLensCache');\n\nexport interface ICodeLensCache {\n\treadonly _serviceBrand: undefined;\n\tput(model: ITextModel, data: CodeLensModel): void;\n\tget(model: ITextModel): CodeLensModel | undefined;\n\tdelete(model: ITextModel): void;\n}\n\ninterface ISerializedCacheData {\n\tlineCount: number;\n\tlines: number[];\n}\n\nclass CacheItem {\n\n\tconstructor(\n\t\treadonly lineCount: number,\n\t\treadonly data: CodeLensModel\n\t) { }\n}\n\nexport class CodeLensCache implements ICodeLensCache {\n\n\tdeclare readonly _serviceBrand: undefined;\n\n\tprivate readonly _fakeProvider = new class implements CodeLensProvider {\n\t\tprovideCodeLenses(): CodeLensList {\n\t\t\tthrow new Error('not supported');\n\t\t}\n\t};\n\n\tprivate readonly _cache = new LRUCache(20, 0.75);\n\n\tconstructor(@IStorageService storageService: IStorageService) {\n\n\t\t// remove old data\n\t\tconst oldkey = 'codelens/cache';\n\t\trunWhenWindowIdle(mainWindow, () => storageService.remove(oldkey, StorageScope.WORKSPACE));\n\n\t\t// restore lens data on start\n\t\tconst key = 'codelens/cache2';\n\t\tconst raw = storageService.get(key, StorageScope.WORKSPACE, '{}');\n\t\tthis._deserialize(raw);\n\n\t\t// store lens data on shutdown\n\t\tEvent.once(storageService.onWillSaveState)(e => {\n\t\t\tif (e.reason === WillSaveStateReason.SHUTDOWN) {\n\t\t\t\tstorageService.store(key, this._serialize(), StorageScope.WORKSPACE, StorageTarget.MACHINE);\n\t\t\t}\n\t\t});\n\t}\n\n\tput(model: ITextModel, data: CodeLensModel): void {\n\t\t// create a copy of the model that is without command-ids\n\t\t// but with comand-labels\n\t\tconst copyItems = data.lenses.map(item => {\n\t\t\treturn {\n\t\t\t\trange: item.symbol.range,\n\t\t\t\tcommand: item.symbol.command && { id: '', title: item.symbol.command?.title },\n\t\t\t};\n\t\t});\n\t\tconst copyModel = new CodeLensModel();\n\t\tcopyModel.add({ lenses: copyItems, dispose: () => { } }, this._fakeProvider);\n\n\t\tconst item = new CacheItem(model.getLineCount(), copyModel);\n\t\tthis._cache.set(model.uri.toString(), item);\n\t}\n\n\tget(model: ITextModel) {\n\t\tconst item = this._cache.get(model.uri.toString());\n\t\treturn item && item.lineCount === model.getLineCount() ? item.data : undefined;\n\t}\n\n\tdelete(model: ITextModel): void {\n\t\tthis._cache.delete(model.uri.toString());\n\t}\n\n\t// --- persistence\n\n\tprivate _serialize(): string {\n\t\tconst data: Record = Object.create(null);\n\t\tfor (const [key, value] of this._cache) {\n\t\t\tconst lines = new Set();\n\t\t\tfor (const d of value.data.lenses) {\n\t\t\t\tlines.add(d.symbol.range.startLineNumber);\n\t\t\t}\n\t\t\tdata[key] = {\n\t\t\t\tlineCount: value.lineCount,\n\t\t\t\tlines: [...lines.values()]\n\t\t\t};\n\t\t}\n\t\treturn JSON.stringify(data);\n\t}\n\n\tprivate _deserialize(raw: string): void {\n\t\ttry {\n\t\t\tconst data: Record = JSON.parse(raw);\n\t\t\tfor (const key in data) {\n\t\t\t\tconst element = data[key];\n\t\t\t\tconst lenses: CodeLens[] = [];\n\t\t\t\tfor (const line of element.lines) {\n\t\t\t\t\tlenses.push({ range: new Range(line, 1, line, 11) });\n\t\t\t\t}\n\n\t\t\t\tconst model = new CodeLensModel();\n\t\t\t\tmodel.add({ lenses, dispose() { } }, this._fakeProvider);\n\t\t\t\tthis._cache.set(key, new CacheItem(element.lineCount, model));\n\t\t\t}\n\t\t} catch {\n\t\t\t// ignore...\n\t\t}\n\t}\n}\n\nregisterSingleton(ICodeLensCache, CodeLensCache, InstantiationType.Delayed);\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\nimport { RunOnceScheduler } from 'vs/base/common/async';\nimport { DisposableStore } from 'vs/base/common/lifecycle';\nimport { LRUCache } from 'vs/base/common/map';\nimport { TernarySearchTree } from 'vs/base/common/ternarySearchTree';\nimport { IPosition } from 'vs/editor/common/core/position';\nimport { ITextModel } from 'vs/editor/common/model';\nimport { CompletionItemKind, CompletionItemKinds } from 'vs/editor/common/languages';\nimport { CompletionItem } from 'vs/editor/contrib/suggest/browser/suggest';\nimport { IConfigurationService } from 'vs/platform/configuration/common/configuration';\nimport { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions';\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\nimport { IStorageService, StorageScope, StorageTarget, WillSaveStateReason } from 'vs/platform/storage/common/storage';\n\nexport abstract class Memory {\n\n\tconstructor(readonly name: MemMode) { }\n\n\tselect(model: ITextModel, pos: IPosition, items: CompletionItem[]): number {\n\t\tif (items.length === 0) {\n\t\t\treturn 0;\n\t\t}\n\t\tconst topScore = items[0].score[0];\n\t\tfor (let i = 0; i < items.length; i++) {\n\t\t\tconst { score, completion: suggestion } = items[i];\n\t\t\tif (score[0] !== topScore) {\n\t\t\t\t// stop when leaving the group of top matches\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (suggestion.preselect) {\n\t\t\t\t// stop when seeing an auto-select-item\n\t\t\t\treturn i;\n\t\t\t}\n\t\t}\n\t\treturn 0;\n\t}\n\n\tabstract memorize(model: ITextModel, pos: IPosition, item: CompletionItem): void;\n\n\tabstract toJSON(): object | undefined;\n\n\tabstract fromJSON(data: object): void;\n}\n\nexport class NoMemory extends Memory {\n\n\tconstructor() {\n\t\tsuper('first');\n\t}\n\n\tmemorize(model: ITextModel, pos: IPosition, item: CompletionItem): void {\n\t\t// no-op\n\t}\n\n\ttoJSON() {\n\t\treturn undefined;\n\t}\n\n\tfromJSON() {\n\t\t//\n\t}\n}\n\nexport interface MemItem {\n\ttype: string | CompletionItemKind;\n\tinsertText: string;\n\ttouch: number;\n}\n\nexport class LRUMemory extends Memory {\n\n\tconstructor() {\n\t\tsuper('recentlyUsed');\n\t}\n\n\tprivate _cache = new LRUCache(300, 0.66);\n\tprivate _seq = 0;\n\n\tmemorize(model: ITextModel, pos: IPosition, item: CompletionItem): void {\n\t\tconst key = `${model.getLanguageId()}/${item.textLabel}`;\n\t\tthis._cache.set(key, {\n\t\t\ttouch: this._seq++,\n\t\t\ttype: item.completion.kind,\n\t\t\tinsertText: item.completion.insertText\n\t\t});\n\t}\n\n\toverride select(model: ITextModel, pos: IPosition, items: CompletionItem[]): number {\n\n\t\tif (items.length === 0) {\n\t\t\treturn 0;\n\t\t}\n\n\t\tconst lineSuffix = model.getLineContent(pos.lineNumber).substr(pos.column - 10, pos.column - 1);\n\t\tif (/\\s$/.test(lineSuffix)) {\n\t\t\treturn super.select(model, pos, items);\n\t\t}\n\n\t\tconst topScore = items[0].score[0];\n\t\tlet indexPreselect = -1;\n\t\tlet indexRecency = -1;\n\t\tlet seq = -1;\n\t\tfor (let i = 0; i < items.length; i++) {\n\t\t\tif (items[i].score[0] !== topScore) {\n\t\t\t\t// consider only top items\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tconst key = `${model.getLanguageId()}/${items[i].textLabel}`;\n\t\t\tconst item = this._cache.peek(key);\n\t\t\tif (item && item.touch > seq && item.type === items[i].completion.kind && item.insertText === items[i].completion.insertText) {\n\t\t\t\tseq = item.touch;\n\t\t\t\tindexRecency = i;\n\t\t\t}\n\t\t\tif (items[i].completion.preselect && indexPreselect === -1) {\n\t\t\t\t// stop when seeing an auto-select-item\n\t\t\t\treturn indexPreselect = i;\n\t\t\t}\n\t\t}\n\t\tif (indexRecency !== -1) {\n\t\t\treturn indexRecency;\n\t\t} else if (indexPreselect !== -1) {\n\t\t\treturn indexPreselect;\n\t\t} else {\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\ttoJSON(): object {\n\t\treturn this._cache.toJSON();\n\t}\n\n\tfromJSON(data: [string, MemItem][]): void {\n\t\tthis._cache.clear();\n\t\tconst seq = 0;\n\t\tfor (const [key, value] of data) {\n\t\t\tvalue.touch = seq;\n\t\t\tvalue.type = typeof value.type === 'number' ? value.type : CompletionItemKinds.fromString(value.type);\n\t\t\tthis._cache.set(key, value);\n\t\t}\n\t\tthis._seq = this._cache.size;\n\t}\n}\n\n\nexport class PrefixMemory extends Memory {\n\n\tconstructor() {\n\t\tsuper('recentlyUsedByPrefix');\n\t}\n\n\tprivate _trie = TernarySearchTree.forStrings();\n\tprivate _seq = 0;\n\n\tmemorize(model: ITextModel, pos: IPosition, item: CompletionItem): void {\n\t\tconst { word } = model.getWordUntilPosition(pos);\n\t\tconst key = `${model.getLanguageId()}/${word}`;\n\t\tthis._trie.set(key, {\n\t\t\ttype: item.completion.kind,\n\t\t\tinsertText: item.completion.insertText,\n\t\t\ttouch: this._seq++\n\t\t});\n\t}\n\n\toverride select(model: ITextModel, pos: IPosition, items: CompletionItem[]): number {\n\t\tconst { word } = model.getWordUntilPosition(pos);\n\t\tif (!word) {\n\t\t\treturn super.select(model, pos, items);\n\t\t}\n\t\tconst key = `${model.getLanguageId()}/${word}`;\n\t\tlet item = this._trie.get(key);\n\t\tif (!item) {\n\t\t\titem = this._trie.findSubstr(key);\n\t\t}\n\t\tif (item) {\n\t\t\tfor (let i = 0; i < items.length; i++) {\n\t\t\t\tconst { kind, insertText } = items[i].completion;\n\t\t\t\tif (kind === item.type && insertText === item.insertText) {\n\t\t\t\t\treturn i;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn super.select(model, pos, items);\n\t}\n\n\ttoJSON(): object {\n\n\t\tconst entries: [string, MemItem][] = [];\n\t\tthis._trie.forEach((value, key) => entries.push([key, value]));\n\n\t\t// sort by last recently used (touch), then\n\t\t// take the top 200 item and normalize their\n\t\t// touch\n\t\tentries\n\t\t\t.sort((a, b) => -(a[1].touch - b[1].touch))\n\t\t\t.forEach((value, i) => value[1].touch = i);\n\n\t\treturn entries.slice(0, 200);\n\t}\n\n\tfromJSON(data: [string, MemItem][]): void {\n\t\tthis._trie.clear();\n\t\tif (data.length > 0) {\n\t\t\tthis._seq = data[0][1].touch + 1;\n\t\t\tfor (const [key, value] of data) {\n\t\t\t\tvalue.type = typeof value.type === 'number' ? value.type : CompletionItemKinds.fromString(value.type);\n\t\t\t\tthis._trie.set(key, value);\n\t\t\t}\n\t\t}\n\t}\n}\n\nexport type MemMode = 'first' | 'recentlyUsed' | 'recentlyUsedByPrefix';\n\nexport class SuggestMemoryService implements ISuggestMemoryService {\n\n\tprivate static readonly _strategyCtors = new Map([\n\t\t['recentlyUsedByPrefix', PrefixMemory],\n\t\t['recentlyUsed', LRUMemory],\n\t\t['first', NoMemory]\n\t]);\n\n\tprivate static readonly _storagePrefix = 'suggest/memories';\n\n\treadonly _serviceBrand: undefined;\n\n\n\tprivate readonly _persistSoon: RunOnceScheduler;\n\tprivate readonly _disposables = new DisposableStore();\n\n\tprivate _strategy?: Memory;\n\n\tconstructor(\n\t\t@IStorageService private readonly _storageService: IStorageService,\n\t\t@IConfigurationService private readonly _configService: IConfigurationService,\n\t) {\n\t\tthis._persistSoon = new RunOnceScheduler(() => this._saveState(), 500);\n\t\tthis._disposables.add(_storageService.onWillSaveState(e => {\n\t\t\tif (e.reason === WillSaveStateReason.SHUTDOWN) {\n\t\t\t\tthis._saveState();\n\t\t\t}\n\t\t}));\n\t}\n\n\tdispose(): void {\n\t\tthis._disposables.dispose();\n\t\tthis._persistSoon.dispose();\n\t}\n\n\tmemorize(model: ITextModel, pos: IPosition, item: CompletionItem): void {\n\t\tthis._withStrategy(model, pos).memorize(model, pos, item);\n\t\tthis._persistSoon.schedule();\n\t}\n\n\tselect(model: ITextModel, pos: IPosition, items: CompletionItem[]): number {\n\t\treturn this._withStrategy(model, pos).select(model, pos, items);\n\t}\n\n\tprivate _withStrategy(model: ITextModel, pos: IPosition): Memory {\n\n\t\tconst mode = this._configService.getValue('editor.suggestSelection', {\n\t\t\toverrideIdentifier: model.getLanguageIdAtPosition(pos.lineNumber, pos.column),\n\t\t\tresource: model.uri\n\t\t});\n\n\t\tif (this._strategy?.name !== mode) {\n\n\t\t\tthis._saveState();\n\t\t\tconst ctor = SuggestMemoryService._strategyCtors.get(mode) || NoMemory;\n\t\t\tthis._strategy = new ctor();\n\n\t\t\ttry {\n\t\t\t\tconst share = this._configService.getValue('editor.suggest.shareSuggestSelections');\n\t\t\t\tconst scope = share ? StorageScope.PROFILE : StorageScope.WORKSPACE;\n\t\t\t\tconst raw = this._storageService.get(`${SuggestMemoryService._storagePrefix}/${mode}`, scope);\n\t\t\t\tif (raw) {\n\t\t\t\t\tthis._strategy.fromJSON(JSON.parse(raw));\n\t\t\t\t}\n\t\t\t} catch (e) {\n\t\t\t\t// things can go wrong with JSON...\n\t\t\t}\n\t\t}\n\n\t\treturn this._strategy;\n\t}\n\n\tprivate _saveState() {\n\t\tif (this._strategy) {\n\t\t\tconst share = this._configService.getValue('editor.suggest.shareSuggestSelections');\n\t\t\tconst scope = share ? StorageScope.PROFILE : StorageScope.WORKSPACE;\n\t\t\tconst raw = JSON.stringify(this._strategy);\n\t\t\tthis._storageService.store(`${SuggestMemoryService._storagePrefix}/${this._strategy.name}`, raw, scope, StorageTarget.MACHINE);\n\t\t}\n\t}\n}\n\n\nexport const ISuggestMemoryService = createDecorator('ISuggestMemories');\n\nexport interface ISuggestMemoryService {\n\treadonly _serviceBrand: undefined;\n\tmemorize(model: ITextModel, pos: IPosition, item: CompletionItem): void;\n\tselect(model: ITextModel, pos: IPosition, items: CompletionItem[]): number;\n}\n\nregisterSingleton(ISuggestMemoryService, SuggestMemoryService, InstantiationType.Delayed);\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\nimport { RunOnceScheduler } from 'vs/base/common/async';\nimport { DebounceEmitter, Emitter, Event } from 'vs/base/common/event';\nimport { DisposableStore } from 'vs/base/common/lifecycle';\nimport { IMenu, IMenuActionOptions, IMenuChangeEvent, IMenuCreateOptions, IMenuItem, IMenuItemHide, IMenuService, isIMenuItem, isISubmenuItem, ISubmenuItem, MenuId, MenuItemAction, MenuRegistry, SubmenuItemAction } from 'vs/platform/actions/common/actions';\nimport { ICommandAction, ILocalizedString } from 'vs/platform/action/common/action';\nimport { ICommandService } from 'vs/platform/commands/common/commands';\nimport { ContextKeyExpression, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';\nimport { IAction, Separator, toAction } from 'vs/base/common/actions';\nimport { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';\nimport { removeFastWithoutKeepingOrder } from 'vs/base/common/arrays';\nimport { localize } from 'vs/nls';\nimport { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';\n\nexport class MenuService implements IMenuService {\n\n\tdeclare readonly _serviceBrand: undefined;\n\n\tprivate readonly _hiddenStates: PersistedMenuHideState;\n\n\tconstructor(\n\t\t@ICommandService private readonly _commandService: ICommandService,\n\t\t@IKeybindingService private readonly _keybindingService: IKeybindingService,\n\t\t@IStorageService storageService: IStorageService,\n\t) {\n\t\tthis._hiddenStates = new PersistedMenuHideState(storageService);\n\t}\n\n\tcreateMenu(id: MenuId, contextKeyService: IContextKeyService, options?: IMenuCreateOptions): IMenu {\n\t\treturn new MenuImpl(id, this._hiddenStates, { emitEventsForSubmenuChanges: false, eventDebounceDelay: 50, ...options }, this._commandService, this._keybindingService, contextKeyService);\n\t}\n\n\tresetHiddenStates(ids?: MenuId[]): void {\n\t\tthis._hiddenStates.reset(ids);\n\t}\n}\n\nclass PersistedMenuHideState {\n\n\tprivate static readonly _key = 'menu.hiddenCommands';\n\n\tprivate readonly _disposables = new DisposableStore();\n\tprivate readonly _onDidChange = new Emitter();\n\treadonly onDidChange: Event = this._onDidChange.event;\n\n\tprivate _ignoreChangeEvent: boolean = false;\n\tprivate _data: Record;\n\n\tprivate _hiddenByDefaultCache = new Map();\n\n\tconstructor(@IStorageService private readonly _storageService: IStorageService) {\n\t\ttry {\n\t\t\tconst raw = _storageService.get(PersistedMenuHideState._key, StorageScope.PROFILE, '{}');\n\t\t\tthis._data = JSON.parse(raw);\n\t\t} catch (err) {\n\t\t\tthis._data = Object.create(null);\n\t\t}\n\n\t\tthis._disposables.add(_storageService.onDidChangeValue(StorageScope.PROFILE, PersistedMenuHideState._key, this._disposables)(() => {\n\t\t\tif (!this._ignoreChangeEvent) {\n\t\t\t\ttry {\n\t\t\t\t\tconst raw = _storageService.get(PersistedMenuHideState._key, StorageScope.PROFILE, '{}');\n\t\t\t\t\tthis._data = JSON.parse(raw);\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconsole.log('FAILED to read storage after UPDATE', err);\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis._onDidChange.fire();\n\t\t}));\n\t}\n\n\tdispose() {\n\t\tthis._onDidChange.dispose();\n\t\tthis._disposables.dispose();\n\t}\n\n\tprivate _isHiddenByDefault(menu: MenuId, commandId: string) {\n\t\treturn this._hiddenByDefaultCache.get(`${menu.id}/${commandId}`) ?? false;\n\t}\n\n\tsetDefaultState(menu: MenuId, commandId: string, hidden: boolean): void {\n\t\tthis._hiddenByDefaultCache.set(`${menu.id}/${commandId}`, hidden);\n\t}\n\n\tisHidden(menu: MenuId, commandId: string): boolean {\n\t\tconst hiddenByDefault = this._isHiddenByDefault(menu, commandId);\n\t\tconst state = this._data[menu.id]?.includes(commandId) ?? false;\n\t\treturn hiddenByDefault ? !state : state;\n\t}\n\n\tupdateHidden(menu: MenuId, commandId: string, hidden: boolean): void {\n\t\tconst hiddenByDefault = this._isHiddenByDefault(menu, commandId);\n\t\tif (hiddenByDefault) {\n\t\t\thidden = !hidden;\n\t\t}\n\t\tconst entries = this._data[menu.id];\n\t\tif (!hidden) {\n\t\t\t// remove and cleanup\n\t\t\tif (entries) {\n\t\t\t\tconst idx = entries.indexOf(commandId);\n\t\t\t\tif (idx >= 0) {\n\t\t\t\t\tremoveFastWithoutKeepingOrder(entries, idx);\n\t\t\t\t}\n\t\t\t\tif (entries.length === 0) {\n\t\t\t\t\tdelete this._data[menu.id];\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\t// add unless already added\n\t\t\tif (!entries) {\n\t\t\t\tthis._data[menu.id] = [commandId];\n\t\t\t} else {\n\t\t\t\tconst idx = entries.indexOf(commandId);\n\t\t\t\tif (idx < 0) {\n\t\t\t\t\tentries.push(commandId);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tthis._persist();\n\t}\n\n\treset(menus?: MenuId[]): void {\n\t\tif (menus === undefined) {\n\t\t\t// reset all\n\t\t\tthis._data = Object.create(null);\n\t\t\tthis._persist();\n\t\t} else {\n\t\t\t// reset only for a specific menu\n\t\t\tfor (const { id } of menus) {\n\t\t\t\tif (this._data[id]) {\n\t\t\t\t\tdelete this._data[id];\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis._persist();\n\t\t}\n\t}\n\n\tprivate _persist(): void {\n\t\ttry {\n\t\t\tthis._ignoreChangeEvent = true;\n\t\t\tconst raw = JSON.stringify(this._data);\n\t\t\tthis._storageService.store(PersistedMenuHideState._key, raw, StorageScope.PROFILE, StorageTarget.USER);\n\t\t} finally {\n\t\t\tthis._ignoreChangeEvent = false;\n\t\t}\n\t}\n}\n\ntype MenuItemGroup = [string, Array];\n\nclass MenuInfo {\n\n\tprivate _menuGroups: MenuItemGroup[] = [];\n\tprivate _structureContextKeys: Set = new Set();\n\tprivate _preconditionContextKeys: Set = new Set();\n\tprivate _toggledContextKeys: Set = new Set();\n\n\tconstructor(\n\t\tprivate readonly _id: MenuId,\n\t\tprivate readonly _hiddenStates: PersistedMenuHideState,\n\t\tprivate readonly _collectContextKeysForSubmenus: boolean,\n\t\t@ICommandService private readonly _commandService: ICommandService,\n\t\t@IKeybindingService private readonly _keybindingService: IKeybindingService,\n\t\t@IContextKeyService private readonly _contextKeyService: IContextKeyService\n\t) {\n\t\tthis.refresh();\n\t}\n\n\tget structureContextKeys(): ReadonlySet {\n\t\treturn this._structureContextKeys;\n\t}\n\n\tget preconditionContextKeys(): ReadonlySet {\n\t\treturn this._preconditionContextKeys;\n\t}\n\n\tget toggledContextKeys(): ReadonlySet {\n\t\treturn this._toggledContextKeys;\n\t}\n\n\trefresh(): void {\n\n\t\t// reset\n\t\tthis._menuGroups.length = 0;\n\t\tthis._structureContextKeys.clear();\n\t\tthis._preconditionContextKeys.clear();\n\t\tthis._toggledContextKeys.clear();\n\n\t\tconst menuItems = MenuRegistry.getMenuItems(this._id);\n\n\t\tlet group: MenuItemGroup | undefined;\n\t\tmenuItems.sort(MenuInfo._compareMenuItems);\n\n\t\tfor (const item of menuItems) {\n\t\t\t// group by groupId\n\t\t\tconst groupName = item.group || '';\n\t\t\tif (!group || group[0] !== groupName) {\n\t\t\t\tgroup = [groupName, []];\n\t\t\t\tthis._menuGroups.push(group);\n\t\t\t}\n\t\t\tgroup[1].push(item);\n\n\t\t\t// keep keys for eventing\n\t\t\tthis._collectContextKeys(item);\n\t\t}\n\t}\n\n\tprivate _collectContextKeys(item: IMenuItem | ISubmenuItem): void {\n\n\t\tMenuInfo._fillInKbExprKeys(item.when, this._structureContextKeys);\n\n\t\tif (isIMenuItem(item)) {\n\t\t\t// keep precondition keys for event if applicable\n\t\t\tif (item.command.precondition) {\n\t\t\t\tMenuInfo._fillInKbExprKeys(item.command.precondition, this._preconditionContextKeys);\n\t\t\t}\n\t\t\t// keep toggled keys for event if applicable\n\t\t\tif (item.command.toggled) {\n\t\t\t\tconst toggledExpression: ContextKeyExpression = (item.command.toggled as { condition: ContextKeyExpression }).condition || item.command.toggled;\n\t\t\t\tMenuInfo._fillInKbExprKeys(toggledExpression, this._toggledContextKeys);\n\t\t\t}\n\n\t\t} else if (this._collectContextKeysForSubmenus) {\n\t\t\t// recursively collect context keys from submenus so that this\n\t\t\t// menu fires events when context key changes affect submenus\n\t\t\tMenuRegistry.getMenuItems(item.submenu).forEach(this._collectContextKeys, this);\n\t\t}\n\t}\n\n\tcreateActionGroups(options: IMenuActionOptions | undefined): [string, Array][] {\n\t\tconst result: [string, Array][] = [];\n\n\t\tfor (const group of this._menuGroups) {\n\t\t\tconst [id, items] = group;\n\n\t\t\tlet activeActions: Array | undefined;\n\t\t\tfor (const item of items) {\n\t\t\t\tif (this._contextKeyService.contextMatchesRules(item.when)) {\n\t\t\t\t\tconst isMenuItem = isIMenuItem(item);\n\t\t\t\t\tif (isMenuItem) {\n\t\t\t\t\t\tthis._hiddenStates.setDefaultState(this._id, item.command.id, !!item.isHiddenByDefault);\n\t\t\t\t\t}\n\n\t\t\t\t\tconst menuHide = createMenuHide(this._id, isMenuItem ? item.command : item, this._hiddenStates);\n\t\t\t\t\tif (isMenuItem) {\n\t\t\t\t\t\t// MenuItemAction\n\t\t\t\t\t\tconst menuKeybinding = createConfigureKeybindingAction(item.command.id, item.when, this._commandService, this._keybindingService);\n\t\t\t\t\t\t(activeActions ??= []).push(new MenuItemAction(item.command, item.alt, options, menuHide, menuKeybinding, this._contextKeyService, this._commandService));\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// SubmenuItemAction\n\t\t\t\t\t\tconst groups = new MenuInfo(item.submenu, this._hiddenStates, this._collectContextKeysForSubmenus, this._commandService, this._keybindingService, this._contextKeyService).createActionGroups(options);\n\t\t\t\t\t\tconst submenuActions = Separator.join(...groups.map(g => g[1]));\n\t\t\t\t\t\tif (submenuActions.length > 0) {\n\t\t\t\t\t\t\t(activeActions ??= []).push(new SubmenuItemAction(item, menuHide, submenuActions));\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\tif (activeActions && activeActions.length > 0) {\n\t\t\t\tresult.push([id, activeActions]);\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate static _fillInKbExprKeys(exp: ContextKeyExpression | undefined, set: Set): void {\n\t\tif (exp) {\n\t\t\tfor (const key of exp.keys()) {\n\t\t\t\tset.add(key);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate static _compareMenuItems(a: IMenuItem | ISubmenuItem, b: IMenuItem | ISubmenuItem): number {\n\n\t\tconst aGroup = a.group;\n\t\tconst bGroup = b.group;\n\n\t\tif (aGroup !== bGroup) {\n\n\t\t\t// Falsy groups come last\n\t\t\tif (!aGroup) {\n\t\t\t\treturn 1;\n\t\t\t} else if (!bGroup) {\n\t\t\t\treturn -1;\n\t\t\t}\n\n\t\t\t// 'navigation' group comes first\n\t\t\tif (aGroup === 'navigation') {\n\t\t\t\treturn -1;\n\t\t\t} else if (bGroup === 'navigation') {\n\t\t\t\treturn 1;\n\t\t\t}\n\n\t\t\t// lexical sort for groups\n\t\t\tconst value = aGroup.localeCompare(bGroup);\n\t\t\tif (value !== 0) {\n\t\t\t\treturn value;\n\t\t\t}\n\t\t}\n\n\t\t// sort on priority - default is 0\n\t\tconst aPrio = a.order || 0;\n\t\tconst bPrio = b.order || 0;\n\t\tif (aPrio < bPrio) {\n\t\t\treturn -1;\n\t\t} else if (aPrio > bPrio) {\n\t\t\treturn 1;\n\t\t}\n\n\t\t// sort on titles\n\t\treturn MenuInfo._compareTitles(\n\t\t\tisIMenuItem(a) ? a.command.title : a.title,\n\t\t\tisIMenuItem(b) ? b.command.title : b.title\n\t\t);\n\t}\n\n\tprivate static _compareTitles(a: string | ILocalizedString, b: string | ILocalizedString) {\n\t\tconst aStr = typeof a === 'string' ? a : a.original;\n\t\tconst bStr = typeof b === 'string' ? b : b.original;\n\t\treturn aStr.localeCompare(bStr);\n\t}\n}\n\nclass MenuImpl implements IMenu {\n\n\tprivate readonly _menuInfo: MenuInfo;\n\tprivate readonly _disposables = new DisposableStore();\n\n\tprivate readonly _onDidChange: Emitter;\n\treadonly onDidChange: Event;\n\n\tconstructor(\n\t\tid: MenuId,\n\t\thiddenStates: PersistedMenuHideState,\n\t\toptions: Required,\n\t\t@ICommandService commandService: ICommandService,\n\t\t@IKeybindingService keybindingService: IKeybindingService,\n\t\t@IContextKeyService contextKeyService: IContextKeyService\n\t) {\n\t\tthis._menuInfo = new MenuInfo(id, hiddenStates, options.emitEventsForSubmenuChanges, commandService, keybindingService, contextKeyService);\n\n\t\t// Rebuild this menu whenever the menu registry reports an event for this MenuId.\n\t\t// This usually happen while code and extensions are loaded and affects the over\n\t\t// structure of the menu\n\t\tconst rebuildMenuSoon = new RunOnceScheduler(() => {\n\t\t\tthis._menuInfo.refresh();\n\t\t\tthis._onDidChange.fire({ menu: this, isStructuralChange: true, isEnablementChange: true, isToggleChange: true });\n\t\t}, options.eventDebounceDelay);\n\t\tthis._disposables.add(rebuildMenuSoon);\n\t\tthis._disposables.add(MenuRegistry.onDidChangeMenu(e => {\n\t\t\tif (e.has(id)) {\n\t\t\t\trebuildMenuSoon.schedule();\n\t\t\t}\n\t\t}));\n\n\t\t// When context keys or storage state changes we need to check if the menu also has changed. However,\n\t\t// we only do that when someone listens on this menu because (1) these events are\n\t\t// firing often and (2) menu are often leaked\n\t\tconst lazyListener = this._disposables.add(new DisposableStore());\n\n\t\tconst merge = (events: IMenuChangeEvent[]): IMenuChangeEvent => {\n\n\t\t\tlet isStructuralChange = false;\n\t\t\tlet isEnablementChange = false;\n\t\t\tlet isToggleChange = false;\n\n\t\t\tfor (const item of events) {\n\t\t\t\tisStructuralChange = isStructuralChange || item.isStructuralChange;\n\t\t\t\tisEnablementChange = isEnablementChange || item.isEnablementChange;\n\t\t\t\tisToggleChange = isToggleChange || item.isToggleChange;\n\t\t\t\tif (isStructuralChange && isEnablementChange && isToggleChange) {\n\t\t\t\t\t// everything is TRUE, no need to continue iterating\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn { menu: this, isStructuralChange, isEnablementChange, isToggleChange };\n\t\t};\n\n\t\tconst startLazyListener = () => {\n\n\t\t\tlazyListener.add(contextKeyService.onDidChangeContext(e => {\n\t\t\t\tconst isStructuralChange = e.affectsSome(this._menuInfo.structureContextKeys);\n\t\t\t\tconst isEnablementChange = e.affectsSome(this._menuInfo.preconditionContextKeys);\n\t\t\t\tconst isToggleChange = e.affectsSome(this._menuInfo.toggledContextKeys);\n\t\t\t\tif (isStructuralChange || isEnablementChange || isToggleChange) {\n\t\t\t\t\tthis._onDidChange.fire({ menu: this, isStructuralChange, isEnablementChange, isToggleChange });\n\t\t\t\t}\n\t\t\t}));\n\t\t\tlazyListener.add(hiddenStates.onDidChange(e => {\n\t\t\t\tthis._onDidChange.fire({ menu: this, isStructuralChange: true, isEnablementChange: false, isToggleChange: false });\n\t\t\t}));\n\t\t};\n\n\t\tthis._onDidChange = new DebounceEmitter({\n\t\t\t// start/stop context key listener\n\t\t\tonWillAddFirstListener: startLazyListener,\n\t\t\tonDidRemoveLastListener: lazyListener.clear.bind(lazyListener),\n\t\t\tdelay: options.eventDebounceDelay,\n\t\t\tmerge\n\t\t});\n\t\tthis.onDidChange = this._onDidChange.event;\n\t}\n\n\tgetActions(options?: IMenuActionOptions | undefined): [string, (MenuItemAction | SubmenuItemAction)[]][] {\n\t\treturn this._menuInfo.createActionGroups(options);\n\t}\n\n\tdispose(): void {\n\t\tthis._disposables.dispose();\n\t\tthis._onDidChange.dispose();\n\t}\n}\n\nfunction createMenuHide(menu: MenuId, command: ICommandAction | ISubmenuItem, states: PersistedMenuHideState): IMenuItemHide {\n\n\tconst id = isISubmenuItem(command) ? command.submenu.id : command.id;\n\tconst title = typeof command.title === 'string' ? command.title : command.title.value;\n\n\tconst hide = toAction({\n\t\tid: `hide/${menu.id}/${id}`,\n\t\tlabel: localize('hide.label', 'Hide \\'{0}\\'', title),\n\t\trun() { states.updateHidden(menu, id, true); }\n\t});\n\n\tconst toggle = toAction({\n\t\tid: `toggle/${menu.id}/${id}`,\n\t\tlabel: title,\n\t\tget checked() { return !states.isHidden(menu, id); },\n\t\trun() { states.updateHidden(menu, id, !!this.checked); }\n\t});\n\n\treturn {\n\t\thide,\n\t\ttoggle,\n\t\tget isHidden() { return !toggle.checked; },\n\t};\n}\n\nexport function createConfigureKeybindingAction(commandId: string, when: ContextKeyExpression | undefined = undefined, commandService: ICommandService, keybindingService: IKeybindingService): IAction {\n\treturn toAction({\n\t\tid: `configureKeybinding/${commandId}`,\n\t\tlabel: localize('configure keybinding', \"Configure Keybinding\"),\n\t\trun() {\n\t\t\t// Only set the when clause when there is no keybinding\n\t\t\t// It is possible that the action and the keybinding have different when clauses\n\t\t\tconst hasKeybinding = !!keybindingService.lookupKeybinding(commandId); // This may only be called inside the `run()` method as it can be expensive on startup. #210529\n\t\t\tconst whenValue = !hasKeybinding && when ? when.serialize() : undefined;\n\t\t\tcommandService.executeCommand('workbench.action.openGlobalKeybindings', `@command:${commandId}` + (whenValue ? ` +when:${whenValue}` : ''));\n\t\t}\n\t});\n}\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\nimport { createDecorator } from 'vs/platform/instantiation/common/instantiation';\nimport { ClassifiedEvent, IGDPRProperty, OmitMetadata, StrictPropertyCheck } from 'vs/platform/telemetry/common/gdprTypings';\n\nexport const ITelemetryService = createDecorator('telemetryService');\n\nexport interface ITelemetryService {\n\n\treadonly _serviceBrand: undefined;\n\n\t/**\n\t * Sends a telemetry event that has been privacy approved.\n\t * Do not call this unless you have been given approval.\n\t */\n\tpublicLog2> = never, T extends IGDPRProperty = never>(eventName: string, data?: StrictPropertyCheck): void;\n}\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\nimport * as nls from 'vs/nls';\nimport { URI } from 'vs/base/common/uri';\nimport { ICodeEditor, IDiffEditor } from 'vs/editor/browser/editorBrowser';\nimport { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';\nimport { Position } from 'vs/editor/common/core/position';\nimport { IEditorContribution, IDiffEditorContribution } from 'vs/editor/common/editorCommon';\nimport { ITextModel } from 'vs/editor/common/model';\nimport { IModelService } from 'vs/editor/common/services/model';\nimport { ITextModelService } from 'vs/editor/common/services/resolverService';\nimport { MenuId, MenuRegistry, Action2 } from 'vs/platform/actions/common/actions';\nimport { CommandsRegistry, ICommandMetadata } from 'vs/platform/commands/common/commands';\nimport { ContextKeyExpr, IContextKeyService, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey';\nimport { ServicesAccessor as InstantiationServicesAccessor, BrandedService, IInstantiationService, IConstructorSignature } from 'vs/platform/instantiation/common/instantiation';\nimport { IKeybindings, KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';\nimport { Registry } from 'vs/platform/registry/common/platform';\nimport { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';\nimport { assertType } from 'vs/base/common/types';\nimport { ThemeIcon } from 'vs/base/common/themables';\nimport { IDisposable } from 'vs/base/common/lifecycle';\nimport { KeyMod, KeyCode } from 'vs/base/common/keyCodes';\nimport { ILogService } from 'vs/platform/log/common/log';\nimport { getActiveElement } from 'vs/base/browser/dom';\n\nexport type ServicesAccessor = InstantiationServicesAccessor;\nexport type EditorContributionCtor = IConstructorSignature;\nexport type DiffEditorContributionCtor = IConstructorSignature;\n\nexport const enum EditorContributionInstantiation {\n\t/**\n\t * The contribution is created eagerly when the {@linkcode ICodeEditor} is instantiated.\n\t * Only Eager contributions can participate in saving or restoring of view state.\n\t */\n\tEager,\n\n\t/**\n\t * The contribution is created at the latest 50ms after the first render after attaching a text model.\n\t * If the contribution is explicitly requested via `getContribution`, it will be instantiated sooner.\n\t * If there is idle time available, it will be instantiated sooner.\n\t */\n\tAfterFirstRender,\n\n\t/**\n\t * The contribution is created before the editor emits events produced by user interaction (mouse events, keyboard events).\n\t * If the contribution is explicitly requested via `getContribution`, it will be instantiated sooner.\n\t * If there is idle time available, it will be instantiated sooner.\n\t */\n\tBeforeFirstInteraction,\n\n\t/**\n\t * The contribution is created when there is idle time available, at the latest 5000ms after the editor creation.\n\t * If the contribution is explicitly requested via `getContribution`, it will be instantiated sooner.\n\t */\n\tEventually,\n\n\t/**\n\t * The contribution is created only when explicitly requested via `getContribution`.\n\t */\n\tLazy,\n}\n\nexport interface IEditorContributionDescription {\n\treadonly id: string;\n\treadonly ctor: EditorContributionCtor;\n\treadonly instantiation: EditorContributionInstantiation;\n}\n\nexport interface IDiffEditorContributionDescription {\n\tctor: DiffEditorContributionCtor;\n}\n\n//#region Command\n\nexport interface ICommandKeybindingsOptions extends IKeybindings {\n\tkbExpr?: ContextKeyExpression | null;\n\tweight: number;\n\t/**\n\t * the default keybinding arguments\n\t */\n\targs?: any;\n}\nexport interface ICommandMenuOptions {\n\tmenuId: MenuId;\n\tgroup: string;\n\torder: number;\n\twhen?: ContextKeyExpression;\n\ttitle: string;\n\ticon?: ThemeIcon;\n}\nexport interface ICommandOptions {\n\tid: string;\n\tprecondition: ContextKeyExpression | undefined;\n\tkbOpts?: ICommandKeybindingsOptions | ICommandKeybindingsOptions[];\n\tmetadata?: ICommandMetadata;\n\tmenuOpts?: ICommandMenuOptions | ICommandMenuOptions[];\n}\nexport abstract class Command {\n\tpublic readonly id: string;\n\tpublic readonly precondition: ContextKeyExpression | undefined;\n\tprivate readonly _kbOpts: ICommandKeybindingsOptions | ICommandKeybindingsOptions[] | undefined;\n\tprivate readonly _menuOpts: ICommandMenuOptions | ICommandMenuOptions[] | undefined;\n\tpublic readonly metadata: ICommandMetadata | undefined;\n\n\tconstructor(opts: ICommandOptions) {\n\t\tthis.id = opts.id;\n\t\tthis.precondition = opts.precondition;\n\t\tthis._kbOpts = opts.kbOpts;\n\t\tthis._menuOpts = opts.menuOpts;\n\t\tthis.metadata = opts.metadata;\n\t}\n\n\tpublic register(): void {\n\n\t\tif (Array.isArray(this._menuOpts)) {\n\t\t\tthis._menuOpts.forEach(this._registerMenuItem, this);\n\t\t} else if (this._menuOpts) {\n\t\t\tthis._registerMenuItem(this._menuOpts);\n\t\t}\n\n\t\tif (this._kbOpts) {\n\t\t\tconst kbOptsArr = Array.isArray(this._kbOpts) ? this._kbOpts : [this._kbOpts];\n\t\t\tfor (const kbOpts of kbOptsArr) {\n\t\t\t\tlet kbWhen = kbOpts.kbExpr;\n\t\t\t\tif (this.precondition) {\n\t\t\t\t\tif (kbWhen) {\n\t\t\t\t\t\tkbWhen = ContextKeyExpr.and(kbWhen, this.precondition);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tkbWhen = this.precondition;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst desc = {\n\t\t\t\t\tid: this.id,\n\t\t\t\t\tweight: kbOpts.weight,\n\t\t\t\t\targs: kbOpts.args,\n\t\t\t\t\twhen: kbWhen,\n\t\t\t\t\tprimary: kbOpts.primary,\n\t\t\t\t\tsecondary: kbOpts.secondary,\n\t\t\t\t\twin: kbOpts.win,\n\t\t\t\t\tlinux: kbOpts.linux,\n\t\t\t\t\tmac: kbOpts.mac,\n\t\t\t\t};\n\n\t\t\t\tKeybindingsRegistry.registerKeybindingRule(desc);\n\t\t\t}\n\t\t}\n\n\t\tCommandsRegistry.registerCommand({\n\t\t\tid: this.id,\n\t\t\thandler: (accessor, args) => this.runCommand(accessor, args),\n\t\t\tmetadata: this.metadata\n\t\t});\n\t}\n\n\tprivate _registerMenuItem(item: ICommandMenuOptions): void {\n\t\tMenuRegistry.appendMenuItem(item.menuId, {\n\t\t\tgroup: item.group,\n\t\t\tcommand: {\n\t\t\t\tid: this.id,\n\t\t\t\ttitle: item.title,\n\t\t\t\ticon: item.icon,\n\t\t\t\tprecondition: this.precondition\n\t\t\t},\n\t\t\twhen: item.when,\n\t\t\torder: item.order\n\t\t});\n\t}\n\n\tpublic abstract runCommand(accessor: ServicesAccessor, args: any): void | Promise;\n}\n\n//#endregion Command\n\n//#region MultiplexingCommand\n\n/**\n * Potential override for a command.\n *\n * @return `true` or a Promise if the command was successfully run. This stops other overrides from being executed.\n */\nexport type CommandImplementation = (accessor: ServicesAccessor, args: unknown) => boolean | Promise;\n\ninterface ICommandImplementationRegistration {\n\tpriority: number;\n\tname: string;\n\timplementation: CommandImplementation;\n\twhen?: ContextKeyExpression;\n}\n\nexport class MultiCommand extends Command {\n\n\tprivate readonly _implementations: ICommandImplementationRegistration[] = [];\n\n\t/**\n\t * A higher priority gets to be looked at first\n\t */\n\tpublic addImplementation(priority: number, name: string, implementation: CommandImplementation, when?: ContextKeyExpression): IDisposable {\n\t\tthis._implementations.push({ priority, name, implementation, when });\n\t\tthis._implementations.sort((a, b) => b.priority - a.priority);\n\t\treturn {\n\t\t\tdispose: () => {\n\t\t\t\tfor (let i = 0; i < this._implementations.length; i++) {\n\t\t\t\t\tif (this._implementations[i].implementation === implementation) {\n\t\t\t\t\t\tthis._implementations.splice(i, 1);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n\n\tpublic runCommand(accessor: ServicesAccessor, args: any): void | Promise {\n\t\tconst logService = accessor.get(ILogService);\n\t\tconst contextKeyService = accessor.get(IContextKeyService);\n\t\tlogService.trace(`Executing Command '${this.id}' which has ${this._implementations.length} bound.`);\n\t\tfor (const impl of this._implementations) {\n\t\t\tif (impl.when) {\n\t\t\t\tconst context = contextKeyService.getContext(getActiveElement());\n\t\t\t\tconst value = impl.when.evaluate(context);\n\t\t\t\tif (!value) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst result = impl.implementation(accessor, args);\n\t\t\tif (result) {\n\t\t\t\tlogService.trace(`Command '${this.id}' was handled by '${impl.name}'.`);\n\t\t\t\tif (typeof result === 'boolean') {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\treturn result;\n\t\t\t}\n\t\t}\n\t\tlogService.trace(`The Command '${this.id}' was not handled by any implementation.`);\n\t}\n}\n\n//#endregion\n\n/**\n * A command that delegates to another command's implementation.\n *\n * This lets different commands be registered but share the same implementation\n */\nexport class ProxyCommand extends Command {\n\tconstructor(\n\t\tprivate readonly command: Command,\n\t\topts: ICommandOptions\n\t) {\n\t\tsuper(opts);\n\t}\n\n\tpublic runCommand(accessor: ServicesAccessor, args: any): void | Promise {\n\t\treturn this.command.runCommand(accessor, args);\n\t}\n}\n\n//#region EditorCommand\n\nexport interface IContributionCommandOptions extends ICommandOptions {\n\thandler: (controller: T, args: any) => void;\n}\nexport interface EditorControllerCommand {\n\tnew(opts: IContributionCommandOptions): EditorCommand;\n}\nexport abstract class EditorCommand extends Command {\n\n\t/**\n\t * Create a command class that is bound to a certain editor contribution.\n\t */\n\tpublic static bindToContribution(controllerGetter: (editor: ICodeEditor) => T | null): EditorControllerCommand {\n\t\treturn class EditorControllerCommandImpl extends EditorCommand {\n\t\t\tprivate readonly _callback: (controller: T, args: any) => void;\n\n\t\t\tconstructor(opts: IContributionCommandOptions) {\n\t\t\t\tsuper(opts);\n\n\t\t\t\tthis._callback = opts.handler;\n\t\t\t}\n\n\t\t\tpublic runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void {\n\t\t\t\tconst controller = controllerGetter(editor);\n\t\t\t\tif (controller) {\n\t\t\t\t\tthis._callback(controller, args);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n\n\tpublic static runEditorCommand(\n\t\taccessor: ServicesAccessor,\n\t\targs: any,\n\t\tprecondition: ContextKeyExpression | undefined,\n\t\trunner: (accessor: ServicesAccessor | null, editor: ICodeEditor, args: any) => void | Promise\n\t): void | Promise {\n\t\tconst codeEditorService = accessor.get(ICodeEditorService);\n\n\t\t// Find the editor with text focus or active\n\t\tconst editor = codeEditorService.getFocusedCodeEditor() || codeEditorService.getActiveCodeEditor();\n\t\tif (!editor) {\n\t\t\t// well, at least we tried...\n\t\t\treturn;\n\t\t}\n\n\t\treturn editor.invokeWithinContext((editorAccessor) => {\n\t\t\tconst kbService = editorAccessor.get(IContextKeyService);\n\t\t\tif (!kbService.contextMatchesRules(precondition ?? undefined)) {\n\t\t\t\t// precondition does not hold\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\treturn runner(editorAccessor, editor, args);\n\t\t});\n\t}\n\n\tpublic runCommand(accessor: ServicesAccessor, args: any): void | Promise {\n\t\treturn EditorCommand.runEditorCommand(accessor, args, this.precondition, (accessor, editor, args) => this.runEditorCommand(accessor, editor, args));\n\t}\n\n\tpublic abstract runEditorCommand(accessor: ServicesAccessor | null, editor: ICodeEditor, args: any): void | Promise;\n}\n\n//#endregion EditorCommand\n\n//#region EditorAction\n\nexport interface IEditorActionContextMenuOptions {\n\tgroup: string;\n\torder: number;\n\twhen?: ContextKeyExpression;\n}\nexport interface IActionOptions extends ICommandOptions {\n\tlabel: string;\n\talias: string;\n\tcontextMenuOpts?: IEditorActionContextMenuOptions | IEditorActionContextMenuOptions[];\n}\n\nexport abstract class EditorAction extends EditorCommand {\n\n\tprivate static convertOptions(opts: IActionOptions): ICommandOptions {\n\n\t\tlet menuOpts: ICommandMenuOptions[];\n\t\tif (Array.isArray(opts.menuOpts)) {\n\t\t\tmenuOpts = opts.menuOpts;\n\t\t} else if (opts.menuOpts) {\n\t\t\tmenuOpts = [opts.menuOpts];\n\t\t} else {\n\t\t\tmenuOpts = [];\n\t\t}\n\n\t\tfunction withDefaults(item: Partial): ICommandMenuOptions {\n\t\t\tif (!item.menuId) {\n\t\t\t\titem.menuId = MenuId.EditorContext;\n\t\t\t}\n\t\t\tif (!item.title) {\n\t\t\t\titem.title = opts.label;\n\t\t\t}\n\t\t\titem.when = ContextKeyExpr.and(opts.precondition, item.when);\n\t\t\treturn item;\n\t\t}\n\n\t\tif (Array.isArray(opts.contextMenuOpts)) {\n\t\t\tmenuOpts.push(...opts.contextMenuOpts.map(withDefaults));\n\t\t} else if (opts.contextMenuOpts) {\n\t\t\tmenuOpts.push(withDefaults(opts.contextMenuOpts));\n\t\t}\n\n\t\topts.menuOpts = menuOpts;\n\t\treturn opts;\n\t}\n\n\tpublic readonly label: string;\n\tpublic readonly alias: string;\n\n\tconstructor(opts: IActionOptions) {\n\t\tsuper(EditorAction.convertOptions(opts));\n\t\tthis.label = opts.label;\n\t\tthis.alias = opts.alias;\n\t}\n\n\tpublic runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void | Promise {\n\t\tthis.reportTelemetry(accessor, editor);\n\t\treturn this.run(accessor, editor, args || {});\n\t}\n\n\tprotected reportTelemetry(accessor: ServicesAccessor, editor: ICodeEditor) {\n\t\ttype EditorActionInvokedClassification = {\n\t\t\towner: 'alexdima';\n\t\t\tcomment: 'An editor action has been invoked.';\n\t\t\tname: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The label of the action that was invoked.' };\n\t\t\tid: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The identifier of the action that was invoked.' };\n\t\t};\n\t\ttype EditorActionInvokedEvent = {\n\t\t\tname: string;\n\t\t\tid: string;\n\t\t};\n\t\taccessor.get(ITelemetryService).publicLog2('editorActionInvoked', { name: this.label, id: this.id });\n\t}\n\n\tpublic abstract run(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void | Promise;\n}\n\nexport type EditorActionImplementation = (accessor: ServicesAccessor, editor: ICodeEditor, args: any) => boolean | Promise;\n\nexport class MultiEditorAction extends EditorAction {\n\n\tprivate readonly _implementations: [number, EditorActionImplementation][] = [];\n\n\t/**\n\t * A higher priority gets to be looked at first\n\t */\n\tpublic addImplementation(priority: number, implementation: EditorActionImplementation): IDisposable {\n\t\tthis._implementations.push([priority, implementation]);\n\t\tthis._implementations.sort((a, b) => b[0] - a[0]);\n\t\treturn {\n\t\t\tdispose: () => {\n\t\t\t\tfor (let i = 0; i < this._implementations.length; i++) {\n\t\t\t\t\tif (this._implementations[i][1] === implementation) {\n\t\t\t\t\t\tthis._implementations.splice(i, 1);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void | Promise {\n\t\tfor (const impl of this._implementations) {\n\t\t\tconst result = impl[1](accessor, editor, args);\n\t\t\tif (result) {\n\t\t\t\tif (typeof result === 'boolean') {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\treturn result;\n\t\t\t}\n\t\t}\n\t}\n\n}\n\n//#endregion EditorAction\n\n//#region EditorAction2\n\nexport abstract class EditorAction2 extends Action2 {\n\n\trun(accessor: ServicesAccessor, ...args: any[]) {\n\t\t// Find the editor with text focus or active\n\t\tconst codeEditorService = accessor.get(ICodeEditorService);\n\t\tconst editor = codeEditorService.getFocusedCodeEditor() || codeEditorService.getActiveCodeEditor();\n\t\tif (!editor) {\n\t\t\t// well, at least we tried...\n\t\t\treturn;\n\t\t}\n\t\t// precondition does hold\n\t\treturn editor.invokeWithinContext((editorAccessor) => {\n\t\t\tconst kbService = editorAccessor.get(IContextKeyService);\n\t\t\tconst logService = editorAccessor.get(ILogService);\n\t\t\tconst enabled = kbService.contextMatchesRules(this.desc.precondition ?? undefined);\n\t\t\tif (!enabled) {\n\t\t\t\tlogService.debug(`[EditorAction2] NOT running command because its precondition is FALSE`, this.desc.id, this.desc.precondition?.serialize());\n\t\t\t\treturn;\n\t\t\t}\n\t\t\treturn this.runEditorCommand(editorAccessor, editor, ...args);\n\t\t});\n\t}\n\n\tabstract runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, ...args: any[]): any;\n}\n\n//#endregion\n\n// --- Registration of commands and actions\n\n\nexport function registerModelAndPositionCommand(id: string, handler: (accessor: ServicesAccessor, model: ITextModel, position: Position, ...args: any[]) => any) {\n\tCommandsRegistry.registerCommand(id, function (accessor, ...args) {\n\n\t\tconst instaService = accessor.get(IInstantiationService);\n\n\t\tconst [resource, position] = args;\n\t\tassertType(URI.isUri(resource));\n\t\tassertType(Position.isIPosition(position));\n\n\t\tconst model = accessor.get(IModelService).getModel(resource);\n\t\tif (model) {\n\t\t\tconst editorPosition = Position.lift(position);\n\t\t\treturn instaService.invokeFunction(handler, model, editorPosition, ...args.slice(2));\n\t\t}\n\n\t\treturn accessor.get(ITextModelService).createModelReference(resource).then(reference => {\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\ttry {\n\t\t\t\t\tconst result = instaService.invokeFunction(handler, reference.object.textEditorModel, Position.lift(position), args.slice(2));\n\t\t\t\t\tresolve(result);\n\t\t\t\t} catch (err) {\n\t\t\t\t\treject(err);\n\t\t\t\t}\n\t\t\t}).finally(() => {\n\t\t\t\treference.dispose();\n\t\t\t});\n\t\t});\n\t});\n}\n\nexport function registerEditorCommand(editorCommand: T): T {\n\tEditorContributionRegistry.INSTANCE.registerEditorCommand(editorCommand);\n\treturn editorCommand;\n}\n\nexport function registerEditorAction(ctor: { new(): T }): T {\n\tconst action = new ctor();\n\tEditorContributionRegistry.INSTANCE.registerEditorAction(action);\n\treturn action;\n}\n\nexport function registerMultiEditorAction(action: T): T {\n\tEditorContributionRegistry.INSTANCE.registerEditorAction(action);\n\treturn action;\n}\n\nexport function registerInstantiatedEditorAction(editorAction: EditorAction): void {\n\tEditorContributionRegistry.INSTANCE.registerEditorAction(editorAction);\n}\n\n/**\n * Registers an editor contribution. Editor contributions have a lifecycle which is bound\n * to a specific code editor instance.\n */\nexport function registerEditorContribution(id: string, ctor: { new(editor: ICodeEditor, ...services: Services): IEditorContribution }, instantiation: EditorContributionInstantiation): void {\n\tEditorContributionRegistry.INSTANCE.registerEditorContribution(id, ctor, instantiation);\n}\n\nexport namespace EditorExtensionsRegistry {\n\n\texport function getEditorCommand(commandId: string): EditorCommand {\n\t\treturn EditorContributionRegistry.INSTANCE.getEditorCommand(commandId);\n\t}\n\n\texport function getEditorActions(): Iterable {\n\t\treturn EditorContributionRegistry.INSTANCE.getEditorActions();\n\t}\n\n\texport function getEditorContributions(): IEditorContributionDescription[] {\n\t\treturn EditorContributionRegistry.INSTANCE.getEditorContributions();\n\t}\n\n\texport function getSomeEditorContributions(ids: string[]): IEditorContributionDescription[] {\n\t\treturn EditorContributionRegistry.INSTANCE.getEditorContributions().filter(c => ids.indexOf(c.id) >= 0);\n\t}\n\n\texport function getDiffEditorContributions(): IDiffEditorContributionDescription[] {\n\t\treturn EditorContributionRegistry.INSTANCE.getDiffEditorContributions();\n\t}\n}\n\n// Editor extension points\nconst Extensions = {\n\tEditorCommonContributions: 'editor.contributions'\n};\n\nclass EditorContributionRegistry {\n\n\tpublic static readonly INSTANCE = new EditorContributionRegistry();\n\n\tprivate readonly editorContributions: IEditorContributionDescription[] = [];\n\tprivate readonly diffEditorContributions: IDiffEditorContributionDescription[] = [];\n\tprivate readonly editorActions: EditorAction[] = [];\n\tprivate readonly editorCommands: { [commandId: string]: EditorCommand } = Object.create(null);\n\n\tconstructor() {\n\t}\n\n\tpublic registerEditorContribution(id: string, ctor: { new(editor: ICodeEditor, ...services: Services): IEditorContribution }, instantiation: EditorContributionInstantiation): void {\n\t\tthis.editorContributions.push({ id, ctor: ctor as EditorContributionCtor, instantiation });\n\t}\n\n\tpublic getEditorContributions(): IEditorContributionDescription[] {\n\t\treturn this.editorContributions.slice(0);\n\t}\n\n\tpublic getDiffEditorContributions(): IDiffEditorContributionDescription[] {\n\t\treturn this.diffEditorContributions.slice(0);\n\t}\n\n\tpublic registerEditorAction(action: EditorAction) {\n\t\taction.register();\n\t\tthis.editorActions.push(action);\n\t}\n\n\tpublic getEditorActions(): Iterable {\n\t\treturn this.editorActions;\n\t}\n\n\tpublic registerEditorCommand(editorCommand: EditorCommand) {\n\t\teditorCommand.register();\n\t\tthis.editorCommands[editorCommand.id] = editorCommand;\n\t}\n\n\tpublic getEditorCommand(commandId: string): EditorCommand {\n\t\treturn (this.editorCommands[commandId] || null);\n\t}\n\n}\nRegistry.add(Extensions.EditorCommonContributions, EditorContributionRegistry.INSTANCE);\n\nfunction registerCommand(command: T): T {\n\tcommand.register();\n\treturn command;\n}\n\nexport const UndoCommand = registerCommand(new MultiCommand({\n\tid: 'undo',\n\tprecondition: undefined,\n\tkbOpts: {\n\t\tweight: KeybindingWeight.EditorCore,\n\t\tprimary: KeyMod.CtrlCmd | KeyCode.KeyZ\n\t},\n\tmenuOpts: [{\n\t\tmenuId: MenuId.MenubarEditMenu,\n\t\tgroup: '1_do',\n\t\ttitle: nls.localize({ key: 'miUndo', comment: ['&& denotes a mnemonic'] }, \"&&Undo\"),\n\t\torder: 1\n\t}, {\n\t\tmenuId: MenuId.CommandPalette,\n\t\tgroup: '',\n\t\ttitle: nls.localize('undo', \"Undo\"),\n\t\torder: 1\n\t}]\n}));\n\nregisterCommand(new ProxyCommand(UndoCommand, { id: 'default:undo', precondition: undefined }));\n\nexport const RedoCommand = registerCommand(new MultiCommand({\n\tid: 'redo',\n\tprecondition: undefined,\n\tkbOpts: {\n\t\tweight: KeybindingWeight.EditorCore,\n\t\tprimary: KeyMod.CtrlCmd | KeyCode.KeyY,\n\t\tsecondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KeyZ],\n\t\tmac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KeyZ }\n\t},\n\tmenuOpts: [{\n\t\tmenuId: MenuId.MenubarEditMenu,\n\t\tgroup: '1_do',\n\t\ttitle: nls.localize({ key: 'miRedo', comment: ['&& denotes a mnemonic'] }, \"&&Redo\"),\n\t\torder: 2\n\t}, {\n\t\tmenuId: MenuId.CommandPalette,\n\t\tgroup: '',\n\t\ttitle: nls.localize('redo', \"Redo\"),\n\t\torder: 1\n\t}]\n}));\n\nregisterCommand(new ProxyCommand(RedoCommand, { id: 'default:redo', precondition: undefined }));\n\nexport const SelectAllCommand = registerCommand(new MultiCommand({\n\tid: 'editor.action.selectAll',\n\tprecondition: undefined,\n\tkbOpts: {\n\t\tweight: KeybindingWeight.EditorCore,\n\t\tkbExpr: null,\n\t\tprimary: KeyMod.CtrlCmd | KeyCode.KeyA\n\t},\n\tmenuOpts: [{\n\t\tmenuId: MenuId.MenubarSelectionMenu,\n\t\tgroup: '1_basic',\n\t\ttitle: nls.localize({ key: 'miSelectAll', comment: ['&& denotes a mnemonic'] }, \"&&Select All\"),\n\t\torder: 1\n\t}, {\n\t\tmenuId: MenuId.CommandPalette,\n\t\tgroup: '',\n\t\ttitle: nls.localize('selectAll', \"Select All\"),\n\t\torder: 1\n\t}]\n}));\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\nimport * as nls from 'vs/nls';\nimport { isFirefox } from 'vs/base/browser/browser';\nimport { KeyCode, KeyMod } from 'vs/base/common/keyCodes';\nimport * as types from 'vs/base/common/types';\nimport { status } from 'vs/base/browser/ui/aria/aria';\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\nimport { Command, EditorCommand, ICommandOptions, registerEditorCommand, MultiCommand, UndoCommand, RedoCommand, SelectAllCommand } from 'vs/editor/browser/editorExtensions';\nimport { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';\nimport { ColumnSelection, IColumnSelectResult } from 'vs/editor/common/cursor/cursorColumnSelection';\nimport { CursorState, EditOperationType, IColumnSelectData, PartialCursorState } from 'vs/editor/common/cursorCommon';\nimport { DeleteOperations } from 'vs/editor/common/cursor/cursorDeleteOperations';\nimport { CursorChangeReason } from 'vs/editor/common/cursorEvents';\nimport { CursorMove as CursorMove_, CursorMoveCommands } from 'vs/editor/common/cursor/cursorMoveCommands';\nimport { TypeOperations } from 'vs/editor/common/cursor/cursorTypeOperations';\nimport { IPosition, Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\nimport { Handler, ScrollType } from 'vs/editor/common/editorCommon';\nimport { EditorContextKeys } from 'vs/editor/common/editorContextKeys';\nimport { VerticalRevealType } from 'vs/editor/common/viewEvents';\nimport { ICommandMetadata } from 'vs/platform/commands/common/commands';\nimport { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';\nimport { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';\nimport { KeybindingWeight, KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry';\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\nimport { IViewModel } from 'vs/editor/common/viewModel';\nimport { ISelection } from 'vs/editor/common/core/selection';\nimport { getActiveElement } from 'vs/base/browser/dom';\n\nconst CORE_WEIGHT = KeybindingWeight.EditorCore;\n\nexport abstract class CoreEditorCommand extends EditorCommand {\n\tpublic runEditorCommand(accessor: ServicesAccessor | null, editor: ICodeEditor, args?: Partial | null): void {\n\t\tconst viewModel = editor._getViewModel();\n\t\tif (!viewModel) {\n\t\t\t// the editor has no view => has no cursors\n\t\t\treturn;\n\t\t}\n\t\tthis.runCoreEditorCommand(viewModel, args || {});\n\t}\n\n\tpublic abstract runCoreEditorCommand(viewModel: IViewModel, args: Partial): void;\n}\n\nexport namespace EditorScroll_ {\n\n\tconst isEditorScrollArgs = function (arg: any): boolean {\n\t\tif (!types.isObject(arg)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst scrollArg: RawArguments = arg;\n\n\t\tif (!types.isString(scrollArg.to)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (!types.isUndefined(scrollArg.by) && !types.isString(scrollArg.by)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (!types.isUndefined(scrollArg.value) && !types.isNumber(scrollArg.value)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (!types.isUndefined(scrollArg.revealCursor) && !types.isBoolean(scrollArg.revealCursor)) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t};\n\n\texport const metadata = {\n\t\tdescription: 'Scroll editor in the given direction',\n\t\targs: [\n\t\t\t{\n\t\t\t\tname: 'Editor scroll argument object',\n\t\t\t\tdescription: `Property-value pairs that can be passed through this argument:\n\t\t\t\t\t* 'to': A mandatory direction value.\n\t\t\t\t\t\t\\`\\`\\`\n\t\t\t\t\t\t'up', 'down'\n\t\t\t\t\t\t\\`\\`\\`\n\t\t\t\t\t* 'by': Unit to move. Default is computed based on 'to' value.\n\t\t\t\t\t\t\\`\\`\\`\n\t\t\t\t\t\t'line', 'wrappedLine', 'page', 'halfPage', 'editor'\n\t\t\t\t\t\t\\`\\`\\`\n\t\t\t\t\t* 'value': Number of units to move. Default is '1'.\n\t\t\t\t\t* 'revealCursor': If 'true' reveals the cursor if it is outside view port.\n\t\t\t\t`,\n\t\t\t\tconstraint: isEditorScrollArgs,\n\t\t\t\tschema: {\n\t\t\t\t\t'type': 'object',\n\t\t\t\t\t'required': ['to'],\n\t\t\t\t\t'properties': {\n\t\t\t\t\t\t'to': {\n\t\t\t\t\t\t\t'type': 'string',\n\t\t\t\t\t\t\t'enum': ['up', 'down']\n\t\t\t\t\t\t},\n\t\t\t\t\t\t'by': {\n\t\t\t\t\t\t\t'type': 'string',\n\t\t\t\t\t\t\t'enum': ['line', 'wrappedLine', 'page', 'halfPage', 'editor']\n\t\t\t\t\t\t},\n\t\t\t\t\t\t'value': {\n\t\t\t\t\t\t\t'type': 'number',\n\t\t\t\t\t\t\t'default': 1\n\t\t\t\t\t\t},\n\t\t\t\t\t\t'revealCursor': {\n\t\t\t\t\t\t\t'type': 'boolean',\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]\n\t};\n\n\t/**\n\t * Directions in the view for editor scroll command.\n\t */\n\texport const RawDirection = {\n\t\tUp: 'up',\n\t\tRight: 'right',\n\t\tDown: 'down',\n\t\tLeft: 'left'\n\t};\n\n\t/**\n\t * Units for editor scroll 'by' argument\n\t */\n\texport const RawUnit = {\n\t\tLine: 'line',\n\t\tWrappedLine: 'wrappedLine',\n\t\tPage: 'page',\n\t\tHalfPage: 'halfPage',\n\t\tEditor: 'editor',\n\t\tColumn: 'column'\n\t};\n\n\t/**\n\t * Arguments for editor scroll command\n\t */\n\texport interface RawArguments {\n\t\tto: string;\n\t\tby?: string;\n\t\tvalue?: number;\n\t\trevealCursor?: boolean;\n\t\tselect?: boolean;\n\t}\n\n\texport function parse(args: Partial): ParsedArguments | null {\n\t\tlet direction: Direction;\n\t\tswitch (args.to) {\n\t\t\tcase RawDirection.Up:\n\t\t\t\tdirection = Direction.Up;\n\t\t\t\tbreak;\n\t\t\tcase RawDirection.Right:\n\t\t\t\tdirection = Direction.Right;\n\t\t\t\tbreak;\n\t\t\tcase RawDirection.Down:\n\t\t\t\tdirection = Direction.Down;\n\t\t\t\tbreak;\n\t\t\tcase RawDirection.Left:\n\t\t\t\tdirection = Direction.Left;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\t// Illegal arguments\n\t\t\t\treturn null;\n\t\t}\n\n\t\tlet unit: Unit;\n\t\tswitch (args.by) {\n\t\t\tcase RawUnit.Line:\n\t\t\t\tunit = Unit.Line;\n\t\t\t\tbreak;\n\t\t\tcase RawUnit.WrappedLine:\n\t\t\t\tunit = Unit.WrappedLine;\n\t\t\t\tbreak;\n\t\t\tcase RawUnit.Page:\n\t\t\t\tunit = Unit.Page;\n\t\t\t\tbreak;\n\t\t\tcase RawUnit.HalfPage:\n\t\t\t\tunit = Unit.HalfPage;\n\t\t\t\tbreak;\n\t\t\tcase RawUnit.Editor:\n\t\t\t\tunit = Unit.Editor;\n\t\t\t\tbreak;\n\t\t\tcase RawUnit.Column:\n\t\t\t\tunit = Unit.Column;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tunit = Unit.WrappedLine;\n\t\t}\n\n\t\tconst value = Math.floor(args.value || 1);\n\t\tconst revealCursor = !!args.revealCursor;\n\n\t\treturn {\n\t\t\tdirection: direction,\n\t\t\tunit: unit,\n\t\t\tvalue: value,\n\t\t\trevealCursor: revealCursor,\n\t\t\tselect: (!!args.select)\n\t\t};\n\t}\n\n\texport interface ParsedArguments {\n\t\tdirection: Direction;\n\t\tunit: Unit;\n\t\tvalue: number;\n\t\trevealCursor: boolean;\n\t\tselect: boolean;\n\t}\n\n\n\texport const enum Direction {\n\t\tUp = 1,\n\t\tRight = 2,\n\t\tDown = 3,\n\t\tLeft = 4\n\t}\n\n\texport const enum Unit {\n\t\tLine = 1,\n\t\tWrappedLine = 2,\n\t\tPage = 3,\n\t\tHalfPage = 4,\n\t\tEditor = 5,\n\t\tColumn = 6\n\t}\n}\n\nexport namespace RevealLine_ {\n\n\tconst isRevealLineArgs = function (arg: any): boolean {\n\t\tif (!types.isObject(arg)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst reveaLineArg: RawArguments = arg;\n\n\t\tif (!types.isNumber(reveaLineArg.lineNumber) && !types.isString(reveaLineArg.lineNumber)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (!types.isUndefined(reveaLineArg.at) && !types.isString(reveaLineArg.at)) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t};\n\n\texport const metadata = {\n\t\tdescription: 'Reveal the given line at the given logical position',\n\t\targs: [\n\t\t\t{\n\t\t\t\tname: 'Reveal line argument object',\n\t\t\t\tdescription: `Property-value pairs that can be passed through this argument:\n\t\t\t\t\t* 'lineNumber': A mandatory line number value.\n\t\t\t\t\t* 'at': Logical position at which line has to be revealed.\n\t\t\t\t\t\t\\`\\`\\`\n\t\t\t\t\t\t'top', 'center', 'bottom'\n\t\t\t\t\t\t\\`\\`\\`\n\t\t\t\t`,\n\t\t\t\tconstraint: isRevealLineArgs,\n\t\t\t\tschema: {\n\t\t\t\t\t'type': 'object',\n\t\t\t\t\t'required': ['lineNumber'],\n\t\t\t\t\t'properties': {\n\t\t\t\t\t\t'lineNumber': {\n\t\t\t\t\t\t\t'type': ['number', 'string'],\n\t\t\t\t\t\t},\n\t\t\t\t\t\t'at': {\n\t\t\t\t\t\t\t'type': 'string',\n\t\t\t\t\t\t\t'enum': ['top', 'center', 'bottom']\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]\n\t};\n\n\t/**\n\t * Arguments for reveal line command\n\t */\n\texport interface RawArguments {\n\t\tlineNumber?: number | string;\n\t\tat?: string;\n\t}\n\n\t/**\n\t * Values for reveal line 'at' argument\n\t */\n\texport const RawAtArgument = {\n\t\tTop: 'top',\n\t\tCenter: 'center',\n\t\tBottom: 'bottom'\n\t};\n}\n\nabstract class EditorOrNativeTextInputCommand {\n\n\tconstructor(target: MultiCommand) {\n\t\t// 1. handle case when focus is in editor.\n\t\ttarget.addImplementation(10000, 'code-editor', (accessor: ServicesAccessor, args: unknown) => {\n\t\t\t// Only if editor text focus (i.e. not if editor has widget focus).\n\t\t\tconst focusedEditor = accessor.get(ICodeEditorService).getFocusedCodeEditor();\n\t\t\tif (focusedEditor && focusedEditor.hasTextFocus()) {\n\t\t\t\treturn this._runEditorCommand(accessor, focusedEditor, args);\n\t\t\t}\n\t\t\treturn false;\n\t\t});\n\n\t\t// 2. handle case when focus is in some other `input` / `textarea`.\n\t\ttarget.addImplementation(1000, 'generic-dom-input-textarea', (accessor: ServicesAccessor, args: unknown) => {\n\t\t\t// Only if focused on an element that allows for entering text\n\t\t\tconst activeElement = getActiveElement();\n\t\t\tif (activeElement && ['input', 'textarea'].indexOf(activeElement.tagName.toLowerCase()) >= 0) {\n\t\t\t\tthis.runDOMCommand(activeElement);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn false;\n\t\t});\n\n\t\t// 3. (default) handle case when focus is somewhere else.\n\t\ttarget.addImplementation(0, 'generic-dom', (accessor: ServicesAccessor, args: unknown) => {\n\t\t\t// Redirecting to active editor\n\t\t\tconst activeEditor = accessor.get(ICodeEditorService).getActiveCodeEditor();\n\t\t\tif (activeEditor) {\n\t\t\t\tactiveEditor.focus();\n\t\t\t\treturn this._runEditorCommand(accessor, activeEditor, args);\n\t\t\t}\n\t\t\treturn false;\n\t\t});\n\t}\n\n\tpublic _runEditorCommand(accessor: ServicesAccessor | null, editor: ICodeEditor, args: unknown): boolean | Promise {\n\t\tconst result = this.runEditorCommand(accessor, editor, args);\n\t\tif (result) {\n\t\t\treturn result;\n\t\t}\n\t\treturn true;\n\t}\n\n\tpublic abstract runDOMCommand(activeElement: Element): void;\n\tpublic abstract runEditorCommand(accessor: ServicesAccessor | null, editor: ICodeEditor, args: unknown): void | Promise;\n}\n\nexport const enum NavigationCommandRevealType {\n\t/**\n\t * Do regular revealing.\n\t */\n\tRegular = 0,\n\t/**\n\t * Do only minimal revealing.\n\t */\n\tMinimal = 1,\n\t/**\n\t * Do not reveal the position.\n\t */\n\tNone = 2\n}\n\nexport namespace CoreNavigationCommands {\n\n\texport interface BaseCommandOptions {\n\t\tsource?: 'mouse' | 'keyboard' | string;\n\t}\n\n\texport interface MoveCommandOptions extends BaseCommandOptions {\n\t\tposition: IPosition;\n\t\tviewPosition?: IPosition;\n\t\trevealType: NavigationCommandRevealType;\n\t}\n\n\tclass BaseMoveToCommand extends CoreEditorCommand {\n\n\t\tprivate readonly _inSelectionMode: boolean;\n\n\t\tconstructor(opts: ICommandOptions & { inSelectionMode: boolean }) {\n\t\t\tsuper(opts);\n\t\t\tthis._inSelectionMode = opts.inSelectionMode;\n\t\t}\n\n\t\tpublic runCoreEditorCommand(viewModel: IViewModel, args: Partial): void {\n\t\t\tif (!args.position) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tviewModel.model.pushStackElement();\n\t\t\tconst cursorStateChanged = viewModel.setCursorStates(\n\t\t\t\targs.source,\n\t\t\t\tCursorChangeReason.Explicit,\n\t\t\t\t[\n\t\t\t\t\tCursorMoveCommands.moveTo(viewModel, viewModel.getPrimaryCursorState(), this._inSelectionMode, args.position, args.viewPosition)\n\t\t\t\t]\n\t\t\t);\n\t\t\tif (cursorStateChanged && args.revealType !== NavigationCommandRevealType.None) {\n\t\t\t\tviewModel.revealAllCursors(args.source, true, true);\n\t\t\t}\n\t\t}\n\t}\n\n\texport const MoveTo: CoreEditorCommand = registerEditorCommand(new BaseMoveToCommand({\n\t\tid: '_moveTo',\n\t\tinSelectionMode: false,\n\t\tprecondition: undefined\n\t}));\n\n\texport const MoveToSelect: CoreEditorCommand = registerEditorCommand(new BaseMoveToCommand({\n\t\tid: '_moveToSelect',\n\t\tinSelectionMode: true,\n\t\tprecondition: undefined\n\t}));\n\n\tabstract class ColumnSelectCommand extends CoreEditorCommand {\n\t\tpublic runCoreEditorCommand(viewModel: IViewModel, args: Partial): void {\n\t\t\tviewModel.model.pushStackElement();\n\t\t\tconst result = this._getColumnSelectResult(viewModel, viewModel.getPrimaryCursorState(), viewModel.getCursorColumnSelectData(), args);\n\t\t\tif (result === null) {\n\t\t\t\t// invalid arguments\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tviewModel.setCursorStates(args.source, CursorChangeReason.Explicit, result.viewStates.map((viewState) => CursorState.fromViewState(viewState)));\n\t\t\tviewModel.setCursorColumnSelectData({\n\t\t\t\tisReal: true,\n\t\t\t\tfromViewLineNumber: result.fromLineNumber,\n\t\t\t\tfromViewVisualColumn: result.fromVisualColumn,\n\t\t\t\ttoViewLineNumber: result.toLineNumber,\n\t\t\t\ttoViewVisualColumn: result.toVisualColumn\n\t\t\t});\n\t\t\tif (result.reversed) {\n\t\t\t\tviewModel.revealTopMostCursor(args.source);\n\t\t\t} else {\n\t\t\t\tviewModel.revealBottomMostCursor(args.source);\n\t\t\t}\n\t\t}\n\n\t\tprotected abstract _getColumnSelectResult(viewModel: IViewModel, primary: CursorState, prevColumnSelectData: IColumnSelectData, args: Partial): IColumnSelectResult | null;\n\n\t}\n\n\texport interface ColumnSelectCommandOptions extends BaseCommandOptions {\n\t\tposition: IPosition;\n\t\tviewPosition: IPosition;\n\t\tmouseColumn: number;\n\t\tdoColumnSelect: boolean;\n\t}\n\n\texport const ColumnSelect: CoreEditorCommand = registerEditorCommand(new class extends ColumnSelectCommand {\n\t\tconstructor() {\n\t\t\tsuper({\n\t\t\t\tid: 'columnSelect',\n\t\t\t\tprecondition: undefined\n\t\t\t});\n\t\t}\n\n\t\tprotected _getColumnSelectResult(viewModel: IViewModel, primary: CursorState, prevColumnSelectData: IColumnSelectData, args: Partial): IColumnSelectResult | null {\n\t\t\tif (typeof args.position === 'undefined' || typeof args.viewPosition === 'undefined' || typeof args.mouseColumn === 'undefined') {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\t// validate `args`\n\t\t\tconst validatedPosition = viewModel.model.validatePosition(args.position);\n\t\t\tconst validatedViewPosition = viewModel.coordinatesConverter.validateViewPosition(new Position(args.viewPosition.lineNumber, args.viewPosition.column), validatedPosition);\n\n\t\t\tconst fromViewLineNumber = args.doColumnSelect ? prevColumnSelectData.fromViewLineNumber : validatedViewPosition.lineNumber;\n\t\t\tconst fromViewVisualColumn = args.doColumnSelect ? prevColumnSelectData.fromViewVisualColumn : args.mouseColumn - 1;\n\t\t\treturn ColumnSelection.columnSelect(viewModel.cursorConfig, viewModel, fromViewLineNumber, fromViewVisualColumn, validatedViewPosition.lineNumber, args.mouseColumn - 1);\n\t\t}\n\t});\n\n\texport const CursorColumnSelectLeft: CoreEditorCommand = registerEditorCommand(new class extends ColumnSelectCommand {\n\t\tconstructor() {\n\t\t\tsuper({\n\t\t\t\tid: 'cursorColumnSelectLeft',\n\t\t\t\tprecondition: undefined,\n\t\t\t\tkbOpts: {\n\t\t\t\t\tweight: CORE_WEIGHT,\n\t\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\t\t\tprimary: KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyCode.LeftArrow,\n\t\t\t\t\tlinux: { primary: 0 }\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\tprotected _getColumnSelectResult(viewModel: IViewModel, primary: CursorState, prevColumnSelectData: IColumnSelectData, args: Partial): IColumnSelectResult {\n\t\t\treturn ColumnSelection.columnSelectLeft(viewModel.cursorConfig, viewModel, prevColumnSelectData);\n\t\t}\n\t});\n\n\texport const CursorColumnSelectRight: CoreEditorCommand = registerEditorCommand(new class extends ColumnSelectCommand {\n\t\tconstructor() {\n\t\t\tsuper({\n\t\t\t\tid: 'cursorColumnSelectRight',\n\t\t\t\tprecondition: undefined,\n\t\t\t\tkbOpts: {\n\t\t\t\t\tweight: CORE_WEIGHT,\n\t\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\t\t\tprimary: KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyCode.RightArrow,\n\t\t\t\t\tlinux: { primary: 0 }\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\tprotected _getColumnSelectResult(viewModel: IViewModel, primary: CursorState, prevColumnSelectData: IColumnSelectData, args: Partial): IColumnSelectResult {\n\t\t\treturn ColumnSelection.columnSelectRight(viewModel.cursorConfig, viewModel, prevColumnSelectData);\n\t\t}\n\t});\n\n\tclass ColumnSelectUpCommand extends ColumnSelectCommand {\n\n\t\tprivate readonly _isPaged: boolean;\n\n\t\tconstructor(opts: ICommandOptions & { isPaged: boolean }) {\n\t\t\tsuper(opts);\n\t\t\tthis._isPaged = opts.isPaged;\n\t\t}\n\n\t\tprotected _getColumnSelectResult(viewModel: IViewModel, primary: CursorState, prevColumnSelectData: IColumnSelectData, args: Partial): IColumnSelectResult {\n\t\t\treturn ColumnSelection.columnSelectUp(viewModel.cursorConfig, viewModel, prevColumnSelectData, this._isPaged);\n\t\t}\n\t}\n\n\texport const CursorColumnSelectUp: CoreEditorCommand = registerEditorCommand(new ColumnSelectUpCommand({\n\t\tisPaged: false,\n\t\tid: 'cursorColumnSelectUp',\n\t\tprecondition: undefined,\n\t\tkbOpts: {\n\t\t\tweight: CORE_WEIGHT,\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\tprimary: KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyCode.UpArrow,\n\t\t\tlinux: { primary: 0 }\n\t\t}\n\t}));\n\n\texport const CursorColumnSelectPageUp: CoreEditorCommand = registerEditorCommand(new ColumnSelectUpCommand({\n\t\tisPaged: true,\n\t\tid: 'cursorColumnSelectPageUp',\n\t\tprecondition: undefined,\n\t\tkbOpts: {\n\t\t\tweight: CORE_WEIGHT,\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\tprimary: KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyCode.PageUp,\n\t\t\tlinux: { primary: 0 }\n\t\t}\n\t}));\n\n\tclass ColumnSelectDownCommand extends ColumnSelectCommand {\n\n\t\tprivate readonly _isPaged: boolean;\n\n\t\tconstructor(opts: ICommandOptions & { isPaged: boolean }) {\n\t\t\tsuper(opts);\n\t\t\tthis._isPaged = opts.isPaged;\n\t\t}\n\n\t\tprotected _getColumnSelectResult(viewModel: IViewModel, primary: CursorState, prevColumnSelectData: IColumnSelectData, args: Partial): IColumnSelectResult {\n\t\t\treturn ColumnSelection.columnSelectDown(viewModel.cursorConfig, viewModel, prevColumnSelectData, this._isPaged);\n\t\t}\n\t}\n\n\texport const CursorColumnSelectDown: CoreEditorCommand = registerEditorCommand(new ColumnSelectDownCommand({\n\t\tisPaged: false,\n\t\tid: 'cursorColumnSelectDown',\n\t\tprecondition: undefined,\n\t\tkbOpts: {\n\t\t\tweight: CORE_WEIGHT,\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\tprimary: KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyCode.DownArrow,\n\t\t\tlinux: { primary: 0 }\n\t\t}\n\t}));\n\n\texport const CursorColumnSelectPageDown: CoreEditorCommand = registerEditorCommand(new ColumnSelectDownCommand({\n\t\tisPaged: true,\n\t\tid: 'cursorColumnSelectPageDown',\n\t\tprecondition: undefined,\n\t\tkbOpts: {\n\t\t\tweight: CORE_WEIGHT,\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\tprimary: KeyMod.CtrlCmd | KeyMod.Shift | KeyMod.Alt | KeyCode.PageDown,\n\t\t\tlinux: { primary: 0 }\n\t\t}\n\t}));\n\n\texport class CursorMoveImpl extends CoreEditorCommand {\n\t\tconstructor() {\n\t\t\tsuper({\n\t\t\t\tid: 'cursorMove',\n\t\t\t\tprecondition: undefined,\n\t\t\t\tmetadata: CursorMove_.metadata\n\t\t\t});\n\t\t}\n\n\t\tpublic runCoreEditorCommand(viewModel: IViewModel, args: Partial): void {\n\t\t\tconst parsed = CursorMove_.parse(args);\n\t\t\tif (!parsed) {\n\t\t\t\t// illegal arguments\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis._runCursorMove(viewModel, args.source, parsed);\n\t\t}\n\n\t\tprivate _runCursorMove(viewModel: IViewModel, source: string | null | undefined, args: CursorMove_.ParsedArguments): void {\n\t\t\tviewModel.model.pushStackElement();\n\t\t\tviewModel.setCursorStates(\n\t\t\t\tsource,\n\t\t\t\tCursorChangeReason.Explicit,\n\t\t\t\tCursorMoveImpl._move(viewModel, viewModel.getCursorStates(), args)\n\t\t\t);\n\t\t\tviewModel.revealAllCursors(source, true);\n\t\t}\n\n\t\tprivate static _move(viewModel: IViewModel, cursors: CursorState[], args: CursorMove_.ParsedArguments): PartialCursorState[] | null {\n\t\t\tconst inSelectionMode = args.select;\n\t\t\tconst value = args.value;\n\n\t\t\tswitch (args.direction) {\n\t\t\t\tcase CursorMove_.Direction.Left:\n\t\t\t\tcase CursorMove_.Direction.Right:\n\t\t\t\tcase CursorMove_.Direction.Up:\n\t\t\t\tcase CursorMove_.Direction.Down:\n\t\t\t\tcase CursorMove_.Direction.PrevBlankLine:\n\t\t\t\tcase CursorMove_.Direction.NextBlankLine:\n\t\t\t\tcase CursorMove_.Direction.WrappedLineStart:\n\t\t\t\tcase CursorMove_.Direction.WrappedLineFirstNonWhitespaceCharacter:\n\t\t\t\tcase CursorMove_.Direction.WrappedLineColumnCenter:\n\t\t\t\tcase CursorMove_.Direction.WrappedLineEnd:\n\t\t\t\tcase CursorMove_.Direction.WrappedLineLastNonWhitespaceCharacter:\n\t\t\t\t\treturn CursorMoveCommands.simpleMove(viewModel, cursors, args.direction, inSelectionMode, value, args.unit);\n\n\t\t\t\tcase CursorMove_.Direction.ViewPortTop:\n\t\t\t\tcase CursorMove_.Direction.ViewPortBottom:\n\t\t\t\tcase CursorMove_.Direction.ViewPortCenter:\n\t\t\t\tcase CursorMove_.Direction.ViewPortIfOutside:\n\t\t\t\t\treturn CursorMoveCommands.viewportMove(viewModel, cursors, args.direction, inSelectionMode, value);\n\t\t\t\tdefault:\n\t\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\t}\n\n\texport const CursorMove: CursorMoveImpl = registerEditorCommand(new CursorMoveImpl());\n\n\tconst enum Constants {\n\t\tPAGE_SIZE_MARKER = -1\n\t}\n\n\texport interface CursorMoveCommandOptions extends BaseCommandOptions {\n\t\tpageSize?: number;\n\t}\n\n\tclass CursorMoveBasedCommand extends CoreEditorCommand {\n\n\t\tprivate readonly _staticArgs: CursorMove_.SimpleMoveArguments;\n\n\t\tconstructor(opts: ICommandOptions & { args: CursorMove_.SimpleMoveArguments }) {\n\t\t\tsuper(opts);\n\t\t\tthis._staticArgs = opts.args;\n\t\t}\n\n\t\tpublic runCoreEditorCommand(viewModel: IViewModel, dynamicArgs: Partial): void {\n\t\t\tlet args = this._staticArgs;\n\t\t\tif (this._staticArgs.value === Constants.PAGE_SIZE_MARKER) {\n\t\t\t\t// -1 is a marker for page size\n\t\t\t\targs = {\n\t\t\t\t\tdirection: this._staticArgs.direction,\n\t\t\t\t\tunit: this._staticArgs.unit,\n\t\t\t\t\tselect: this._staticArgs.select,\n\t\t\t\t\tvalue: dynamicArgs.pageSize || viewModel.cursorConfig.pageSize\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tviewModel.model.pushStackElement();\n\t\t\tviewModel.setCursorStates(\n\t\t\t\tdynamicArgs.source,\n\t\t\t\tCursorChangeReason.Explicit,\n\t\t\t\tCursorMoveCommands.simpleMove(viewModel, viewModel.getCursorStates(), args.direction, args.select, args.value, args.unit)\n\t\t\t);\n\t\t\tviewModel.revealAllCursors(dynamicArgs.source, true);\n\t\t}\n\t}\n\n\texport const CursorLeft: CoreEditorCommand = registerEditorCommand(new CursorMoveBasedCommand({\n\t\targs: {\n\t\t\tdirection: CursorMove_.Direction.Left,\n\t\t\tunit: CursorMove_.Unit.None,\n\t\t\tselect: false,\n\t\t\tvalue: 1\n\t\t},\n\t\tid: 'cursorLeft',\n\t\tprecondition: undefined,\n\t\tkbOpts: {\n\t\t\tweight: CORE_WEIGHT,\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\tprimary: KeyCode.LeftArrow,\n\t\t\tmac: { primary: KeyCode.LeftArrow, secondary: [KeyMod.WinCtrl | KeyCode.KeyB] }\n\t\t}\n\t}));\n\n\texport const CursorLeftSelect: CoreEditorCommand = registerEditorCommand(new CursorMoveBasedCommand({\n\t\targs: {\n\t\t\tdirection: CursorMove_.Direction.Left,\n\t\t\tunit: CursorMove_.Unit.None,\n\t\t\tselect: true,\n\t\t\tvalue: 1\n\t\t},\n\t\tid: 'cursorLeftSelect',\n\t\tprecondition: undefined,\n\t\tkbOpts: {\n\t\t\tweight: CORE_WEIGHT,\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\tprimary: KeyMod.Shift | KeyCode.LeftArrow\n\t\t}\n\t}));\n\n\texport const CursorRight: CoreEditorCommand = registerEditorCommand(new CursorMoveBasedCommand({\n\t\targs: {\n\t\t\tdirection: CursorMove_.Direction.Right,\n\t\t\tunit: CursorMove_.Unit.None,\n\t\t\tselect: false,\n\t\t\tvalue: 1\n\t\t},\n\t\tid: 'cursorRight',\n\t\tprecondition: undefined,\n\t\tkbOpts: {\n\t\t\tweight: CORE_WEIGHT,\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\tprimary: KeyCode.RightArrow,\n\t\t\tmac: { primary: KeyCode.RightArrow, secondary: [KeyMod.WinCtrl | KeyCode.KeyF] }\n\t\t}\n\t}));\n\n\texport const CursorRightSelect: CoreEditorCommand = registerEditorCommand(new CursorMoveBasedCommand({\n\t\targs: {\n\t\t\tdirection: CursorMove_.Direction.Right,\n\t\t\tunit: CursorMove_.Unit.None,\n\t\t\tselect: true,\n\t\t\tvalue: 1\n\t\t},\n\t\tid: 'cursorRightSelect',\n\t\tprecondition: undefined,\n\t\tkbOpts: {\n\t\t\tweight: CORE_WEIGHT,\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\tprimary: KeyMod.Shift | KeyCode.RightArrow\n\t\t}\n\t}));\n\n\texport const CursorUp: CoreEditorCommand = registerEditorCommand(new CursorMoveBasedCommand({\n\t\targs: {\n\t\t\tdirection: CursorMove_.Direction.Up,\n\t\t\tunit: CursorMove_.Unit.WrappedLine,\n\t\t\tselect: false,\n\t\t\tvalue: 1\n\t\t},\n\t\tid: 'cursorUp',\n\t\tprecondition: undefined,\n\t\tkbOpts: {\n\t\t\tweight: CORE_WEIGHT,\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\tprimary: KeyCode.UpArrow,\n\t\t\tmac: { primary: KeyCode.UpArrow, secondary: [KeyMod.WinCtrl | KeyCode.KeyP] }\n\t\t}\n\t}));\n\n\texport const CursorUpSelect: CoreEditorCommand = registerEditorCommand(new CursorMoveBasedCommand({\n\t\targs: {\n\t\t\tdirection: CursorMove_.Direction.Up,\n\t\t\tunit: CursorMove_.Unit.WrappedLine,\n\t\t\tselect: true,\n\t\t\tvalue: 1\n\t\t},\n\t\tid: 'cursorUpSelect',\n\t\tprecondition: undefined,\n\t\tkbOpts: {\n\t\t\tweight: CORE_WEIGHT,\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\tprimary: KeyMod.Shift | KeyCode.UpArrow,\n\t\t\tsecondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.UpArrow],\n\t\t\tmac: { primary: KeyMod.Shift | KeyCode.UpArrow },\n\t\t\tlinux: { primary: KeyMod.Shift | KeyCode.UpArrow }\n\t\t}\n\t}));\n\n\texport const CursorPageUp: CoreEditorCommand = registerEditorCommand(new CursorMoveBasedCommand({\n\t\targs: {\n\t\t\tdirection: CursorMove_.Direction.Up,\n\t\t\tunit: CursorMove_.Unit.WrappedLine,\n\t\t\tselect: false,\n\t\t\tvalue: Constants.PAGE_SIZE_MARKER\n\t\t},\n\t\tid: 'cursorPageUp',\n\t\tprecondition: undefined,\n\t\tkbOpts: {\n\t\t\tweight: CORE_WEIGHT,\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\tprimary: KeyCode.PageUp\n\t\t}\n\t}));\n\n\texport const CursorPageUpSelect: CoreEditorCommand = registerEditorCommand(new CursorMoveBasedCommand({\n\t\targs: {\n\t\t\tdirection: CursorMove_.Direction.Up,\n\t\t\tunit: CursorMove_.Unit.WrappedLine,\n\t\t\tselect: true,\n\t\t\tvalue: Constants.PAGE_SIZE_MARKER\n\t\t},\n\t\tid: 'cursorPageUpSelect',\n\t\tprecondition: undefined,\n\t\tkbOpts: {\n\t\t\tweight: CORE_WEIGHT,\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\tprimary: KeyMod.Shift | KeyCode.PageUp\n\t\t}\n\t}));\n\n\texport const CursorDown: CoreEditorCommand = registerEditorCommand(new CursorMoveBasedCommand({\n\t\targs: {\n\t\t\tdirection: CursorMove_.Direction.Down,\n\t\t\tunit: CursorMove_.Unit.WrappedLine,\n\t\t\tselect: false,\n\t\t\tvalue: 1\n\t\t},\n\t\tid: 'cursorDown',\n\t\tprecondition: undefined,\n\t\tkbOpts: {\n\t\t\tweight: CORE_WEIGHT,\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\tprimary: KeyCode.DownArrow,\n\t\t\tmac: { primary: KeyCode.DownArrow, secondary: [KeyMod.WinCtrl | KeyCode.KeyN] }\n\t\t}\n\t}));\n\n\texport const CursorDownSelect: CoreEditorCommand = registerEditorCommand(new CursorMoveBasedCommand({\n\t\targs: {\n\t\t\tdirection: CursorMove_.Direction.Down,\n\t\t\tunit: CursorMove_.Unit.WrappedLine,\n\t\t\tselect: true,\n\t\t\tvalue: 1\n\t\t},\n\t\tid: 'cursorDownSelect',\n\t\tprecondition: undefined,\n\t\tkbOpts: {\n\t\t\tweight: CORE_WEIGHT,\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\tprimary: KeyMod.Shift | KeyCode.DownArrow,\n\t\t\tsecondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.DownArrow],\n\t\t\tmac: { primary: KeyMod.Shift | KeyCode.DownArrow },\n\t\t\tlinux: { primary: KeyMod.Shift | KeyCode.DownArrow }\n\t\t}\n\t}));\n\n\texport const CursorPageDown: CoreEditorCommand = registerEditorCommand(new CursorMoveBasedCommand({\n\t\targs: {\n\t\t\tdirection: CursorMove_.Direction.Down,\n\t\t\tunit: CursorMove_.Unit.WrappedLine,\n\t\t\tselect: false,\n\t\t\tvalue: Constants.PAGE_SIZE_MARKER\n\t\t},\n\t\tid: 'cursorPageDown',\n\t\tprecondition: undefined,\n\t\tkbOpts: {\n\t\t\tweight: CORE_WEIGHT,\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\tprimary: KeyCode.PageDown\n\t\t}\n\t}));\n\n\texport const CursorPageDownSelect: CoreEditorCommand = registerEditorCommand(new CursorMoveBasedCommand({\n\t\targs: {\n\t\t\tdirection: CursorMove_.Direction.Down,\n\t\t\tunit: CursorMove_.Unit.WrappedLine,\n\t\t\tselect: true,\n\t\t\tvalue: Constants.PAGE_SIZE_MARKER\n\t\t},\n\t\tid: 'cursorPageDownSelect',\n\t\tprecondition: undefined,\n\t\tkbOpts: {\n\t\t\tweight: CORE_WEIGHT,\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\tprimary: KeyMod.Shift | KeyCode.PageDown\n\t\t}\n\t}));\n\n\texport interface CreateCursorCommandOptions extends MoveCommandOptions {\n\t\twholeLine?: boolean;\n\t}\n\n\texport const CreateCursor: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand {\n\t\tconstructor() {\n\t\t\tsuper({\n\t\t\t\tid: 'createCursor',\n\t\t\t\tprecondition: undefined\n\t\t\t});\n\t\t}\n\n\t\tpublic runCoreEditorCommand(viewModel: IViewModel, args: Partial): void {\n\t\t\tif (!args.position) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tlet newState: PartialCursorState;\n\t\t\tif (args.wholeLine) {\n\t\t\t\tnewState = CursorMoveCommands.line(viewModel, viewModel.getPrimaryCursorState(), false, args.position, args.viewPosition);\n\t\t\t} else {\n\t\t\t\tnewState = CursorMoveCommands.moveTo(viewModel, viewModel.getPrimaryCursorState(), false, args.position, args.viewPosition);\n\t\t\t}\n\n\t\t\tconst states: PartialCursorState[] = viewModel.getCursorStates();\n\n\t\t\t// Check if we should remove a cursor (sort of like a toggle)\n\t\t\tif (states.length > 1) {\n\t\t\t\tconst newModelPosition = (newState.modelState ? newState.modelState.position : null);\n\t\t\t\tconst newViewPosition = (newState.viewState ? newState.viewState.position : null);\n\n\t\t\t\tfor (let i = 0, len = states.length; i < len; i++) {\n\t\t\t\t\tconst state = states[i];\n\n\t\t\t\t\tif (newModelPosition && !state.modelState!.selection.containsPosition(newModelPosition)) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (newViewPosition && !state.viewState!.selection.containsPosition(newViewPosition)) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\t// => Remove the cursor\n\t\t\t\t\tstates.splice(i, 1);\n\n\t\t\t\t\tviewModel.model.pushStackElement();\n\t\t\t\t\tviewModel.setCursorStates(\n\t\t\t\t\t\targs.source,\n\t\t\t\t\t\tCursorChangeReason.Explicit,\n\t\t\t\t\t\tstates\n\t\t\t\t\t);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// => Add the new cursor\n\t\t\tstates.push(newState);\n\n\t\t\tviewModel.model.pushStackElement();\n\t\t\tviewModel.setCursorStates(\n\t\t\t\targs.source,\n\t\t\t\tCursorChangeReason.Explicit,\n\t\t\t\tstates\n\t\t\t);\n\t\t}\n\t});\n\n\texport const LastCursorMoveToSelect: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand {\n\t\tconstructor() {\n\t\t\tsuper({\n\t\t\t\tid: '_lastCursorMoveToSelect',\n\t\t\t\tprecondition: undefined\n\t\t\t});\n\t\t}\n\n\t\tpublic runCoreEditorCommand(viewModel: IViewModel, args: Partial): void {\n\t\t\tif (!args.position) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst lastAddedCursorIndex = viewModel.getLastAddedCursorIndex();\n\n\t\t\tconst states = viewModel.getCursorStates();\n\t\t\tconst newStates: PartialCursorState[] = states.slice(0);\n\t\t\tnewStates[lastAddedCursorIndex] = CursorMoveCommands.moveTo(viewModel, states[lastAddedCursorIndex], true, args.position, args.viewPosition);\n\n\t\t\tviewModel.model.pushStackElement();\n\t\t\tviewModel.setCursorStates(\n\t\t\t\targs.source,\n\t\t\t\tCursorChangeReason.Explicit,\n\t\t\t\tnewStates\n\t\t\t);\n\t\t}\n\t});\n\n\tclass HomeCommand extends CoreEditorCommand {\n\n\t\tprivate readonly _inSelectionMode: boolean;\n\n\t\tconstructor(opts: ICommandOptions & { inSelectionMode: boolean }) {\n\t\t\tsuper(opts);\n\t\t\tthis._inSelectionMode = opts.inSelectionMode;\n\t\t}\n\n\t\tpublic runCoreEditorCommand(viewModel: IViewModel, args: Partial): void {\n\t\t\tviewModel.model.pushStackElement();\n\t\t\tviewModel.setCursorStates(\n\t\t\t\targs.source,\n\t\t\t\tCursorChangeReason.Explicit,\n\t\t\t\tCursorMoveCommands.moveToBeginningOfLine(viewModel, viewModel.getCursorStates(), this._inSelectionMode)\n\t\t\t);\n\t\t\tviewModel.revealAllCursors(args.source, true);\n\t\t}\n\t}\n\n\texport const CursorHome: CoreEditorCommand = registerEditorCommand(new HomeCommand({\n\t\tinSelectionMode: false,\n\t\tid: 'cursorHome',\n\t\tprecondition: undefined,\n\t\tkbOpts: {\n\t\t\tweight: CORE_WEIGHT,\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\tprimary: KeyCode.Home,\n\t\t\tmac: { primary: KeyCode.Home, secondary: [KeyMod.CtrlCmd | KeyCode.LeftArrow] }\n\t\t}\n\t}));\n\n\texport const CursorHomeSelect: CoreEditorCommand = registerEditorCommand(new HomeCommand({\n\t\tinSelectionMode: true,\n\t\tid: 'cursorHomeSelect',\n\t\tprecondition: undefined,\n\t\tkbOpts: {\n\t\t\tweight: CORE_WEIGHT,\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\tprimary: KeyMod.Shift | KeyCode.Home,\n\t\t\tmac: { primary: KeyMod.Shift | KeyCode.Home, secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.LeftArrow] }\n\t\t}\n\t}));\n\n\tclass LineStartCommand extends CoreEditorCommand {\n\n\t\tprivate readonly _inSelectionMode: boolean;\n\n\t\tconstructor(opts: ICommandOptions & { inSelectionMode: boolean }) {\n\t\t\tsuper(opts);\n\t\t\tthis._inSelectionMode = opts.inSelectionMode;\n\t\t}\n\n\t\tpublic runCoreEditorCommand(viewModel: IViewModel, args: Partial): void {\n\t\t\tviewModel.model.pushStackElement();\n\t\t\tviewModel.setCursorStates(\n\t\t\t\targs.source,\n\t\t\t\tCursorChangeReason.Explicit,\n\t\t\t\tthis._exec(viewModel.getCursorStates())\n\t\t\t);\n\t\t\tviewModel.revealAllCursors(args.source, true);\n\t\t}\n\n\t\tprivate _exec(cursors: CursorState[]): PartialCursorState[] {\n\t\t\tconst result: PartialCursorState[] = [];\n\t\t\tfor (let i = 0, len = cursors.length; i < len; i++) {\n\t\t\t\tconst cursor = cursors[i];\n\t\t\t\tconst lineNumber = cursor.modelState.position.lineNumber;\n\t\t\t\tresult[i] = CursorState.fromModelState(cursor.modelState.move(this._inSelectionMode, lineNumber, 1, 0));\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\t}\n\n\texport const CursorLineStart: CoreEditorCommand = registerEditorCommand(new LineStartCommand({\n\t\tinSelectionMode: false,\n\t\tid: 'cursorLineStart',\n\t\tprecondition: undefined,\n\t\tkbOpts: {\n\t\t\tweight: CORE_WEIGHT,\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\tprimary: 0,\n\t\t\tmac: { primary: KeyMod.WinCtrl | KeyCode.KeyA }\n\t\t}\n\t}));\n\n\texport const CursorLineStartSelect: CoreEditorCommand = registerEditorCommand(new LineStartCommand({\n\t\tinSelectionMode: true,\n\t\tid: 'cursorLineStartSelect',\n\t\tprecondition: undefined,\n\t\tkbOpts: {\n\t\t\tweight: CORE_WEIGHT,\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\tprimary: 0,\n\t\t\tmac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.KeyA }\n\t\t}\n\t}));\n\n\texport interface EndCommandOptions extends BaseCommandOptions {\n\t\tsticky?: boolean;\n\t}\n\n\tclass EndCommand extends CoreEditorCommand {\n\n\t\tprivate readonly _inSelectionMode: boolean;\n\n\t\tconstructor(opts: ICommandOptions & { inSelectionMode: boolean }) {\n\t\t\tsuper(opts);\n\t\t\tthis._inSelectionMode = opts.inSelectionMode;\n\t\t}\n\n\t\tpublic runCoreEditorCommand(viewModel: IViewModel, args: Partial): void {\n\t\t\tviewModel.model.pushStackElement();\n\t\t\tviewModel.setCursorStates(\n\t\t\t\targs.source,\n\t\t\t\tCursorChangeReason.Explicit,\n\t\t\t\tCursorMoveCommands.moveToEndOfLine(viewModel, viewModel.getCursorStates(), this._inSelectionMode, args.sticky || false)\n\t\t\t);\n\t\t\tviewModel.revealAllCursors(args.source, true);\n\t\t}\n\t}\n\n\texport const CursorEnd: CoreEditorCommand = registerEditorCommand(new EndCommand({\n\t\tinSelectionMode: false,\n\t\tid: 'cursorEnd',\n\t\tprecondition: undefined,\n\t\tkbOpts: {\n\t\t\targs: { sticky: false },\n\t\t\tweight: CORE_WEIGHT,\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\tprimary: KeyCode.End,\n\t\t\tmac: { primary: KeyCode.End, secondary: [KeyMod.CtrlCmd | KeyCode.RightArrow] }\n\t\t},\n\t\tmetadata: {\n\t\t\tdescription: `Go to End`,\n\t\t\targs: [{\n\t\t\t\tname: 'args',\n\t\t\t\tschema: {\n\t\t\t\t\ttype: 'object',\n\t\t\t\t\tproperties: {\n\t\t\t\t\t\t'sticky': {\n\t\t\t\t\t\t\tdescription: nls.localize('stickydesc', \"Stick to the end even when going to longer lines\"),\n\t\t\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\t\t\tdefault: false\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}\n\t}));\n\n\texport const CursorEndSelect: CoreEditorCommand = registerEditorCommand(new EndCommand({\n\t\tinSelectionMode: true,\n\t\tid: 'cursorEndSelect',\n\t\tprecondition: undefined,\n\t\tkbOpts: {\n\t\t\targs: { sticky: false },\n\t\t\tweight: CORE_WEIGHT,\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\tprimary: KeyMod.Shift | KeyCode.End,\n\t\t\tmac: { primary: KeyMod.Shift | KeyCode.End, secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.RightArrow] }\n\t\t},\n\t\tmetadata: {\n\t\t\tdescription: `Select to End`,\n\t\t\targs: [{\n\t\t\t\tname: 'args',\n\t\t\t\tschema: {\n\t\t\t\t\ttype: 'object',\n\t\t\t\t\tproperties: {\n\t\t\t\t\t\t'sticky': {\n\t\t\t\t\t\t\tdescription: nls.localize('stickydesc', \"Stick to the end even when going to longer lines\"),\n\t\t\t\t\t\t\ttype: 'boolean',\n\t\t\t\t\t\t\tdefault: false\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}\n\t}));\n\n\tclass LineEndCommand extends CoreEditorCommand {\n\n\t\tprivate readonly _inSelectionMode: boolean;\n\n\t\tconstructor(opts: ICommandOptions & { inSelectionMode: boolean }) {\n\t\t\tsuper(opts);\n\t\t\tthis._inSelectionMode = opts.inSelectionMode;\n\t\t}\n\n\t\tpublic runCoreEditorCommand(viewModel: IViewModel, args: Partial): void {\n\t\t\tviewModel.model.pushStackElement();\n\t\t\tviewModel.setCursorStates(\n\t\t\t\targs.source,\n\t\t\t\tCursorChangeReason.Explicit,\n\t\t\t\tthis._exec(viewModel, viewModel.getCursorStates())\n\t\t\t);\n\t\t\tviewModel.revealAllCursors(args.source, true);\n\t\t}\n\n\t\tprivate _exec(viewModel: IViewModel, cursors: CursorState[]): PartialCursorState[] {\n\t\t\tconst result: PartialCursorState[] = [];\n\t\t\tfor (let i = 0, len = cursors.length; i < len; i++) {\n\t\t\t\tconst cursor = cursors[i];\n\t\t\t\tconst lineNumber = cursor.modelState.position.lineNumber;\n\t\t\t\tconst maxColumn = viewModel.model.getLineMaxColumn(lineNumber);\n\t\t\t\tresult[i] = CursorState.fromModelState(cursor.modelState.move(this._inSelectionMode, lineNumber, maxColumn, 0));\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\t}\n\n\texport const CursorLineEnd: CoreEditorCommand = registerEditorCommand(new LineEndCommand({\n\t\tinSelectionMode: false,\n\t\tid: 'cursorLineEnd',\n\t\tprecondition: undefined,\n\t\tkbOpts: {\n\t\t\tweight: CORE_WEIGHT,\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\tprimary: 0,\n\t\t\tmac: { primary: KeyMod.WinCtrl | KeyCode.KeyE }\n\t\t}\n\t}));\n\n\texport const CursorLineEndSelect: CoreEditorCommand = registerEditorCommand(new LineEndCommand({\n\t\tinSelectionMode: true,\n\t\tid: 'cursorLineEndSelect',\n\t\tprecondition: undefined,\n\t\tkbOpts: {\n\t\t\tweight: CORE_WEIGHT,\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\tprimary: 0,\n\t\t\tmac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.KeyE }\n\t\t}\n\t}));\n\n\tclass TopCommand extends CoreEditorCommand {\n\n\t\tprivate readonly _inSelectionMode: boolean;\n\n\t\tconstructor(opts: ICommandOptions & { inSelectionMode: boolean }) {\n\t\t\tsuper(opts);\n\t\t\tthis._inSelectionMode = opts.inSelectionMode;\n\t\t}\n\n\t\tpublic runCoreEditorCommand(viewModel: IViewModel, args: Partial): void {\n\t\t\tviewModel.model.pushStackElement();\n\t\t\tviewModel.setCursorStates(\n\t\t\t\targs.source,\n\t\t\t\tCursorChangeReason.Explicit,\n\t\t\t\tCursorMoveCommands.moveToBeginningOfBuffer(viewModel, viewModel.getCursorStates(), this._inSelectionMode)\n\t\t\t);\n\t\t\tviewModel.revealAllCursors(args.source, true);\n\t\t}\n\t}\n\n\texport const CursorTop: CoreEditorCommand = registerEditorCommand(new TopCommand({\n\t\tinSelectionMode: false,\n\t\tid: 'cursorTop',\n\t\tprecondition: undefined,\n\t\tkbOpts: {\n\t\t\tweight: CORE_WEIGHT,\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\tprimary: KeyMod.CtrlCmd | KeyCode.Home,\n\t\t\tmac: { primary: KeyMod.CtrlCmd | KeyCode.UpArrow }\n\t\t}\n\t}));\n\n\texport const CursorTopSelect: CoreEditorCommand = registerEditorCommand(new TopCommand({\n\t\tinSelectionMode: true,\n\t\tid: 'cursorTopSelect',\n\t\tprecondition: undefined,\n\t\tkbOpts: {\n\t\t\tweight: CORE_WEIGHT,\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\tprimary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.Home,\n\t\t\tmac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.UpArrow }\n\t\t}\n\t}));\n\n\tclass BottomCommand extends CoreEditorCommand {\n\n\t\tprivate readonly _inSelectionMode: boolean;\n\n\t\tconstructor(opts: ICommandOptions & { inSelectionMode: boolean }) {\n\t\t\tsuper(opts);\n\t\t\tthis._inSelectionMode = opts.inSelectionMode;\n\t\t}\n\n\t\tpublic runCoreEditorCommand(viewModel: IViewModel, args: Partial): void {\n\t\t\tviewModel.model.pushStackElement();\n\t\t\tviewModel.setCursorStates(\n\t\t\t\targs.source,\n\t\t\t\tCursorChangeReason.Explicit,\n\t\t\t\tCursorMoveCommands.moveToEndOfBuffer(viewModel, viewModel.getCursorStates(), this._inSelectionMode)\n\t\t\t);\n\t\t\tviewModel.revealAllCursors(args.source, true);\n\t\t}\n\t}\n\n\texport const CursorBottom: CoreEditorCommand = registerEditorCommand(new BottomCommand({\n\t\tinSelectionMode: false,\n\t\tid: 'cursorBottom',\n\t\tprecondition: undefined,\n\t\tkbOpts: {\n\t\t\tweight: CORE_WEIGHT,\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\tprimary: KeyMod.CtrlCmd | KeyCode.End,\n\t\t\tmac: { primary: KeyMod.CtrlCmd | KeyCode.DownArrow }\n\t\t}\n\t}));\n\n\texport const CursorBottomSelect: CoreEditorCommand = registerEditorCommand(new BottomCommand({\n\t\tinSelectionMode: true,\n\t\tid: 'cursorBottomSelect',\n\t\tprecondition: undefined,\n\t\tkbOpts: {\n\t\t\tweight: CORE_WEIGHT,\n\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\tprimary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.End,\n\t\t\tmac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.DownArrow }\n\t\t}\n\t}));\n\n\texport type EditorScrollCommandOptions = EditorScroll_.RawArguments & BaseCommandOptions;\n\n\texport class EditorScrollImpl extends CoreEditorCommand {\n\t\tconstructor() {\n\t\t\tsuper({\n\t\t\t\tid: 'editorScroll',\n\t\t\t\tprecondition: undefined,\n\t\t\t\tmetadata: EditorScroll_.metadata\n\t\t\t});\n\t\t}\n\n\t\tdetermineScrollMethod(args: EditorScroll_.ParsedArguments) {\n\t\t\tconst horizontalUnits = [EditorScroll_.Unit.Column];\n\t\t\tconst verticalUnits = [\n\t\t\t\tEditorScroll_.Unit.Line,\n\t\t\t\tEditorScroll_.Unit.WrappedLine,\n\t\t\t\tEditorScroll_.Unit.Page,\n\t\t\t\tEditorScroll_.Unit.HalfPage,\n\t\t\t\tEditorScroll_.Unit.Editor,\n\t\t\t\tEditorScroll_.Unit.Column\n\t\t\t];\n\t\t\tconst horizontalDirections = [EditorScroll_.Direction.Left, EditorScroll_.Direction.Right];\n\t\t\tconst verticalDirections = [EditorScroll_.Direction.Up, EditorScroll_.Direction.Down];\n\n\t\t\tif (horizontalUnits.includes(args.unit) && horizontalDirections.includes(args.direction)) {\n\t\t\t\treturn this._runHorizontalEditorScroll.bind(this);\n\t\t\t}\n\t\t\tif (verticalUnits.includes(args.unit) && verticalDirections.includes(args.direction)) {\n\t\t\t\treturn this._runVerticalEditorScroll.bind(this);\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t\tpublic runCoreEditorCommand(viewModel: IViewModel, args: Partial): void {\n\t\t\tconst parsed = EditorScroll_.parse(args);\n\t\t\tif (!parsed) {\n\t\t\t\t// illegal arguments\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst runEditorScroll = this.determineScrollMethod(parsed);\n\t\t\tif (!runEditorScroll) {\n\t\t\t\t// Incompatible unit and direction\n\t\t\t\treturn;\n\t\t\t}\n\t\t\trunEditorScroll(viewModel, args.source, parsed);\n\t\t}\n\n\t\t_runVerticalEditorScroll(viewModel: IViewModel, source: string | null | undefined, args: EditorScroll_.ParsedArguments): void {\n\n\t\t\tconst desiredScrollTop = this._computeDesiredScrollTop(viewModel, args);\n\n\t\t\tif (args.revealCursor) {\n\t\t\t\t// must ensure cursor is in new visible range\n\t\t\t\tconst desiredVisibleViewRange = viewModel.getCompletelyVisibleViewRangeAtScrollTop(desiredScrollTop);\n\t\t\t\tviewModel.setCursorStates(\n\t\t\t\t\tsource,\n\t\t\t\t\tCursorChangeReason.Explicit,\n\t\t\t\t\t[\n\t\t\t\t\t\tCursorMoveCommands.findPositionInViewportIfOutside(viewModel, viewModel.getPrimaryCursorState(), desiredVisibleViewRange, args.select)\n\t\t\t\t\t]\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tviewModel.viewLayout.setScrollPosition({ scrollTop: desiredScrollTop }, ScrollType.Smooth);\n\t\t}\n\n\t\tprivate _computeDesiredScrollTop(viewModel: IViewModel, args: EditorScroll_.ParsedArguments): number {\n\n\t\t\tif (args.unit === EditorScroll_.Unit.Line) {\n\t\t\t\t// scrolling by model lines\n\t\t\t\tconst futureViewport = viewModel.viewLayout.getFutureViewport();\n\t\t\t\tconst visibleViewRange = viewModel.getCompletelyVisibleViewRangeAtScrollTop(futureViewport.top);\n\t\t\t\tconst visibleModelRange = viewModel.coordinatesConverter.convertViewRangeToModelRange(visibleViewRange);\n\n\t\t\t\tlet desiredTopModelLineNumber: number;\n\t\t\t\tif (args.direction === EditorScroll_.Direction.Up) {\n\t\t\t\t\t// must go x model lines up\n\t\t\t\t\tdesiredTopModelLineNumber = Math.max(1, visibleModelRange.startLineNumber - args.value);\n\t\t\t\t} else {\n\t\t\t\t\t// must go x model lines down\n\t\t\t\t\tdesiredTopModelLineNumber = Math.min(viewModel.model.getLineCount(), visibleModelRange.startLineNumber + args.value);\n\t\t\t\t}\n\n\t\t\t\tconst viewPosition = viewModel.coordinatesConverter.convertModelPositionToViewPosition(new Position(desiredTopModelLineNumber, 1));\n\t\t\t\treturn viewModel.viewLayout.getVerticalOffsetForLineNumber(viewPosition.lineNumber);\n\t\t\t}\n\n\t\t\tif (args.unit === EditorScroll_.Unit.Editor) {\n\t\t\t\tlet desiredTopModelLineNumber = 0;\n\t\t\t\tif (args.direction === EditorScroll_.Direction.Down) {\n\t\t\t\t\tdesiredTopModelLineNumber = viewModel.model.getLineCount() - viewModel.cursorConfig.pageSize;\n\t\t\t\t}\n\t\t\t\treturn viewModel.viewLayout.getVerticalOffsetForLineNumber(desiredTopModelLineNumber);\n\t\t\t}\n\n\t\t\tlet noOfLines: number;\n\t\t\tif (args.unit === EditorScroll_.Unit.Page) {\n\t\t\t\tnoOfLines = viewModel.cursorConfig.pageSize * args.value;\n\t\t\t} else if (args.unit === EditorScroll_.Unit.HalfPage) {\n\t\t\t\tnoOfLines = Math.round(viewModel.cursorConfig.pageSize / 2) * args.value;\n\t\t\t} else {\n\t\t\t\tnoOfLines = args.value;\n\t\t\t}\n\t\t\tconst deltaLines = (args.direction === EditorScroll_.Direction.Up ? -1 : 1) * noOfLines;\n\t\t\treturn viewModel.viewLayout.getCurrentScrollTop() + deltaLines * viewModel.cursorConfig.lineHeight;\n\t\t}\n\n\t\t_runHorizontalEditorScroll(viewModel: IViewModel, source: string | null | undefined, args: EditorScroll_.ParsedArguments): void {\n\t\t\tconst desiredScrollLeft = this._computeDesiredScrollLeft(viewModel, args);\n\t\t\tviewModel.viewLayout.setScrollPosition({ scrollLeft: desiredScrollLeft }, ScrollType.Smooth);\n\t\t}\n\n\t\t_computeDesiredScrollLeft(viewModel: IViewModel, args: EditorScroll_.ParsedArguments) {\n\t\t\tconst deltaColumns = (args.direction === EditorScroll_.Direction.Left ? -1 : 1) * args.value;\n\t\t\treturn viewModel.viewLayout.getCurrentScrollLeft() + deltaColumns * viewModel.cursorConfig.typicalHalfwidthCharacterWidth;\n\t\t}\n\t}\n\n\texport const EditorScroll: EditorScrollImpl = registerEditorCommand(new EditorScrollImpl());\n\n\texport const ScrollLineUp: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand {\n\t\tconstructor() {\n\t\t\tsuper({\n\t\t\t\tid: 'scrollLineUp',\n\t\t\t\tprecondition: undefined,\n\t\t\t\tkbOpts: {\n\t\t\t\t\tweight: CORE_WEIGHT,\n\t\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\t\t\tprimary: KeyMod.CtrlCmd | KeyCode.UpArrow,\n\t\t\t\t\tmac: { primary: KeyMod.WinCtrl | KeyCode.PageUp }\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\trunCoreEditorCommand(viewModel: IViewModel, args: Partial): void {\n\t\t\tEditorScroll.runCoreEditorCommand(viewModel, {\n\t\t\t\tto: EditorScroll_.RawDirection.Up,\n\t\t\t\tby: EditorScroll_.RawUnit.WrappedLine,\n\t\t\t\tvalue: 1,\n\t\t\t\trevealCursor: false,\n\t\t\t\tselect: false,\n\t\t\t\tsource: args.source\n\t\t\t});\n\t\t}\n\t});\n\n\texport const ScrollPageUp: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand {\n\t\tconstructor() {\n\t\t\tsuper({\n\t\t\t\tid: 'scrollPageUp',\n\t\t\t\tprecondition: undefined,\n\t\t\t\tkbOpts: {\n\t\t\t\t\tweight: CORE_WEIGHT,\n\t\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\t\t\tprimary: KeyMod.CtrlCmd | KeyCode.PageUp,\n\t\t\t\t\twin: { primary: KeyMod.Alt | KeyCode.PageUp },\n\t\t\t\t\tlinux: { primary: KeyMod.Alt | KeyCode.PageUp }\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\trunCoreEditorCommand(viewModel: IViewModel, args: Partial): void {\n\t\t\tEditorScroll.runCoreEditorCommand(viewModel, {\n\t\t\t\tto: EditorScroll_.RawDirection.Up,\n\t\t\t\tby: EditorScroll_.RawUnit.Page,\n\t\t\t\tvalue: 1,\n\t\t\t\trevealCursor: false,\n\t\t\t\tselect: false,\n\t\t\t\tsource: args.source\n\t\t\t});\n\t\t}\n\t});\n\n\texport const ScrollEditorTop: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand {\n\t\tconstructor() {\n\t\t\tsuper({\n\t\t\t\tid: 'scrollEditorTop',\n\t\t\t\tprecondition: undefined,\n\t\t\t\tkbOpts: {\n\t\t\t\t\tweight: CORE_WEIGHT,\n\t\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\trunCoreEditorCommand(viewModel: IViewModel, args: Partial): void {\n\t\t\tEditorScroll.runCoreEditorCommand(viewModel, {\n\t\t\t\tto: EditorScroll_.RawDirection.Up,\n\t\t\t\tby: EditorScroll_.RawUnit.Editor,\n\t\t\t\tvalue: 1,\n\t\t\t\trevealCursor: false,\n\t\t\t\tselect: false,\n\t\t\t\tsource: args.source\n\t\t\t});\n\t\t}\n\t});\n\n\texport const ScrollLineDown: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand {\n\t\tconstructor() {\n\t\t\tsuper({\n\t\t\t\tid: 'scrollLineDown',\n\t\t\t\tprecondition: undefined,\n\t\t\t\tkbOpts: {\n\t\t\t\t\tweight: CORE_WEIGHT,\n\t\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\t\t\tprimary: KeyMod.CtrlCmd | KeyCode.DownArrow,\n\t\t\t\t\tmac: { primary: KeyMod.WinCtrl | KeyCode.PageDown }\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\trunCoreEditorCommand(viewModel: IViewModel, args: Partial): void {\n\t\t\tEditorScroll.runCoreEditorCommand(viewModel, {\n\t\t\t\tto: EditorScroll_.RawDirection.Down,\n\t\t\t\tby: EditorScroll_.RawUnit.WrappedLine,\n\t\t\t\tvalue: 1,\n\t\t\t\trevealCursor: false,\n\t\t\t\tselect: false,\n\t\t\t\tsource: args.source\n\t\t\t});\n\t\t}\n\t});\n\n\texport const ScrollPageDown: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand {\n\t\tconstructor() {\n\t\t\tsuper({\n\t\t\t\tid: 'scrollPageDown',\n\t\t\t\tprecondition: undefined,\n\t\t\t\tkbOpts: {\n\t\t\t\t\tweight: CORE_WEIGHT,\n\t\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\t\t\tprimary: KeyMod.CtrlCmd | KeyCode.PageDown,\n\t\t\t\t\twin: { primary: KeyMod.Alt | KeyCode.PageDown },\n\t\t\t\t\tlinux: { primary: KeyMod.Alt | KeyCode.PageDown }\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\trunCoreEditorCommand(viewModel: IViewModel, args: Partial): void {\n\t\t\tEditorScroll.runCoreEditorCommand(viewModel, {\n\t\t\t\tto: EditorScroll_.RawDirection.Down,\n\t\t\t\tby: EditorScroll_.RawUnit.Page,\n\t\t\t\tvalue: 1,\n\t\t\t\trevealCursor: false,\n\t\t\t\tselect: false,\n\t\t\t\tsource: args.source\n\t\t\t});\n\t\t}\n\t});\n\n\texport const ScrollEditorBottom: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand {\n\t\tconstructor() {\n\t\t\tsuper({\n\t\t\t\tid: 'scrollEditorBottom',\n\t\t\t\tprecondition: undefined,\n\t\t\t\tkbOpts: {\n\t\t\t\t\tweight: CORE_WEIGHT,\n\t\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\trunCoreEditorCommand(viewModel: IViewModel, args: Partial): void {\n\t\t\tEditorScroll.runCoreEditorCommand(viewModel, {\n\t\t\t\tto: EditorScroll_.RawDirection.Down,\n\t\t\t\tby: EditorScroll_.RawUnit.Editor,\n\t\t\t\tvalue: 1,\n\t\t\t\trevealCursor: false,\n\t\t\t\tselect: false,\n\t\t\t\tsource: args.source\n\t\t\t});\n\t\t}\n\t});\n\n\texport const ScrollLeft: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand {\n\t\tconstructor() {\n\t\t\tsuper({\n\t\t\t\tid: 'scrollLeft',\n\t\t\t\tprecondition: undefined,\n\t\t\t\tkbOpts: {\n\t\t\t\t\tweight: CORE_WEIGHT,\n\t\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\trunCoreEditorCommand(viewModel: IViewModel, args: Partial): void {\n\t\t\tEditorScroll.runCoreEditorCommand(viewModel, {\n\t\t\t\tto: EditorScroll_.RawDirection.Left,\n\t\t\t\tby: EditorScroll_.RawUnit.Column,\n\t\t\t\tvalue: 2,\n\t\t\t\trevealCursor: false,\n\t\t\t\tselect: false,\n\t\t\t\tsource: args.source\n\t\t\t});\n\t\t}\n\t});\n\n\texport const ScrollRight: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand {\n\t\tconstructor() {\n\t\t\tsuper({\n\t\t\t\tid: 'scrollRight',\n\t\t\t\tprecondition: undefined,\n\t\t\t\tkbOpts: {\n\t\t\t\t\tweight: CORE_WEIGHT,\n\t\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\trunCoreEditorCommand(viewModel: IViewModel, args: Partial): void {\n\t\t\tEditorScroll.runCoreEditorCommand(viewModel, {\n\t\t\t\tto: EditorScroll_.RawDirection.Right,\n\t\t\t\tby: EditorScroll_.RawUnit.Column,\n\t\t\t\tvalue: 2,\n\t\t\t\trevealCursor: false,\n\t\t\t\tselect: false,\n\t\t\t\tsource: args.source\n\t\t\t});\n\t\t}\n\t});\n\n\tclass WordCommand extends CoreEditorCommand {\n\n\t\tprivate readonly _inSelectionMode: boolean;\n\n\t\tconstructor(opts: ICommandOptions & { inSelectionMode: boolean }) {\n\t\t\tsuper(opts);\n\t\t\tthis._inSelectionMode = opts.inSelectionMode;\n\t\t}\n\n\t\tpublic runCoreEditorCommand(viewModel: IViewModel, args: Partial): void {\n\t\t\tif (!args.position) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tviewModel.model.pushStackElement();\n\t\t\tviewModel.setCursorStates(\n\t\t\t\targs.source,\n\t\t\t\tCursorChangeReason.Explicit,\n\t\t\t\t[\n\t\t\t\t\tCursorMoveCommands.word(viewModel, viewModel.getPrimaryCursorState(), this._inSelectionMode, args.position)\n\t\t\t\t]\n\t\t\t);\n\t\t\tif (args.revealType !== NavigationCommandRevealType.None) {\n\t\t\t\tviewModel.revealAllCursors(args.source, true, true);\n\t\t\t}\n\t\t}\n\t}\n\n\texport const WordSelect: CoreEditorCommand = registerEditorCommand(new WordCommand({\n\t\tinSelectionMode: false,\n\t\tid: '_wordSelect',\n\t\tprecondition: undefined\n\t}));\n\n\texport const WordSelectDrag: CoreEditorCommand = registerEditorCommand(new WordCommand({\n\t\tinSelectionMode: true,\n\t\tid: '_wordSelectDrag',\n\t\tprecondition: undefined\n\t}));\n\n\texport const LastCursorWordSelect: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand {\n\t\tconstructor() {\n\t\t\tsuper({\n\t\t\t\tid: 'lastCursorWordSelect',\n\t\t\t\tprecondition: undefined\n\t\t\t});\n\t\t}\n\n\t\tpublic runCoreEditorCommand(viewModel: IViewModel, args: Partial): void {\n\t\t\tif (!args.position) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst lastAddedCursorIndex = viewModel.getLastAddedCursorIndex();\n\n\t\t\tconst states = viewModel.getCursorStates();\n\t\t\tconst newStates: PartialCursorState[] = states.slice(0);\n\t\t\tconst lastAddedState = states[lastAddedCursorIndex];\n\t\t\tnewStates[lastAddedCursorIndex] = CursorMoveCommands.word(viewModel, lastAddedState, lastAddedState.modelState.hasSelection(), args.position);\n\n\t\t\tviewModel.model.pushStackElement();\n\t\t\tviewModel.setCursorStates(\n\t\t\t\targs.source,\n\t\t\t\tCursorChangeReason.Explicit,\n\t\t\t\tnewStates\n\t\t\t);\n\t\t}\n\t});\n\n\tclass LineCommand extends CoreEditorCommand {\n\t\tprivate readonly _inSelectionMode: boolean;\n\n\t\tconstructor(opts: ICommandOptions & { inSelectionMode: boolean }) {\n\t\t\tsuper(opts);\n\t\t\tthis._inSelectionMode = opts.inSelectionMode;\n\t\t}\n\n\t\tpublic runCoreEditorCommand(viewModel: IViewModel, args: Partial): void {\n\t\t\tif (!args.position) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tviewModel.model.pushStackElement();\n\t\t\tviewModel.setCursorStates(\n\t\t\t\targs.source,\n\t\t\t\tCursorChangeReason.Explicit,\n\t\t\t\t[\n\t\t\t\t\tCursorMoveCommands.line(viewModel, viewModel.getPrimaryCursorState(), this._inSelectionMode, args.position, args.viewPosition)\n\t\t\t\t]\n\t\t\t);\n\t\t\tif (args.revealType !== NavigationCommandRevealType.None) {\n\t\t\t\tviewModel.revealAllCursors(args.source, false, true);\n\t\t\t}\n\t\t}\n\t}\n\n\texport const LineSelect: CoreEditorCommand = registerEditorCommand(new LineCommand({\n\t\tinSelectionMode: false,\n\t\tid: '_lineSelect',\n\t\tprecondition: undefined\n\t}));\n\n\texport const LineSelectDrag: CoreEditorCommand = registerEditorCommand(new LineCommand({\n\t\tinSelectionMode: true,\n\t\tid: '_lineSelectDrag',\n\t\tprecondition: undefined\n\t}));\n\n\tclass LastCursorLineCommand extends CoreEditorCommand {\n\t\tprivate readonly _inSelectionMode: boolean;\n\n\t\tconstructor(opts: ICommandOptions & { inSelectionMode: boolean }) {\n\t\t\tsuper(opts);\n\t\t\tthis._inSelectionMode = opts.inSelectionMode;\n\t\t}\n\n\t\tpublic runCoreEditorCommand(viewModel: IViewModel, args: Partial): void {\n\t\t\tif (!args.position) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst lastAddedCursorIndex = viewModel.getLastAddedCursorIndex();\n\n\t\t\tconst states = viewModel.getCursorStates();\n\t\t\tconst newStates: PartialCursorState[] = states.slice(0);\n\t\t\tnewStates[lastAddedCursorIndex] = CursorMoveCommands.line(viewModel, states[lastAddedCursorIndex], this._inSelectionMode, args.position, args.viewPosition);\n\n\t\t\tviewModel.model.pushStackElement();\n\t\t\tviewModel.setCursorStates(\n\t\t\t\targs.source,\n\t\t\t\tCursorChangeReason.Explicit,\n\t\t\t\tnewStates\n\t\t\t);\n\t\t}\n\t}\n\n\texport const LastCursorLineSelect: CoreEditorCommand = registerEditorCommand(new LastCursorLineCommand({\n\t\tinSelectionMode: false,\n\t\tid: 'lastCursorLineSelect',\n\t\tprecondition: undefined\n\t}));\n\n\texport const LastCursorLineSelectDrag: CoreEditorCommand = registerEditorCommand(new LastCursorLineCommand({\n\t\tinSelectionMode: true,\n\t\tid: 'lastCursorLineSelectDrag',\n\t\tprecondition: undefined\n\t}));\n\n\texport const CancelSelection: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand {\n\t\tconstructor() {\n\t\t\tsuper({\n\t\t\t\tid: 'cancelSelection',\n\t\t\t\tprecondition: EditorContextKeys.hasNonEmptySelection,\n\t\t\t\tkbOpts: {\n\t\t\t\t\tweight: CORE_WEIGHT,\n\t\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\t\t\tprimary: KeyCode.Escape,\n\t\t\t\t\tsecondary: [KeyMod.Shift | KeyCode.Escape]\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\tpublic runCoreEditorCommand(viewModel: IViewModel, args: Partial): void {\n\t\t\tviewModel.model.pushStackElement();\n\t\t\tviewModel.setCursorStates(\n\t\t\t\targs.source,\n\t\t\t\tCursorChangeReason.Explicit,\n\t\t\t\t[\n\t\t\t\t\tCursorMoveCommands.cancelSelection(viewModel, viewModel.getPrimaryCursorState())\n\t\t\t\t]\n\t\t\t);\n\t\t\tviewModel.revealAllCursors(args.source, true);\n\t\t}\n\t});\n\n\texport const RemoveSecondaryCursors: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand {\n\t\tconstructor() {\n\t\t\tsuper({\n\t\t\t\tid: 'removeSecondaryCursors',\n\t\t\t\tprecondition: EditorContextKeys.hasMultipleSelections,\n\t\t\t\tkbOpts: {\n\t\t\t\t\tweight: CORE_WEIGHT + 1,\n\t\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\t\t\tprimary: KeyCode.Escape,\n\t\t\t\t\tsecondary: [KeyMod.Shift | KeyCode.Escape]\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\tpublic runCoreEditorCommand(viewModel: IViewModel, args: Partial): void {\n\t\t\tviewModel.model.pushStackElement();\n\t\t\tviewModel.setCursorStates(\n\t\t\t\targs.source,\n\t\t\t\tCursorChangeReason.Explicit,\n\t\t\t\t[\n\t\t\t\t\tviewModel.getPrimaryCursorState()\n\t\t\t\t]\n\t\t\t);\n\t\t\tviewModel.revealAllCursors(args.source, true);\n\t\t\tstatus(nls.localize('removedCursor', \"Removed secondary cursors\"));\n\t\t}\n\t});\n\n\texport type RevealLineCommandOptions = RevealLine_.RawArguments & BaseCommandOptions;\n\n\texport const RevealLine: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand {\n\t\tconstructor() {\n\t\t\tsuper({\n\t\t\t\tid: 'revealLine',\n\t\t\t\tprecondition: undefined,\n\t\t\t\tmetadata: RevealLine_.metadata\n\t\t\t});\n\t\t}\n\n\t\tpublic runCoreEditorCommand(viewModel: IViewModel, args: Partial): void {\n\t\t\tconst revealLineArg = args;\n\t\t\tconst lineNumberArg = revealLineArg.lineNumber || 0;\n\t\t\tlet lineNumber = typeof lineNumberArg === 'number' ? (lineNumberArg + 1) : (parseInt(lineNumberArg) + 1);\n\t\t\tif (lineNumber < 1) {\n\t\t\t\tlineNumber = 1;\n\t\t\t}\n\t\t\tconst lineCount = viewModel.model.getLineCount();\n\t\t\tif (lineNumber > lineCount) {\n\t\t\t\tlineNumber = lineCount;\n\t\t\t}\n\n\t\t\tconst range = new Range(\n\t\t\t\tlineNumber, 1,\n\t\t\t\tlineNumber, viewModel.model.getLineMaxColumn(lineNumber)\n\t\t\t);\n\n\t\t\tlet revealAt = VerticalRevealType.Simple;\n\t\t\tif (revealLineArg.at) {\n\t\t\t\tswitch (revealLineArg.at) {\n\t\t\t\t\tcase RevealLine_.RawAtArgument.Top:\n\t\t\t\t\t\trevealAt = VerticalRevealType.Top;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase RevealLine_.RawAtArgument.Center:\n\t\t\t\t\t\trevealAt = VerticalRevealType.Center;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase RevealLine_.RawAtArgument.Bottom:\n\t\t\t\t\t\trevealAt = VerticalRevealType.Bottom;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst viewRange = viewModel.coordinatesConverter.convertModelRangeToViewRange(range);\n\n\t\t\tviewModel.revealRange(args.source, false, viewRange, revealAt, ScrollType.Smooth);\n\t\t}\n\t});\n\n\texport const SelectAll = new class extends EditorOrNativeTextInputCommand {\n\t\tconstructor() {\n\t\t\tsuper(SelectAllCommand);\n\t\t}\n\t\tpublic runDOMCommand(activeElement: Element): void {\n\t\t\tif (isFirefox) {\n\t\t\t\t(activeElement).focus();\n\t\t\t\t(activeElement).select();\n\t\t\t}\n\n\t\t\tactiveElement.ownerDocument.execCommand('selectAll');\n\t\t}\n\t\tpublic runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, args: unknown): void {\n\t\t\tconst viewModel = editor._getViewModel();\n\t\t\tif (!viewModel) {\n\t\t\t\t// the editor has no view => has no cursors\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.runCoreEditorCommand(viewModel, args);\n\t\t}\n\t\tpublic runCoreEditorCommand(viewModel: IViewModel, args: unknown): void {\n\t\t\tviewModel.model.pushStackElement();\n\t\t\tviewModel.setCursorStates(\n\t\t\t\t'keyboard',\n\t\t\t\tCursorChangeReason.Explicit,\n\t\t\t\t[\n\t\t\t\t\tCursorMoveCommands.selectAll(viewModel, viewModel.getPrimaryCursorState())\n\t\t\t\t]\n\t\t\t);\n\t\t}\n\t}();\n\n\texport interface SetSelectionCommandOptions extends BaseCommandOptions {\n\t\tselection: ISelection;\n\t}\n\n\texport const SetSelection: CoreEditorCommand = registerEditorCommand(new class extends CoreEditorCommand {\n\t\tconstructor() {\n\t\t\tsuper({\n\t\t\t\tid: 'setSelection',\n\t\t\t\tprecondition: undefined\n\t\t\t});\n\t\t}\n\n\t\tpublic runCoreEditorCommand(viewModel: IViewModel, args: Partial): void {\n\t\t\tif (!args.selection) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tviewModel.model.pushStackElement();\n\t\t\tviewModel.setCursorStates(\n\t\t\t\targs.source,\n\t\t\t\tCursorChangeReason.Explicit,\n\t\t\t\t[\n\t\t\t\t\tCursorState.fromModelSelection(args.selection)\n\t\t\t\t]\n\t\t\t);\n\t\t}\n\t});\n}\n\nconst columnSelectionCondition = ContextKeyExpr.and(\n\tEditorContextKeys.textInputFocus,\n\tEditorContextKeys.columnSelection\n);\nfunction registerColumnSelection(id: string, keybinding: number): void {\n\tKeybindingsRegistry.registerKeybindingRule({\n\t\tid: id,\n\t\tprimary: keybinding,\n\t\twhen: columnSelectionCondition,\n\t\tweight: CORE_WEIGHT + 1\n\t});\n}\n\nregisterColumnSelection(CoreNavigationCommands.CursorColumnSelectLeft.id, KeyMod.Shift | KeyCode.LeftArrow);\nregisterColumnSelection(CoreNavigationCommands.CursorColumnSelectRight.id, KeyMod.Shift | KeyCode.RightArrow);\nregisterColumnSelection(CoreNavigationCommands.CursorColumnSelectUp.id, KeyMod.Shift | KeyCode.UpArrow);\nregisterColumnSelection(CoreNavigationCommands.CursorColumnSelectPageUp.id, KeyMod.Shift | KeyCode.PageUp);\nregisterColumnSelection(CoreNavigationCommands.CursorColumnSelectDown.id, KeyMod.Shift | KeyCode.DownArrow);\nregisterColumnSelection(CoreNavigationCommands.CursorColumnSelectPageDown.id, KeyMod.Shift | KeyCode.PageDown);\n\nfunction registerCommand(command: T): T {\n\tcommand.register();\n\treturn command;\n}\n\nexport namespace CoreEditingCommands {\n\n\texport abstract class CoreEditingCommand extends EditorCommand {\n\t\tpublic runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, args: unknown): void {\n\t\t\tconst viewModel = editor._getViewModel();\n\t\t\tif (!viewModel) {\n\t\t\t\t// the editor has no view => has no cursors\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.runCoreEditingCommand(editor, viewModel, args || {});\n\t\t}\n\n\t\tpublic abstract runCoreEditingCommand(editor: ICodeEditor, viewModel: IViewModel, args: unknown): void;\n\t}\n\n\texport const LineBreakInsert: EditorCommand = registerEditorCommand(new class extends CoreEditingCommand {\n\t\tconstructor() {\n\t\t\tsuper({\n\t\t\t\tid: 'lineBreakInsert',\n\t\t\t\tprecondition: EditorContextKeys.writable,\n\t\t\t\tkbOpts: {\n\t\t\t\t\tweight: CORE_WEIGHT,\n\t\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\t\t\tprimary: 0,\n\t\t\t\t\tmac: { primary: KeyMod.WinCtrl | KeyCode.KeyO }\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\tpublic runCoreEditingCommand(editor: ICodeEditor, viewModel: IViewModel, args: unknown): void {\n\t\t\teditor.pushUndoStop();\n\t\t\teditor.executeCommands(this.id, TypeOperations.lineBreakInsert(viewModel.cursorConfig, viewModel.model, viewModel.getCursorStates().map(s => s.modelState.selection)));\n\t\t}\n\t});\n\n\texport const Outdent: EditorCommand = registerEditorCommand(new class extends CoreEditingCommand {\n\t\tconstructor() {\n\t\t\tsuper({\n\t\t\t\tid: 'outdent',\n\t\t\t\tprecondition: EditorContextKeys.writable,\n\t\t\t\tkbOpts: {\n\t\t\t\t\tweight: CORE_WEIGHT,\n\t\t\t\t\tkbExpr: ContextKeyExpr.and(\n\t\t\t\t\t\tEditorContextKeys.editorTextFocus,\n\t\t\t\t\t\tEditorContextKeys.tabDoesNotMoveFocus\n\t\t\t\t\t),\n\t\t\t\t\tprimary: KeyMod.Shift | KeyCode.Tab\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\tpublic runCoreEditingCommand(editor: ICodeEditor, viewModel: IViewModel, args: unknown): void {\n\t\t\teditor.pushUndoStop();\n\t\t\teditor.executeCommands(this.id, TypeOperations.outdent(viewModel.cursorConfig, viewModel.model, viewModel.getCursorStates().map(s => s.modelState.selection)));\n\t\t\teditor.pushUndoStop();\n\t\t}\n\t});\n\n\texport const Tab: EditorCommand = registerEditorCommand(new class extends CoreEditingCommand {\n\t\tconstructor() {\n\t\t\tsuper({\n\t\t\t\tid: 'tab',\n\t\t\t\tprecondition: EditorContextKeys.writable,\n\t\t\t\tkbOpts: {\n\t\t\t\t\tweight: CORE_WEIGHT,\n\t\t\t\t\tkbExpr: ContextKeyExpr.and(\n\t\t\t\t\t\tEditorContextKeys.editorTextFocus,\n\t\t\t\t\t\tEditorContextKeys.tabDoesNotMoveFocus\n\t\t\t\t\t),\n\t\t\t\t\tprimary: KeyCode.Tab\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\tpublic runCoreEditingCommand(editor: ICodeEditor, viewModel: IViewModel, args: unknown): void {\n\t\t\teditor.pushUndoStop();\n\t\t\teditor.executeCommands(this.id, TypeOperations.tab(viewModel.cursorConfig, viewModel.model, viewModel.getCursorStates().map(s => s.modelState.selection)));\n\t\t\teditor.pushUndoStop();\n\t\t}\n\t});\n\n\texport const DeleteLeft: EditorCommand = registerEditorCommand(new class extends CoreEditingCommand {\n\t\tconstructor() {\n\t\t\tsuper({\n\t\t\t\tid: 'deleteLeft',\n\t\t\t\tprecondition: undefined,\n\t\t\t\tkbOpts: {\n\t\t\t\t\tweight: CORE_WEIGHT,\n\t\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\t\t\tprimary: KeyCode.Backspace,\n\t\t\t\t\tsecondary: [KeyMod.Shift | KeyCode.Backspace],\n\t\t\t\t\tmac: { primary: KeyCode.Backspace, secondary: [KeyMod.Shift | KeyCode.Backspace, KeyMod.WinCtrl | KeyCode.KeyH, KeyMod.WinCtrl | KeyCode.Backspace] }\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\tpublic runCoreEditingCommand(editor: ICodeEditor, viewModel: IViewModel, args: unknown): void {\n\t\t\tconst [shouldPushStackElementBefore, commands] = DeleteOperations.deleteLeft(viewModel.getPrevEditOperationType(), viewModel.cursorConfig, viewModel.model, viewModel.getCursorStates().map(s => s.modelState.selection), viewModel.getCursorAutoClosedCharacters());\n\t\t\tif (shouldPushStackElementBefore) {\n\t\t\t\teditor.pushUndoStop();\n\t\t\t}\n\t\t\teditor.executeCommands(this.id, commands);\n\t\t\tviewModel.setPrevEditOperationType(EditOperationType.DeletingLeft);\n\t\t}\n\t});\n\n\texport const DeleteRight: EditorCommand = registerEditorCommand(new class extends CoreEditingCommand {\n\t\tconstructor() {\n\t\t\tsuper({\n\t\t\t\tid: 'deleteRight',\n\t\t\t\tprecondition: undefined,\n\t\t\t\tkbOpts: {\n\t\t\t\t\tweight: CORE_WEIGHT,\n\t\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\t\t\tprimary: KeyCode.Delete,\n\t\t\t\t\tmac: { primary: KeyCode.Delete, secondary: [KeyMod.WinCtrl | KeyCode.KeyD, KeyMod.WinCtrl | KeyCode.Delete] }\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\tpublic runCoreEditingCommand(editor: ICodeEditor, viewModel: IViewModel, args: unknown): void {\n\t\t\tconst [shouldPushStackElementBefore, commands] = DeleteOperations.deleteRight(viewModel.getPrevEditOperationType(), viewModel.cursorConfig, viewModel.model, viewModel.getCursorStates().map(s => s.modelState.selection));\n\t\t\tif (shouldPushStackElementBefore) {\n\t\t\t\teditor.pushUndoStop();\n\t\t\t}\n\t\t\teditor.executeCommands(this.id, commands);\n\t\t\tviewModel.setPrevEditOperationType(EditOperationType.DeletingRight);\n\t\t}\n\t});\n\n\texport const Undo = new class extends EditorOrNativeTextInputCommand {\n\t\tconstructor() {\n\t\t\tsuper(UndoCommand);\n\t\t}\n\t\tpublic runDOMCommand(activeElement: Element): void {\n\t\t\tactiveElement.ownerDocument.execCommand('undo');\n\t\t}\n\t\tpublic runEditorCommand(accessor: ServicesAccessor | null, editor: ICodeEditor, args: unknown): void | Promise {\n\t\t\tif (!editor.hasModel() || editor.getOption(EditorOption.readOnly) === true) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\treturn editor.getModel().undo();\n\t\t}\n\t}();\n\n\texport const Redo = new class extends EditorOrNativeTextInputCommand {\n\t\tconstructor() {\n\t\t\tsuper(RedoCommand);\n\t\t}\n\t\tpublic runDOMCommand(activeElement: Element): void {\n\t\t\tactiveElement.ownerDocument.execCommand('redo');\n\t\t}\n\t\tpublic runEditorCommand(accessor: ServicesAccessor | null, editor: ICodeEditor, args: unknown): void | Promise {\n\t\t\tif (!editor.hasModel() || editor.getOption(EditorOption.readOnly) === true) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\treturn editor.getModel().redo();\n\t\t}\n\t}();\n}\n\n/**\n * A command that will invoke a command on the focused editor.\n */\nclass EditorHandlerCommand extends Command {\n\n\tprivate readonly _handlerId: string;\n\n\tconstructor(id: string, handlerId: string, metadata?: ICommandMetadata) {\n\t\tsuper({\n\t\t\tid: id,\n\t\t\tprecondition: undefined,\n\t\t\tmetadata\n\t\t});\n\t\tthis._handlerId = handlerId;\n\t}\n\n\tpublic runCommand(accessor: ServicesAccessor, args: unknown): void {\n\t\tconst editor = accessor.get(ICodeEditorService).getFocusedCodeEditor();\n\t\tif (!editor) {\n\t\t\treturn;\n\t\t}\n\n\t\teditor.trigger('keyboard', this._handlerId, args);\n\t}\n}\n\nfunction registerOverwritableCommand(handlerId: string, metadata?: ICommandMetadata): void {\n\tregisterCommand(new EditorHandlerCommand('default:' + handlerId, handlerId));\n\tregisterCommand(new EditorHandlerCommand(handlerId, handlerId, metadata));\n}\n\nregisterOverwritableCommand(Handler.Type, {\n\tdescription: `Type`,\n\targs: [{\n\t\tname: 'args',\n\t\tschema: {\n\t\t\t'type': 'object',\n\t\t\t'required': ['text'],\n\t\t\t'properties': {\n\t\t\t\t'text': {\n\t\t\t\t\t'type': 'string'\n\t\t\t\t}\n\t\t\t},\n\t\t}\n\t}]\n});\nregisterOverwritableCommand(Handler.ReplacePreviousChar);\nregisterOverwritableCommand(Handler.CompositionType);\nregisterOverwritableCommand(Handler.CompositionStart);\nregisterOverwritableCommand(Handler.CompositionEnd);\nregisterOverwritableCommand(Handler.Paste);\nregisterOverwritableCommand(Handler.Cut);\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\nimport { IMarkerDecorationsService } from 'vs/editor/common/services/markerDecorations';\nimport { EditorContributionInstantiation, registerEditorContribution } from 'vs/editor/browser/editorExtensions';\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\nimport { IEditorContribution } from 'vs/editor/common/editorCommon';\n\nexport class MarkerDecorationsContribution implements IEditorContribution {\n\n\tpublic static readonly ID: string = 'editor.contrib.markerDecorations';\n\n\tconstructor(\n\t\t_editor: ICodeEditor,\n\t\t@IMarkerDecorationsService _markerDecorationsService: IMarkerDecorationsService\n\t) {\n\t\t// Doesn't do anything, just requires `IMarkerDecorationsService` to make sure it gets instantiated\n\t}\n\n\tdispose(): void {\n\t}\n}\n\nregisterEditorContribution(MarkerDecorationsContribution.ID, MarkerDecorationsContribution, EditorContributionInstantiation.Eager); // eager because it instantiates IMarkerDecorationsService which is responsible for rendering squiggles\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\nimport { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';\nimport { CoreNavigationCommands, NavigationCommandRevealType } from 'vs/editor/browser/coreCommands';\nimport { IEditorMouseEvent, IPartialEditorMouseEvent } from 'vs/editor/browser/editorBrowser';\nimport { ViewUserInputEvents } from 'vs/editor/browser/view/viewUserInputEvents';\nimport { Position } from 'vs/editor/common/core/position';\nimport { Selection } from 'vs/editor/common/core/selection';\nimport { IEditorConfiguration } from 'vs/editor/common/config/editorConfiguration';\nimport { IViewModel } from 'vs/editor/common/viewModel';\nimport { IMouseWheelEvent } from 'vs/base/browser/mouseEvent';\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\nimport * as platform from 'vs/base/common/platform';\n\nexport interface IMouseDispatchData {\n\tposition: Position;\n\t/**\n\t * Desired mouse column (e.g. when position.column gets clamped to text length -- clicking after text on a line).\n\t */\n\tmouseColumn: number;\n\trevealType: NavigationCommandRevealType;\n\tstartedOnLineNumbers: boolean;\n\n\tinSelectionMode: boolean;\n\tmouseDownCount: number;\n\taltKey: boolean;\n\tctrlKey: boolean;\n\tmetaKey: boolean;\n\tshiftKey: boolean;\n\n\tleftButton: boolean;\n\tmiddleButton: boolean;\n\tonInjectedText: boolean;\n}\n\nexport interface ICommandDelegate {\n\tpaste(text: string, pasteOnNewLine: boolean, multicursorText: string[] | null, mode: string | null): void;\n\ttype(text: string): void;\n\tcompositionType(text: string, replacePrevCharCnt: number, replaceNextCharCnt: number, positionDelta: number): void;\n\tstartComposition(): void;\n\tendComposition(): void;\n\tcut(): void;\n}\n\nexport class ViewController {\n\n\tprivate readonly configuration: IEditorConfiguration;\n\tprivate readonly viewModel: IViewModel;\n\tprivate readonly userInputEvents: ViewUserInputEvents;\n\tprivate readonly commandDelegate: ICommandDelegate;\n\n\tconstructor(\n\t\tconfiguration: IEditorConfiguration,\n\t\tviewModel: IViewModel,\n\t\tuserInputEvents: ViewUserInputEvents,\n\t\tcommandDelegate: ICommandDelegate\n\t) {\n\t\tthis.configuration = configuration;\n\t\tthis.viewModel = viewModel;\n\t\tthis.userInputEvents = userInputEvents;\n\t\tthis.commandDelegate = commandDelegate;\n\t}\n\n\tpublic paste(text: string, pasteOnNewLine: boolean, multicursorText: string[] | null, mode: string | null): void {\n\t\tthis.commandDelegate.paste(text, pasteOnNewLine, multicursorText, mode);\n\t}\n\n\tpublic type(text: string): void {\n\t\tthis.commandDelegate.type(text);\n\t}\n\n\tpublic compositionType(text: string, replacePrevCharCnt: number, replaceNextCharCnt: number, positionDelta: number): void {\n\t\tthis.commandDelegate.compositionType(text, replacePrevCharCnt, replaceNextCharCnt, positionDelta);\n\t}\n\n\tpublic compositionStart(): void {\n\t\tthis.commandDelegate.startComposition();\n\t}\n\n\tpublic compositionEnd(): void {\n\t\tthis.commandDelegate.endComposition();\n\t}\n\n\tpublic cut(): void {\n\t\tthis.commandDelegate.cut();\n\t}\n\n\tpublic setSelection(modelSelection: Selection): void {\n\t\tCoreNavigationCommands.SetSelection.runCoreEditorCommand(this.viewModel, {\n\t\t\tsource: 'keyboard',\n\t\t\tselection: modelSelection\n\t\t});\n\t}\n\n\tprivate _validateViewColumn(viewPosition: Position): Position {\n\t\tconst minColumn = this.viewModel.getLineMinColumn(viewPosition.lineNumber);\n\t\tif (viewPosition.column < minColumn) {\n\t\t\treturn new Position(viewPosition.lineNumber, minColumn);\n\t\t}\n\t\treturn viewPosition;\n\t}\n\n\tprivate _hasMulticursorModifier(data: IMouseDispatchData): boolean {\n\t\tswitch (this.configuration.options.get(EditorOption.multiCursorModifier)) {\n\t\t\tcase 'altKey':\n\t\t\t\treturn data.altKey;\n\t\t\tcase 'ctrlKey':\n\t\t\t\treturn data.ctrlKey;\n\t\t\tcase 'metaKey':\n\t\t\t\treturn data.metaKey;\n\t\t\tdefault:\n\t\t\t\treturn false;\n\t\t}\n\t}\n\n\tprivate _hasNonMulticursorModifier(data: IMouseDispatchData): boolean {\n\t\tswitch (this.configuration.options.get(EditorOption.multiCursorModifier)) {\n\t\t\tcase 'altKey':\n\t\t\t\treturn data.ctrlKey || data.metaKey;\n\t\t\tcase 'ctrlKey':\n\t\t\t\treturn data.altKey || data.metaKey;\n\t\t\tcase 'metaKey':\n\t\t\t\treturn data.ctrlKey || data.altKey;\n\t\t\tdefault:\n\t\t\t\treturn false;\n\t\t}\n\t}\n\n\tpublic dispatchMouse(data: IMouseDispatchData): void {\n\t\tconst options = this.configuration.options;\n\t\tconst selectionClipboardIsOn = (platform.isLinux && options.get(EditorOption.selectionClipboard));\n\t\tconst columnSelection = options.get(EditorOption.columnSelection);\n\t\tif (data.middleButton && !selectionClipboardIsOn) {\n\t\t\tthis._columnSelect(data.position, data.mouseColumn, data.inSelectionMode);\n\t\t} else if (data.startedOnLineNumbers) {\n\t\t\t// If the dragging started on the gutter, then have operations work on the entire line\n\t\t\tif (this._hasMulticursorModifier(data)) {\n\t\t\t\tif (data.inSelectionMode) {\n\t\t\t\t\tthis._lastCursorLineSelect(data.position, data.revealType);\n\t\t\t\t} else {\n\t\t\t\t\tthis._createCursor(data.position, true);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (data.inSelectionMode) {\n\t\t\t\t\tthis._lineSelectDrag(data.position, data.revealType);\n\t\t\t\t} else {\n\t\t\t\t\tthis._lineSelect(data.position, data.revealType);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (data.mouseDownCount >= 4) {\n\t\t\tthis._selectAll();\n\t\t} else if (data.mouseDownCount === 3) {\n\t\t\tif (this._hasMulticursorModifier(data)) {\n\t\t\t\tif (data.inSelectionMode) {\n\t\t\t\t\tthis._lastCursorLineSelectDrag(data.position, data.revealType);\n\t\t\t\t} else {\n\t\t\t\t\tthis._lastCursorLineSelect(data.position, data.revealType);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (data.inSelectionMode) {\n\t\t\t\t\tthis._lineSelectDrag(data.position, data.revealType);\n\t\t\t\t} else {\n\t\t\t\t\tthis._lineSelect(data.position, data.revealType);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (data.mouseDownCount === 2) {\n\t\t\tif (!data.onInjectedText) {\n\t\t\t\tif (this._hasMulticursorModifier(data)) {\n\t\t\t\t\tthis._lastCursorWordSelect(data.position, data.revealType);\n\t\t\t\t} else {\n\t\t\t\t\tif (data.inSelectionMode) {\n\t\t\t\t\t\tthis._wordSelectDrag(data.position, data.revealType);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis._wordSelect(data.position, data.revealType);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tif (this._hasMulticursorModifier(data)) {\n\t\t\t\tif (!this._hasNonMulticursorModifier(data)) {\n\t\t\t\t\tif (data.shiftKey) {\n\t\t\t\t\t\tthis._columnSelect(data.position, data.mouseColumn, true);\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Do multi-cursor operations only when purely alt is pressed\n\t\t\t\t\t\tif (data.inSelectionMode) {\n\t\t\t\t\t\t\tthis._lastCursorMoveToSelect(data.position, data.revealType);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tthis._createCursor(data.position, false);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (data.inSelectionMode) {\n\t\t\t\t\tif (data.altKey) {\n\t\t\t\t\t\tthis._columnSelect(data.position, data.mouseColumn, true);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif (columnSelection) {\n\t\t\t\t\t\t\tthis._columnSelect(data.position, data.mouseColumn, true);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tthis._moveToSelect(data.position, data.revealType);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tthis.moveTo(data.position, data.revealType);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate _usualArgs(viewPosition: Position, revealType: NavigationCommandRevealType): CoreNavigationCommands.MoveCommandOptions {\n\t\tviewPosition = this._validateViewColumn(viewPosition);\n\t\treturn {\n\t\t\tsource: 'mouse',\n\t\t\tposition: this._convertViewToModelPosition(viewPosition),\n\t\t\tviewPosition,\n\t\t\trevealType\n\t\t};\n\t}\n\n\tpublic moveTo(viewPosition: Position, revealType: NavigationCommandRevealType): void {\n\t\tCoreNavigationCommands.MoveTo.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition, revealType));\n\t}\n\n\tprivate _moveToSelect(viewPosition: Position, revealType: NavigationCommandRevealType): void {\n\t\tCoreNavigationCommands.MoveToSelect.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition, revealType));\n\t}\n\n\tprivate _columnSelect(viewPosition: Position, mouseColumn: number, doColumnSelect: boolean): void {\n\t\tviewPosition = this._validateViewColumn(viewPosition);\n\t\tCoreNavigationCommands.ColumnSelect.runCoreEditorCommand(this.viewModel, {\n\t\t\tsource: 'mouse',\n\t\t\tposition: this._convertViewToModelPosition(viewPosition),\n\t\t\tviewPosition: viewPosition,\n\t\t\tmouseColumn: mouseColumn,\n\t\t\tdoColumnSelect: doColumnSelect\n\t\t});\n\t}\n\n\tprivate _createCursor(viewPosition: Position, wholeLine: boolean): void {\n\t\tviewPosition = this._validateViewColumn(viewPosition);\n\t\tCoreNavigationCommands.CreateCursor.runCoreEditorCommand(this.viewModel, {\n\t\t\tsource: 'mouse',\n\t\t\tposition: this._convertViewToModelPosition(viewPosition),\n\t\t\tviewPosition: viewPosition,\n\t\t\twholeLine: wholeLine\n\t\t});\n\t}\n\n\tprivate _lastCursorMoveToSelect(viewPosition: Position, revealType: NavigationCommandRevealType): void {\n\t\tCoreNavigationCommands.LastCursorMoveToSelect.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition, revealType));\n\t}\n\n\tprivate _wordSelect(viewPosition: Position, revealType: NavigationCommandRevealType): void {\n\t\tCoreNavigationCommands.WordSelect.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition, revealType));\n\t}\n\n\tprivate _wordSelectDrag(viewPosition: Position, revealType: NavigationCommandRevealType): void {\n\t\tCoreNavigationCommands.WordSelectDrag.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition, revealType));\n\t}\n\n\tprivate _lastCursorWordSelect(viewPosition: Position, revealType: NavigationCommandRevealType): void {\n\t\tCoreNavigationCommands.LastCursorWordSelect.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition, revealType));\n\t}\n\n\tprivate _lineSelect(viewPosition: Position, revealType: NavigationCommandRevealType): void {\n\t\tCoreNavigationCommands.LineSelect.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition, revealType));\n\t}\n\n\tprivate _lineSelectDrag(viewPosition: Position, revealType: NavigationCommandRevealType): void {\n\t\tCoreNavigationCommands.LineSelectDrag.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition, revealType));\n\t}\n\n\tprivate _lastCursorLineSelect(viewPosition: Position, revealType: NavigationCommandRevealType): void {\n\t\tCoreNavigationCommands.LastCursorLineSelect.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition, revealType));\n\t}\n\n\tprivate _lastCursorLineSelectDrag(viewPosition: Position, revealType: NavigationCommandRevealType): void {\n\t\tCoreNavigationCommands.LastCursorLineSelectDrag.runCoreEditorCommand(this.viewModel, this._usualArgs(viewPosition, revealType));\n\t}\n\n\tprivate _selectAll(): void {\n\t\tCoreNavigationCommands.SelectAll.runCoreEditorCommand(this.viewModel, { source: 'mouse' });\n\t}\n\n\t// ----------------------\n\n\tprivate _convertViewToModelPosition(viewPosition: Position): Position {\n\t\treturn this.viewModel.coordinatesConverter.convertViewPositionToModelPosition(viewPosition);\n\t}\n\n\tpublic emitKeyDown(e: IKeyboardEvent): void {\n\t\tthis.userInputEvents.emitKeyDown(e);\n\t}\n\n\tpublic emitKeyUp(e: IKeyboardEvent): void {\n\t\tthis.userInputEvents.emitKeyUp(e);\n\t}\n\n\tpublic emitContextMenu(e: IEditorMouseEvent): void {\n\t\tthis.userInputEvents.emitContextMenu(e);\n\t}\n\n\tpublic emitMouseMove(e: IEditorMouseEvent): void {\n\t\tthis.userInputEvents.emitMouseMove(e);\n\t}\n\n\tpublic emitMouseLeave(e: IPartialEditorMouseEvent): void {\n\t\tthis.userInputEvents.emitMouseLeave(e);\n\t}\n\n\tpublic emitMouseUp(e: IEditorMouseEvent): void {\n\t\tthis.userInputEvents.emitMouseUp(e);\n\t}\n\n\tpublic emitMouseDown(e: IEditorMouseEvent): void {\n\t\tthis.userInputEvents.emitMouseDown(e);\n\t}\n\n\tpublic emitMouseDrag(e: IEditorMouseEvent): void {\n\t\tthis.userInputEvents.emitMouseDrag(e);\n\t}\n\n\tpublic emitMouseDrop(e: IPartialEditorMouseEvent): void {\n\t\tthis.userInputEvents.emitMouseDrop(e);\n\t}\n\n\tpublic emitMouseDropCanceled(): void {\n\t\tthis.userInputEvents.emitMouseDropCanceled();\n\t}\n\n\tpublic emitMouseWheel(e: IMouseWheelEvent): void {\n\t\tthis.userInputEvents.emitMouseWheel(e);\n\t}\n}\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\nimport { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions';\nimport { IInstantiationService, createDecorator } from 'vs/platform/instantiation/common/instantiation';\nimport { CancellationToken } from 'vs/base/common/cancellation';\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { IDisposable } from 'vs/base/common/lifecycle';\nimport { StopWatch } from 'vs/base/common/stopwatch';\nimport { LineRange } from 'vs/editor/common/core/lineRange';\nimport { IDocumentDiff, IDocumentDiffProvider, IDocumentDiffProviderOptions } from 'vs/editor/common/diff/documentDiffProvider';\nimport { DetailedLineRangeMapping, RangeMapping } from 'vs/editor/common/diff/rangeMapping';\nimport { ITextModel } from 'vs/editor/common/model';\nimport { DiffAlgorithmName, IEditorWorkerService } from 'vs/editor/common/services/editorWorker';\nimport { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';\n\nexport const IDiffProviderFactoryService = createDecorator('diffProviderFactoryService');\n\nexport interface IDocumentDiffFactoryOptions {\n\treadonly diffAlgorithm?: 'legacy' | 'advanced';\n}\n\nexport interface IDiffProviderFactoryService {\n\treadonly _serviceBrand: undefined;\n\tcreateDiffProvider(options: IDocumentDiffFactoryOptions): IDocumentDiffProvider;\n}\n\nexport class WorkerBasedDiffProviderFactoryService implements IDiffProviderFactoryService {\n\treadonly _serviceBrand: undefined;\n\n\tconstructor(\n\t\t@IInstantiationService private readonly instantiationService: IInstantiationService,\n\t) { }\n\n\tcreateDiffProvider(options: IDocumentDiffFactoryOptions): IDocumentDiffProvider {\n\t\treturn this.instantiationService.createInstance(WorkerBasedDocumentDiffProvider, options);\n\t}\n}\n\nregisterSingleton(IDiffProviderFactoryService, WorkerBasedDiffProviderFactoryService, InstantiationType.Delayed);\n\nexport class WorkerBasedDocumentDiffProvider implements IDocumentDiffProvider, IDisposable {\n\tprivate onDidChangeEventEmitter = new Emitter();\n\tpublic readonly onDidChange: Event = this.onDidChangeEventEmitter.event;\n\n\tprivate diffAlgorithm: DiffAlgorithmName | IDocumentDiffProvider = 'advanced';\n\tprivate diffAlgorithmOnDidChangeSubscription: IDisposable | undefined = undefined;\n\n\tprivate static readonly diffCache = new Map();\n\n\tconstructor(\n\t\toptions: IWorkerBasedDocumentDiffProviderOptions,\n\t\t@IEditorWorkerService private readonly editorWorkerService: IEditorWorkerService,\n\t\t@ITelemetryService private readonly telemetryService: ITelemetryService,\n\t) {\n\t\tthis.setOptions(options);\n\t}\n\n\tpublic dispose(): void {\n\t\tthis.diffAlgorithmOnDidChangeSubscription?.dispose();\n\t}\n\n\tasync computeDiff(original: ITextModel, modified: ITextModel, options: IDocumentDiffProviderOptions, cancellationToken: CancellationToken): Promise {\n\t\tif (typeof this.diffAlgorithm !== 'string') {\n\t\t\treturn this.diffAlgorithm.computeDiff(original, modified, options, cancellationToken);\n\t\t}\n\n\t\tif (original.isDisposed() || modified.isDisposed()) {\n\t\t\t// TODO@hediet\n\t\t\treturn {\n\t\t\t\tchanges: [],\n\t\t\t\tidentical: true,\n\t\t\t\tquitEarly: false,\n\t\t\t\tmoves: [],\n\t\t\t};\n\t\t}\n\n\t\t// This significantly speeds up the case when the original file is empty\n\t\tif (original.getLineCount() === 1 && original.getLineMaxColumn(1) === 1) {\n\t\t\tif (modified.getLineCount() === 1 && modified.getLineMaxColumn(1) === 1) {\n\t\t\t\treturn {\n\t\t\t\t\tchanges: [],\n\t\t\t\t\tidentical: true,\n\t\t\t\t\tquitEarly: false,\n\t\t\t\t\tmoves: [],\n\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tchanges: [\n\t\t\t\t\tnew DetailedLineRangeMapping(\n\t\t\t\t\t\tnew LineRange(1, 2),\n\t\t\t\t\t\tnew LineRange(1, modified.getLineCount() + 1),\n\t\t\t\t\t\t[\n\t\t\t\t\t\t\tnew RangeMapping(\n\t\t\t\t\t\t\t\toriginal.getFullModelRange(),\n\t\t\t\t\t\t\t\tmodified.getFullModelRange(),\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t]\n\t\t\t\t\t)\n\t\t\t\t],\n\t\t\t\tidentical: false,\n\t\t\t\tquitEarly: false,\n\t\t\t\tmoves: [],\n\t\t\t};\n\t\t}\n\n\t\tconst uriKey = JSON.stringify([original.uri.toString(), modified.uri.toString()]);\n\t\tconst context = JSON.stringify([original.id, modified.id, original.getAlternativeVersionId(), modified.getAlternativeVersionId(), JSON.stringify(options)]);\n\t\tconst c = WorkerBasedDocumentDiffProvider.diffCache.get(uriKey);\n\t\tif (c && c.context === context) {\n\t\t\treturn c.result;\n\t\t}\n\n\t\tconst sw = StopWatch.create();\n\t\tconst result = await this.editorWorkerService.computeDiff(original.uri, modified.uri, options, this.diffAlgorithm);\n\t\tconst timeMs = sw.elapsed();\n\n\t\tthis.telemetryService.publicLog2<{\n\t\t\ttimeMs: number;\n\t\t\ttimedOut: boolean;\n\t\t\tdetectedMoves: number;\n\t\t}, {\n\t\t\towner: 'hediet';\n\n\t\t\ttimeMs: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'To understand if the new diff algorithm is slower/faster than the old one' };\n\t\t\ttimedOut: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'To understand how often the new diff algorithm times out' };\n\t\t\tdetectedMoves: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'To understand how often the new diff algorithm detects moves' };\n\n\t\t\tcomment: 'This event gives insight about the performance of the new diff algorithm.';\n\t\t}>('diffEditor.computeDiff', {\n\t\t\ttimeMs,\n\t\t\ttimedOut: result?.quitEarly ?? true,\n\t\t\tdetectedMoves: options.computeMoves ? (result?.moves.length ?? 0) : -1,\n\t\t});\n\n\t\tif (cancellationToken.isCancellationRequested) {\n\t\t\t// Text models might be disposed!\n\t\t\treturn {\n\t\t\t\tchanges: [],\n\t\t\t\tidentical: false,\n\t\t\t\tquitEarly: true,\n\t\t\t\tmoves: [],\n\t\t\t};\n\t\t}\n\n\t\tif (!result) {\n\t\t\tthrow new Error('no diff result available');\n\t\t}\n\n\t\t// max 10 items in cache\n\t\tif (WorkerBasedDocumentDiffProvider.diffCache.size > 10) {\n\t\t\tWorkerBasedDocumentDiffProvider.diffCache.delete(WorkerBasedDocumentDiffProvider.diffCache.keys().next().value);\n\t\t}\n\n\t\tWorkerBasedDocumentDiffProvider.diffCache.set(uriKey, { result, context });\n\t\treturn result;\n\t}\n\n\tpublic setOptions(newOptions: IWorkerBasedDocumentDiffProviderOptions): void {\n\t\tlet didChange = false;\n\t\tif (newOptions.diffAlgorithm) {\n\t\t\tif (this.diffAlgorithm !== newOptions.diffAlgorithm) {\n\t\t\t\tthis.diffAlgorithmOnDidChangeSubscription?.dispose();\n\t\t\t\tthis.diffAlgorithmOnDidChangeSubscription = undefined;\n\n\t\t\t\tthis.diffAlgorithm = newOptions.diffAlgorithm;\n\t\t\t\tif (typeof newOptions.diffAlgorithm !== 'string') {\n\t\t\t\t\tthis.diffAlgorithmOnDidChangeSubscription = newOptions.diffAlgorithm.onDidChange(() => this.onDidChangeEventEmitter.fire());\n\t\t\t\t}\n\t\t\t\tdidChange = true;\n\t\t\t}\n\t\t}\n\t\tif (didChange) {\n\t\t\tthis.onDidChangeEventEmitter.fire();\n\t\t}\n\t}\n}\n\ninterface IWorkerBasedDocumentDiffProviderOptions {\n\treadonly diffAlgorithm?: 'legacy' | 'advanced' | IDocumentDiffProvider;\n}\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\nimport { RunOnceScheduler } from 'vs/base/common/async';\nimport { CancellationTokenSource } from 'vs/base/common/cancellation';\nimport { Disposable, toDisposable } from 'vs/base/common/lifecycle';\nimport { IObservable, IReader, ISettableObservable, ITransaction, autorun, autorunWithStore, derived, observableSignal, observableSignalFromEvent, observableValue, transaction, waitForState } from 'vs/base/common/observable';\nimport { IDiffProviderFactoryService } from 'vs/editor/browser/widget/diffEditor/diffProviderFactoryService';\nimport { filterWithPrevious, readHotReloadableExport } from 'vs/editor/browser/widget/diffEditor/utils';\nimport { ISerializedLineRange, LineRange, LineRangeSet } from 'vs/editor/common/core/lineRange';\nimport { DefaultLinesDiffComputer } from 'vs/editor/common/diff/defaultLinesDiffComputer/defaultLinesDiffComputer';\nimport { IDocumentDiff } from 'vs/editor/common/diff/documentDiffProvider';\nimport { MovedText } from 'vs/editor/common/diff/linesDiffComputer';\nimport { DetailedLineRangeMapping, LineRangeMapping, RangeMapping } from 'vs/editor/common/diff/rangeMapping';\nimport { IDiffEditorModel, IDiffEditorViewModel } from 'vs/editor/common/editorCommon';\nimport { ITextModel } from 'vs/editor/common/model';\nimport { TextEditInfo } from 'vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/beforeEditPositionMapper';\nimport { combineTextEditInfos } from 'vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/combineTextEditInfos';\nimport { DiffEditorOptions } from './diffEditorOptions';\nimport { optimizeSequenceDiffs } from 'vs/editor/common/diff/defaultLinesDiffComputer/heuristicSequenceOptimizations';\nimport { isDefined } from 'vs/base/common/types';\nimport { groupAdjacentBy } from 'vs/base/common/arrays';\nimport { softAssert } from 'vs/base/common/assert';\n\nexport class DiffEditorViewModel extends Disposable implements IDiffEditorViewModel {\n\tprivate readonly _isDiffUpToDate = observableValue(this, false);\n\tpublic readonly isDiffUpToDate: IObservable = this._isDiffUpToDate;\n\n\tprivate _lastDiff: IDocumentDiff | undefined;\n\tprivate readonly _diff = observableValue(this, undefined);\n\tpublic readonly diff: IObservable = this._diff;\n\n\tprivate readonly _unchangedRegions = observableValue<{ regions: UnchangedRegion[]; originalDecorationIds: string[]; modifiedDecorationIds: string[] } | undefined>(this, undefined);\n\tpublic readonly unchangedRegions: IObservable = derived(this, r => {\n\t\tif (this._options.hideUnchangedRegions.read(r)) {\n\t\t\treturn this._unchangedRegions.read(r)?.regions ?? [];\n\t\t} else {\n\t\t\t// Reset state\n\t\t\ttransaction(tx => {\n\t\t\t\tfor (const r of this._unchangedRegions.get()?.regions || []) {\n\t\t\t\t\tr.collapseAll(tx);\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn [];\n\t\t}\n\t}\n\t);\n\n\tpublic readonly movedTextToCompare = observableValue(this, undefined);\n\n\tprivate readonly _activeMovedText = observableValue(this, undefined);\n\tprivate readonly _hoveredMovedText = observableValue(this, undefined);\n\n\n\tpublic readonly activeMovedText = derived(this, r => this.movedTextToCompare.read(r) ?? this._hoveredMovedText.read(r) ?? this._activeMovedText.read(r));\n\n\tpublic setActiveMovedText(movedText: MovedText | undefined): void {\n\t\tthis._activeMovedText.set(movedText, undefined);\n\t}\n\n\tprivate readonly _cancellationTokenSource = new CancellationTokenSource();\n\n\tprivate readonly _diffProvider = derived(this, reader => {\n\t\tconst diffProvider = this._diffProviderFactoryService.createDiffProvider({\n\t\t\tdiffAlgorithm: this._options.diffAlgorithm.read(reader)\n\t\t});\n\t\tconst onChangeSignal = observableSignalFromEvent('onDidChange', diffProvider.onDidChange);\n\t\treturn {\n\t\t\tdiffProvider,\n\t\t\tonChangeSignal,\n\t\t};\n\t});\n\n\tconstructor(\n\t\tpublic readonly model: IDiffEditorModel,\n\t\tprivate readonly _options: DiffEditorOptions,\n\t\t@IDiffProviderFactoryService private readonly _diffProviderFactoryService: IDiffProviderFactoryService,\n\t) {\n\t\tsuper();\n\n\t\tthis._register(toDisposable(() => this._cancellationTokenSource.cancel()));\n\n\t\tconst contentChangedSignal = observableSignal('contentChangedSignal');\n\t\tconst debouncer = this._register(new RunOnceScheduler(() => contentChangedSignal.trigger(undefined), 200));\n\n\t\tthis._register(autorun(reader => {\n\t\t\t/** @description collapse touching unchanged ranges */\n\n\t\t\tconst lastUnchangedRegions = this._unchangedRegions.read(reader);\n\t\t\tif (!lastUnchangedRegions || lastUnchangedRegions.regions.some(r => r.isDragged.read(reader))) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst lastUnchangedRegionsOrigRanges = lastUnchangedRegions.originalDecorationIds\n\t\t\t\t.map(id => model.original.getDecorationRange(id))\n\t\t\t\t.map(r => r ? LineRange.fromRangeInclusive(r) : undefined);\n\t\t\tconst lastUnchangedRegionsModRanges = lastUnchangedRegions.modifiedDecorationIds\n\t\t\t\t.map(id => model.modified.getDecorationRange(id))\n\t\t\t\t.map(r => r ? LineRange.fromRangeInclusive(r) : undefined);\n\t\t\tconst updatedLastUnchangedRegions = lastUnchangedRegions.regions.map((r, idx) =>\n\t\t\t\t(!lastUnchangedRegionsOrigRanges[idx] || !lastUnchangedRegionsModRanges[idx]) ? undefined :\n\t\t\t\t\tnew UnchangedRegion(\n\t\t\t\t\t\tlastUnchangedRegionsOrigRanges[idx]!.startLineNumber,\n\t\t\t\t\t\tlastUnchangedRegionsModRanges[idx]!.startLineNumber,\n\t\t\t\t\t\tlastUnchangedRegionsOrigRanges[idx]!.length,\n\t\t\t\t\t\tr.visibleLineCountTop.read(reader),\n\t\t\t\t\t\tr.visibleLineCountBottom.read(reader),\n\t\t\t\t\t)).filter(isDefined);\n\n\t\t\tconst newRanges: UnchangedRegion[] = [];\n\n\t\t\tlet didChange = false;\n\t\t\tfor (const touching of groupAdjacentBy(updatedLastUnchangedRegions, (a, b) => a.getHiddenModifiedRange(reader).endLineNumberExclusive === b.getHiddenModifiedRange(reader).startLineNumber)) {\n\t\t\t\tif (touching.length > 1) {\n\t\t\t\t\tdidChange = true;\n\t\t\t\t\tconst sumLineCount = touching.reduce((sum, r) => sum + r.lineCount, 0);\n\t\t\t\t\tconst r = new UnchangedRegion(touching[0].originalLineNumber, touching[0].modifiedLineNumber, sumLineCount, touching[0].visibleLineCountTop.get(), touching[touching.length - 1].visibleLineCountBottom.get());\n\t\t\t\t\tnewRanges.push(r);\n\t\t\t\t} else {\n\t\t\t\t\tnewRanges.push(touching[0]);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (didChange) {\n\t\t\t\tconst originalDecorationIds = model.original.deltaDecorations(\n\t\t\t\t\tlastUnchangedRegions.originalDecorationIds,\n\t\t\t\t\tnewRanges.map(r => ({ range: r.originalUnchangedRange.toInclusiveRange()!, options: { description: 'unchanged' } }))\n\t\t\t\t);\n\t\t\t\tconst modifiedDecorationIds = model.modified.deltaDecorations(\n\t\t\t\t\tlastUnchangedRegions.modifiedDecorationIds,\n\t\t\t\t\tnewRanges.map(r => ({ range: r.modifiedUnchangedRange.toInclusiveRange()!, options: { description: 'unchanged' } }))\n\t\t\t\t);\n\n\t\t\t\ttransaction(tx => {\n\t\t\t\t\tthis._unchangedRegions.set(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tregions: newRanges,\n\t\t\t\t\t\t\toriginalDecorationIds,\n\t\t\t\t\t\t\tmodifiedDecorationIds\n\t\t\t\t\t\t},\n\t\t\t\t\t\ttx\n\t\t\t\t\t);\n\t\t\t\t});\n\t\t\t}\n\t\t}));\n\n\t\tconst updateUnchangedRegions = (result: IDocumentDiff, tx: ITransaction, reader?: IReader) => {\n\t\t\tconst newUnchangedRegions = UnchangedRegion.fromDiffs(\n\t\t\t\tresult.changes,\n\t\t\t\tmodel.original.getLineCount(),\n\t\t\t\tmodel.modified.getLineCount(),\n\t\t\t\tthis._options.hideUnchangedRegionsMinimumLineCount.read(reader),\n\t\t\t\tthis._options.hideUnchangedRegionsContextLineCount.read(reader),\n\t\t\t);\n\n\t\t\t// Transfer state from cur state\n\t\t\tlet visibleRegions: LineRangeMapping[] | undefined = undefined;\n\n\t\t\tconst lastUnchangedRegions = this._unchangedRegions.get();\n\t\t\tif (lastUnchangedRegions) {\n\t\t\t\tconst lastUnchangedRegionsOrigRanges = lastUnchangedRegions.originalDecorationIds\n\t\t\t\t\t.map(id => model.original.getDecorationRange(id))\n\t\t\t\t\t.map(r => r ? LineRange.fromRangeInclusive(r) : undefined);\n\t\t\t\tconst lastUnchangedRegionsModRanges = lastUnchangedRegions.modifiedDecorationIds\n\t\t\t\t\t.map(id => model.modified.getDecorationRange(id))\n\t\t\t\t\t.map(r => r ? LineRange.fromRangeInclusive(r) : undefined);\n\t\t\t\tconst updatedLastUnchangedRegions = filterWithPrevious(\n\t\t\t\t\tlastUnchangedRegions.regions\n\t\t\t\t\t\t.map((r, idx) => {\n\t\t\t\t\t\t\tif (!lastUnchangedRegionsOrigRanges[idx] || !lastUnchangedRegionsModRanges[idx]) { return undefined; }\n\t\t\t\t\t\t\tconst length = lastUnchangedRegionsOrigRanges[idx]!.length;\n\t\t\t\t\t\t\treturn new UnchangedRegion(\n\t\t\t\t\t\t\t\tlastUnchangedRegionsOrigRanges[idx]!.startLineNumber,\n\t\t\t\t\t\t\t\tlastUnchangedRegionsModRanges[idx]!.startLineNumber,\n\t\t\t\t\t\t\t\tlength,\n\t\t\t\t\t\t\t\t// The visible area can shrink by edits -> we have to account for this\n\t\t\t\t\t\t\t\tMath.min(r.visibleLineCountTop.get(), length),\n\t\t\t\t\t\t\t\tMath.min(r.visibleLineCountBottom.get(), length - r.visibleLineCountTop.get()),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t).filter(isDefined),\n\t\t\t\t\t(cur, prev) => !prev || (cur.modifiedLineNumber >= prev.modifiedLineNumber + prev.lineCount && cur.originalLineNumber >= prev.originalLineNumber + prev.lineCount)\n\t\t\t\t);\n\n\t\t\t\tlet hiddenRegions = updatedLastUnchangedRegions.map(r => new LineRangeMapping(r.getHiddenOriginalRange(reader), r.getHiddenModifiedRange(reader)));\n\t\t\t\thiddenRegions = LineRangeMapping.clip(hiddenRegions, LineRange.ofLength(1, model.original.getLineCount()), LineRange.ofLength(1, model.modified.getLineCount()));\n\t\t\t\tvisibleRegions = LineRangeMapping.inverse(hiddenRegions, model.original.getLineCount(), model.modified.getLineCount());\n\t\t\t}\n\n\t\t\tconst newUnchangedRegions2 = [];\n\t\t\tif (visibleRegions) {\n\t\t\t\tfor (const r of newUnchangedRegions) {\n\t\t\t\t\tconst intersecting = visibleRegions.filter(f => f.original.intersectsStrict(r.originalUnchangedRange) && f.modified.intersectsStrict(r.modifiedUnchangedRange));\n\t\t\t\t\tnewUnchangedRegions2.push(...r.setVisibleRanges(intersecting, tx));\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tnewUnchangedRegions2.push(...newUnchangedRegions);\n\t\t\t}\n\n\t\t\tconst originalDecorationIds = model.original.deltaDecorations(\n\t\t\t\tlastUnchangedRegions?.originalDecorationIds || [],\n\t\t\t\tnewUnchangedRegions2.map(r => ({ range: r.originalUnchangedRange.toInclusiveRange()!, options: { description: 'unchanged' } }))\n\t\t\t);\n\t\t\tconst modifiedDecorationIds = model.modified.deltaDecorations(\n\t\t\t\tlastUnchangedRegions?.modifiedDecorationIds || [],\n\t\t\t\tnewUnchangedRegions2.map(r => ({ range: r.modifiedUnchangedRange.toInclusiveRange()!, options: { description: 'unchanged' } }))\n\t\t\t);\n\n\t\t\tthis._unchangedRegions.set(\n\t\t\t\t{\n\t\t\t\t\tregions: newUnchangedRegions2,\n\t\t\t\t\toriginalDecorationIds,\n\t\t\t\t\tmodifiedDecorationIds\n\t\t\t\t},\n\t\t\t\ttx\n\t\t\t);\n\t\t};\n\n\t\tthis._register(model.modified.onDidChangeContent((e) => {\n\t\t\tconst diff = this._diff.get();\n\t\t\tif (diff) {\n\t\t\t\tconst textEdits = TextEditInfo.fromModelContentChanges(e.changes);\n\t\t\t\tconst result = applyModifiedEdits(this._lastDiff!, textEdits, model.original, model.modified);\n\t\t\t\tif (result) {\n\t\t\t\t\tthis._lastDiff = result;\n\t\t\t\t\ttransaction(tx => {\n\t\t\t\t\t\tthis._diff.set(DiffState.fromDiffResult(this._lastDiff!), tx);\n\t\t\t\t\t\tupdateUnchangedRegions(result, tx);\n\t\t\t\t\t\tconst currentSyncedMovedText = this.movedTextToCompare.get();\n\t\t\t\t\t\tthis.movedTextToCompare.set(currentSyncedMovedText ? this._lastDiff!.moves.find(m => m.lineRangeMapping.modified.intersect(currentSyncedMovedText.lineRangeMapping.modified)) : undefined, tx);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis._isDiffUpToDate.set(false, undefined);\n\t\t\tdebouncer.schedule();\n\t\t}));\n\t\tthis._register(model.original.onDidChangeContent((e) => {\n\t\t\tconst diff = this._diff.get();\n\t\t\tif (diff) {\n\t\t\t\tconst textEdits = TextEditInfo.fromModelContentChanges(e.changes);\n\t\t\t\tconst result = applyOriginalEdits(this._lastDiff!, textEdits, model.original, model.modified);\n\t\t\t\tif (result) {\n\t\t\t\t\tthis._lastDiff = result;\n\t\t\t\t\ttransaction(tx => {\n\t\t\t\t\t\tthis._diff.set(DiffState.fromDiffResult(this._lastDiff!), tx);\n\t\t\t\t\t\tupdateUnchangedRegions(result, tx);\n\t\t\t\t\t\tconst currentSyncedMovedText = this.movedTextToCompare.get();\n\t\t\t\t\t\tthis.movedTextToCompare.set(currentSyncedMovedText ? this._lastDiff!.moves.find(m => m.lineRangeMapping.modified.intersect(currentSyncedMovedText.lineRangeMapping.modified)) : undefined, tx);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis._isDiffUpToDate.set(false, undefined);\n\t\t\tdebouncer.schedule();\n\t\t}));\n\n\t\tthis._register(autorunWithStore(async (reader, store) => {\n\t\t\t/** @description compute diff */\n\n\t\t\t// So that they get recomputed when these settings change\n\t\t\tthis._options.hideUnchangedRegionsMinimumLineCount.read(reader);\n\t\t\tthis._options.hideUnchangedRegionsContextLineCount.read(reader);\n\n\t\t\tdebouncer.cancel();\n\t\t\tcontentChangedSignal.read(reader);\n\t\t\tconst documentDiffProvider = this._diffProvider.read(reader);\n\t\t\tdocumentDiffProvider.onChangeSignal.read(reader);\n\n\t\t\treadHotReloadableExport(DefaultLinesDiffComputer, reader);\n\t\t\treadHotReloadableExport(optimizeSequenceDiffs, reader);\n\n\t\t\tthis._isDiffUpToDate.set(false, undefined);\n\n\t\t\tlet originalTextEditInfos: TextEditInfo[] = [];\n\t\t\tstore.add(model.original.onDidChangeContent((e) => {\n\t\t\t\tconst edits = TextEditInfo.fromModelContentChanges(e.changes);\n\t\t\t\toriginalTextEditInfos = combineTextEditInfos(originalTextEditInfos, edits);\n\t\t\t}));\n\n\t\t\tlet modifiedTextEditInfos: TextEditInfo[] = [];\n\t\t\tstore.add(model.modified.onDidChangeContent((e) => {\n\t\t\t\tconst edits = TextEditInfo.fromModelContentChanges(e.changes);\n\t\t\t\tmodifiedTextEditInfos = combineTextEditInfos(modifiedTextEditInfos, edits);\n\t\t\t}));\n\n\t\t\tlet result = await documentDiffProvider.diffProvider.computeDiff(model.original, model.modified, {\n\t\t\t\tignoreTrimWhitespace: this._options.ignoreTrimWhitespace.read(reader),\n\t\t\t\tmaxComputationTimeMs: this._options.maxComputationTimeMs.read(reader),\n\t\t\t\tcomputeMoves: this._options.showMoves.read(reader),\n\t\t\t}, this._cancellationTokenSource.token);\n\n\t\t\tif (this._cancellationTokenSource.token.isCancellationRequested) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (model.original.isDisposed() || model.modified.isDisposed()) {\n\t\t\t\t// TODO@hediet fishy?\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tresult = normalizeDocumentDiff(result, model.original, model.modified);\n\t\t\tresult = applyOriginalEdits(result, originalTextEditInfos, model.original, model.modified) ?? result;\n\t\t\tresult = applyModifiedEdits(result, modifiedTextEditInfos, model.original, model.modified) ?? result;\n\n\t\t\ttransaction(tx => {\n\t\t\t\t/** @description write diff result */\n\t\t\t\tupdateUnchangedRegions(result, tx);\n\n\t\t\t\tthis._lastDiff = result;\n\t\t\t\tconst state = DiffState.fromDiffResult(result);\n\t\t\t\tthis._diff.set(state, tx);\n\t\t\t\tthis._isDiffUpToDate.set(true, tx);\n\t\t\t\tconst currentSyncedMovedText = this.movedTextToCompare.get();\n\t\t\t\tthis.movedTextToCompare.set(currentSyncedMovedText ? this._lastDiff.moves.find(m => m.lineRangeMapping.modified.intersect(currentSyncedMovedText.lineRangeMapping.modified)) : undefined, tx);\n\t\t\t});\n\t\t}));\n\t}\n\n\tpublic ensureModifiedLineIsVisible(lineNumber: number, preference: RevealPreference, tx: ITransaction | undefined): void {\n\t\tif (this.diff.get()?.mappings.length === 0) {\n\t\t\treturn;\n\t\t}\n\t\tconst unchangedRegions = this._unchangedRegions.get()?.regions || [];\n\t\tfor (const r of unchangedRegions) {\n\t\t\tif (r.getHiddenModifiedRange(undefined).contains(lineNumber)) {\n\t\t\t\tr.showModifiedLine(lineNumber, preference, tx);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic ensureOriginalLineIsVisible(lineNumber: number, preference: RevealPreference, tx: ITransaction | undefined): void {\n\t\tif (this.diff.get()?.mappings.length === 0) {\n\t\t\treturn;\n\t\t}\n\t\tconst unchangedRegions = this._unchangedRegions.get()?.regions || [];\n\t\tfor (const r of unchangedRegions) {\n\t\t\tif (r.getHiddenOriginalRange(undefined).contains(lineNumber)) {\n\t\t\t\tr.showOriginalLine(lineNumber, preference, tx);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic async waitForDiff(): Promise {\n\t\tawait waitForState(this.isDiffUpToDate, s => s);\n\t}\n\n\tpublic serializeState(): SerializedState {\n\t\tconst regions = this._unchangedRegions.get();\n\t\treturn {\n\t\t\tcollapsedRegions: regions?.regions.map(r => ({ range: r.getHiddenModifiedRange(undefined).serialize() }))\n\t\t};\n\t}\n\n\tpublic restoreSerializedState(state: SerializedState): void {\n\t\tconst ranges = state.collapsedRegions?.map(r => LineRange.deserialize(r.range));\n\t\tconst regions = this._unchangedRegions.get();\n\t\tif (!regions || !ranges) {\n\t\t\treturn;\n\t\t}\n\t\ttransaction(tx => {\n\t\t\tfor (const r of regions.regions) {\n\t\t\t\tfor (const range of ranges) {\n\t\t\t\t\tif (r.modifiedUnchangedRange.intersect(range)) {\n\t\t\t\t\t\tr.setHiddenModifiedRange(range, tx);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t}\n}\n\nfunction normalizeDocumentDiff(diff: IDocumentDiff, original: ITextModel, modified: ITextModel): IDocumentDiff {\n\treturn {\n\t\tchanges: diff.changes.map(c => new DetailedLineRangeMapping(\n\t\t\tc.original,\n\t\t\tc.modified,\n\t\t\tc.innerChanges ? c.innerChanges.map(i => normalizeRangeMapping(i, original, modified)) : undefined\n\t\t)),\n\t\tmoves: diff.moves,\n\t\tidentical: diff.identical,\n\t\tquitEarly: diff.quitEarly,\n\t};\n}\n\nfunction normalizeRangeMapping(rangeMapping: RangeMapping, original: ITextModel, modified: ITextModel): RangeMapping {\n\tlet originalRange = rangeMapping.originalRange;\n\tlet modifiedRange = rangeMapping.modifiedRange;\n\tif (\n\t\t(originalRange.endColumn !== 1 || modifiedRange.endColumn !== 1) &&\n\t\toriginalRange.endColumn === original.getLineMaxColumn(originalRange.endLineNumber)\n\t\t&& modifiedRange.endColumn === modified.getLineMaxColumn(modifiedRange.endLineNumber)\n\t\t&& originalRange.endLineNumber < original.getLineCount()\n\t\t&& modifiedRange.endLineNumber < modified.getLineCount()\n\t) {\n\t\toriginalRange = originalRange.setEndPosition(originalRange.endLineNumber + 1, 1);\n\t\tmodifiedRange = modifiedRange.setEndPosition(modifiedRange.endLineNumber + 1, 1);\n\t}\n\treturn new RangeMapping(originalRange, modifiedRange);\n}\n\ninterface SerializedState {\n\tcollapsedRegions: { range: ISerializedLineRange }[] | undefined;\n}\n\nexport class DiffState {\n\tpublic static fromDiffResult(result: IDocumentDiff): DiffState {\n\t\treturn new DiffState(\n\t\t\tresult.changes.map(c => new DiffMapping(c)),\n\t\t\tresult.moves || [],\n\t\t\tresult.identical,\n\t\t\tresult.quitEarly,\n\t\t);\n\t}\n\n\tconstructor(\n\t\tpublic readonly mappings: readonly DiffMapping[],\n\t\tpublic readonly movedTexts: readonly MovedText[],\n\t\tpublic readonly identical: boolean,\n\t\tpublic readonly quitEarly: boolean,\n\t) { }\n}\n\nexport class DiffMapping {\n\tconstructor(\n\t\treadonly lineRangeMapping: DetailedLineRangeMapping,\n\t) {\n\t\t/*\n\t\treadonly movedTo: MovedText | undefined,\n\t\treadonly movedFrom: MovedText | undefined,\n\n\t\tif (movedTo) {\n\t\t\tassertFn(() =>\n\t\t\t\tmovedTo.lineRangeMapping.modifiedRange.equals(lineRangeMapping.modifiedRange)\n\t\t\t\t&& lineRangeMapping.originalRange.isEmpty\n\t\t\t\t&& !movedFrom\n\t\t\t);\n\t\t} else if (movedFrom) {\n\t\t\tassertFn(() =>\n\t\t\t\tmovedFrom.lineRangeMapping.originalRange.equals(lineRangeMapping.originalRange)\n\t\t\t\t&& lineRangeMapping.modifiedRange.isEmpty\n\t\t\t\t&& !movedTo\n\t\t\t);\n\t\t}\n\t\t*/\n\t}\n}\n\nexport class UnchangedRegion {\n\tpublic static fromDiffs(\n\t\tchanges: readonly DetailedLineRangeMapping[],\n\t\toriginalLineCount: number,\n\t\tmodifiedLineCount: number,\n\t\tminHiddenLineCount: number,\n\t\tminContext: number,\n\t): UnchangedRegion[] {\n\t\tconst inversedMappings = DetailedLineRangeMapping.inverse(changes, originalLineCount, modifiedLineCount);\n\t\tconst result: UnchangedRegion[] = [];\n\n\t\tfor (const mapping of inversedMappings) {\n\t\t\tlet origStart = mapping.original.startLineNumber;\n\t\t\tlet modStart = mapping.modified.startLineNumber;\n\t\t\tlet length = mapping.original.length;\n\n\t\t\tconst atStart = origStart === 1 && modStart === 1;\n\t\t\tconst atEnd = origStart + length === originalLineCount + 1 && modStart + length === modifiedLineCount + 1;\n\n\t\t\tif ((atStart || atEnd) && length >= minContext + minHiddenLineCount) {\n\t\t\t\tif (atStart && !atEnd) {\n\t\t\t\t\tlength -= minContext;\n\t\t\t\t}\n\t\t\t\tif (atEnd && !atStart) {\n\t\t\t\t\torigStart += minContext;\n\t\t\t\t\tmodStart += minContext;\n\t\t\t\t\tlength -= minContext;\n\t\t\t\t}\n\t\t\t\tresult.push(new UnchangedRegion(origStart, modStart, length, 0, 0));\n\t\t\t} else if (length >= minContext * 2 + minHiddenLineCount) {\n\t\t\t\torigStart += minContext;\n\t\t\t\tmodStart += minContext;\n\t\t\t\tlength -= minContext * 2;\n\t\t\t\tresult.push(new UnchangedRegion(origStart, modStart, length, 0, 0));\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic get originalUnchangedRange(): LineRange {\n\t\treturn LineRange.ofLength(this.originalLineNumber, this.lineCount);\n\t}\n\n\tpublic get modifiedUnchangedRange(): LineRange {\n\t\treturn LineRange.ofLength(this.modifiedLineNumber, this.lineCount);\n\t}\n\n\tprivate readonly _visibleLineCountTop = observableValue(this, 0);\n\tpublic readonly visibleLineCountTop: ISettableObservable = this._visibleLineCountTop;\n\n\tprivate readonly _visibleLineCountBottom = observableValue(this, 0);\n\tpublic readonly visibleLineCountBottom: ISettableObservable = this._visibleLineCountBottom;\n\n\tprivate readonly _shouldHideControls = derived(this, reader => /** @description isVisible */\n\t\tthis.visibleLineCountTop.read(reader) + this.visibleLineCountBottom.read(reader) === this.lineCount && !this.isDragged.read(reader));\n\n\tpublic readonly isDragged = observableValue(this, undefined);\n\n\tconstructor(\n\t\tpublic readonly originalLineNumber: number,\n\t\tpublic readonly modifiedLineNumber: number,\n\t\tpublic readonly lineCount: number,\n\t\tvisibleLineCountTop: number,\n\t\tvisibleLineCountBottom: number,\n\t) {\n\t\tconst visibleLineCountTop2 = Math.max(Math.min(visibleLineCountTop, this.lineCount), 0);\n\t\tconst visibleLineCountBottom2 = Math.max(Math.min(visibleLineCountBottom, this.lineCount - visibleLineCountTop), 0);\n\n\t\tsoftAssert(visibleLineCountTop === visibleLineCountTop2);\n\t\tsoftAssert(visibleLineCountBottom === visibleLineCountBottom2);\n\n\t\tthis._visibleLineCountTop.set(visibleLineCountTop2, undefined);\n\t\tthis._visibleLineCountBottom.set(visibleLineCountBottom2, undefined);\n\t}\n\n\tpublic setVisibleRanges(visibleRanges: LineRangeMapping[], tx: ITransaction): UnchangedRegion[] {\n\t\tconst result: UnchangedRegion[] = [];\n\n\t\tconst hiddenModified = new LineRangeSet(visibleRanges.map(r => r.modified)).subtractFrom(this.modifiedUnchangedRange);\n\n\t\tlet originalStartLineNumber = this.originalLineNumber;\n\t\tlet modifiedStartLineNumber = this.modifiedLineNumber;\n\t\tconst modifiedEndLineNumberEx = this.modifiedLineNumber + this.lineCount;\n\t\tif (hiddenModified.ranges.length === 0) {\n\t\t\tthis.showAll(tx);\n\t\t\tresult.push(this);\n\t\t} else {\n\t\t\tlet i = 0;\n\t\t\tfor (const r of hiddenModified.ranges) {\n\t\t\t\tconst isLast = i === hiddenModified.ranges.length - 1;\n\t\t\t\ti++;\n\n\t\t\t\tconst length = (isLast ? modifiedEndLineNumberEx : r.endLineNumberExclusive) - modifiedStartLineNumber;\n\n\t\t\t\tconst newR = new UnchangedRegion(originalStartLineNumber, modifiedStartLineNumber, length, 0, 0);\n\t\t\t\tnewR.setHiddenModifiedRange(r, tx);\n\t\t\t\tresult.push(newR);\n\n\t\t\t\toriginalStartLineNumber = newR.originalUnchangedRange.endLineNumberExclusive;\n\t\t\t\tmodifiedStartLineNumber = newR.modifiedUnchangedRange.endLineNumberExclusive;\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic shouldHideControls(reader: IReader | undefined): boolean {\n\t\treturn this._shouldHideControls.read(reader);\n\t}\n\n\tpublic getHiddenOriginalRange(reader: IReader | undefined): LineRange {\n\t\treturn LineRange.ofLength(\n\t\t\tthis.originalLineNumber + this._visibleLineCountTop.read(reader),\n\t\t\tthis.lineCount - this._visibleLineCountTop.read(reader) - this._visibleLineCountBottom.read(reader),\n\t\t);\n\t}\n\n\tpublic getHiddenModifiedRange(reader: IReader | undefined): LineRange {\n\t\treturn LineRange.ofLength(\n\t\t\tthis.modifiedLineNumber + this._visibleLineCountTop.read(reader),\n\t\t\tthis.lineCount - this._visibleLineCountTop.read(reader) - this._visibleLineCountBottom.read(reader),\n\t\t);\n\t}\n\n\tpublic setHiddenModifiedRange(range: LineRange, tx: ITransaction) {\n\t\tconst visibleLineCountTop = range.startLineNumber - this.modifiedLineNumber;\n\t\tconst visibleLineCountBottom = (this.modifiedLineNumber + this.lineCount) - range.endLineNumberExclusive;\n\t\tthis.setState(visibleLineCountTop, visibleLineCountBottom, tx);\n\t}\n\n\tpublic getMaxVisibleLineCountTop() {\n\t\treturn this.lineCount - this._visibleLineCountBottom.get();\n\t}\n\n\tpublic getMaxVisibleLineCountBottom() {\n\t\treturn this.lineCount - this._visibleLineCountTop.get();\n\t}\n\n\tpublic showMoreAbove(count = 10, tx: ITransaction | undefined): void {\n\t\tconst maxVisibleLineCountTop = this.getMaxVisibleLineCountTop();\n\t\tthis._visibleLineCountTop.set(Math.min(this._visibleLineCountTop.get() + count, maxVisibleLineCountTop), tx);\n\t}\n\n\tpublic showMoreBelow(count = 10, tx: ITransaction | undefined): void {\n\t\tconst maxVisibleLineCountBottom = this.lineCount - this._visibleLineCountTop.get();\n\t\tthis._visibleLineCountBottom.set(Math.min(this._visibleLineCountBottom.get() + count, maxVisibleLineCountBottom), tx);\n\t}\n\n\tpublic showAll(tx: ITransaction | undefined): void {\n\t\tthis._visibleLineCountBottom.set(this.lineCount - this._visibleLineCountTop.get(), tx);\n\t}\n\n\tpublic showModifiedLine(lineNumber: number, preference: RevealPreference, tx: ITransaction | undefined): void {\n\t\tconst top = lineNumber + 1 - (this.modifiedLineNumber + this._visibleLineCountTop.get());\n\t\tconst bottom = (this.modifiedLineNumber - this._visibleLineCountBottom.get() + this.lineCount) - lineNumber;\n\t\tif (preference === RevealPreference.FromCloserSide && top < bottom || preference === RevealPreference.FromTop) {\n\t\t\tthis._visibleLineCountTop.set(this._visibleLineCountTop.get() + top, tx);\n\t\t} else {\n\t\t\tthis._visibleLineCountBottom.set(this._visibleLineCountBottom.get() + bottom, tx);\n\t\t}\n\t}\n\n\tpublic showOriginalLine(lineNumber: number, preference: RevealPreference, tx: ITransaction | undefined): void {\n\t\tconst top = lineNumber - this.originalLineNumber;\n\t\tconst bottom = (this.originalLineNumber + this.lineCount) - lineNumber;\n\t\tif (preference === RevealPreference.FromCloserSide && top < bottom || preference === RevealPreference.FromTop) {\n\t\t\tthis._visibleLineCountTop.set(Math.min(this._visibleLineCountTop.get() + bottom - top, this.getMaxVisibleLineCountTop()), tx);\n\t\t} else {\n\t\t\tthis._visibleLineCountBottom.set(Math.min(this._visibleLineCountBottom.get() + top - bottom, this.getMaxVisibleLineCountBottom()), tx);\n\t\t}\n\t}\n\n\tpublic collapseAll(tx: ITransaction | undefined): void {\n\t\tthis._visibleLineCountTop.set(0, tx);\n\t\tthis._visibleLineCountBottom.set(0, tx);\n\t}\n\n\tpublic setState(visibleLineCountTop: number, visibleLineCountBottom: number, tx: ITransaction | undefined): void {\n\t\tvisibleLineCountTop = Math.max(Math.min(visibleLineCountTop, this.lineCount), 0);\n\t\tvisibleLineCountBottom = Math.max(Math.min(visibleLineCountBottom, this.lineCount - visibleLineCountTop), 0);\n\n\t\tthis._visibleLineCountTop.set(visibleLineCountTop, tx);\n\t\tthis._visibleLineCountBottom.set(visibleLineCountBottom, tx);\n\t}\n}\n\nexport const enum RevealPreference {\n\tFromCloserSide,\n\tFromTop,\n\tFromBottom,\n}\n\nfunction applyOriginalEdits(diff: IDocumentDiff, textEdits: TextEditInfo[], originalTextModel: ITextModel, modifiedTextModel: ITextModel): IDocumentDiff | undefined {\n\treturn undefined;\n\t/*\n\tTODO@hediet\n\tif (textEdits.length === 0) {\n\t\treturn diff;\n\t}\n\n\tconst diff2 = flip(diff);\n\tconst diff3 = applyModifiedEdits(diff2, textEdits, modifiedTextModel, originalTextModel);\n\tif (!diff3) {\n\t\treturn undefined;\n\t}\n\treturn flip(diff3);*/\n}\n/*\nfunction flip(diff: IDocumentDiff): IDocumentDiff {\n\treturn {\n\t\tchanges: diff.changes.map(c => c.flip()),\n\t\tmoves: diff.moves.map(m => m.flip()),\n\t\tidentical: diff.identical,\n\t\tquitEarly: diff.quitEarly,\n\t};\n}\n*/\nfunction applyModifiedEdits(diff: IDocumentDiff, textEdits: TextEditInfo[], originalTextModel: ITextModel, modifiedTextModel: ITextModel): IDocumentDiff | undefined {\n\treturn undefined;\n\t/*\n\tTODO@hediet\n\tif (textEdits.length === 0) {\n\t\treturn diff;\n\t}\n\tif (diff.changes.some(c => !c.innerChanges) || diff.moves.length > 0) {\n\t\t// TODO support these cases\n\t\treturn undefined;\n\t}\n\n\tconst changes = applyModifiedEditsToLineRangeMappings(diff.changes, textEdits, originalTextModel, modifiedTextModel);\n\n\tconst moves = diff.moves.map(m => {\n\t\tconst newModifiedRange = applyEditToLineRange(m.lineRangeMapping.modified, textEdits);\n\t\treturn newModifiedRange ? new MovedText(\n\t\t\tnew SimpleLineRangeMapping(m.lineRangeMapping.original, newModifiedRange),\n\t\t\tapplyModifiedEditsToLineRangeMappings(m.changes, textEdits, originalTextModel, modifiedTextModel),\n\t\t) : undefined;\n\t}).filter(isDefined);\n\n\treturn {\n\t\tidentical: false,\n\t\tquitEarly: false,\n\t\tchanges,\n\t\tmoves,\n\t};*/\n}\n/*\nfunction applyEditToLineRange(range: LineRange, textEdits: TextEditInfo[]): LineRange | undefined {\n\tlet rangeStartLineNumber = range.startLineNumber;\n\tlet rangeEndLineNumberEx = range.endLineNumberExclusive;\n\n\tfor (let i = textEdits.length - 1; i >= 0; i--) {\n\t\tconst textEdit = textEdits[i];\n\t\tconst textEditStartLineNumber = lengthGetLineCount(textEdit.startOffset) + 1;\n\t\tconst textEditEndLineNumber = lengthGetLineCount(textEdit.endOffset) + 1;\n\t\tconst newLengthLineCount = lengthGetLineCount(textEdit.newLength);\n\t\tconst delta = newLengthLineCount - (textEditEndLineNumber - textEditStartLineNumber);\n\n\t\tif (textEditEndLineNumber < rangeStartLineNumber) {\n\t\t\t// the text edit is before us\n\t\t\trangeStartLineNumber += delta;\n\t\t\trangeEndLineNumberEx += delta;\n\t\t} else if (textEditStartLineNumber > rangeEndLineNumberEx) {\n\t\t\t// the text edit is after us\n\t\t\t// NOOP\n\t\t} else if (textEditStartLineNumber < rangeStartLineNumber && rangeEndLineNumberEx < textEditEndLineNumber) {\n\t\t\t// the range is fully contained in the text edit\n\t\t\treturn undefined;\n\t\t} else if (textEditStartLineNumber < rangeStartLineNumber && textEditEndLineNumber <= rangeEndLineNumberEx) {\n\t\t\t// the text edit ends inside our range\n\t\t\trangeStartLineNumber = textEditEndLineNumber + 1;\n\t\t\trangeStartLineNumber += delta;\n\t\t\trangeEndLineNumberEx += delta;\n\t\t} else if (rangeStartLineNumber <= textEditStartLineNumber && textEditEndLineNumber < rangeStartLineNumber) {\n\t\t\t// the text edit starts inside our range\n\t\t\trangeEndLineNumberEx = textEditStartLineNumber;\n\t\t} else {\n\t\t\trangeEndLineNumberEx += delta;\n\t\t}\n\t}\n\n\treturn new LineRange(rangeStartLineNumber, rangeEndLineNumberEx);\n}\n\nfunction applyModifiedEditsToLineRangeMappings(changes: readonly LineRangeMapping[], textEdits: TextEditInfo[], originalTextModel: ITextModel, modifiedTextModel: ITextModel): LineRangeMapping[] {\n\tconst diffTextEdits = changes.flatMap(c => c.innerChanges!.map(c => new TextEditInfo(\n\t\tpositionToLength(c.originalRange.getStartPosition()),\n\t\tpositionToLength(c.originalRange.getEndPosition()),\n\t\tlengthOfRange(c.modifiedRange).toLength(),\n\t)));\n\n\tconst combined = combineTextEditInfos(diffTextEdits, textEdits);\n\n\tlet lastOriginalEndOffset = lengthZero;\n\tlet lastModifiedEndOffset = lengthZero;\n\tconst rangeMappings = combined.map(c => {\n\t\tconst modifiedStartOffset = lengthAdd(lastModifiedEndOffset, lengthDiffNonNegative(lastOriginalEndOffset, c.startOffset));\n\t\tlastOriginalEndOffset = c.endOffset;\n\t\tlastModifiedEndOffset = lengthAdd(modifiedStartOffset, c.newLength);\n\n\t\treturn new RangeMapping(\n\t\t\tRange.fromPositions(lengthToPosition(c.startOffset), lengthToPosition(c.endOffset)),\n\t\t\tRange.fromPositions(lengthToPosition(modifiedStartOffset), lengthToPosition(lastModifiedEndOffset)),\n\t\t);\n\t});\n\n\tconst newChanges = lineRangeMappingFromRangeMappings(\n\t\trangeMappings,\n\t\toriginalTextModel.getLinesContent(),\n\t\tmodifiedTextModel.getLinesContent(),\n\t);\n\treturn newChanges;\n}\n*/\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\nimport { alert } from 'vs/base/browser/ui/aria/aria';\nimport { MarkdownString } from 'vs/base/common/htmlContent';\nimport { KeyChord, KeyCode, KeyMod } from 'vs/base/common/keyCodes';\nimport { IDisposable } from 'vs/base/common/lifecycle';\nimport 'vs/css!./anchorSelect';\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\nimport { EditorAction, EditorContributionInstantiation, registerEditorAction, registerEditorContribution, ServicesAccessor } from 'vs/editor/browser/editorExtensions';\nimport { Selection } from 'vs/editor/common/core/selection';\nimport { IEditorContribution } from 'vs/editor/common/editorCommon';\nimport { EditorContextKeys } from 'vs/editor/common/editorContextKeys';\nimport { TrackedRangeStickiness } from 'vs/editor/common/model';\nimport { localize } from 'vs/nls';\nimport { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';\nimport { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';\n\nexport const SelectionAnchorSet = new RawContextKey('selectionAnchorSet', false);\n\nclass SelectionAnchorController implements IEditorContribution {\n\n\tpublic static readonly ID = 'editor.contrib.selectionAnchorController';\n\n\tstatic get(editor: ICodeEditor): SelectionAnchorController | null {\n\t\treturn editor.getContribution(SelectionAnchorController.ID);\n\t}\n\n\tprivate decorationId: string | undefined;\n\tprivate selectionAnchorSetContextKey: IContextKey;\n\tprivate modelChangeListener: IDisposable;\n\n\tconstructor(\n\t\tprivate editor: ICodeEditor,\n\t\t@IContextKeyService contextKeyService: IContextKeyService\n\t) {\n\t\tthis.selectionAnchorSetContextKey = SelectionAnchorSet.bindTo(contextKeyService);\n\t\tthis.modelChangeListener = editor.onDidChangeModel(() => this.selectionAnchorSetContextKey.reset());\n\t}\n\n\tsetSelectionAnchor(): void {\n\t\tif (this.editor.hasModel()) {\n\t\t\tconst position = this.editor.getPosition();\n\t\t\tthis.editor.changeDecorations((accessor) => {\n\t\t\t\tif (this.decorationId) {\n\t\t\t\t\taccessor.removeDecoration(this.decorationId);\n\t\t\t\t}\n\t\t\t\tthis.decorationId = accessor.addDecoration(\n\t\t\t\t\tSelection.fromPositions(position, position),\n\t\t\t\t\t{\n\t\t\t\t\t\tdescription: 'selection-anchor',\n\t\t\t\t\t\tstickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges,\n\t\t\t\t\t\thoverMessage: new MarkdownString().appendText(localize('selectionAnchor', \"Selection Anchor\")),\n\t\t\t\t\t\tclassName: 'selection-anchor'\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t});\n\t\t\tthis.selectionAnchorSetContextKey.set(!!this.decorationId);\n\t\t\talert(localize('anchorSet', \"Anchor set at {0}:{1}\", position.lineNumber, position.column));\n\t\t}\n\t}\n\n\tgoToSelectionAnchor(): void {\n\t\tif (this.editor.hasModel() && this.decorationId) {\n\t\t\tconst anchorPosition = this.editor.getModel().getDecorationRange(this.decorationId);\n\t\t\tif (anchorPosition) {\n\t\t\t\tthis.editor.setPosition(anchorPosition.getStartPosition());\n\t\t\t}\n\t\t}\n\t}\n\n\tselectFromAnchorToCursor(): void {\n\t\tif (this.editor.hasModel() && this.decorationId) {\n\t\t\tconst start = this.editor.getModel().getDecorationRange(this.decorationId);\n\t\t\tif (start) {\n\t\t\t\tconst end = this.editor.getPosition();\n\t\t\t\tthis.editor.setSelection(Selection.fromPositions(start.getStartPosition(), end));\n\t\t\t\tthis.cancelSelectionAnchor();\n\t\t\t}\n\t\t}\n\t}\n\n\tcancelSelectionAnchor(): void {\n\t\tif (this.decorationId) {\n\t\t\tconst decorationId = this.decorationId;\n\t\t\tthis.editor.changeDecorations((accessor) => {\n\t\t\t\taccessor.removeDecoration(decorationId);\n\t\t\t\tthis.decorationId = undefined;\n\t\t\t});\n\t\t\tthis.selectionAnchorSetContextKey.set(false);\n\t\t}\n\t}\n\n\tdispose(): void {\n\t\tthis.cancelSelectionAnchor();\n\t\tthis.modelChangeListener.dispose();\n\t}\n}\n\nclass SetSelectionAnchor extends EditorAction {\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'editor.action.setSelectionAnchor',\n\t\t\tlabel: localize('setSelectionAnchor', \"Set Selection Anchor\"),\n\t\t\talias: 'Set Selection Anchor',\n\t\t\tprecondition: undefined,\n\t\t\tkbOpts: {\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\n\t\t\t\tprimary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.KeyB),\n\t\t\t\tweight: KeybindingWeight.EditorContrib\n\t\t\t}\n\t\t});\n\t}\n\n\tasync run(_accessor: ServicesAccessor, editor: ICodeEditor): Promise {\n\t\tSelectionAnchorController.get(editor)?.setSelectionAnchor();\n\t}\n}\n\nclass GoToSelectionAnchor extends EditorAction {\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'editor.action.goToSelectionAnchor',\n\t\t\tlabel: localize('goToSelectionAnchor', \"Go to Selection Anchor\"),\n\t\t\talias: 'Go to Selection Anchor',\n\t\t\tprecondition: SelectionAnchorSet,\n\t\t});\n\t}\n\n\tasync run(_accessor: ServicesAccessor, editor: ICodeEditor): Promise {\n\t\tSelectionAnchorController.get(editor)?.goToSelectionAnchor();\n\t}\n}\n\nclass SelectFromAnchorToCursor extends EditorAction {\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'editor.action.selectFromAnchorToCursor',\n\t\t\tlabel: localize('selectFromAnchorToCursor', \"Select from Anchor to Cursor\"),\n\t\t\talias: 'Select from Anchor to Cursor',\n\t\t\tprecondition: SelectionAnchorSet,\n\t\t\tkbOpts: {\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\n\t\t\t\tprimary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.KeyK),\n\t\t\t\tweight: KeybindingWeight.EditorContrib\n\t\t\t}\n\t\t});\n\t}\n\n\tasync run(_accessor: ServicesAccessor, editor: ICodeEditor): Promise {\n\t\tSelectionAnchorController.get(editor)?.selectFromAnchorToCursor();\n\t}\n}\n\nclass CancelSelectionAnchor extends EditorAction {\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'editor.action.cancelSelectionAnchor',\n\t\t\tlabel: localize('cancelSelectionAnchor', \"Cancel Selection Anchor\"),\n\t\t\talias: 'Cancel Selection Anchor',\n\t\t\tprecondition: SelectionAnchorSet,\n\t\t\tkbOpts: {\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\n\t\t\t\tprimary: KeyCode.Escape,\n\t\t\t\tweight: KeybindingWeight.EditorContrib\n\t\t\t}\n\t\t});\n\t}\n\n\tasync run(_accessor: ServicesAccessor, editor: ICodeEditor): Promise {\n\t\tSelectionAnchorController.get(editor)?.cancelSelectionAnchor();\n\t}\n}\n\nregisterEditorContribution(SelectionAnchorController.ID, SelectionAnchorController, EditorContributionInstantiation.Lazy);\nregisterEditorAction(SetSelectionAnchor);\nregisterEditorAction(GoToSelectionAnchor);\nregisterEditorAction(SelectFromAnchorToCursor);\nregisterEditorAction(CancelSelectionAnchor);\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\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\nimport { EditorAction, IActionOptions, registerEditorAction, ServicesAccessor } from 'vs/editor/browser/editorExtensions';\nimport { ICommand } from 'vs/editor/common/editorCommon';\nimport { EditorContextKeys } from 'vs/editor/common/editorContextKeys';\nimport { MoveCaretCommand } from 'vs/editor/contrib/caretOperations/browser/moveCaretCommand';\nimport * as nls from 'vs/nls';\n\nclass MoveCaretAction extends EditorAction {\n\n\tprivate readonly left: boolean;\n\n\tconstructor(left: boolean, opts: IActionOptions) {\n\t\tsuper(opts);\n\n\t\tthis.left = left;\n\t}\n\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor): void {\n\t\tif (!editor.hasModel()) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst commands: ICommand[] = [];\n\t\tconst selections = editor.getSelections();\n\n\t\tfor (const selection of selections) {\n\t\t\tcommands.push(new MoveCaretCommand(selection, this.left));\n\t\t}\n\n\t\teditor.pushUndoStop();\n\t\teditor.executeCommands(this.id, commands);\n\t\teditor.pushUndoStop();\n\t}\n}\n\nclass MoveCaretLeftAction extends MoveCaretAction {\n\tconstructor() {\n\t\tsuper(true, {\n\t\t\tid: 'editor.action.moveCarretLeftAction',\n\t\t\tlabel: nls.localize('caret.moveLeft', \"Move Selected Text Left\"),\n\t\t\talias: 'Move Selected Text Left',\n\t\t\tprecondition: EditorContextKeys.writable\n\t\t});\n\t}\n}\n\nclass MoveCaretRightAction extends MoveCaretAction {\n\tconstructor() {\n\t\tsuper(false, {\n\t\t\tid: 'editor.action.moveCarretRightAction',\n\t\t\tlabel: nls.localize('caret.moveRight', \"Move Selected Text Right\"),\n\t\t\talias: 'Move Selected Text Right',\n\t\t\tprecondition: EditorContextKeys.writable\n\t\t});\n\t}\n}\n\nregisterEditorAction(MoveCaretLeftAction);\nregisterEditorAction(MoveCaretRightAction);\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\nimport { KeyCode, KeyMod } from 'vs/base/common/keyCodes';\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\nimport { EditorAction, registerEditorAction, ServicesAccessor } from 'vs/editor/browser/editorExtensions';\nimport { ReplaceCommand } from 'vs/editor/common/commands/replaceCommand';\nimport { MoveOperations } from 'vs/editor/common/cursor/cursorMoveOperations';\nimport { Range } from 'vs/editor/common/core/range';\nimport { ICommand } from 'vs/editor/common/editorCommon';\nimport { EditorContextKeys } from 'vs/editor/common/editorContextKeys';\nimport * as nls from 'vs/nls';\nimport { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';\n\nclass TransposeLettersAction extends EditorAction {\n\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'editor.action.transposeLetters',\n\t\t\tlabel: nls.localize('transposeLetters.label', \"Transpose Letters\"),\n\t\t\talias: 'Transpose Letters',\n\t\t\tprecondition: EditorContextKeys.writable,\n\t\t\tkbOpts: {\n\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\t\tprimary: 0,\n\t\t\t\tmac: {\n\t\t\t\t\tprimary: KeyMod.WinCtrl | KeyCode.KeyT\n\t\t\t\t},\n\t\t\t\tweight: KeybindingWeight.EditorContrib\n\t\t\t}\n\t\t});\n\t}\n\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor): void {\n\t\tif (!editor.hasModel()) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst model = editor.getModel();\n\t\tconst commands: ICommand[] = [];\n\t\tconst selections = editor.getSelections();\n\n\t\tfor (const selection of selections) {\n\t\t\tif (!selection.isEmpty()) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst lineNumber = selection.startLineNumber;\n\t\t\tconst column = selection.startColumn;\n\n\t\t\tconst lastColumn = model.getLineMaxColumn(lineNumber);\n\n\t\t\tif (lineNumber === 1 && (column === 1 || (column === 2 && lastColumn === 2))) {\n\t\t\t\t// at beginning of file, nothing to do\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// handle special case: when at end of line, transpose left two chars\n\t\t\t// otherwise, transpose left and right chars\n\t\t\tconst endPosition = (column === lastColumn) ?\n\t\t\t\tselection.getPosition() :\n\t\t\t\tMoveOperations.rightPosition(model, selection.getPosition().lineNumber, selection.getPosition().column);\n\n\t\t\tconst middlePosition = MoveOperations.leftPosition(model, endPosition);\n\t\t\tconst beginPosition = MoveOperations.leftPosition(model, middlePosition);\n\n\t\t\tconst leftChar = model.getValueInRange(Range.fromPositions(beginPosition, middlePosition));\n\t\t\tconst rightChar = model.getValueInRange(Range.fromPositions(middlePosition, endPosition));\n\n\t\t\tconst replaceRange = Range.fromPositions(beginPosition, endPosition);\n\t\t\tcommands.push(new ReplaceCommand(replaceRange, rightChar + leftChar));\n\t\t}\n\n\t\tif (commands.length > 0) {\n\t\t\teditor.pushUndoStop();\n\t\t\teditor.executeCommands(this.id, commands);\n\t\t\teditor.pushUndoStop();\n\t\t}\n\t}\n}\n\nregisterEditorAction(TransposeLettersAction);\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\nimport { KeyChord, KeyCode, KeyMod } from 'vs/base/common/keyCodes';\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\nimport { EditorAction, IActionOptions, registerEditorAction, ServicesAccessor } from 'vs/editor/browser/editorExtensions';\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\nimport { Range } from 'vs/editor/common/core/range';\nimport { ICommand } from 'vs/editor/common/editorCommon';\nimport { EditorContextKeys } from 'vs/editor/common/editorContextKeys';\nimport { ILanguageConfigurationService } from 'vs/editor/common/languages/languageConfigurationRegistry';\nimport { BlockCommentCommand } from 'vs/editor/contrib/comment/browser/blockCommentCommand';\nimport { LineCommentCommand, Type } from 'vs/editor/contrib/comment/browser/lineCommentCommand';\nimport * as nls from 'vs/nls';\nimport { MenuId } from 'vs/platform/actions/common/actions';\nimport { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';\n\nabstract class CommentLineAction extends EditorAction {\n\n\tprivate readonly _type: Type;\n\n\tconstructor(type: Type, opts: IActionOptions) {\n\t\tsuper(opts);\n\t\tthis._type = type;\n\t}\n\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor): void {\n\t\tconst languageConfigurationService = accessor.get(ILanguageConfigurationService);\n\n\t\tif (!editor.hasModel()) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst model = editor.getModel();\n\t\tconst commands: ICommand[] = [];\n\t\tconst modelOptions = model.getOptions();\n\t\tconst commentsOptions = editor.getOption(EditorOption.comments);\n\n\t\tconst selections = editor.getSelections().map((selection, index) => ({ selection, index, ignoreFirstLine: false }));\n\t\tselections.sort((a, b) => Range.compareRangesUsingStarts(a.selection, b.selection));\n\n\t\t// Remove selections that would result in copying the same line\n\t\tlet prev = selections[0];\n\t\tfor (let i = 1; i < selections.length; i++) {\n\t\t\tconst curr = selections[i];\n\t\t\tif (prev.selection.endLineNumber === curr.selection.startLineNumber) {\n\t\t\t\t// these two selections would copy the same line\n\t\t\t\tif (prev.index < curr.index) {\n\t\t\t\t\t// prev wins\n\t\t\t\t\tcurr.ignoreFirstLine = true;\n\t\t\t\t} else {\n\t\t\t\t\t// curr wins\n\t\t\t\t\tprev.ignoreFirstLine = true;\n\t\t\t\t\tprev = curr;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\n\t\tfor (const selection of selections) {\n\t\t\tcommands.push(new LineCommentCommand(\n\t\t\t\tlanguageConfigurationService,\n\t\t\t\tselection.selection,\n\t\t\t\tmodelOptions.indentSize,\n\t\t\t\tthis._type,\n\t\t\t\tcommentsOptions.insertSpace,\n\t\t\t\tcommentsOptions.ignoreEmptyLines,\n\t\t\t\tselection.ignoreFirstLine\n\t\t\t));\n\t\t}\n\n\t\teditor.pushUndoStop();\n\t\teditor.executeCommands(this.id, commands);\n\t\teditor.pushUndoStop();\n\t}\n\n}\n\nclass ToggleCommentLineAction extends CommentLineAction {\n\tconstructor() {\n\t\tsuper(Type.Toggle, {\n\t\t\tid: 'editor.action.commentLine',\n\t\t\tlabel: nls.localize('comment.line', \"Toggle Line Comment\"),\n\t\t\talias: 'Toggle Line Comment',\n\t\t\tprecondition: EditorContextKeys.writable,\n\t\t\tkbOpts: {\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\n\t\t\t\tprimary: KeyMod.CtrlCmd | KeyCode.Slash,\n\t\t\t\tweight: KeybindingWeight.EditorContrib\n\t\t\t},\n\t\t\tmenuOpts: {\n\t\t\t\tmenuId: MenuId.MenubarEditMenu,\n\t\t\t\tgroup: '5_insert',\n\t\t\t\ttitle: nls.localize({ key: 'miToggleLineComment', comment: ['&& denotes a mnemonic'] }, \"&&Toggle Line Comment\"),\n\t\t\t\torder: 1\n\t\t\t}\n\t\t});\n\t}\n}\n\nclass AddLineCommentAction extends CommentLineAction {\n\tconstructor() {\n\t\tsuper(Type.ForceAdd, {\n\t\t\tid: 'editor.action.addCommentLine',\n\t\t\tlabel: nls.localize('comment.line.add', \"Add Line Comment\"),\n\t\t\talias: 'Add Line Comment',\n\t\t\tprecondition: EditorContextKeys.writable,\n\t\t\tkbOpts: {\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\n\t\t\t\tprimary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.KeyC),\n\t\t\t\tweight: KeybindingWeight.EditorContrib\n\t\t\t}\n\t\t});\n\t}\n}\n\nclass RemoveLineCommentAction extends CommentLineAction {\n\tconstructor() {\n\t\tsuper(Type.ForceRemove, {\n\t\t\tid: 'editor.action.removeCommentLine',\n\t\t\tlabel: nls.localize('comment.line.remove', \"Remove Line Comment\"),\n\t\t\talias: 'Remove Line Comment',\n\t\t\tprecondition: EditorContextKeys.writable,\n\t\t\tkbOpts: {\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\n\t\t\t\tprimary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.KeyU),\n\t\t\t\tweight: KeybindingWeight.EditorContrib\n\t\t\t}\n\t\t});\n\t}\n}\n\nclass BlockCommentAction extends EditorAction {\n\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'editor.action.blockComment',\n\t\t\tlabel: nls.localize('comment.block', \"Toggle Block Comment\"),\n\t\t\talias: 'Toggle Block Comment',\n\t\t\tprecondition: EditorContextKeys.writable,\n\t\t\tkbOpts: {\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\n\t\t\t\tprimary: KeyMod.Shift | KeyMod.Alt | KeyCode.KeyA,\n\t\t\t\tlinux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KeyA },\n\t\t\t\tweight: KeybindingWeight.EditorContrib\n\t\t\t},\n\t\t\tmenuOpts: {\n\t\t\t\tmenuId: MenuId.MenubarEditMenu,\n\t\t\t\tgroup: '5_insert',\n\t\t\t\ttitle: nls.localize({ key: 'miToggleBlockComment', comment: ['&& denotes a mnemonic'] }, \"Toggle &&Block Comment\"),\n\t\t\t\torder: 2\n\t\t\t}\n\t\t});\n\t}\n\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor): void {\n\t\tconst languageConfigurationService = accessor.get(ILanguageConfigurationService);\n\n\t\tif (!editor.hasModel()) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst commentsOptions = editor.getOption(EditorOption.comments);\n\t\tconst commands: ICommand[] = [];\n\t\tconst selections = editor.getSelections();\n\t\tfor (const selection of selections) {\n\t\t\tcommands.push(new BlockCommentCommand(selection, commentsOptions.insertSpace, languageConfigurationService));\n\t\t}\n\n\t\teditor.pushUndoStop();\n\t\teditor.executeCommands(this.id, commands);\n\t\teditor.pushUndoStop();\n\t}\n}\n\nregisterEditorAction(ToggleCommentLineAction);\nregisterEditorAction(AddLineCommentAction);\nregisterEditorAction(RemoveLineCommentAction);\nregisterEditorAction(BlockCommentAction);\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\nimport { KeyCode, KeyMod } from 'vs/base/common/keyCodes';\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\nimport { EditorAction, EditorContributionInstantiation, registerEditorAction, registerEditorContribution, ServicesAccessor } from 'vs/editor/browser/editorExtensions';\nimport { Selection } from 'vs/editor/common/core/selection';\nimport { IEditorContribution } from 'vs/editor/common/editorCommon';\nimport { EditorContextKeys } from 'vs/editor/common/editorContextKeys';\nimport * as nls from 'vs/nls';\nimport { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';\n\nclass CursorState {\n\treadonly selections: readonly Selection[];\n\n\tconstructor(selections: readonly Selection[]) {\n\t\tthis.selections = selections;\n\t}\n\n\tpublic equals(other: CursorState): boolean {\n\t\tconst thisLen = this.selections.length;\n\t\tconst otherLen = other.selections.length;\n\t\tif (thisLen !== otherLen) {\n\t\t\treturn false;\n\t\t}\n\t\tfor (let i = 0; i < thisLen; i++) {\n\t\t\tif (!this.selections[i].equalsSelection(other.selections[i])) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n}\n\nclass StackElement {\n\tconstructor(\n\t\tpublic readonly cursorState: CursorState,\n\t\tpublic readonly scrollTop: number,\n\t\tpublic readonly scrollLeft: number\n\t) { }\n}\n\nexport class CursorUndoRedoController extends Disposable implements IEditorContribution {\n\n\tpublic static readonly ID = 'editor.contrib.cursorUndoRedoController';\n\n\tpublic static get(editor: ICodeEditor): CursorUndoRedoController | null {\n\t\treturn editor.getContribution(CursorUndoRedoController.ID);\n\t}\n\n\tprivate readonly _editor: ICodeEditor;\n\tprivate _isCursorUndoRedo: boolean;\n\n\tprivate _undoStack: StackElement[];\n\tprivate _redoStack: StackElement[];\n\n\tconstructor(editor: ICodeEditor) {\n\t\tsuper();\n\t\tthis._editor = editor;\n\t\tthis._isCursorUndoRedo = false;\n\n\t\tthis._undoStack = [];\n\t\tthis._redoStack = [];\n\n\t\tthis._register(editor.onDidChangeModel((e) => {\n\t\t\tthis._undoStack = [];\n\t\t\tthis._redoStack = [];\n\t\t}));\n\t\tthis._register(editor.onDidChangeModelContent((e) => {\n\t\t\tthis._undoStack = [];\n\t\t\tthis._redoStack = [];\n\t\t}));\n\t\tthis._register(editor.onDidChangeCursorSelection((e) => {\n\t\t\tif (this._isCursorUndoRedo) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (!e.oldSelections) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (e.oldModelVersionId !== e.modelVersionId) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst prevState = new CursorState(e.oldSelections);\n\t\t\tconst isEqualToLastUndoStack = (this._undoStack.length > 0 && this._undoStack[this._undoStack.length - 1].cursorState.equals(prevState));\n\t\t\tif (!isEqualToLastUndoStack) {\n\t\t\t\tthis._undoStack.push(new StackElement(prevState, editor.getScrollTop(), editor.getScrollLeft()));\n\t\t\t\tthis._redoStack = [];\n\t\t\t\tif (this._undoStack.length > 50) {\n\t\t\t\t\t// keep the cursor undo stack bounded\n\t\t\t\t\tthis._undoStack.shift();\n\t\t\t\t}\n\t\t\t}\n\t\t}));\n\t}\n\n\tpublic cursorUndo(): void {\n\t\tif (!this._editor.hasModel() || this._undoStack.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._redoStack.push(new StackElement(new CursorState(this._editor.getSelections()), this._editor.getScrollTop(), this._editor.getScrollLeft()));\n\t\tthis._applyState(this._undoStack.pop()!);\n\t}\n\n\tpublic cursorRedo(): void {\n\t\tif (!this._editor.hasModel() || this._redoStack.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._undoStack.push(new StackElement(new CursorState(this._editor.getSelections()), this._editor.getScrollTop(), this._editor.getScrollLeft()));\n\t\tthis._applyState(this._redoStack.pop()!);\n\t}\n\n\tprivate _applyState(stackElement: StackElement): void {\n\t\tthis._isCursorUndoRedo = true;\n\t\tthis._editor.setSelections(stackElement.cursorState.selections);\n\t\tthis._editor.setScrollPosition({\n\t\t\tscrollTop: stackElement.scrollTop,\n\t\t\tscrollLeft: stackElement.scrollLeft\n\t\t});\n\t\tthis._isCursorUndoRedo = false;\n\t}\n}\n\nexport class CursorUndo extends EditorAction {\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'cursorUndo',\n\t\t\tlabel: nls.localize('cursor.undo', \"Cursor Undo\"),\n\t\t\talias: 'Cursor Undo',\n\t\t\tprecondition: undefined,\n\t\t\tkbOpts: {\n\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\t\tprimary: KeyMod.CtrlCmd | KeyCode.KeyU,\n\t\t\t\tweight: KeybindingWeight.EditorContrib\n\t\t\t}\n\t\t});\n\t}\n\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void {\n\t\tCursorUndoRedoController.get(editor)?.cursorUndo();\n\t}\n}\n\nexport class CursorRedo extends EditorAction {\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'cursorRedo',\n\t\t\tlabel: nls.localize('cursor.redo', \"Cursor Redo\"),\n\t\t\talias: 'Cursor Redo',\n\t\t\tprecondition: undefined\n\t\t});\n\t}\n\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void {\n\t\tCursorUndoRedoController.get(editor)?.cursorRedo();\n\t}\n}\n\nregisterEditorContribution(CursorUndoRedoController.ID, CursorUndoRedoController, EditorContributionInstantiation.Eager); // eager because it needs to listen to record cursor state ASAP\nregisterEditorAction(CursorUndo);\nregisterEditorAction(CursorRedo);\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\nimport { KeyCode } from 'vs/base/common/keyCodes';\nimport { EditorCommand, registerEditorCommand } from 'vs/editor/browser/editorExtensions';\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\nimport { IContextKeyService, RawContextKey, IContextKey } from 'vs/platform/contextkey/common/contextkey';\nimport { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';\nimport { CancellationTokenSource, CancellationToken } from 'vs/base/common/cancellation';\nimport { LinkedList } from 'vs/base/common/linkedList';\nimport { createDecorator, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';\nimport { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions';\nimport { localize } from 'vs/nls';\n\n\nconst IEditorCancellationTokens = createDecorator('IEditorCancelService');\n\ninterface IEditorCancellationTokens {\n\treadonly _serviceBrand: undefined;\n\tadd(editor: ICodeEditor, cts: CancellationTokenSource): () => void;\n\tcancel(editor: ICodeEditor): void;\n}\n\nconst ctxCancellableOperation = new RawContextKey('cancellableOperation', false, localize('cancellableOperation', 'Whether the editor runs a cancellable operation, e.g. like \\'Peek References\\''));\n\nregisterSingleton(IEditorCancellationTokens, class implements IEditorCancellationTokens {\n\n\tdeclare readonly _serviceBrand: undefined;\n\n\tprivate readonly _tokens = new WeakMap; tokens: LinkedList }>();\n\n\tadd(editor: ICodeEditor, cts: CancellationTokenSource): () => void {\n\t\tlet data = this._tokens.get(editor);\n\t\tif (!data) {\n\t\t\tdata = editor.invokeWithinContext(accessor => {\n\t\t\t\tconst key = ctxCancellableOperation.bindTo(accessor.get(IContextKeyService));\n\t\t\t\tconst tokens = new LinkedList();\n\t\t\t\treturn { key, tokens };\n\t\t\t});\n\t\t\tthis._tokens.set(editor, data);\n\t\t}\n\n\t\tlet removeFn: Function | undefined;\n\n\t\tdata.key.set(true);\n\t\tremoveFn = data.tokens.push(cts);\n\n\t\treturn () => {\n\t\t\t// remove w/o cancellation\n\t\t\tif (removeFn) {\n\t\t\t\tremoveFn();\n\t\t\t\tdata.key.set(!data.tokens.isEmpty());\n\t\t\t\tremoveFn = undefined;\n\t\t\t}\n\t\t};\n\t}\n\n\tcancel(editor: ICodeEditor): void {\n\t\tconst data = this._tokens.get(editor);\n\t\tif (!data) {\n\t\t\treturn;\n\t\t}\n\t\t// remove with cancellation\n\t\tconst cts = data.tokens.pop();\n\t\tif (cts) {\n\t\t\tcts.cancel();\n\t\t\tdata.key.set(!data.tokens.isEmpty());\n\t\t}\n\t}\n\n}, InstantiationType.Delayed);\n\nexport class EditorKeybindingCancellationTokenSource extends CancellationTokenSource {\n\n\tprivate readonly _unregister: Function;\n\n\tconstructor(readonly editor: ICodeEditor, parent?: CancellationToken) {\n\t\tsuper(parent);\n\t\tthis._unregister = editor.invokeWithinContext(accessor => accessor.get(IEditorCancellationTokens).add(editor, this));\n\t}\n\n\toverride dispose(): void {\n\t\tthis._unregister();\n\t\tsuper.dispose();\n\t}\n}\n\nregisterEditorCommand(new class extends EditorCommand {\n\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'editor.cancelOperation',\n\t\t\tkbOpts: {\n\t\t\t\tweight: KeybindingWeight.EditorContrib,\n\t\t\t\tprimary: KeyCode.Escape\n\t\t\t},\n\t\t\tprecondition: ctxCancellableOperation\n\t\t});\n\t}\n\n\trunEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor): void {\n\t\taccessor.get(IEditorCancellationTokens).cancel(editor);\n\t}\n});\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\nimport * as strings from 'vs/base/common/strings';\nimport { ICodeEditor, IActiveCodeEditor } from 'vs/editor/browser/editorBrowser';\nimport { Position } from 'vs/editor/common/core/position';\nimport { Range, IRange } from 'vs/editor/common/core/range';\nimport { CancellationTokenSource, CancellationToken } from 'vs/base/common/cancellation';\nimport { IDisposable, DisposableStore } from 'vs/base/common/lifecycle';\nimport { ITextModel } from 'vs/editor/common/model';\nimport { EditorKeybindingCancellationTokenSource } from 'vs/editor/contrib/editorState/browser/keybindingCancellation';\n\nexport const enum CodeEditorStateFlag {\n\tValue = 1,\n\tSelection = 2,\n\tPosition = 4,\n\tScroll = 8\n}\n\nexport class EditorState {\n\n\tprivate readonly flags: number;\n\n\tprivate readonly position: Position | null;\n\tprivate readonly selection: Range | null;\n\tprivate readonly modelVersionId: string | null;\n\tprivate readonly scrollLeft: number;\n\tprivate readonly scrollTop: number;\n\n\tconstructor(editor: ICodeEditor, flags: number) {\n\t\tthis.flags = flags;\n\n\t\tif ((this.flags & CodeEditorStateFlag.Value) !== 0) {\n\t\t\tconst model = editor.getModel();\n\t\t\tthis.modelVersionId = model ? strings.format('{0}#{1}', model.uri.toString(), model.getVersionId()) : null;\n\t\t} else {\n\t\t\tthis.modelVersionId = null;\n\t\t}\n\t\tif ((this.flags & CodeEditorStateFlag.Position) !== 0) {\n\t\t\tthis.position = editor.getPosition();\n\t\t} else {\n\t\t\tthis.position = null;\n\t\t}\n\t\tif ((this.flags & CodeEditorStateFlag.Selection) !== 0) {\n\t\t\tthis.selection = editor.getSelection();\n\t\t} else {\n\t\t\tthis.selection = null;\n\t\t}\n\t\tif ((this.flags & CodeEditorStateFlag.Scroll) !== 0) {\n\t\t\tthis.scrollLeft = editor.getScrollLeft();\n\t\t\tthis.scrollTop = editor.getScrollTop();\n\t\t} else {\n\t\t\tthis.scrollLeft = -1;\n\t\t\tthis.scrollTop = -1;\n\t\t}\n\t}\n\n\tprivate _equals(other: any): boolean {\n\n\t\tif (!(other instanceof EditorState)) {\n\t\t\treturn false;\n\t\t}\n\t\tconst state = other;\n\n\t\tif (this.modelVersionId !== state.modelVersionId) {\n\t\t\treturn false;\n\t\t}\n\t\tif (this.scrollLeft !== state.scrollLeft || this.scrollTop !== state.scrollTop) {\n\t\t\treturn false;\n\t\t}\n\t\tif (!this.position && state.position || this.position && !state.position || this.position && state.position && !this.position.equals(state.position)) {\n\t\t\treturn false;\n\t\t}\n\t\tif (!this.selection && state.selection || this.selection && !state.selection || this.selection && state.selection && !this.selection.equalsRange(state.selection)) {\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\tpublic validate(editor: ICodeEditor): boolean {\n\t\treturn this._equals(new EditorState(editor, this.flags));\n\t}\n}\n\n/**\n * A cancellation token source that cancels when the editor changes as expressed\n * by the provided flags\n * @param range If provided, changes in position and selection within this range will not trigger cancellation\n */\nexport class EditorStateCancellationTokenSource extends EditorKeybindingCancellationTokenSource implements IDisposable {\n\n\tprivate readonly _listener = new DisposableStore();\n\n\tconstructor(editor: IActiveCodeEditor, flags: CodeEditorStateFlag, range?: IRange, parent?: CancellationToken) {\n\t\tsuper(editor, parent);\n\n\t\tif (flags & CodeEditorStateFlag.Position) {\n\t\t\tthis._listener.add(editor.onDidChangeCursorPosition(e => {\n\t\t\t\tif (!range || !Range.containsPosition(range, e.position)) {\n\t\t\t\t\tthis.cancel();\n\t\t\t\t}\n\t\t\t}));\n\t\t}\n\t\tif (flags & CodeEditorStateFlag.Selection) {\n\t\t\tthis._listener.add(editor.onDidChangeCursorSelection(e => {\n\t\t\t\tif (!range || !Range.containsRange(range, e.selection)) {\n\t\t\t\t\tthis.cancel();\n\t\t\t\t}\n\t\t\t}));\n\t\t}\n\t\tif (flags & CodeEditorStateFlag.Scroll) {\n\t\t\tthis._listener.add(editor.onDidScrollChange(_ => this.cancel()));\n\t\t}\n\t\tif (flags & CodeEditorStateFlag.Value) {\n\t\t\tthis._listener.add(editor.onDidChangeModel(_ => this.cancel()));\n\t\t\tthis._listener.add(editor.onDidChangeModelContent(_ => this.cancel()));\n\t\t}\n\t}\n\n\toverride dispose() {\n\t\tthis._listener.dispose();\n\t\tsuper.dispose();\n\t}\n}\n\n/**\n * A cancellation token source that cancels when the provided model changes\n */\nexport class TextModelCancellationTokenSource extends CancellationTokenSource implements IDisposable {\n\n\tprivate _listener: IDisposable;\n\n\tconstructor(model: ITextModel, parent?: CancellationToken) {\n\t\tsuper(parent);\n\t\tthis._listener = model.onDidChangeContent(() => this.cancel());\n\t}\n\n\toverride dispose() {\n\t\tthis._listener.dispose();\n\t\tsuper.dispose();\n\t}\n}\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\nimport { coalesce, equals, isNonEmptyArray } from 'vs/base/common/arrays';\nimport { CancellationToken } from 'vs/base/common/cancellation';\nimport { illegalArgument, isCancellationError, onUnexpectedExternalError } from 'vs/base/common/errors';\nimport { Disposable, DisposableStore } from 'vs/base/common/lifecycle';\nimport { URI } from 'vs/base/common/uri';\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\nimport { IBulkEditService } from 'vs/editor/browser/services/bulkEditService';\nimport { Range } from 'vs/editor/common/core/range';\nimport { Selection } from 'vs/editor/common/core/selection';\nimport { LanguageFeatureRegistry } from 'vs/editor/common/languageFeatureRegistry';\nimport * as languages from 'vs/editor/common/languages';\nimport { ITextModel } from 'vs/editor/common/model';\nimport { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';\nimport { IModelService } from 'vs/editor/common/services/model';\nimport { TextModelCancellationTokenSource } from 'vs/editor/contrib/editorState/browser/editorState';\nimport * as nls from 'vs/nls';\nimport { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands';\nimport { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';\nimport { INotificationService } from 'vs/platform/notification/common/notification';\nimport { IProgress, Progress } from 'vs/platform/progress/common/progress';\nimport { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';\nimport { CodeActionFilter, CodeActionItem, CodeActionKind, CodeActionSet, CodeActionTrigger, CodeActionTriggerSource, filtersAction, mayIncludeActionsOfKind } from '../common/types';\nimport { HierarchicalKind } from 'vs/base/common/hierarchicalKind';\n\nexport const codeActionCommandId = 'editor.action.codeAction';\nexport const quickFixCommandId = 'editor.action.quickFix';\nexport const autoFixCommandId = 'editor.action.autoFix';\nexport const refactorCommandId = 'editor.action.refactor';\nexport const sourceActionCommandId = 'editor.action.sourceAction';\nexport const organizeImportsCommandId = 'editor.action.organizeImports';\nexport const fixAllCommandId = 'editor.action.fixAll';\n\nclass ManagedCodeActionSet extends Disposable implements CodeActionSet {\n\n\tprivate static codeActionsPreferredComparator(a: languages.CodeAction, b: languages.CodeAction): number {\n\t\tif (a.isPreferred && !b.isPreferred) {\n\t\t\treturn -1;\n\t\t} else if (!a.isPreferred && b.isPreferred) {\n\t\t\treturn 1;\n\t\t} else {\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\tprivate static codeActionsComparator({ action: a }: CodeActionItem, { action: b }: CodeActionItem): number {\n\t\tif (a.isAI && !b.isAI) {\n\t\t\treturn 1;\n\t\t} else if (!a.isAI && b.isAI) {\n\t\t\treturn -1;\n\t\t}\n\t\tif (isNonEmptyArray(a.diagnostics)) {\n\t\t\treturn isNonEmptyArray(b.diagnostics) ? ManagedCodeActionSet.codeActionsPreferredComparator(a, b) : -1;\n\t\t} else if (isNonEmptyArray(b.diagnostics)) {\n\t\t\treturn 1;\n\t\t} else {\n\t\t\treturn ManagedCodeActionSet.codeActionsPreferredComparator(a, b); // both have no diagnostics\n\t\t}\n\t}\n\n\tpublic readonly validActions: readonly CodeActionItem[];\n\tpublic readonly allActions: readonly CodeActionItem[];\n\n\tpublic constructor(\n\t\tactions: readonly CodeActionItem[],\n\t\tpublic readonly documentation: readonly languages.Command[],\n\t\tdisposables: DisposableStore,\n\t) {\n\t\tsuper();\n\n\t\tthis._register(disposables);\n\n\t\tthis.allActions = [...actions].sort(ManagedCodeActionSet.codeActionsComparator);\n\t\tthis.validActions = this.allActions.filter(({ action }) => !action.disabled);\n\t}\n\n\tpublic get hasAutoFix() {\n\t\treturn this.validActions.some(({ action: fix }) => !!fix.kind && CodeActionKind.QuickFix.contains(new HierarchicalKind(fix.kind)) && !!fix.isPreferred);\n\t}\n\n\tpublic get hasAIFix() {\n\t\treturn this.validActions.some(({ action: fix }) => !!fix.isAI);\n\t}\n\n\tpublic get allAIFixes() {\n\t\treturn this.validActions.every(({ action: fix }) => !!fix.isAI);\n\t}\n}\n\nconst emptyCodeActionsResponse = { actions: [] as CodeActionItem[], documentation: undefined };\n\nexport async function getCodeActions(\n\tregistry: LanguageFeatureRegistry,\n\tmodel: ITextModel,\n\trangeOrSelection: Range | Selection,\n\ttrigger: CodeActionTrigger,\n\tprogress: IProgress,\n\ttoken: CancellationToken,\n): Promise {\n\tconst filter = trigger.filter || {};\n\tconst notebookFilter: CodeActionFilter = {\n\t\t...filter,\n\t\texcludes: [...(filter.excludes || []), CodeActionKind.Notebook],\n\t};\n\n\tconst codeActionContext: languages.CodeActionContext = {\n\t\tonly: filter.include?.value,\n\t\ttrigger: trigger.type,\n\t};\n\n\tconst cts = new TextModelCancellationTokenSource(model, token);\n\t// if the trigger is auto (autosave, lightbulb, etc), we should exclude notebook codeActions\n\tconst excludeNotebookCodeActions = (trigger.type === languages.CodeActionTriggerType.Auto);\n\tconst providers = getCodeActionProviders(registry, model, (excludeNotebookCodeActions) ? notebookFilter : filter);\n\n\tconst disposables = new DisposableStore();\n\tconst promises = providers.map(async provider => {\n\t\ttry {\n\t\t\tprogress.report(provider);\n\t\t\tconst providedCodeActions = await provider.provideCodeActions(model, rangeOrSelection, codeActionContext, cts.token);\n\t\t\tif (providedCodeActions) {\n\t\t\t\tdisposables.add(providedCodeActions);\n\t\t\t}\n\n\t\t\tif (cts.token.isCancellationRequested) {\n\t\t\t\treturn emptyCodeActionsResponse;\n\t\t\t}\n\n\t\t\tconst filteredActions = (providedCodeActions?.actions || []).filter(action => action && filtersAction(filter, action));\n\t\t\tconst documentation = getDocumentationFromProvider(provider, filteredActions, filter.include);\n\t\t\treturn {\n\t\t\t\tactions: filteredActions.map(action => new CodeActionItem(action, provider)),\n\t\t\t\tdocumentation\n\t\t\t};\n\t\t} catch (err) {\n\t\t\tif (isCancellationError(err)) {\n\t\t\t\tthrow err;\n\t\t\t}\n\t\t\tonUnexpectedExternalError(err);\n\t\t\treturn emptyCodeActionsResponse;\n\t\t}\n\t});\n\n\tconst listener = registry.onDidChange(() => {\n\t\tconst newProviders = registry.all(model);\n\t\tif (!equals(newProviders, providers)) {\n\t\t\tcts.cancel();\n\t\t}\n\t});\n\n\ttry {\n\t\tconst actions = await Promise.all(promises);\n\t\tconst allActions = actions.map(x => x.actions).flat();\n\t\tconst allDocumentation = [\n\t\t\t...coalesce(actions.map(x => x.documentation)),\n\t\t\t...getAdditionalDocumentationForShowingActions(registry, model, trigger, allActions)\n\t\t];\n\t\treturn new ManagedCodeActionSet(allActions, allDocumentation, disposables);\n\t} finally {\n\t\tlistener.dispose();\n\t\tcts.dispose();\n\t}\n}\n\nfunction getCodeActionProviders(\n\tregistry: LanguageFeatureRegistry,\n\tmodel: ITextModel,\n\tfilter: CodeActionFilter\n) {\n\treturn registry.all(model)\n\t\t// Don't include providers that we know will not return code actions of interest\n\t\t.filter(provider => {\n\t\t\tif (!provider.providedCodeActionKinds) {\n\t\t\t\t// We don't know what type of actions this provider will return.\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn provider.providedCodeActionKinds.some(kind => mayIncludeActionsOfKind(filter, new HierarchicalKind(kind)));\n\t\t});\n}\n\nfunction* getAdditionalDocumentationForShowingActions(\n\tregistry: LanguageFeatureRegistry,\n\tmodel: ITextModel,\n\ttrigger: CodeActionTrigger,\n\tactionsToShow: readonly CodeActionItem[],\n): Iterable {\n\tif (model && actionsToShow.length) {\n\t\tfor (const provider of registry.all(model)) {\n\t\t\tif (provider._getAdditionalMenuItems) {\n\t\t\t\tyield* provider._getAdditionalMenuItems?.({ trigger: trigger.type, only: trigger.filter?.include?.value }, actionsToShow.map(item => item.action));\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction getDocumentationFromProvider(\n\tprovider: languages.CodeActionProvider,\n\tprovidedCodeActions: readonly languages.CodeAction[],\n\tonly?: HierarchicalKind\n): languages.Command | undefined {\n\tif (!provider.documentation) {\n\t\treturn undefined;\n\t}\n\n\tconst documentation = provider.documentation.map(entry => ({ kind: new HierarchicalKind(entry.kind), command: entry.command }));\n\n\tif (only) {\n\t\tlet currentBest: { readonly kind: HierarchicalKind; readonly command: languages.Command } | undefined;\n\t\tfor (const entry of documentation) {\n\t\t\tif (entry.kind.contains(only)) {\n\t\t\t\tif (!currentBest) {\n\t\t\t\t\tcurrentBest = entry;\n\t\t\t\t} else {\n\t\t\t\t\t// Take best match\n\t\t\t\t\tif (currentBest.kind.contains(entry.kind)) {\n\t\t\t\t\t\tcurrentBest = entry;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (currentBest) {\n\t\t\treturn currentBest?.command;\n\t\t}\n\t}\n\n\t// Otherwise, check to see if any of the provided actions match.\n\tfor (const action of providedCodeActions) {\n\t\tif (!action.kind) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tfor (const entry of documentation) {\n\t\t\tif (entry.kind.contains(new HierarchicalKind(action.kind))) {\n\t\t\t\treturn entry.command;\n\t\t\t}\n\t\t}\n\t}\n\treturn undefined;\n}\n\nexport enum ApplyCodeActionReason {\n\tOnSave = 'onSave',\n\tFromProblemsView = 'fromProblemsView',\n\tFromCodeActions = 'fromCodeActions',\n\tFromAILightbulb = 'fromAILightbulb' // direct invocation when clicking on the AI lightbulb\n}\n\nexport async function applyCodeAction(\n\taccessor: ServicesAccessor,\n\titem: CodeActionItem,\n\tcodeActionReason: ApplyCodeActionReason,\n\toptions?: { readonly preview?: boolean; readonly editor?: ICodeEditor },\n\ttoken: CancellationToken = CancellationToken.None,\n): Promise {\n\tconst bulkEditService = accessor.get(IBulkEditService);\n\tconst commandService = accessor.get(ICommandService);\n\tconst telemetryService = accessor.get(ITelemetryService);\n\tconst notificationService = accessor.get(INotificationService);\n\n\ttype ApplyCodeActionEvent = {\n\t\tcodeActionTitle: string;\n\t\tcodeActionKind: string | undefined;\n\t\tcodeActionIsPreferred: boolean;\n\t\treason: ApplyCodeActionReason;\n\t};\n\ttype ApplyCodeEventClassification = {\n\t\tcodeActionTitle: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The display label of the applied code action' };\n\t\tcodeActionKind: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The kind (refactor, quickfix) of the applied code action' };\n\t\tcodeActionIsPreferred: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Was the code action marked as being a preferred action?' };\n\t\treason: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The kind of action used to trigger apply code action.' };\n\t\towner: 'justschen';\n\t\tcomment: 'Event used to gain insights into which code actions are being triggered';\n\t};\n\n\ttelemetryService.publicLog2('codeAction.applyCodeAction', {\n\t\tcodeActionTitle: item.action.title,\n\t\tcodeActionKind: item.action.kind,\n\t\tcodeActionIsPreferred: !!item.action.isPreferred,\n\t\treason: codeActionReason,\n\t});\n\n\tawait item.resolve(token);\n\tif (token.isCancellationRequested) {\n\t\treturn;\n\t}\n\n\tif (item.action.edit?.edits.length) {\n\t\tconst result = await bulkEditService.apply(item.action.edit, {\n\t\t\teditor: options?.editor,\n\t\t\tlabel: item.action.title,\n\t\t\tquotableLabel: item.action.title,\n\t\t\tcode: 'undoredo.codeAction',\n\t\t\trespectAutoSaveConfig: codeActionReason !== ApplyCodeActionReason.OnSave,\n\t\t\tshowPreview: options?.preview,\n\t\t});\n\n\t\tif (!result.isApplied) {\n\t\t\treturn;\n\t\t}\n\t}\n\n\tif (item.action.command) {\n\t\ttry {\n\t\t\tawait commandService.executeCommand(item.action.command.id, ...(item.action.command.arguments || []));\n\t\t} catch (err) {\n\t\t\tconst message = asMessage(err);\n\t\t\tnotificationService.error(\n\t\t\t\ttypeof message === 'string'\n\t\t\t\t\t? message\n\t\t\t\t\t: nls.localize('applyCodeActionFailed', \"An unknown error occurred while applying the code action\"));\n\t\t}\n\t}\n}\n\nfunction asMessage(err: any): string | undefined {\n\tif (typeof err === 'string') {\n\t\treturn err;\n\t} else if (err instanceof Error && typeof err.message === 'string') {\n\t\treturn err.message;\n\t} else {\n\t\treturn undefined;\n\t}\n}\n\nCommandsRegistry.registerCommand('_executeCodeActionProvider', async function (accessor, resource: URI, rangeOrSelection: Range | Selection, kind?: string, itemResolveCount?: number): Promise> {\n\tif (!(resource instanceof URI)) {\n\t\tthrow illegalArgument();\n\t}\n\n\tconst { codeActionProvider } = accessor.get(ILanguageFeaturesService);\n\tconst model = accessor.get(IModelService).getModel(resource);\n\tif (!model) {\n\t\tthrow illegalArgument();\n\t}\n\n\tconst validatedRangeOrSelection = Selection.isISelection(rangeOrSelection)\n\t\t? Selection.liftSelection(rangeOrSelection)\n\t\t: Range.isIRange(rangeOrSelection)\n\t\t\t? model.validateRange(rangeOrSelection)\n\t\t\t: undefined;\n\n\tif (!validatedRangeOrSelection) {\n\t\tthrow illegalArgument();\n\t}\n\n\tconst include = typeof kind === 'string' ? new HierarchicalKind(kind) : undefined;\n\tconst codeActionSet = await getCodeActions(\n\t\tcodeActionProvider,\n\t\tmodel,\n\t\tvalidatedRangeOrSelection,\n\t\t{ type: languages.CodeActionTriggerType.Invoke, triggerAction: CodeActionTriggerSource.Default, filter: { includeSourceActions: true, include } },\n\t\tProgress.None,\n\t\tCancellationToken.None);\n\n\tconst resolving: Promise[] = [];\n\tconst resolveCount = Math.min(codeActionSet.validActions.length, typeof itemResolveCount === 'number' ? itemResolveCount : 0);\n\tfor (let i = 0; i < resolveCount; i++) {\n\t\tresolving.push(codeActionSet.validActions[i].resolve(CancellationToken.None));\n\t}\n\n\ttry {\n\t\tawait Promise.all(resolving);\n\t\treturn codeActionSet.validActions.map(item => item.action);\n\t} finally {\n\t\tsetTimeout(() => codeActionSet.dispose(), 100);\n\t}\n});\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\nimport { HierarchicalKind } from 'vs/base/common/hierarchicalKind';\nimport { ResolvedKeybinding } from 'vs/base/common/keybindings';\nimport { Lazy } from 'vs/base/common/lazy';\nimport { CodeAction } from 'vs/editor/common/languages';\nimport { codeActionCommandId, fixAllCommandId, organizeImportsCommandId, refactorCommandId, sourceActionCommandId } from 'vs/editor/contrib/codeAction/browser/codeAction';\nimport { CodeActionAutoApply, CodeActionCommandArgs, CodeActionKind } from 'vs/editor/contrib/codeAction/common/types';\nimport { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';\n\ninterface ResolveCodeActionKeybinding {\n\treadonly kind: HierarchicalKind;\n\treadonly preferred: boolean;\n\treadonly resolvedKeybinding: ResolvedKeybinding;\n}\n\nexport class CodeActionKeybindingResolver {\n\tprivate static readonly codeActionCommands: readonly string[] = [\n\t\trefactorCommandId,\n\t\tcodeActionCommandId,\n\t\tsourceActionCommandId,\n\t\torganizeImportsCommandId,\n\t\tfixAllCommandId\n\t];\n\n\tconstructor(\n\t\t@IKeybindingService private readonly keybindingService: IKeybindingService\n\t) { }\n\n\tpublic getResolver(): (action: CodeAction) => ResolvedKeybinding | undefined {\n\t\t// Lazy since we may not actually ever read the value\n\t\tconst allCodeActionBindings = new Lazy(() => this.keybindingService.getKeybindings()\n\t\t\t.filter(item => CodeActionKeybindingResolver.codeActionCommands.indexOf(item.command!) >= 0)\n\t\t\t.filter(item => item.resolvedKeybinding)\n\t\t\t.map((item): ResolveCodeActionKeybinding => {\n\t\t\t\t// Special case these commands since they come built-in with VS Code and don't use 'commandArgs'\n\t\t\t\tlet commandArgs = item.commandArgs;\n\t\t\t\tif (item.command === organizeImportsCommandId) {\n\t\t\t\t\tcommandArgs = { kind: CodeActionKind.SourceOrganizeImports.value };\n\t\t\t\t} else if (item.command === fixAllCommandId) {\n\t\t\t\t\tcommandArgs = { kind: CodeActionKind.SourceFixAll.value };\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\tresolvedKeybinding: item.resolvedKeybinding!,\n\t\t\t\t\t...CodeActionCommandArgs.fromUser(commandArgs, {\n\t\t\t\t\t\tkind: HierarchicalKind.None,\n\t\t\t\t\t\tapply: CodeActionAutoApply.Never\n\t\t\t\t\t})\n\t\t\t\t};\n\t\t\t}));\n\n\t\treturn (action) => {\n\t\t\tif (action.kind) {\n\t\t\t\tconst binding = this.bestKeybindingForCodeAction(action, allCodeActionBindings.value);\n\t\t\t\treturn binding?.resolvedKeybinding;\n\t\t\t}\n\t\t\treturn undefined;\n\t\t};\n\t}\n\n\tprivate bestKeybindingForCodeAction(\n\t\taction: CodeAction,\n\t\tcandidates: readonly ResolveCodeActionKeybinding[]\n\t): ResolveCodeActionKeybinding | undefined {\n\t\tif (!action.kind) {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst kind = new HierarchicalKind(action.kind);\n\n\t\treturn candidates\n\t\t\t.filter(candidate => candidate.kind.contains(kind))\n\t\t\t.filter(candidate => {\n\t\t\t\tif (candidate.preferred) {\n\t\t\t\t\t// If the candidate keybinding only applies to preferred actions, the this action must also be preferred\n\t\t\t\t\treturn action.isPreferred;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t})\n\t\t\t.reduceRight((currentBest, candidate) => {\n\t\t\t\tif (!currentBest) {\n\t\t\t\t\treturn candidate;\n\t\t\t\t}\n\t\t\t\t// Select the more specific binding\n\t\t\t\treturn currentBest.kind.contains(candidate.kind) ? candidate : currentBest;\n\t\t\t}, undefined as ResolveCodeActionKeybinding | undefined);\n\t}\n}\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\nimport { CancelablePromise, createCancelablePromise, TimeoutTimer } from 'vs/base/common/async';\nimport { isCancellationError } from 'vs/base/common/errors';\nimport { Emitter } from 'vs/base/common/event';\nimport { Disposable, MutableDisposable } from 'vs/base/common/lifecycle';\nimport { isEqual } from 'vs/base/common/resources';\nimport { URI } from 'vs/base/common/uri';\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\nimport { EditorOption, ShowLightbulbIconMode } from 'vs/editor/common/config/editorOptions';\nimport { Position } from 'vs/editor/common/core/position';\nimport { Selection } from 'vs/editor/common/core/selection';\nimport { LanguageFeatureRegistry } from 'vs/editor/common/languageFeatureRegistry';\nimport { CodeActionProvider, CodeActionTriggerType } from 'vs/editor/common/languages';\nimport { IConfigurationService } from 'vs/platform/configuration/common/configuration';\nimport { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';\nimport { IMarkerService } from 'vs/platform/markers/common/markers';\nimport { IEditorProgressService, Progress } from 'vs/platform/progress/common/progress';\nimport { CodeActionKind, CodeActionSet, CodeActionTrigger, CodeActionTriggerSource } from '../common/types';\nimport { getCodeActions } from './codeAction';\nimport { HierarchicalKind } from 'vs/base/common/hierarchicalKind';\n\nexport const SUPPORTED_CODE_ACTIONS = new RawContextKey('supportedCodeAction', '');\n\nexport const APPLY_FIX_ALL_COMMAND_ID = '_typescript.applyFixAllCodeAction';\n\ntype TriggeredCodeAction = {\n\treadonly selection: Selection;\n\treadonly trigger: CodeActionTrigger;\n};\n\nclass CodeActionOracle extends Disposable {\n\n\tprivate readonly _autoTriggerTimer = this._register(new TimeoutTimer());\n\n\tconstructor(\n\t\tprivate readonly _editor: ICodeEditor,\n\t\tprivate readonly _markerService: IMarkerService,\n\t\tprivate readonly _signalChange: (triggered: TriggeredCodeAction | undefined) => void,\n\t\tprivate readonly _delay: number = 250,\n\t) {\n\t\tsuper();\n\t\tthis._register(this._markerService.onMarkerChanged(e => this._onMarkerChanges(e)));\n\t\tthis._register(this._editor.onDidChangeCursorPosition(() => this._tryAutoTrigger()));\n\t}\n\n\tpublic trigger(trigger: CodeActionTrigger): void {\n\t\tconst selection = this._getRangeOfSelectionUnlessWhitespaceEnclosed(trigger);\n\t\tthis._signalChange(selection ? { trigger, selection } : undefined);\n\t}\n\n\tprivate _onMarkerChanges(resources: readonly URI[]): void {\n\t\tconst model = this._editor.getModel();\n\t\tif (model && resources.some(resource => isEqual(resource, model.uri))) {\n\t\t\tthis._tryAutoTrigger();\n\t\t}\n\t}\n\n\tprivate _tryAutoTrigger() {\n\t\tthis._autoTriggerTimer.cancelAndSet(() => {\n\t\t\tthis.trigger({ type: CodeActionTriggerType.Auto, triggerAction: CodeActionTriggerSource.Default });\n\t\t}, this._delay);\n\t}\n\n\tprivate _getRangeOfSelectionUnlessWhitespaceEnclosed(trigger: CodeActionTrigger): Selection | undefined {\n\t\tif (!this._editor.hasModel()) {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst selection = this._editor.getSelection();\n\t\tif (trigger.type === CodeActionTriggerType.Invoke) {\n\t\t\treturn selection;\n\t\t}\n\t\tconst enabled = this._editor.getOption(EditorOption.lightbulb).enabled;\n\t\tif (enabled === ShowLightbulbIconMode.Off) {\n\t\t\treturn undefined;\n\t\t} else if (enabled === ShowLightbulbIconMode.On) {\n\t\t\treturn selection;\n\t\t} else if (enabled === ShowLightbulbIconMode.OnCode) {\n\t\t\tconst isSelectionEmpty = selection.isEmpty();\n\t\t\tif (!isSelectionEmpty) {\n\t\t\t\treturn selection;\n\t\t\t}\n\t\t\tconst model = this._editor.getModel();\n\t\t\tconst { lineNumber, column } = selection.getPosition();\n\t\t\tconst line = model.getLineContent(lineNumber);\n\t\t\tif (line.length === 0) {\n\t\t\t\t// empty line\n\t\t\t\treturn undefined;\n\t\t\t} else if (column === 1) {\n\t\t\t\t// look only right\n\t\t\t\tif (/\\s/.test(line[0])) {\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\t\t\t} else if (column === model.getLineMaxColumn(lineNumber)) {\n\t\t\t\t// look only left\n\t\t\t\tif (/\\s/.test(line[line.length - 1])) {\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// look left and right\n\t\t\t\tif (/\\s/.test(line[column - 2]) && /\\s/.test(line[column - 1])) {\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn selection;\n\t}\n}\n\nexport namespace CodeActionsState {\n\n\texport const enum Type { Empty, Triggered }\n\n\texport const Empty = { type: Type.Empty } as const;\n\n\texport class Triggered {\n\t\treadonly type = Type.Triggered;\n\n\t\tpublic readonly actions: Promise;\n\n\t\tconstructor(\n\t\t\tpublic readonly trigger: CodeActionTrigger,\n\t\t\tpublic readonly position: Position,\n\t\t\tprivate readonly _cancellablePromise: CancelablePromise,\n\t\t) {\n\t\t\tthis.actions = _cancellablePromise.catch((e): CodeActionSet => {\n\t\t\t\tif (isCancellationError(e)) {\n\t\t\t\t\treturn emptyCodeActionSet;\n\t\t\t\t}\n\t\t\t\tthrow e;\n\t\t\t});\n\t\t}\n\n\t\tpublic cancel() {\n\t\t\tthis._cancellablePromise.cancel();\n\t\t}\n\t}\n\n\texport type State = typeof Empty | Triggered;\n}\n\nconst emptyCodeActionSet = Object.freeze({\n\tallActions: [],\n\tvalidActions: [],\n\tdispose: () => { },\n\tdocumentation: [],\n\thasAutoFix: false,\n\thasAIFix: false,\n\tallAIFixes: false,\n});\n\n\nexport class CodeActionModel extends Disposable {\n\n\tprivate readonly _codeActionOracle = this._register(new MutableDisposable());\n\tprivate _state: CodeActionsState.State = CodeActionsState.Empty;\n\n\tprivate readonly _supportedCodeActions: IContextKey;\n\n\tprivate readonly _onDidChangeState = this._register(new Emitter());\n\tpublic readonly onDidChangeState = this._onDidChangeState.event;\n\n\tprivate _disposed = false;\n\n\tconstructor(\n\t\tprivate readonly _editor: ICodeEditor,\n\t\tprivate readonly _registry: LanguageFeatureRegistry,\n\t\tprivate readonly _markerService: IMarkerService,\n\t\tcontextKeyService: IContextKeyService,\n\t\tprivate readonly _progressService?: IEditorProgressService,\n\t\tprivate readonly _configurationService?: IConfigurationService,\n\t) {\n\t\tsuper();\n\t\tthis._supportedCodeActions = SUPPORTED_CODE_ACTIONS.bindTo(contextKeyService);\n\n\t\tthis._register(this._editor.onDidChangeModel(() => this._update()));\n\t\tthis._register(this._editor.onDidChangeModelLanguage(() => this._update()));\n\t\tthis._register(this._registry.onDidChange(() => this._update()));\n\t\tthis._register(this._editor.onDidChangeConfiguration((e) => {\n\t\t\tif (e.hasChanged(EditorOption.lightbulb)) {\n\t\t\t\tthis._update();\n\t\t\t}\n\t\t}));\n\t\tthis._update();\n\t}\n\n\toverride dispose(): void {\n\t\tif (this._disposed) {\n\t\t\treturn;\n\t\t}\n\t\tthis._disposed = true;\n\n\t\tsuper.dispose();\n\t\tthis.setState(CodeActionsState.Empty, true);\n\t}\n\n\tprivate _settingEnabledNearbyQuickfixes(): boolean {\n\t\tconst model = this._editor?.getModel();\n\t\treturn this._configurationService ? this._configurationService.getValue('editor.codeActionWidget.includeNearbyQuickFixes', { resource: model?.uri }) : false;\n\t}\n\n\tprivate _update(): void {\n\t\tif (this._disposed) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._codeActionOracle.value = undefined;\n\n\t\tthis.setState(CodeActionsState.Empty);\n\n\t\tconst model = this._editor.getModel();\n\t\tif (model\n\t\t\t&& this._registry.has(model)\n\t\t\t&& !this._editor.getOption(EditorOption.readOnly)\n\t\t) {\n\t\t\tconst supportedActions: string[] = this._registry.all(model).flatMap(provider => provider.providedCodeActionKinds ?? []);\n\t\t\tthis._supportedCodeActions.set(supportedActions.join(' '));\n\n\t\t\tthis._codeActionOracle.value = new CodeActionOracle(this._editor, this._markerService, trigger => {\n\t\t\t\tif (!trigger) {\n\t\t\t\t\tthis.setState(CodeActionsState.Empty);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst startPosition = trigger.selection.getStartPosition();\n\n\t\t\t\tconst actions = createCancelablePromise(async token => {\n\t\t\t\t\tif (this._settingEnabledNearbyQuickfixes() && trigger.trigger.type === CodeActionTriggerType.Invoke && (trigger.trigger.triggerAction === CodeActionTriggerSource.QuickFix || trigger.trigger.filter?.include?.contains(CodeActionKind.QuickFix))) {\n\t\t\t\t\t\tconst codeActionSet = await getCodeActions(this._registry, model, trigger.selection, trigger.trigger, Progress.None, token);\n\t\t\t\t\t\tconst allCodeActions = [...codeActionSet.allActions];\n\t\t\t\t\t\tif (token.isCancellationRequested) {\n\t\t\t\t\t\t\treturn emptyCodeActionSet;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Search for quickfixes in the curret code action set.\n\t\t\t\t\t\tconst foundQuickfix = codeActionSet.validActions?.some(action => action.action.kind ? CodeActionKind.QuickFix.contains(new HierarchicalKind(action.action.kind)) : false);\n\t\t\t\t\t\tconst allMarkers = this._markerService.read({ resource: model.uri });\n\t\t\t\t\t\tif (foundQuickfix) {\n\t\t\t\t\t\t\tfor (const action of codeActionSet.validActions) {\n\t\t\t\t\t\t\t\tif (action.action.command?.arguments?.some(arg => typeof arg === 'string' && arg.includes(APPLY_FIX_ALL_COMMAND_ID))) {\n\t\t\t\t\t\t\t\t\taction.action.diagnostics = [...allMarkers.filter(marker => marker.relatedInformation)];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn { validActions: codeActionSet.validActions, allActions: allCodeActions, documentation: codeActionSet.documentation, hasAutoFix: codeActionSet.hasAutoFix, hasAIFix: codeActionSet.hasAIFix, allAIFixes: codeActionSet.allAIFixes, dispose: () => { codeActionSet.dispose(); } };\n\t\t\t\t\t\t} else if (!foundQuickfix) {\n\t\t\t\t\t\t\t// If markers exists, and there are no quickfixes found or length is zero, check for quickfixes on that line.\n\t\t\t\t\t\t\tif (allMarkers.length > 0) {\n\t\t\t\t\t\t\t\tconst currPosition = trigger.selection.getPosition();\n\t\t\t\t\t\t\t\tlet trackedPosition = currPosition;\n\t\t\t\t\t\t\t\tlet distance = Number.MAX_VALUE;\n\t\t\t\t\t\t\t\tconst currentActions = [...codeActionSet.validActions];\n\n\t\t\t\t\t\t\t\tfor (const marker of allMarkers) {\n\t\t\t\t\t\t\t\t\tconst col = marker.endColumn;\n\t\t\t\t\t\t\t\t\tconst row = marker.endLineNumber;\n\t\t\t\t\t\t\t\t\tconst startRow = marker.startLineNumber;\n\n\t\t\t\t\t\t\t\t\t// Found quickfix on the same line and check relative distance to other markers\n\t\t\t\t\t\t\t\t\tif ((row === currPosition.lineNumber || startRow === currPosition.lineNumber)) {\n\t\t\t\t\t\t\t\t\t\ttrackedPosition = new Position(row, col);\n\t\t\t\t\t\t\t\t\t\tconst newCodeActionTrigger: CodeActionTrigger = {\n\t\t\t\t\t\t\t\t\t\t\ttype: trigger.trigger.type,\n\t\t\t\t\t\t\t\t\t\t\ttriggerAction: trigger.trigger.triggerAction,\n\t\t\t\t\t\t\t\t\t\t\tfilter: { include: trigger.trigger.filter?.include ? trigger.trigger.filter?.include : CodeActionKind.QuickFix },\n\t\t\t\t\t\t\t\t\t\t\tautoApply: trigger.trigger.autoApply,\n\t\t\t\t\t\t\t\t\t\t\tcontext: { notAvailableMessage: trigger.trigger.context?.notAvailableMessage || '', position: trackedPosition }\n\t\t\t\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\t\t\t\tconst selectionAsPosition = new Selection(trackedPosition.lineNumber, trackedPosition.column, trackedPosition.lineNumber, trackedPosition.column);\n\t\t\t\t\t\t\t\t\t\tconst actionsAtMarker = await getCodeActions(this._registry, model, selectionAsPosition, newCodeActionTrigger, Progress.None, token);\n\n\t\t\t\t\t\t\t\t\t\tif (actionsAtMarker.validActions.length !== 0) {\n\t\t\t\t\t\t\t\t\t\t\tfor (const action of actionsAtMarker.validActions) {\n\t\t\t\t\t\t\t\t\t\t\t\tif (action.action.command?.arguments?.some(arg => typeof arg === 'string' && arg.includes(APPLY_FIX_ALL_COMMAND_ID))) {\n\t\t\t\t\t\t\t\t\t\t\t\t\taction.action.diagnostics = [...allMarkers.filter(marker => marker.relatedInformation)];\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t\tif (codeActionSet.allActions.length === 0) {\n\t\t\t\t\t\t\t\t\t\t\t\tallCodeActions.push(...actionsAtMarker.allActions);\n\t\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t\t// Already filtered through to only get quickfixes, so no need to filter again.\n\t\t\t\t\t\t\t\t\t\t\tif (Math.abs(currPosition.column - col) < distance) {\n\t\t\t\t\t\t\t\t\t\t\t\tcurrentActions.unshift(...actionsAtMarker.validActions);\n\t\t\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\t\t\tcurrentActions.push(...actionsAtMarker.validActions);\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\tdistance = Math.abs(currPosition.column - col);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tconst filteredActions = currentActions.filter((action, index, self) =>\n\t\t\t\t\t\t\t\t\tself.findIndex((a) => a.action.title === action.action.title) === index);\n\n\t\t\t\t\t\t\t\tfilteredActions.sort((a, b) => {\n\t\t\t\t\t\t\t\t\tif (a.action.isPreferred && !b.action.isPreferred) {\n\t\t\t\t\t\t\t\t\t\treturn -1;\n\t\t\t\t\t\t\t\t\t} else if (!a.action.isPreferred && b.action.isPreferred) {\n\t\t\t\t\t\t\t\t\t\treturn 1;\n\t\t\t\t\t\t\t\t\t} else if (a.action.isAI && !b.action.isAI) {\n\t\t\t\t\t\t\t\t\t\treturn 1;\n\t\t\t\t\t\t\t\t\t} else if (!a.action.isAI && b.action.isAI) {\n\t\t\t\t\t\t\t\t\t\treturn -1;\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\treturn 0;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\t\t// Only retriggers if actually found quickfix on the same line as cursor\n\t\t\t\t\t\t\t\treturn { validActions: filteredActions, allActions: allCodeActions, documentation: codeActionSet.documentation, hasAutoFix: codeActionSet.hasAutoFix, hasAIFix: codeActionSet.hasAIFix, allAIFixes: codeActionSet.allAIFixes, dispose: () => { codeActionSet.dispose(); } };\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t// temporarilly hiding here as this is enabled/disabled behind a setting.\n\t\t\t\t\treturn getCodeActions(this._registry, model, trigger.selection, trigger.trigger, Progress.None, token);\n\t\t\t\t});\n\t\t\t\tif (trigger.trigger.type === CodeActionTriggerType.Invoke) {\n\t\t\t\t\tthis._progressService?.showWhile(actions, 250);\n\t\t\t\t}\n\t\t\t\tconst newState = new CodeActionsState.Triggered(trigger.trigger, startPosition, actions);\n\t\t\t\tlet isManualToAutoTransition = false;\n\t\t\t\tif (this._state.type === CodeActionsState.Type.Triggered) {\n\t\t\t\t\t// Check if the current state is manual and the new state is automatic\n\t\t\t\t\tisManualToAutoTransition = this._state.trigger.type === CodeActionTriggerType.Invoke &&\n\t\t\t\t\t\tnewState.type === CodeActionsState.Type.Triggered &&\n\t\t\t\t\t\tnewState.trigger.type === CodeActionTriggerType.Auto &&\n\t\t\t\t\t\tthis._state.position !== newState.position;\n\t\t\t\t}\n\n\t\t\t\t// Do not trigger state if current state is manual and incoming state is automatic\n\t\t\t\tif (!isManualToAutoTransition) {\n\t\t\t\t\tthis.setState(newState);\n\t\t\t\t} else {\n\t\t\t\t\t// Reset the new state after getting code actions back.\n\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\tthis.setState(newState);\n\t\t\t\t\t}, 500);\n\t\t\t\t}\n\t\t\t}, undefined);\n\t\t\tthis._codeActionOracle.value.trigger({ type: CodeActionTriggerType.Auto, triggerAction: CodeActionTriggerSource.Default });\n\t\t} else {\n\t\t\tthis._supportedCodeActions.reset();\n\t\t}\n\t}\n\n\tpublic trigger(trigger: CodeActionTrigger) {\n\t\tthis._codeActionOracle.value?.trigger(trigger);\n\t}\n\n\tprivate setState(newState: CodeActionsState.State, skipNotify?: boolean) {\n\t\tif (newState === this._state) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Cancel old request\n\t\tif (this._state.type === CodeActionsState.Type.Triggered) {\n\t\t\tthis._state.cancel();\n\t\t}\n\n\t\tthis._state = newState;\n\n\t\tif (!skipNotify && !this._disposed) {\n\t\t\tthis._onDidChangeState.fire(newState);\n\t\t}\n\t}\n}\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\nimport * as dom from 'vs/base/browser/dom';\nimport { Gesture } from 'vs/base/browser/touch';\nimport { Codicon } from 'vs/base/common/codicons';\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport { ThemeIcon } from 'vs/base/common/themables';\nimport 'vs/css!./lightBulbWidget';\nimport { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser';\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\nimport { IPosition } from 'vs/editor/common/core/position';\nimport { computeIndentLevel } from 'vs/editor/common/model/utils';\nimport { autoFixCommandId, quickFixCommandId } from 'vs/editor/contrib/codeAction/browser/codeAction';\nimport { CodeActionSet, CodeActionTrigger } from 'vs/editor/contrib/codeAction/common/types';\nimport * as nls from 'vs/nls';\nimport { ICommandService } from 'vs/platform/commands/common/commands';\nimport { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';\n\nnamespace LightBulbState {\n\n\texport const enum Type {\n\t\tHidden,\n\t\tShowing,\n\t}\n\n\texport const Hidden = { type: Type.Hidden } as const;\n\n\texport class Showing {\n\t\treadonly type = Type.Showing;\n\n\t\tconstructor(\n\t\t\tpublic readonly actions: CodeActionSet,\n\t\t\tpublic readonly trigger: CodeActionTrigger,\n\t\t\tpublic readonly editorPosition: IPosition,\n\t\t\tpublic readonly widgetPosition: IContentWidgetPosition,\n\t\t) { }\n\t}\n\n\texport type State = typeof Hidden | Showing;\n}\n\nexport class LightBulbWidget extends Disposable implements IContentWidget {\n\n\tpublic static readonly ID = 'editor.contrib.lightbulbWidget';\n\n\tprivate static readonly _posPref = [ContentWidgetPositionPreference.EXACT];\n\n\tprivate readonly _domNode: HTMLElement;\n\n\tprivate readonly _onClick = this._register(new Emitter<{ readonly x: number; readonly y: number; readonly actions: CodeActionSet; readonly trigger: CodeActionTrigger }>());\n\tpublic readonly onClick = this._onClick.event;\n\n\tprivate _state: LightBulbState.State = LightBulbState.Hidden;\n\tprivate _iconClasses: string[] = [];\n\n\tprivate _preferredKbLabel?: string;\n\tprivate _quickFixKbLabel?: string;\n\n\tconstructor(\n\t\tprivate readonly _editor: ICodeEditor,\n\t\t@IKeybindingService private readonly _keybindingService: IKeybindingService,\n\t\t@ICommandService commandService: ICommandService\n\t) {\n\t\tsuper();\n\n\t\tthis._domNode = dom.$('div.lightBulbWidget');\n\t\tthis._domNode.role = 'listbox';\n\t\tthis._register(Gesture.ignoreTarget(this._domNode));\n\n\t\tthis._editor.addContentWidget(this);\n\n\t\tthis._register(this._editor.onDidChangeModelContent(_ => {\n\t\t\t// cancel when the line in question has been removed\n\t\t\tconst editorModel = this._editor.getModel();\n\t\t\tif (this.state.type !== LightBulbState.Type.Showing || !editorModel || this.state.editorPosition.lineNumber >= editorModel.getLineCount()) {\n\t\t\t\tthis.hide();\n\t\t\t}\n\t\t}));\n\n\t\tthis._register(dom.addStandardDisposableGenericMouseDownListener(this._domNode, e => {\n\t\t\tif (this.state.type !== LightBulbState.Type.Showing) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Make sure that focus / cursor location is not lost when clicking widget icon\n\t\t\tthis._editor.focus();\n\t\t\te.preventDefault();\n\n\t\t\t// a bit of extra work to make sure the menu\n\t\t\t// doesn't cover the line-text\n\t\t\tconst { top, height } = dom.getDomNodePagePosition(this._domNode);\n\t\t\tconst lineHeight = this._editor.getOption(EditorOption.lineHeight);\n\n\t\t\tlet pad = Math.floor(lineHeight / 3);\n\t\t\tif (this.state.widgetPosition.position !== null && this.state.widgetPosition.position.lineNumber < this.state.editorPosition.lineNumber) {\n\t\t\t\tpad += lineHeight;\n\t\t\t}\n\n\t\t\tthis._onClick.fire({\n\t\t\t\tx: e.posx,\n\t\t\t\ty: top + height + pad,\n\t\t\t\tactions: this.state.actions,\n\t\t\t\ttrigger: this.state.trigger,\n\t\t\t});\n\t\t}));\n\n\t\tthis._register(dom.addDisposableListener(this._domNode, 'mouseenter', (e: MouseEvent) => {\n\t\t\tif ((e.buttons & 1) !== 1) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// mouse enters lightbulb while the primary/left button\n\t\t\t// is being pressed -> hide the lightbulb\n\t\t\tthis.hide();\n\t\t}));\n\n\n\t\tthis._register(Event.runAndSubscribe(this._keybindingService.onDidUpdateKeybindings, () => {\n\t\t\tthis._preferredKbLabel = this._keybindingService.lookupKeybinding(autoFixCommandId)?.getLabel() ?? undefined;\n\t\t\tthis._quickFixKbLabel = this._keybindingService.lookupKeybinding(quickFixCommandId)?.getLabel() ?? undefined;\n\n\t\t\tthis._updateLightBulbTitleAndIcon();\n\t\t}));\n\t}\n\n\toverride dispose(): void {\n\t\tsuper.dispose();\n\t\tthis._editor.removeContentWidget(this);\n\t}\n\n\tgetId(): string {\n\t\treturn 'LightBulbWidget';\n\t}\n\n\tgetDomNode(): HTMLElement {\n\t\treturn this._domNode;\n\t}\n\n\tgetPosition(): IContentWidgetPosition | null {\n\t\treturn this._state.type === LightBulbState.Type.Showing ? this._state.widgetPosition : null;\n\t}\n\n\tpublic update(actions: CodeActionSet, trigger: CodeActionTrigger, atPosition: IPosition) {\n\t\tif (actions.validActions.length <= 0) {\n\t\t\treturn this.hide();\n\t\t}\n\n\t\tconst options = this._editor.getOptions();\n\t\tif (!options.get(EditorOption.lightbulb).enabled) {\n\t\t\treturn this.hide();\n\t\t}\n\n\n\t\tconst model = this._editor.getModel();\n\t\tif (!model) {\n\t\t\treturn this.hide();\n\t\t}\n\n\t\tconst { lineNumber, column } = model.validatePosition(atPosition);\n\n\t\tconst tabSize = model.getOptions().tabSize;\n\t\tconst fontInfo = this._editor.getOptions().get(EditorOption.fontInfo);\n\t\tconst lineContent = model.getLineContent(lineNumber);\n\t\tconst indent = computeIndentLevel(lineContent, tabSize);\n\t\tconst lineHasSpace = fontInfo.spaceWidth * indent > 22;\n\t\tconst isFolded = (lineNumber: number) => {\n\t\t\treturn lineNumber > 2 && this._editor.getTopForLineNumber(lineNumber) === this._editor.getTopForLineNumber(lineNumber - 1);\n\t\t};\n\n\t\tlet effectiveLineNumber = lineNumber;\n\t\tlet effectiveColumnNumber = 1;\n\t\tif (!lineHasSpace) {\n\t\t\tif (lineNumber > 1 && !isFolded(lineNumber - 1)) {\n\t\t\t\teffectiveLineNumber -= 1;\n\t\t\t} else if ((lineNumber < model.getLineCount()) && !isFolded(lineNumber + 1)) {\n\t\t\t\teffectiveLineNumber += 1;\n\t\t\t} else if (column * fontInfo.spaceWidth < 22) {\n\t\t\t\t// cannot show lightbulb above/below and showing\n\t\t\t\t// it inline would overlay the cursor...\n\t\t\t\treturn this.hide();\n\t\t\t}\n\t\t\teffectiveColumnNumber = /^\\S\\s*$/.test(model.getLineContent(effectiveLineNumber)) ? 2 : 1;\n\t\t}\n\n\t\tthis.state = new LightBulbState.Showing(actions, trigger, atPosition, {\n\t\t\tposition: { lineNumber: effectiveLineNumber, column: effectiveColumnNumber },\n\t\t\tpreference: LightBulbWidget._posPref\n\t\t});\n\n\t\tconst validActions = actions.validActions;\n\t\tconst actionKind = actions.validActions[0].action.kind;\n\t\tif (validActions.length !== 1 || !actionKind) {\n\t\t\tthis._editor.layoutContentWidget(this);\n\t\t\treturn;\n\t\t}\n\n\n\t\tthis._editor.layoutContentWidget(this);\n\t}\n\n\tpublic hide(): void {\n\t\tif (this.state === LightBulbState.Hidden) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.state = LightBulbState.Hidden;\n\t\tthis._editor.layoutContentWidget(this);\n\t}\n\n\tprivate get state(): LightBulbState.State { return this._state; }\n\n\tprivate set state(value) {\n\t\tthis._state = value;\n\t\tthis._updateLightBulbTitleAndIcon();\n\t}\n\n\tprivate _updateLightBulbTitleAndIcon(): void {\n\t\tthis._domNode.classList.remove(...this._iconClasses);\n\t\tthis._iconClasses = [];\n\t\tif (this.state.type !== LightBulbState.Type.Showing) {\n\t\t\treturn;\n\t\t}\n\t\tlet icon: ThemeIcon;\n\t\tlet autoRun = false;\n\t\tif (this.state.actions.allAIFixes) {\n\t\t\ticon = Codicon.sparkleFilled;\n\t\t\tif (this.state.actions.validActions.length === 1) {\n\t\t\t\tautoRun = true;\n\t\t\t}\n\t\t} else if (this.state.actions.hasAutoFix) {\n\t\t\tif (this.state.actions.hasAIFix) {\n\t\t\t\ticon = Codicon.lightbulbSparkleAutofix;\n\t\t\t} else {\n\t\t\t\ticon = Codicon.lightbulbAutofix;\n\t\t\t}\n\t\t} else if (this.state.actions.hasAIFix) {\n\t\t\ticon = Codicon.lightbulbSparkle;\n\t\t} else {\n\t\t\ticon = Codicon.lightBulb;\n\t\t}\n\t\tthis._updateLightbulbTitle(this.state.actions.hasAutoFix, autoRun);\n\t\tthis._iconClasses = ThemeIcon.asClassNameArray(icon);\n\t\tthis._domNode.classList.add(...this._iconClasses);\n\t}\n\n\tprivate _updateLightbulbTitle(autoFix: boolean, autoRun: boolean): void {\n\t\tif (this.state.type !== LightBulbState.Type.Showing) {\n\t\t\treturn;\n\t\t}\n\t\tif (autoRun) {\n\t\t\tthis.title = nls.localize('codeActionAutoRun', \"Run: {0}\", this.state.actions.validActions[0].action.title);\n\t\t} else if (autoFix && this._preferredKbLabel) {\n\t\t\tthis.title = nls.localize('preferredcodeActionWithKb', \"Show Code Actions. Preferred Quick Fix Available ({0})\", this._preferredKbLabel);\n\t\t} else if (!autoFix && this._quickFixKbLabel) {\n\t\t\tthis.title = nls.localize('codeActionWithKb', \"Show Code Actions ({0})\", this._quickFixKbLabel);\n\t\t} else if (!autoFix) {\n\t\t\tthis.title = nls.localize('codeAction', \"Show Code Actions\");\n\t\t}\n\t}\n\n\tprivate set title(value: string) {\n\t\tthis._domNode.title = value;\n\t}\n}\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\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\nimport { EditorAction, registerEditorAction, ServicesAccessor } from 'vs/editor/browser/editorExtensions';\nimport { EditorZoom } from 'vs/editor/common/config/editorZoom';\nimport * as nls from 'vs/nls';\n\nclass EditorFontZoomIn extends EditorAction {\n\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'editor.action.fontZoomIn',\n\t\t\tlabel: nls.localize('EditorFontZoomIn.label', \"Increase Editor Font Size\"),\n\t\t\talias: 'Increase Editor Font Size',\n\t\t\tprecondition: undefined\n\t\t});\n\t}\n\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor): void {\n\t\tEditorZoom.setZoomLevel(EditorZoom.getZoomLevel() + 1);\n\t}\n}\n\nclass EditorFontZoomOut extends EditorAction {\n\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'editor.action.fontZoomOut',\n\t\t\tlabel: nls.localize('EditorFontZoomOut.label', \"Decrease Editor Font Size\"),\n\t\t\talias: 'Decrease Editor Font Size',\n\t\t\tprecondition: undefined\n\t\t});\n\t}\n\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor): void {\n\t\tEditorZoom.setZoomLevel(EditorZoom.getZoomLevel() - 1);\n\t}\n}\n\nclass EditorFontZoomReset extends EditorAction {\n\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'editor.action.fontZoomReset',\n\t\t\tlabel: nls.localize('EditorFontZoomReset.label', \"Reset Editor Font Size\"),\n\t\t\talias: 'Reset Editor Font Size',\n\t\t\tprecondition: undefined\n\t\t});\n\t}\n\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor): void {\n\t\tEditorZoom.setZoomLevel(0);\n\t}\n}\n\nregisterEditorAction(EditorFontZoomIn);\nregisterEditorAction(EditorFontZoomOut);\nregisterEditorAction(EditorFontZoomReset);\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\nimport { asArray, isNonEmptyArray } from 'vs/base/common/arrays';\nimport { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';\nimport { onUnexpectedExternalError } from 'vs/base/common/errors';\nimport { Iterable } from 'vs/base/common/iterator';\nimport { IDisposable } from 'vs/base/common/lifecycle';\nimport { LinkedList } from 'vs/base/common/linkedList';\nimport { assertType } from 'vs/base/common/types';\nimport { URI } from 'vs/base/common/uri';\nimport { CodeEditorStateFlag, EditorStateCancellationTokenSource, TextModelCancellationTokenSource } from 'vs/editor/contrib/editorState/browser/editorState';\nimport { IActiveCodeEditor, isCodeEditor } from 'vs/editor/browser/editorBrowser';\nimport { ServicesAccessor } from 'vs/editor/browser/editorExtensions';\nimport { Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\nimport { Selection } from 'vs/editor/common/core/selection';\nimport { ScrollType } from 'vs/editor/common/editorCommon';\nimport { ITextModel } from 'vs/editor/common/model';\nimport { DocumentFormattingEditProvider, DocumentRangeFormattingEditProvider, FormattingOptions, TextEdit } from 'vs/editor/common/languages';\nimport { IEditorWorkerService } from 'vs/editor/common/services/editorWorker';\nimport { ITextModelService } from 'vs/editor/common/services/resolverService';\nimport { FormattingEdit } from 'vs/editor/contrib/format/browser/formattingEdit';\nimport { CommandsRegistry } from 'vs/platform/commands/common/commands';\nimport { ExtensionIdentifierSet } from 'vs/platform/extensions/common/extensions';\nimport { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';\nimport { IProgress } from 'vs/platform/progress/common/progress';\nimport { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';\nimport { LanguageFeatureRegistry } from 'vs/editor/common/languageFeatureRegistry';\nimport { ILogService } from 'vs/platform/log/common/log';\nimport { AccessibilitySignal, IAccessibilitySignalService } from 'vs/platform/accessibilitySignal/browser/accessibilitySignalService';\n\nexport function getRealAndSyntheticDocumentFormattersOrdered(\n\tdocumentFormattingEditProvider: LanguageFeatureRegistry,\n\tdocumentRangeFormattingEditProvider: LanguageFeatureRegistry,\n\tmodel: ITextModel\n): DocumentFormattingEditProvider[] {\n\tconst result: DocumentFormattingEditProvider[] = [];\n\tconst seen = new ExtensionIdentifierSet();\n\n\t// (1) add all document formatter\n\tconst docFormatter = documentFormattingEditProvider.ordered(model);\n\tfor (const formatter of docFormatter) {\n\t\tresult.push(formatter);\n\t\tif (formatter.extensionId) {\n\t\t\tseen.add(formatter.extensionId);\n\t\t}\n\t}\n\n\t// (2) add all range formatter as document formatter (unless the same extension already did that)\n\tconst rangeFormatter = documentRangeFormattingEditProvider.ordered(model);\n\tfor (const formatter of rangeFormatter) {\n\t\tif (formatter.extensionId) {\n\t\t\tif (seen.has(formatter.extensionId)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tseen.add(formatter.extensionId);\n\t\t}\n\t\tresult.push({\n\t\t\tdisplayName: formatter.displayName,\n\t\t\textensionId: formatter.extensionId,\n\t\t\tprovideDocumentFormattingEdits(model, options, token) {\n\t\t\t\treturn formatter.provideDocumentRangeFormattingEdits(model, model.getFullModelRange(), options, token);\n\t\t\t}\n\t\t});\n\t}\n\treturn result;\n}\n\nexport const enum FormattingKind {\n\tFile = 1,\n\tSelection = 2\n}\n\nexport const enum FormattingMode {\n\tExplicit = 1,\n\tSilent = 2\n}\n\nexport interface IFormattingEditProviderSelector {\n\t(formatter: T[], document: ITextModel, mode: FormattingMode, kind: FormattingKind): Promise;\n}\n\nexport abstract class FormattingConflicts {\n\n\tprivate static readonly _selectors = new LinkedList();\n\n\tstatic setFormatterSelector(selector: IFormattingEditProviderSelector): IDisposable {\n\t\tconst remove = FormattingConflicts._selectors.unshift(selector);\n\t\treturn { dispose: remove };\n\t}\n\n\tstatic async select(formatter: T[], document: ITextModel, mode: FormattingMode, kind: FormattingKind): Promise {\n\t\tif (formatter.length === 0) {\n\t\t\treturn undefined;\n\t\t}\n\t\tconst selector = Iterable.first(FormattingConflicts._selectors);\n\t\tif (selector) {\n\t\t\treturn await selector(formatter, document, mode, kind);\n\t\t}\n\t\treturn undefined;\n\t}\n}\n\nexport async function formatDocumentRangesWithSelectedProvider(\n\taccessor: ServicesAccessor,\n\teditorOrModel: ITextModel | IActiveCodeEditor,\n\trangeOrRanges: Range | Range[],\n\tmode: FormattingMode,\n\tprogress: IProgress,\n\ttoken: CancellationToken,\n\tuserGesture: boolean\n): Promise {\n\n\tconst instaService = accessor.get(IInstantiationService);\n\tconst { documentRangeFormattingEditProvider: documentRangeFormattingEditProviderRegistry } = accessor.get(ILanguageFeaturesService);\n\tconst model = isCodeEditor(editorOrModel) ? editorOrModel.getModel() : editorOrModel;\n\tconst provider = documentRangeFormattingEditProviderRegistry.ordered(model);\n\tconst selected = await FormattingConflicts.select(provider, model, mode, FormattingKind.Selection);\n\tif (selected) {\n\t\tprogress.report(selected);\n\t\tawait instaService.invokeFunction(formatDocumentRangesWithProvider, selected, editorOrModel, rangeOrRanges, token, userGesture);\n\t}\n}\n\nexport async function formatDocumentRangesWithProvider(\n\taccessor: ServicesAccessor,\n\tprovider: DocumentRangeFormattingEditProvider,\n\teditorOrModel: ITextModel | IActiveCodeEditor,\n\trangeOrRanges: Range | Range[],\n\ttoken: CancellationToken,\n\tuserGesture: boolean\n): Promise {\n\tconst workerService = accessor.get(IEditorWorkerService);\n\tconst logService = accessor.get(ILogService);\n\tconst accessibilitySignalService = accessor.get(IAccessibilitySignalService);\n\n\tlet model: ITextModel;\n\tlet cts: CancellationTokenSource;\n\tif (isCodeEditor(editorOrModel)) {\n\t\tmodel = editorOrModel.getModel();\n\t\tcts = new EditorStateCancellationTokenSource(editorOrModel, CodeEditorStateFlag.Value | CodeEditorStateFlag.Position, undefined, token);\n\t} else {\n\t\tmodel = editorOrModel;\n\t\tcts = new TextModelCancellationTokenSource(editorOrModel, token);\n\t}\n\n\t// make sure that ranges don't overlap nor touch each other\n\tconst ranges: Range[] = [];\n\tlet len = 0;\n\tfor (const range of asArray(rangeOrRanges).sort(Range.compareRangesUsingStarts)) {\n\t\tif (len > 0 && Range.areIntersectingOrTouching(ranges[len - 1], range)) {\n\t\t\tranges[len - 1] = Range.fromPositions(ranges[len - 1].getStartPosition(), range.getEndPosition());\n\t\t} else {\n\t\t\tlen = ranges.push(range);\n\t\t}\n\t}\n\n\tconst computeEdits = async (range: Range) => {\n\t\tlogService.trace(`[format][provideDocumentRangeFormattingEdits] (request)`, provider.extensionId?.value, range);\n\n\t\tconst result = (await provider.provideDocumentRangeFormattingEdits(\n\t\t\tmodel,\n\t\t\trange,\n\t\t\tmodel.getFormattingOptions(),\n\t\t\tcts.token\n\t\t)) || [];\n\n\t\tlogService.trace(`[format][provideDocumentRangeFormattingEdits] (response)`, provider.extensionId?.value, result);\n\n\t\treturn result;\n\t};\n\n\tconst hasIntersectingEdit = (a: TextEdit[], b: TextEdit[]) => {\n\t\tif (!a.length || !b.length) {\n\t\t\treturn false;\n\t\t}\n\t\t// quick exit if the list of ranges are completely unrelated [O(n)]\n\t\tconst mergedA = a.reduce((acc, val) => { return Range.plusRange(acc, val.range); }, a[0].range);\n\t\tif (!b.some(x => { return Range.intersectRanges(mergedA, x.range); })) {\n\t\t\treturn false;\n\t\t}\n\t\t// fallback to a complete check [O(n^2)]\n\t\tfor (const edit of a) {\n\t\t\tfor (const otherEdit of b) {\n\t\t\t\tif (Range.intersectRanges(edit.range, otherEdit.range)) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t};\n\n\tconst allEdits: TextEdit[] = [];\n\tconst rawEditsList: TextEdit[][] = [];\n\ttry {\n\t\tif (typeof provider.provideDocumentRangesFormattingEdits === 'function') {\n\t\t\tlogService.trace(`[format][provideDocumentRangeFormattingEdits] (request)`, provider.extensionId?.value, ranges);\n\t\t\tconst result = (await provider.provideDocumentRangesFormattingEdits(\n\t\t\t\tmodel,\n\t\t\t\tranges,\n\t\t\t\tmodel.getFormattingOptions(),\n\t\t\t\tcts.token\n\t\t\t)) || [];\n\t\t\tlogService.trace(`[format][provideDocumentRangeFormattingEdits] (response)`, provider.extensionId?.value, result);\n\t\t\trawEditsList.push(result);\n\t\t} else {\n\n\t\t\tfor (const range of ranges) {\n\t\t\t\tif (cts.token.isCancellationRequested) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\trawEditsList.push(await computeEdits(range));\n\t\t\t}\n\n\t\t\tfor (let i = 0; i < ranges.length; ++i) {\n\t\t\t\tfor (let j = i + 1; j < ranges.length; ++j) {\n\t\t\t\t\tif (cts.token.isCancellationRequested) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t\tif (hasIntersectingEdit(rawEditsList[i], rawEditsList[j])) {\n\t\t\t\t\t\t// Merge ranges i and j into a single range, recompute the associated edits\n\t\t\t\t\t\tconst mergedRange = Range.plusRange(ranges[i], ranges[j]);\n\t\t\t\t\t\tconst edits = await computeEdits(mergedRange);\n\t\t\t\t\t\tranges.splice(j, 1);\n\t\t\t\t\t\tranges.splice(i, 1);\n\t\t\t\t\t\tranges.push(mergedRange);\n\t\t\t\t\t\trawEditsList.splice(j, 1);\n\t\t\t\t\t\trawEditsList.splice(i, 1);\n\t\t\t\t\t\trawEditsList.push(edits);\n\t\t\t\t\t\t// Restart scanning\n\t\t\t\t\t\ti = 0;\n\t\t\t\t\t\tj = 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfor (const rawEdits of rawEditsList) {\n\t\t\tif (cts.token.isCancellationRequested) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tconst minimalEdits = await workerService.computeMoreMinimalEdits(model.uri, rawEdits);\n\t\t\tif (minimalEdits) {\n\t\t\t\tallEdits.push(...minimalEdits);\n\t\t\t}\n\t\t}\n\t} finally {\n\t\tcts.dispose();\n\t}\n\n\tif (allEdits.length === 0) {\n\t\treturn false;\n\t}\n\n\tif (isCodeEditor(editorOrModel)) {\n\t\t// use editor to apply edits\n\t\tFormattingEdit.execute(editorOrModel, allEdits, true);\n\t\teditorOrModel.revealPositionInCenterIfOutsideViewport(editorOrModel.getPosition(), ScrollType.Immediate);\n\n\t} else {\n\t\t// use model to apply edits\n\t\tconst [{ range }] = allEdits;\n\t\tconst initialSelection = new Selection(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn);\n\t\tmodel.pushEditOperations([initialSelection], allEdits.map(edit => {\n\t\t\treturn {\n\t\t\t\ttext: edit.text,\n\t\t\t\trange: Range.lift(edit.range),\n\t\t\t\tforceMoveMarkers: true\n\t\t\t};\n\t\t}), undoEdits => {\n\t\t\tfor (const { range } of undoEdits) {\n\t\t\t\tif (Range.areIntersectingOrTouching(range, initialSelection)) {\n\t\t\t\t\treturn [new Selection(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn)];\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t});\n\t}\n\taccessibilitySignalService.playSignal(AccessibilitySignal.format, { userGesture });\n\treturn true;\n}\n\nexport async function formatDocumentWithSelectedProvider(\n\taccessor: ServicesAccessor,\n\teditorOrModel: ITextModel | IActiveCodeEditor,\n\tmode: FormattingMode,\n\tprogress: IProgress,\n\ttoken: CancellationToken,\n\tuserGesture?: boolean\n): Promise {\n\n\tconst instaService = accessor.get(IInstantiationService);\n\tconst languageFeaturesService = accessor.get(ILanguageFeaturesService);\n\tconst model = isCodeEditor(editorOrModel) ? editorOrModel.getModel() : editorOrModel;\n\tconst provider = getRealAndSyntheticDocumentFormattersOrdered(languageFeaturesService.documentFormattingEditProvider, languageFeaturesService.documentRangeFormattingEditProvider, model);\n\tconst selected = await FormattingConflicts.select(provider, model, mode, FormattingKind.File);\n\tif (selected) {\n\t\tprogress.report(selected);\n\t\tawait instaService.invokeFunction(formatDocumentWithProvider, selected, editorOrModel, mode, token, userGesture);\n\t}\n}\n\nexport async function formatDocumentWithProvider(\n\taccessor: ServicesAccessor,\n\tprovider: DocumentFormattingEditProvider,\n\teditorOrModel: ITextModel | IActiveCodeEditor,\n\tmode: FormattingMode,\n\ttoken: CancellationToken,\n\tuserGesture?: boolean\n): Promise {\n\tconst workerService = accessor.get(IEditorWorkerService);\n\tconst accessibilitySignalService = accessor.get(IAccessibilitySignalService);\n\n\tlet model: ITextModel;\n\tlet cts: CancellationTokenSource;\n\tif (isCodeEditor(editorOrModel)) {\n\t\tmodel = editorOrModel.getModel();\n\t\tcts = new EditorStateCancellationTokenSource(editorOrModel, CodeEditorStateFlag.Value | CodeEditorStateFlag.Position, undefined, token);\n\t} else {\n\t\tmodel = editorOrModel;\n\t\tcts = new TextModelCancellationTokenSource(editorOrModel, token);\n\t}\n\n\tlet edits: TextEdit[] | undefined;\n\ttry {\n\t\tconst rawEdits = await provider.provideDocumentFormattingEdits(\n\t\t\tmodel,\n\t\t\tmodel.getFormattingOptions(),\n\t\t\tcts.token\n\t\t);\n\n\t\tedits = await workerService.computeMoreMinimalEdits(model.uri, rawEdits);\n\n\t\tif (cts.token.isCancellationRequested) {\n\t\t\treturn true;\n\t\t}\n\n\t} finally {\n\t\tcts.dispose();\n\t}\n\n\tif (!edits || edits.length === 0) {\n\t\treturn false;\n\t}\n\n\tif (isCodeEditor(editorOrModel)) {\n\t\t// use editor to apply edits\n\t\tFormattingEdit.execute(editorOrModel, edits, mode !== FormattingMode.Silent);\n\n\t\tif (mode !== FormattingMode.Silent) {\n\t\t\teditorOrModel.revealPositionInCenterIfOutsideViewport(editorOrModel.getPosition(), ScrollType.Immediate);\n\t\t}\n\n\t} else {\n\t\t// use model to apply edits\n\t\tconst [{ range }] = edits;\n\t\tconst initialSelection = new Selection(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn);\n\t\tmodel.pushEditOperations([initialSelection], edits.map(edit => {\n\t\t\treturn {\n\t\t\t\ttext: edit.text,\n\t\t\t\trange: Range.lift(edit.range),\n\t\t\t\tforceMoveMarkers: true\n\t\t\t};\n\t\t}), undoEdits => {\n\t\t\tfor (const { range } of undoEdits) {\n\t\t\t\tif (Range.areIntersectingOrTouching(range, initialSelection)) {\n\t\t\t\t\treturn [new Selection(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn)];\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t});\n\t}\n\taccessibilitySignalService.playSignal(AccessibilitySignal.format, { userGesture });\n\treturn true;\n}\n\nexport async function getDocumentRangeFormattingEditsUntilResult(\n\tworkerService: IEditorWorkerService,\n\tlanguageFeaturesService: ILanguageFeaturesService,\n\tmodel: ITextModel,\n\trange: Range,\n\toptions: FormattingOptions,\n\ttoken: CancellationToken\n): Promise {\n\n\tconst providers = languageFeaturesService.documentRangeFormattingEditProvider.ordered(model);\n\tfor (const provider of providers) {\n\t\tconst rawEdits = await Promise.resolve(provider.provideDocumentRangeFormattingEdits(model, range, options, token)).catch(onUnexpectedExternalError);\n\t\tif (isNonEmptyArray(rawEdits)) {\n\t\t\treturn await workerService.computeMoreMinimalEdits(model.uri, rawEdits);\n\t\t}\n\t}\n\treturn undefined;\n}\n\nexport async function getDocumentFormattingEditsUntilResult(\n\tworkerService: IEditorWorkerService,\n\tlanguageFeaturesService: ILanguageFeaturesService,\n\tmodel: ITextModel,\n\toptions: FormattingOptions,\n\ttoken: CancellationToken\n): Promise {\n\n\tconst providers = getRealAndSyntheticDocumentFormattersOrdered(languageFeaturesService.documentFormattingEditProvider, languageFeaturesService.documentRangeFormattingEditProvider, model);\n\tfor (const provider of providers) {\n\t\tconst rawEdits = await Promise.resolve(provider.provideDocumentFormattingEdits(model, options, token)).catch(onUnexpectedExternalError);\n\t\tif (isNonEmptyArray(rawEdits)) {\n\t\t\treturn await workerService.computeMoreMinimalEdits(model.uri, rawEdits);\n\t\t}\n\t}\n\treturn undefined;\n}\n\nexport function getOnTypeFormattingEdits(\n\tworkerService: IEditorWorkerService,\n\tlanguageFeaturesService: ILanguageFeaturesService,\n\tmodel: ITextModel,\n\tposition: Position,\n\tch: string,\n\toptions: FormattingOptions,\n\ttoken: CancellationToken\n): Promise {\n\n\tconst providers = languageFeaturesService.onTypeFormattingEditProvider.ordered(model);\n\n\tif (providers.length === 0) {\n\t\treturn Promise.resolve(undefined);\n\t}\n\n\tif (providers[0].autoFormatTriggerCharacters.indexOf(ch) < 0) {\n\t\treturn Promise.resolve(undefined);\n\t}\n\n\treturn Promise.resolve(providers[0].provideOnTypeFormattingEdits(model, position, ch, options, token)).catch(onUnexpectedExternalError).then(edits => {\n\t\treturn workerService.computeMoreMinimalEdits(model.uri, edits);\n\t});\n}\n\nCommandsRegistry.registerCommand('_executeFormatRangeProvider', async function (accessor, ...args) {\n\tconst [resource, range, options] = args;\n\tassertType(URI.isUri(resource));\n\tassertType(Range.isIRange(range));\n\n\tconst resolverService = accessor.get(ITextModelService);\n\tconst workerService = accessor.get(IEditorWorkerService);\n\tconst languageFeaturesService = accessor.get(ILanguageFeaturesService);\n\tconst reference = await resolverService.createModelReference(resource);\n\ttry {\n\t\treturn getDocumentRangeFormattingEditsUntilResult(workerService, languageFeaturesService, reference.object.textEditorModel, Range.lift(range), options, CancellationToken.None);\n\t} finally {\n\t\treference.dispose();\n\t}\n});\n\nCommandsRegistry.registerCommand('_executeFormatDocumentProvider', async function (accessor, ...args) {\n\tconst [resource, options] = args;\n\tassertType(URI.isUri(resource));\n\n\tconst resolverService = accessor.get(ITextModelService);\n\tconst workerService = accessor.get(IEditorWorkerService);\n\tconst languageFeaturesService = accessor.get(ILanguageFeaturesService);\n\tconst reference = await resolverService.createModelReference(resource);\n\ttry {\n\t\treturn getDocumentFormattingEditsUntilResult(workerService, languageFeaturesService, reference.object.textEditorModel, options, CancellationToken.None);\n\t} finally {\n\t\treference.dispose();\n\t}\n});\n\nCommandsRegistry.registerCommand('_executeFormatOnTypeProvider', async function (accessor, ...args) {\n\tconst [resource, position, ch, options] = args;\n\tassertType(URI.isUri(resource));\n\tassertType(Position.isIPosition(position));\n\tassertType(typeof ch === 'string');\n\n\tconst resolverService = accessor.get(ITextModelService);\n\tconst workerService = accessor.get(IEditorWorkerService);\n\tconst languageFeaturesService = accessor.get(ILanguageFeaturesService);\n\tconst reference = await resolverService.createModelReference(resource);\n\ttry {\n\t\treturn getOnTypeFormattingEdits(workerService, languageFeaturesService, reference.object.textEditorModel, Position.lift(position), ch, options, CancellationToken.None);\n\t} finally {\n\t\treference.dispose();\n\t}\n});\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\nimport { isNonEmptyArray } from 'vs/base/common/arrays';\nimport { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';\nimport { onUnexpectedError } from 'vs/base/common/errors';\nimport { KeyChord, KeyCode, KeyMod } from 'vs/base/common/keyCodes';\nimport { DisposableStore } from 'vs/base/common/lifecycle';\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\nimport { EditorAction, EditorContributionInstantiation, registerEditorAction, registerEditorContribution, ServicesAccessor } from 'vs/editor/browser/editorExtensions';\nimport { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\nimport { CharacterSet } from 'vs/editor/common/core/characterClassifier';\nimport { Range } from 'vs/editor/common/core/range';\nimport { IEditorContribution } from 'vs/editor/common/editorCommon';\nimport { EditorContextKeys } from 'vs/editor/common/editorContextKeys';\nimport { IEditorWorkerService } from 'vs/editor/common/services/editorWorker';\nimport { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';\nimport { formatDocumentRangesWithSelectedProvider, formatDocumentWithSelectedProvider, FormattingMode, getOnTypeFormattingEdits } from 'vs/editor/contrib/format/browser/format';\nimport { FormattingEdit } from 'vs/editor/contrib/format/browser/formattingEdit';\nimport * as nls from 'vs/nls';\nimport { AccessibilitySignal, IAccessibilitySignalService } from 'vs/platform/accessibilitySignal/browser/accessibilitySignalService';\nimport { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands';\nimport { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';\nimport { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';\nimport { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';\nimport { IEditorProgressService, Progress } from 'vs/platform/progress/common/progress';\n\nexport class FormatOnType implements IEditorContribution {\n\n\tpublic static readonly ID = 'editor.contrib.autoFormat';\n\n\n\tprivate readonly _disposables = new DisposableStore();\n\tprivate readonly _sessionDisposables = new DisposableStore();\n\n\tconstructor(\n\t\tprivate readonly _editor: ICodeEditor,\n\t\t@ILanguageFeaturesService private readonly _languageFeaturesService: ILanguageFeaturesService,\n\t\t@IEditorWorkerService private readonly _workerService: IEditorWorkerService,\n\t\t@IAccessibilitySignalService private readonly _accessibilitySignalService: IAccessibilitySignalService\n\t) {\n\t\tthis._disposables.add(_languageFeaturesService.onTypeFormattingEditProvider.onDidChange(this._update, this));\n\t\tthis._disposables.add(_editor.onDidChangeModel(() => this._update()));\n\t\tthis._disposables.add(_editor.onDidChangeModelLanguage(() => this._update()));\n\t\tthis._disposables.add(_editor.onDidChangeConfiguration(e => {\n\t\t\tif (e.hasChanged(EditorOption.formatOnType)) {\n\t\t\t\tthis._update();\n\t\t\t}\n\t\t}));\n\t\tthis._update();\n\t}\n\n\tdispose(): void {\n\t\tthis._disposables.dispose();\n\t\tthis._sessionDisposables.dispose();\n\t}\n\n\tprivate _update(): void {\n\n\t\t// clean up\n\t\tthis._sessionDisposables.clear();\n\n\t\t// we are disabled\n\t\tif (!this._editor.getOption(EditorOption.formatOnType)) {\n\t\t\treturn;\n\t\t}\n\n\t\t// no model\n\t\tif (!this._editor.hasModel()) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst model = this._editor.getModel();\n\n\t\t// no support\n\t\tconst [support] = this._languageFeaturesService.onTypeFormattingEditProvider.ordered(model);\n\t\tif (!support || !support.autoFormatTriggerCharacters) {\n\t\t\treturn;\n\t\t}\n\n\t\t// register typing listeners that will trigger the format\n\t\tconst triggerChars = new CharacterSet();\n\t\tfor (const ch of support.autoFormatTriggerCharacters) {\n\t\t\ttriggerChars.add(ch.charCodeAt(0));\n\t\t}\n\t\tthis._sessionDisposables.add(this._editor.onDidType((text: string) => {\n\t\t\tconst lastCharCode = text.charCodeAt(text.length - 1);\n\t\t\tif (triggerChars.has(lastCharCode)) {\n\t\t\t\tthis._trigger(String.fromCharCode(lastCharCode));\n\t\t\t}\n\t\t}));\n\t}\n\n\tprivate _trigger(ch: string): void {\n\t\tif (!this._editor.hasModel()) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (this._editor.getSelections().length > 1 || !this._editor.getSelection().isEmpty()) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst model = this._editor.getModel();\n\t\tconst position = this._editor.getPosition();\n\t\tconst cts = new CancellationTokenSource();\n\n\t\t// install a listener that checks if edits happens before the\n\t\t// position on which we format right now. If so, we won't\n\t\t// apply the format edits\n\t\tconst unbind = this._editor.onDidChangeModelContent((e) => {\n\t\t\tif (e.isFlush) {\n\t\t\t\t// a model.setValue() was called\n\t\t\t\t// cancel only once\n\t\t\t\tcts.cancel();\n\t\t\t\tunbind.dispose();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tfor (let i = 0, len = e.changes.length; i < len; i++) {\n\t\t\t\tconst change = e.changes[i];\n\t\t\t\tif (change.range.endLineNumber <= position.lineNumber) {\n\t\t\t\t\t// cancel only once\n\t\t\t\t\tcts.cancel();\n\t\t\t\t\tunbind.dispose();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\tgetOnTypeFormattingEdits(\n\t\t\tthis._workerService,\n\t\t\tthis._languageFeaturesService,\n\t\t\tmodel,\n\t\t\tposition,\n\t\t\tch,\n\t\t\tmodel.getFormattingOptions(),\n\t\t\tcts.token\n\t\t).then(edits => {\n\t\t\tif (cts.token.isCancellationRequested) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (isNonEmptyArray(edits)) {\n\t\t\t\tthis._accessibilitySignalService.playSignal(AccessibilitySignal.format, { userGesture: false });\n\t\t\t\tFormattingEdit.execute(this._editor, edits, true);\n\t\t\t}\n\t\t}).finally(() => {\n\t\t\tunbind.dispose();\n\t\t});\n\t}\n}\n\nclass FormatOnPaste implements IEditorContribution {\n\n\tpublic static readonly ID = 'editor.contrib.formatOnPaste';\n\n\tprivate readonly _callOnDispose = new DisposableStore();\n\tprivate readonly _callOnModel = new DisposableStore();\n\n\tconstructor(\n\t\tprivate readonly editor: ICodeEditor,\n\t\t@ILanguageFeaturesService private readonly _languageFeaturesService: ILanguageFeaturesService,\n\t\t@IInstantiationService private readonly _instantiationService: IInstantiationService,\n\t) {\n\t\tthis._callOnDispose.add(editor.onDidChangeConfiguration(() => this._update()));\n\t\tthis._callOnDispose.add(editor.onDidChangeModel(() => this._update()));\n\t\tthis._callOnDispose.add(editor.onDidChangeModelLanguage(() => this._update()));\n\t\tthis._callOnDispose.add(_languageFeaturesService.documentRangeFormattingEditProvider.onDidChange(this._update, this));\n\t}\n\n\tdispose(): void {\n\t\tthis._callOnDispose.dispose();\n\t\tthis._callOnModel.dispose();\n\t}\n\n\tprivate _update(): void {\n\n\t\t// clean up\n\t\tthis._callOnModel.clear();\n\n\t\t// we are disabled\n\t\tif (!this.editor.getOption(EditorOption.formatOnPaste)) {\n\t\t\treturn;\n\t\t}\n\n\t\t// no model\n\t\tif (!this.editor.hasModel()) {\n\t\t\treturn;\n\t\t}\n\n\t\t// no formatter\n\t\tif (!this._languageFeaturesService.documentRangeFormattingEditProvider.has(this.editor.getModel())) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._callOnModel.add(this.editor.onDidPaste(({ range }) => this._trigger(range)));\n\t}\n\n\tprivate _trigger(range: Range): void {\n\t\tif (!this.editor.hasModel()) {\n\t\t\treturn;\n\t\t}\n\t\tif (this.editor.getSelections().length > 1) {\n\t\t\treturn;\n\t\t}\n\t\tthis._instantiationService.invokeFunction(formatDocumentRangesWithSelectedProvider, this.editor, range, FormattingMode.Silent, Progress.None, CancellationToken.None, false).catch(onUnexpectedError);\n\t}\n}\n\nclass FormatDocumentAction extends EditorAction {\n\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'editor.action.formatDocument',\n\t\t\tlabel: nls.localize('formatDocument.label', \"Format Document\"),\n\t\t\talias: 'Format Document',\n\t\t\tprecondition: ContextKeyExpr.and(EditorContextKeys.notInCompositeEditor, EditorContextKeys.writable, EditorContextKeys.hasDocumentFormattingProvider),\n\t\t\tkbOpts: {\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\n\t\t\t\tprimary: KeyMod.Shift | KeyMod.Alt | KeyCode.KeyF,\n\t\t\t\tlinux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KeyI },\n\t\t\t\tweight: KeybindingWeight.EditorContrib\n\t\t\t},\n\t\t\tcontextMenuOpts: {\n\t\t\t\tgroup: '1_modification',\n\t\t\t\torder: 1.3\n\t\t\t}\n\t\t});\n\t}\n\n\tasync run(accessor: ServicesAccessor, editor: ICodeEditor): Promise {\n\t\tif (editor.hasModel()) {\n\t\t\tconst instaService = accessor.get(IInstantiationService);\n\t\t\tconst progressService = accessor.get(IEditorProgressService);\n\t\t\tawait progressService.showWhile(\n\t\t\t\tinstaService.invokeFunction(formatDocumentWithSelectedProvider, editor, FormattingMode.Explicit, Progress.None, CancellationToken.None, true),\n\t\t\t\t250\n\t\t\t);\n\t\t}\n\t}\n}\n\nclass FormatSelectionAction extends EditorAction {\n\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'editor.action.formatSelection',\n\t\t\tlabel: nls.localize('formatSelection.label', \"Format Selection\"),\n\t\t\talias: 'Format Selection',\n\t\t\tprecondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasDocumentSelectionFormattingProvider),\n\t\t\tkbOpts: {\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\n\t\t\t\tprimary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.KeyF),\n\t\t\t\tweight: KeybindingWeight.EditorContrib\n\t\t\t},\n\t\t\tcontextMenuOpts: {\n\t\t\t\twhen: EditorContextKeys.hasNonEmptySelection,\n\t\t\t\tgroup: '1_modification',\n\t\t\t\torder: 1.31\n\t\t\t}\n\t\t});\n\t}\n\n\tasync run(accessor: ServicesAccessor, editor: ICodeEditor): Promise {\n\t\tif (!editor.hasModel()) {\n\t\t\treturn;\n\t\t}\n\t\tconst instaService = accessor.get(IInstantiationService);\n\t\tconst model = editor.getModel();\n\n\t\tconst ranges = editor.getSelections().map(range => {\n\t\t\treturn range.isEmpty()\n\t\t\t\t? new Range(range.startLineNumber, 1, range.startLineNumber, model.getLineMaxColumn(range.startLineNumber))\n\t\t\t\t: range;\n\t\t});\n\n\t\tconst progressService = accessor.get(IEditorProgressService);\n\t\tawait progressService.showWhile(\n\t\t\tinstaService.invokeFunction(formatDocumentRangesWithSelectedProvider, editor, ranges, FormattingMode.Explicit, Progress.None, CancellationToken.None, true),\n\t\t\t250\n\t\t);\n\t}\n}\n\nregisterEditorContribution(FormatOnType.ID, FormatOnType, EditorContributionInstantiation.BeforeFirstInteraction);\nregisterEditorContribution(FormatOnPaste.ID, FormatOnPaste, EditorContributionInstantiation.BeforeFirstInteraction);\nregisterEditorAction(FormatDocumentAction);\nregisterEditorAction(FormatSelectionAction);\n\n// this is the old format action that does both (format document OR format selection)\n// and we keep it here such that existing keybinding configurations etc will still work\nCommandsRegistry.registerCommand('editor.action.format', async accessor => {\n\tconst editor = accessor.get(ICodeEditorService).getFocusedCodeEditor();\n\tif (!editor || !editor.hasModel()) {\n\t\treturn;\n\t}\n\tconst commandService = accessor.get(ICommandService);\n\tif (editor.getSelection().isEmpty()) {\n\t\tawait commandService.executeCommand('editor.action.formatDocument');\n\t} else {\n\t\tawait commandService.executeCommand('editor.action.formatSelection');\n\t}\n});\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\nimport { coalesce } from 'vs/base/common/arrays';\nimport { CancellationToken } from 'vs/base/common/cancellation';\nimport { onUnexpectedExternalError } from 'vs/base/common/errors';\nimport { matchesSomeScheme, Schemas } from 'vs/base/common/network';\nimport { registerModelAndPositionCommand } from 'vs/editor/browser/editorExtensions';\nimport { Position } from 'vs/editor/common/core/position';\nimport { LanguageFeatureRegistry } from 'vs/editor/common/languageFeatureRegistry';\nimport { DeclarationProvider, DefinitionProvider, ImplementationProvider, LocationLink, ProviderResult, ReferenceProvider, TypeDefinitionProvider } from 'vs/editor/common/languages';\nimport { ITextModel } from 'vs/editor/common/model';\nimport { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';\nimport { ReferencesModel } from 'vs/editor/contrib/gotoSymbol/browser/referencesModel';\n\nfunction shouldIncludeLocationLink(sourceModel: ITextModel, loc: LocationLink): boolean {\n\t// Always allow the location if the request comes from a document with the same scheme.\n\tif (loc.uri.scheme === sourceModel.uri.scheme) {\n\t\treturn true;\n\t}\n\n\t// Otherwise filter out locations from internal schemes\n\tif (matchesSomeScheme(loc.uri, Schemas.walkThroughSnippet, Schemas.vscodeChatCodeBlock, Schemas.vscodeChatCodeCompareBlock)) {\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n\nasync function getLocationLinks(\n\tmodel: ITextModel,\n\tposition: Position,\n\tregistry: LanguageFeatureRegistry,\n\tprovide: (provider: T, model: ITextModel, position: Position) => ProviderResult\n): Promise {\n\tconst provider = registry.ordered(model);\n\n\t// get results\n\tconst promises = provider.map((provider): Promise => {\n\t\treturn Promise.resolve(provide(provider, model, position)).then(undefined, err => {\n\t\t\tonUnexpectedExternalError(err);\n\t\t\treturn undefined;\n\t\t});\n\t});\n\n\tconst values = await Promise.all(promises);\n\treturn coalesce(values.flat()).filter(loc => shouldIncludeLocationLink(model, loc));\n}\n\nexport function getDefinitionsAtPosition(registry: LanguageFeatureRegistry, model: ITextModel, position: Position, token: CancellationToken): Promise {\n\treturn getLocationLinks(model, position, registry, (provider, model, position) => {\n\t\treturn provider.provideDefinition(model, position, token);\n\t});\n}\n\nexport function getDeclarationsAtPosition(registry: LanguageFeatureRegistry, model: ITextModel, position: Position, token: CancellationToken): Promise {\n\treturn getLocationLinks(model, position, registry, (provider, model, position) => {\n\t\treturn provider.provideDeclaration(model, position, token);\n\t});\n}\n\nexport function getImplementationsAtPosition(registry: LanguageFeatureRegistry, model: ITextModel, position: Position, token: CancellationToken): Promise {\n\treturn getLocationLinks(model, position, registry, (provider, model, position) => {\n\t\treturn provider.provideImplementation(model, position, token);\n\t});\n}\n\nexport function getTypeDefinitionsAtPosition(registry: LanguageFeatureRegistry, model: ITextModel, position: Position, token: CancellationToken): Promise {\n\treturn getLocationLinks(model, position, registry, (provider, model, position) => {\n\t\treturn provider.provideTypeDefinition(model, position, token);\n\t});\n}\n\nexport function getReferencesAtPosition(registry: LanguageFeatureRegistry, model: ITextModel, position: Position, compact: boolean, token: CancellationToken): Promise {\n\treturn getLocationLinks(model, position, registry, async (provider, model, position) => {\n\t\tconst result = (await provider.provideReferences(model, position, { includeDeclaration: true }, token))?.filter(ref => shouldIncludeLocationLink(model, ref));\n\t\tif (!compact || !result || result.length !== 2) {\n\t\t\treturn result;\n\t\t}\n\t\tconst resultWithoutDeclaration = (await provider.provideReferences(model, position, { includeDeclaration: false }, token))?.filter(ref => shouldIncludeLocationLink(model, ref));\n\t\tif (resultWithoutDeclaration && resultWithoutDeclaration.length === 1) {\n\t\t\treturn resultWithoutDeclaration;\n\t\t}\n\t\treturn result;\n\t});\n}\n\n// -- API commands ----\n\nasync function _sortedAndDeduped(callback: () => Promise): Promise {\n\tconst rawLinks = await callback();\n\tconst model = new ReferencesModel(rawLinks, '');\n\tconst modelLinks = model.references.map(ref => ref.link);\n\tmodel.dispose();\n\treturn modelLinks;\n}\n\nregisterModelAndPositionCommand('_executeDefinitionProvider', (accessor, model, position) => {\n\tconst languageFeaturesService = accessor.get(ILanguageFeaturesService);\n\tconst promise = getDefinitionsAtPosition(languageFeaturesService.definitionProvider, model, position, CancellationToken.None);\n\treturn _sortedAndDeduped(() => promise);\n});\n\nregisterModelAndPositionCommand('_executeTypeDefinitionProvider', (accessor, model, position) => {\n\tconst languageFeaturesService = accessor.get(ILanguageFeaturesService);\n\tconst promise = getTypeDefinitionsAtPosition(languageFeaturesService.typeDefinitionProvider, model, position, CancellationToken.None);\n\treturn _sortedAndDeduped(() => promise);\n});\n\nregisterModelAndPositionCommand('_executeDeclarationProvider', (accessor, model, position) => {\n\tconst languageFeaturesService = accessor.get(ILanguageFeaturesService);\n\tconst promise = getDeclarationsAtPosition(languageFeaturesService.declarationProvider, model, position, CancellationToken.None);\n\treturn _sortedAndDeduped(() => promise);\n});\n\nregisterModelAndPositionCommand('_executeReferenceProvider', (accessor, model, position) => {\n\tconst languageFeaturesService = accessor.get(ILanguageFeaturesService);\n\tconst promise = getReferencesAtPosition(languageFeaturesService.referenceProvider, model, position, false, CancellationToken.None);\n\treturn _sortedAndDeduped(() => promise);\n});\n\nregisterModelAndPositionCommand('_executeImplementationProvider', (accessor, model, position) => {\n\tconst languageFeaturesService = accessor.get(ILanguageFeaturesService);\n\tconst promise = getImplementationsAtPosition(languageFeaturesService.implementationProvider, model, position, CancellationToken.None);\n\treturn _sortedAndDeduped(() => promise);\n});\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\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { KeyCode } from 'vs/base/common/keyCodes';\nimport { combinedDisposable, DisposableStore, dispose, IDisposable } from 'vs/base/common/lifecycle';\nimport { isEqual } from 'vs/base/common/resources';\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\nimport { EditorCommand, registerEditorCommand } from 'vs/editor/browser/editorExtensions';\nimport { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';\nimport { Range } from 'vs/editor/common/core/range';\nimport { OneReference, ReferencesModel } from 'vs/editor/contrib/gotoSymbol/browser/referencesModel';\nimport { localize } from 'vs/nls';\nimport { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';\nimport { TextEditorSelectionRevealType } from 'vs/platform/editor/common/editor';\nimport { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions';\nimport { createDecorator, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';\nimport { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';\nimport { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';\nimport { INotificationService } from 'vs/platform/notification/common/notification';\n\nexport const ctxHasSymbols = new RawContextKey('hasSymbols', false, localize('hasSymbols', \"Whether there are symbol locations that can be navigated via keyboard-only.\"));\n\nexport const ISymbolNavigationService = createDecorator('ISymbolNavigationService');\n\nexport interface ISymbolNavigationService {\n\treadonly _serviceBrand: undefined;\n\treset(): void;\n\tput(anchor: OneReference): void;\n\trevealNext(source: ICodeEditor): Promise;\n}\n\nclass SymbolNavigationService implements ISymbolNavigationService {\n\n\tdeclare readonly _serviceBrand: undefined;\n\n\tprivate readonly _ctxHasSymbols: IContextKey;\n\n\tprivate _currentModel?: ReferencesModel = undefined;\n\tprivate _currentIdx: number = -1;\n\tprivate _currentState?: IDisposable;\n\tprivate _currentMessage?: IDisposable;\n\tprivate _ignoreEditorChange: boolean = false;\n\n\tconstructor(\n\t\t@IContextKeyService contextKeyService: IContextKeyService,\n\t\t@ICodeEditorService private readonly _editorService: ICodeEditorService,\n\t\t@INotificationService private readonly _notificationService: INotificationService,\n\t\t@IKeybindingService private readonly _keybindingService: IKeybindingService,\n\t) {\n\t\tthis._ctxHasSymbols = ctxHasSymbols.bindTo(contextKeyService);\n\t}\n\n\treset(): void {\n\t\tthis._ctxHasSymbols.reset();\n\t\tthis._currentState?.dispose();\n\t\tthis._currentMessage?.dispose();\n\t\tthis._currentModel = undefined;\n\t\tthis._currentIdx = -1;\n\t}\n\n\tput(anchor: OneReference): void {\n\t\tconst refModel = anchor.parent.parent;\n\n\t\tif (refModel.references.length <= 1) {\n\t\t\tthis.reset();\n\t\t\treturn;\n\t\t}\n\n\t\tthis._currentModel = refModel;\n\t\tthis._currentIdx = refModel.references.indexOf(anchor);\n\t\tthis._ctxHasSymbols.set(true);\n\t\tthis._showMessage();\n\n\t\tconst editorState = new EditorState(this._editorService);\n\t\tconst listener = editorState.onDidChange(_ => {\n\n\t\t\tif (this._ignoreEditorChange) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst editor = this._editorService.getActiveCodeEditor();\n\t\t\tif (!editor) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst model = editor.getModel();\n\t\t\tconst position = editor.getPosition();\n\t\t\tif (!model || !position) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlet seenUri: boolean = false;\n\t\t\tlet seenPosition: boolean = false;\n\t\t\tfor (const reference of refModel.references) {\n\t\t\t\tif (isEqual(reference.uri, model.uri)) {\n\t\t\t\t\tseenUri = true;\n\t\t\t\t\tseenPosition = seenPosition || Range.containsPosition(reference.range, position);\n\t\t\t\t} else if (seenUri) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!seenUri || !seenPosition) {\n\t\t\t\tthis.reset();\n\t\t\t}\n\t\t});\n\n\t\tthis._currentState = combinedDisposable(editorState, listener);\n\t}\n\n\trevealNext(source: ICodeEditor): Promise {\n\t\tif (!this._currentModel) {\n\t\t\treturn Promise.resolve();\n\t\t}\n\n\t\t// get next result and advance\n\t\tthis._currentIdx += 1;\n\t\tthis._currentIdx %= this._currentModel.references.length;\n\t\tconst reference = this._currentModel.references[this._currentIdx];\n\n\t\t// status\n\t\tthis._showMessage();\n\n\t\t// open editor, ignore events while that happens\n\t\tthis._ignoreEditorChange = true;\n\t\treturn this._editorService.openCodeEditor({\n\t\t\tresource: reference.uri,\n\t\t\toptions: {\n\t\t\t\tselection: Range.collapseToStart(reference.range),\n\t\t\t\tselectionRevealType: TextEditorSelectionRevealType.NearTopIfOutsideViewport\n\t\t\t}\n\t\t}, source).finally(() => {\n\t\t\tthis._ignoreEditorChange = false;\n\t\t});\n\n\t}\n\n\tprivate _showMessage(): void {\n\n\t\tthis._currentMessage?.dispose();\n\n\t\tconst kb = this._keybindingService.lookupKeybinding('editor.gotoNextSymbolFromResult');\n\t\tconst message = kb\n\t\t\t? localize('location.kb', \"Symbol {0} of {1}, {2} for next\", this._currentIdx + 1, this._currentModel!.references.length, kb.getLabel())\n\t\t\t: localize('location', \"Symbol {0} of {1}\", this._currentIdx + 1, this._currentModel!.references.length);\n\n\t\tthis._currentMessage = this._notificationService.status(message);\n\t}\n}\n\nregisterSingleton(ISymbolNavigationService, SymbolNavigationService, InstantiationType.Delayed);\n\nregisterEditorCommand(new class extends EditorCommand {\n\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'editor.gotoNextSymbolFromResult',\n\t\t\tprecondition: ctxHasSymbols,\n\t\t\tkbOpts: {\n\t\t\t\tweight: KeybindingWeight.EditorContrib,\n\t\t\t\tprimary: KeyCode.F12\n\t\t\t}\n\t\t});\n\t}\n\n\trunEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor): void | Promise {\n\t\treturn accessor.get(ISymbolNavigationService).revealNext(editor);\n\t}\n});\n\nKeybindingsRegistry.registerCommandAndKeybindingRule({\n\tid: 'editor.gotoNextSymbolFromResult.cancel',\n\tweight: KeybindingWeight.EditorContrib,\n\twhen: ctxHasSymbols,\n\tprimary: KeyCode.Escape,\n\thandler(accessor) {\n\t\taccessor.get(ISymbolNavigationService).reset();\n\t}\n});\n\n//\n\nclass EditorState {\n\n\tprivate readonly _listener = new Map();\n\tprivate readonly _disposables = new DisposableStore();\n\n\tprivate readonly _onDidChange = new Emitter<{ editor: ICodeEditor }>();\n\treadonly onDidChange: Event<{ editor: ICodeEditor }> = this._onDidChange.event;\n\n\tconstructor(@ICodeEditorService editorService: ICodeEditorService) {\n\t\tthis._disposables.add(editorService.onCodeEditorRemove(this._onDidRemoveEditor, this));\n\t\tthis._disposables.add(editorService.onCodeEditorAdd(this._onDidAddEditor, this));\n\t\teditorService.listCodeEditors().forEach(this._onDidAddEditor, this);\n\t}\n\n\tdispose(): void {\n\t\tthis._disposables.dispose();\n\t\tthis._onDidChange.dispose();\n\t\tdispose(this._listener.values());\n\t}\n\n\tprivate _onDidAddEditor(editor: ICodeEditor): void {\n\t\tthis._listener.set(editor, combinedDisposable(\n\t\t\teditor.onDidChangeCursorPosition(_ => this._onDidChange.fire({ editor })),\n\t\t\teditor.onDidChangeModelContent(_ => this._onDidChange.fire({ editor })),\n\t\t));\n\t}\n\n\tprivate _onDidRemoveEditor(editor: ICodeEditor): void {\n\t\tthis._listener.get(editor)?.dispose();\n\t\tthis._listener.delete(editor);\n\t}\n}\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\nimport { AsyncIterableObject } from 'vs/base/common/async';\nimport { CancellationToken } from 'vs/base/common/cancellation';\nimport { onUnexpectedExternalError } from 'vs/base/common/errors';\nimport { registerModelAndPositionCommand } from 'vs/editor/browser/editorExtensions';\nimport { Position } from 'vs/editor/common/core/position';\nimport { ITextModel } from 'vs/editor/common/model';\nimport { Hover, HoverProvider } from 'vs/editor/common/languages';\nimport { LanguageFeatureRegistry } from 'vs/editor/common/languageFeatureRegistry';\nimport { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';\n\nexport class HoverProviderResult {\n\tconstructor(\n\t\tpublic readonly provider: HoverProvider,\n\t\tpublic readonly hover: Hover,\n\t\tpublic readonly ordinal: number\n\t) { }\n}\n\n/**\n * Does not throw or return a rejected promise (returns undefined instead).\n */\nasync function executeProvider(provider: HoverProvider, ordinal: number, model: ITextModel, position: Position, token: CancellationToken): Promise {\n\tconst result = await Promise\n\t\t.resolve(provider.provideHover(model, position, token))\n\t\t.catch(onUnexpectedExternalError);\n\tif (!result || !isValid(result)) {\n\t\treturn undefined;\n\t}\n\treturn new HoverProviderResult(provider, result, ordinal);\n}\n\nexport function getHoverProviderResultsAsAsyncIterable(registry: LanguageFeatureRegistry, model: ITextModel, position: Position, token: CancellationToken): AsyncIterableObject {\n\tconst providers = registry.ordered(model);\n\tconst promises = providers.map((provider, index) => executeProvider(provider, index, model, position, token));\n\treturn AsyncIterableObject.fromPromises(promises).coalesce();\n}\n\nexport function getHoversPromise(registry: LanguageFeatureRegistry, model: ITextModel, position: Position, token: CancellationToken): Promise {\n\treturn getHoverProviderResultsAsAsyncIterable(registry, model, position, token).map(item => item.hover).toPromise();\n}\n\nregisterModelAndPositionCommand('_executeHoverProvider', (accessor, model, position): Promise => {\n\tconst languageFeaturesService = accessor.get(ILanguageFeaturesService);\n\treturn getHoversPromise(languageFeaturesService.hoverProvider, model, position, CancellationToken.None);\n});\n\nfunction isValid(result: Hover) {\n\tconst hasRange = (typeof result.range !== 'undefined');\n\tconst hasHtmlContent = typeof result.contents !== 'undefined' && result.contents && result.contents.length > 0;\n\treturn hasRange && hasHtmlContent;\n}\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\nimport { DisposableStore } from 'vs/base/common/lifecycle';\nimport * as strings from 'vs/base/common/strings';\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\nimport { EditorAction, EditorContributionInstantiation, IActionOptions, registerEditorAction, registerEditorContribution, ServicesAccessor } from 'vs/editor/browser/editorExtensions';\nimport { ShiftCommand } from 'vs/editor/common/commands/shiftCommand';\nimport { EditorAutoIndentStrategy, EditorOption } from 'vs/editor/common/config/editorOptions';\nimport { ISingleEditOperation } from 'vs/editor/common/core/editOperation';\nimport { IRange, Range } from 'vs/editor/common/core/range';\nimport { Selection } from 'vs/editor/common/core/selection';\nimport { ICommand, ICursorStateComputerData, IEditOperationBuilder, IEditorContribution } from 'vs/editor/common/editorCommon';\nimport { EditorContextKeys } from 'vs/editor/common/editorContextKeys';\nimport { EndOfLineSequence, ITextModel } from 'vs/editor/common/model';\nimport { TextEdit } from 'vs/editor/common/languages';\nimport { StandardTokenType } from 'vs/editor/common/encodedTokenAttributes';\nimport { ILanguageConfigurationService } from 'vs/editor/common/languages/languageConfigurationRegistry';\nimport { IndentConsts } from 'vs/editor/common/languages/supports/indentRules';\nimport { IModelService } from 'vs/editor/common/services/model';\nimport * as indentUtils from 'vs/editor/contrib/indentation/common/indentUtils';\nimport * as nls from 'vs/nls';\nimport { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';\nimport { getGoodIndentForLine, getIndentMetadata } from 'vs/editor/common/languages/autoIndent';\nimport { getReindentEditOperations } from '../common/indentation';\n\nexport class IndentationToSpacesAction extends EditorAction {\n\tpublic static readonly ID = 'editor.action.indentationToSpaces';\n\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: IndentationToSpacesAction.ID,\n\t\t\tlabel: nls.localize('indentationToSpaces', \"Convert Indentation to Spaces\"),\n\t\t\talias: 'Convert Indentation to Spaces',\n\t\t\tprecondition: EditorContextKeys.writable,\n\t\t\tmetadata: {\n\t\t\t\tdescription: nls.localize2('indentationToSpacesDescription', \"Convert the tab indentation to spaces.\"),\n\t\t\t}\n\t\t});\n\t}\n\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor): void {\n\t\tconst model = editor.getModel();\n\t\tif (!model) {\n\t\t\treturn;\n\t\t}\n\t\tconst modelOpts = model.getOptions();\n\t\tconst selection = editor.getSelection();\n\t\tif (!selection) {\n\t\t\treturn;\n\t\t}\n\t\tconst command = new IndentationToSpacesCommand(selection, modelOpts.tabSize);\n\n\t\teditor.pushUndoStop();\n\t\teditor.executeCommands(this.id, [command]);\n\t\teditor.pushUndoStop();\n\n\t\tmodel.updateOptions({\n\t\t\tinsertSpaces: true\n\t\t});\n\t}\n}\n\nexport class IndentationToTabsAction extends EditorAction {\n\tpublic static readonly ID = 'editor.action.indentationToTabs';\n\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: IndentationToTabsAction.ID,\n\t\t\tlabel: nls.localize('indentationToTabs', \"Convert Indentation to Tabs\"),\n\t\t\talias: 'Convert Indentation to Tabs',\n\t\t\tprecondition: EditorContextKeys.writable,\n\t\t\tmetadata: {\n\t\t\t\tdescription: nls.localize2('indentationToTabsDescription', \"Convert the spaces indentation to tabs.\"),\n\t\t\t}\n\t\t});\n\t}\n\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor): void {\n\t\tconst model = editor.getModel();\n\t\tif (!model) {\n\t\t\treturn;\n\t\t}\n\t\tconst modelOpts = model.getOptions();\n\t\tconst selection = editor.getSelection();\n\t\tif (!selection) {\n\t\t\treturn;\n\t\t}\n\t\tconst command = new IndentationToTabsCommand(selection, modelOpts.tabSize);\n\n\t\teditor.pushUndoStop();\n\t\teditor.executeCommands(this.id, [command]);\n\t\teditor.pushUndoStop();\n\n\t\tmodel.updateOptions({\n\t\t\tinsertSpaces: false\n\t\t});\n\t}\n}\n\nexport class ChangeIndentationSizeAction extends EditorAction {\n\n\tconstructor(private readonly insertSpaces: boolean, private readonly displaySizeOnly: boolean, opts: IActionOptions) {\n\t\tsuper(opts);\n\t}\n\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor): void {\n\t\tconst quickInputService = accessor.get(IQuickInputService);\n\t\tconst modelService = accessor.get(IModelService);\n\n\t\tconst model = editor.getModel();\n\t\tif (!model) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst creationOpts = modelService.getCreationOptions(model.getLanguageId(), model.uri, model.isForSimpleWidget);\n\t\tconst modelOpts = model.getOptions();\n\t\tconst picks = [1, 2, 3, 4, 5, 6, 7, 8].map(n => ({\n\t\t\tid: n.toString(),\n\t\t\tlabel: n.toString(),\n\t\t\t// add description for tabSize value set in the configuration\n\t\t\tdescription: (\n\t\t\t\tn === creationOpts.tabSize && n === modelOpts.tabSize\n\t\t\t\t\t? nls.localize('configuredTabSize', \"Configured Tab Size\")\n\t\t\t\t\t: n === creationOpts.tabSize\n\t\t\t\t\t\t? nls.localize('defaultTabSize', \"Default Tab Size\")\n\t\t\t\t\t\t: n === modelOpts.tabSize\n\t\t\t\t\t\t\t? nls.localize('currentTabSize', \"Current Tab Size\")\n\t\t\t\t\t\t\t: undefined\n\t\t\t)\n\t\t}));\n\n\t\t// auto focus the tabSize set for the current editor\n\t\tconst autoFocusIndex = Math.min(model.getOptions().tabSize - 1, 7);\n\n\t\tsetTimeout(() => {\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 => {\n\t\t\t\tif (pick) {\n\t\t\t\t\tif (model && !model.isDisposed()) {\n\t\t\t\t\t\tconst pickedVal = parseInt(pick.label, 10);\n\t\t\t\t\t\tif (this.displaySizeOnly) {\n\t\t\t\t\t\t\tmodel.updateOptions({\n\t\t\t\t\t\t\t\ttabSize: pickedVal\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tmodel.updateOptions({\n\t\t\t\t\t\t\t\ttabSize: pickedVal,\n\t\t\t\t\t\t\t\tindentSize: pickedVal,\n\t\t\t\t\t\t\t\tinsertSpaces: this.insertSpaces\n\t\t\t\t\t\t\t});\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}, 50/* quick input is sensitive to being opened so soon after another */);\n\t}\n}\n\nexport class IndentUsingTabs extends ChangeIndentationSizeAction {\n\n\tpublic static readonly ID = 'editor.action.indentUsingTabs';\n\n\tconstructor() {\n\t\tsuper(false, false, {\n\t\t\tid: IndentUsingTabs.ID,\n\t\t\tlabel: nls.localize('indentUsingTabs', \"Indent Using Tabs\"),\n\t\t\talias: 'Indent Using Tabs',\n\t\t\tprecondition: undefined,\n\t\t\tmetadata: {\n\t\t\t\tdescription: nls.localize2('indentUsingTabsDescription', \"Use indentation with tabs.\"),\n\t\t\t}\n\t\t});\n\t}\n}\n\nexport class IndentUsingSpaces extends ChangeIndentationSizeAction {\n\n\tpublic static readonly ID = 'editor.action.indentUsingSpaces';\n\n\tconstructor() {\n\t\tsuper(true, false, {\n\t\t\tid: IndentUsingSpaces.ID,\n\t\t\tlabel: nls.localize('indentUsingSpaces', \"Indent Using Spaces\"),\n\t\t\talias: 'Indent Using Spaces',\n\t\t\tprecondition: undefined,\n\t\t\tmetadata: {\n\t\t\t\tdescription: nls.localize2('indentUsingSpacesDescription', \"Use indentation with spaces.\"),\n\t\t\t}\n\t\t});\n\t}\n}\n\nexport class ChangeTabDisplaySize extends ChangeIndentationSizeAction {\n\n\tpublic static readonly ID = 'editor.action.changeTabDisplaySize';\n\n\tconstructor() {\n\t\tsuper(true, true, {\n\t\t\tid: ChangeTabDisplaySize.ID,\n\t\t\tlabel: nls.localize('changeTabDisplaySize', \"Change Tab Display Size\"),\n\t\t\talias: 'Change Tab Display Size',\n\t\t\tprecondition: undefined,\n\t\t\tmetadata: {\n\t\t\t\tdescription: nls.localize2('changeTabDisplaySizeDescription', \"Change the space size equivalent of the tab.\"),\n\t\t\t}\n\t\t});\n\t}\n}\n\nexport class DetectIndentation extends EditorAction {\n\n\tpublic static readonly ID = 'editor.action.detectIndentation';\n\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: DetectIndentation.ID,\n\t\t\tlabel: nls.localize('detectIndentation', \"Detect Indentation from Content\"),\n\t\t\talias: 'Detect Indentation from Content',\n\t\t\tprecondition: undefined,\n\t\t\tmetadata: {\n\t\t\t\tdescription: nls.localize2('detectIndentationDescription', \"Detect the indentation from content.\"),\n\t\t\t}\n\t\t});\n\t}\n\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor): void {\n\t\tconst modelService = accessor.get(IModelService);\n\n\t\tconst model = editor.getModel();\n\t\tif (!model) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst creationOpts = modelService.getCreationOptions(model.getLanguageId(), model.uri, model.isForSimpleWidget);\n\t\tmodel.detectIndentation(creationOpts.insertSpaces, creationOpts.tabSize);\n\t}\n}\n\nexport class ReindentLinesAction extends EditorAction {\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'editor.action.reindentlines',\n\t\t\tlabel: nls.localize('editor.reindentlines', \"Reindent Lines\"),\n\t\t\talias: 'Reindent Lines',\n\t\t\tprecondition: EditorContextKeys.writable,\n\t\t\tmetadata: {\n\t\t\t\tdescription: nls.localize2('editor.reindentlinesDescription', \"Reindent the lines of the editor.\"),\n\t\t\t}\n\t\t});\n\t}\n\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor): void {\n\t\tconst languageConfigurationService = accessor.get(ILanguageConfigurationService);\n\n\t\tconst model = editor.getModel();\n\t\tif (!model) {\n\t\t\treturn;\n\t\t}\n\t\tconst edits = getReindentEditOperations(model, languageConfigurationService, 1, model.getLineCount());\n\t\tif (edits.length > 0) {\n\t\t\teditor.pushUndoStop();\n\t\t\teditor.executeEdits(this.id, edits);\n\t\t\teditor.pushUndoStop();\n\t\t}\n\t}\n}\n\nexport class ReindentSelectedLinesAction extends EditorAction {\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'editor.action.reindentselectedlines',\n\t\t\tlabel: nls.localize('editor.reindentselectedlines', \"Reindent Selected Lines\"),\n\t\t\talias: 'Reindent Selected Lines',\n\t\t\tprecondition: EditorContextKeys.writable,\n\t\t\tmetadata: {\n\t\t\t\tdescription: nls.localize2('editor.reindentselectedlinesDescription', \"Reindent the selected lines of the editor.\"),\n\t\t\t}\n\t\t});\n\t}\n\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor): void {\n\t\tconst languageConfigurationService = accessor.get(ILanguageConfigurationService);\n\n\t\tconst model = editor.getModel();\n\t\tif (!model) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst selections = editor.getSelections();\n\t\tif (selections === null) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst edits: ISingleEditOperation[] = [];\n\n\t\tfor (const selection of selections) {\n\t\t\tlet startLineNumber = selection.startLineNumber;\n\t\t\tlet endLineNumber = selection.endLineNumber;\n\n\t\t\tif (startLineNumber !== endLineNumber && selection.endColumn === 1) {\n\t\t\t\tendLineNumber--;\n\t\t\t}\n\n\t\t\tif (startLineNumber === 1) {\n\t\t\t\tif (startLineNumber === endLineNumber) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tstartLineNumber--;\n\t\t\t}\n\n\t\t\tconst editOperations = getReindentEditOperations(model, languageConfigurationService, startLineNumber, endLineNumber);\n\t\t\tedits.push(...editOperations);\n\t\t}\n\n\t\tif (edits.length > 0) {\n\t\t\teditor.pushUndoStop();\n\t\t\teditor.executeEdits(this.id, edits);\n\t\t\teditor.pushUndoStop();\n\t\t}\n\t}\n}\n\nexport class AutoIndentOnPasteCommand implements ICommand {\n\n\tprivate readonly _edits: { range: IRange; text: string; eol?: EndOfLineSequence }[];\n\n\tprivate readonly _initialSelection: Selection;\n\tprivate _selectionId: string | null;\n\n\tconstructor(edits: TextEdit[], initialSelection: Selection) {\n\t\tthis._initialSelection = initialSelection;\n\t\tthis._edits = [];\n\t\tthis._selectionId = null;\n\n\t\tfor (const edit of edits) {\n\t\t\tif (edit.range && typeof edit.text === 'string') {\n\t\t\t\tthis._edits.push(edit as { range: IRange; text: string; eol?: EndOfLineSequence });\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {\n\t\tfor (const edit of this._edits) {\n\t\t\tbuilder.addEditOperation(Range.lift(edit.range), edit.text);\n\t\t}\n\n\t\tlet selectionIsSet = false;\n\t\tif (Array.isArray(this._edits) && this._edits.length === 1 && this._initialSelection.isEmpty()) {\n\t\t\tif (this._edits[0].range.startColumn === this._initialSelection.endColumn &&\n\t\t\t\tthis._edits[0].range.startLineNumber === this._initialSelection.endLineNumber) {\n\t\t\t\tselectionIsSet = true;\n\t\t\t\tthis._selectionId = builder.trackSelection(this._initialSelection, true);\n\t\t\t} else if (this._edits[0].range.endColumn === this._initialSelection.startColumn &&\n\t\t\t\tthis._edits[0].range.endLineNumber === this._initialSelection.startLineNumber) {\n\t\t\t\tselectionIsSet = true;\n\t\t\t\tthis._selectionId = builder.trackSelection(this._initialSelection, false);\n\t\t\t}\n\t\t}\n\n\t\tif (!selectionIsSet) {\n\t\t\tthis._selectionId = builder.trackSelection(this._initialSelection);\n\t\t}\n\t}\n\n\tpublic computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {\n\t\treturn helper.getTrackedSelection(this._selectionId!);\n\t}\n}\n\nexport class AutoIndentOnPaste implements IEditorContribution {\n\tpublic static readonly ID = 'editor.contrib.autoIndentOnPaste';\n\n\tprivate readonly callOnDispose = new DisposableStore();\n\tprivate readonly callOnModel = new DisposableStore();\n\n\tconstructor(\n\t\tprivate readonly editor: ICodeEditor,\n\t\t@ILanguageConfigurationService private readonly _languageConfigurationService: ILanguageConfigurationService\n\t) {\n\n\t\tthis.callOnDispose.add(editor.onDidChangeConfiguration(() => this.update()));\n\t\tthis.callOnDispose.add(editor.onDidChangeModel(() => this.update()));\n\t\tthis.callOnDispose.add(editor.onDidChangeModelLanguage(() => this.update()));\n\t}\n\n\tprivate update(): void {\n\n\t\t// clean up\n\t\tthis.callOnModel.clear();\n\n\t\t// we are disabled\n\t\tif (this.editor.getOption(EditorOption.autoIndent) < EditorAutoIndentStrategy.Full || this.editor.getOption(EditorOption.formatOnPaste)) {\n\t\t\treturn;\n\t\t}\n\n\t\t// no model\n\t\tif (!this.editor.hasModel()) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.callOnModel.add(this.editor.onDidPaste(({ range }) => {\n\t\t\tthis.trigger(range);\n\t\t}));\n\t}\n\n\tpublic trigger(range: Range): void {\n\t\tconst selections = this.editor.getSelections();\n\t\tif (selections === null || selections.length > 1) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst model = this.editor.getModel();\n\t\tif (!model) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (!model.tokenization.isCheapToTokenize(range.getStartPosition().lineNumber)) {\n\t\t\treturn;\n\t\t}\n\t\tconst autoIndent = this.editor.getOption(EditorOption.autoIndent);\n\t\tconst { tabSize, indentSize, insertSpaces } = model.getOptions();\n\t\tconst textEdits: TextEdit[] = [];\n\n\t\tconst indentConverter = {\n\t\t\tshiftIndent: (indentation: string) => {\n\t\t\t\treturn ShiftCommand.shiftIndent(indentation, indentation.length + 1, tabSize, indentSize, insertSpaces);\n\t\t\t},\n\t\t\tunshiftIndent: (indentation: string) => {\n\t\t\t\treturn ShiftCommand.unshiftIndent(indentation, indentation.length + 1, tabSize, indentSize, insertSpaces);\n\t\t\t}\n\t\t};\n\n\t\tlet startLineNumber = range.startLineNumber;\n\n\t\twhile (startLineNumber <= range.endLineNumber) {\n\t\t\tif (this.shouldIgnoreLine(model, startLineNumber)) {\n\t\t\t\tstartLineNumber++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\tif (startLineNumber > range.endLineNumber) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet firstLineText = model.getLineContent(startLineNumber);\n\t\tif (!/\\S/.test(firstLineText.substring(0, range.startColumn - 1))) {\n\t\t\tconst indentOfFirstLine = getGoodIndentForLine(autoIndent, model, model.getLanguageId(), startLineNumber, indentConverter, this._languageConfigurationService);\n\n\t\t\tif (indentOfFirstLine !== null) {\n\t\t\t\tconst oldIndentation = strings.getLeadingWhitespace(firstLineText);\n\t\t\t\tconst newSpaceCnt = indentUtils.getSpaceCnt(indentOfFirstLine, tabSize);\n\t\t\t\tconst oldSpaceCnt = indentUtils.getSpaceCnt(oldIndentation, tabSize);\n\n\t\t\t\tif (newSpaceCnt !== oldSpaceCnt) {\n\t\t\t\t\tconst newIndent = indentUtils.generateIndent(newSpaceCnt, tabSize, insertSpaces);\n\t\t\t\t\ttextEdits.push({\n\t\t\t\t\t\trange: new Range(startLineNumber, 1, startLineNumber, oldIndentation.length + 1),\n\t\t\t\t\t\ttext: newIndent\n\t\t\t\t\t});\n\t\t\t\t\tfirstLineText = newIndent + firstLineText.substr(oldIndentation.length);\n\t\t\t\t} else {\n\t\t\t\t\tconst indentMetadata = getIndentMetadata(model, startLineNumber, this._languageConfigurationService);\n\n\t\t\t\t\tif (indentMetadata === 0 || indentMetadata === IndentConsts.UNINDENT_MASK) {\n\t\t\t\t\t\t// we paste content into a line where only contains whitespaces\n\t\t\t\t\t\t// after pasting, the indentation of the first line is already correct\n\t\t\t\t\t\t// the first line doesn't match any indentation rule\n\t\t\t\t\t\t// then no-op.\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst firstLineNumber = startLineNumber;\n\n\t\t// ignore empty or ignored lines\n\t\twhile (startLineNumber < range.endLineNumber) {\n\t\t\tif (!/\\S/.test(model.getLineContent(startLineNumber + 1))) {\n\t\t\t\tstartLineNumber++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\tif (startLineNumber !== range.endLineNumber) {\n\t\t\tconst virtualModel = {\n\t\t\t\ttokenization: {\n\t\t\t\t\tgetLineTokens: (lineNumber: number) => {\n\t\t\t\t\t\treturn model.tokenization.getLineTokens(lineNumber);\n\t\t\t\t\t},\n\t\t\t\t\tgetLanguageId: () => {\n\t\t\t\t\t\treturn model.getLanguageId();\n\t\t\t\t\t},\n\t\t\t\t\tgetLanguageIdAtPosition: (lineNumber: number, column: number) => {\n\t\t\t\t\t\treturn model.getLanguageIdAtPosition(lineNumber, column);\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tgetLineContent: (lineNumber: number) => {\n\t\t\t\t\tif (lineNumber === firstLineNumber) {\n\t\t\t\t\t\treturn firstLineText;\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn model.getLineContent(lineNumber);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t};\n\t\t\tconst indentOfSecondLine = getGoodIndentForLine(autoIndent, virtualModel, model.getLanguageId(), startLineNumber + 1, indentConverter, this._languageConfigurationService);\n\t\t\tif (indentOfSecondLine !== null) {\n\t\t\t\tconst newSpaceCntOfSecondLine = indentUtils.getSpaceCnt(indentOfSecondLine, tabSize);\n\t\t\t\tconst oldSpaceCntOfSecondLine = indentUtils.getSpaceCnt(strings.getLeadingWhitespace(model.getLineContent(startLineNumber + 1)), tabSize);\n\n\t\t\t\tif (newSpaceCntOfSecondLine !== oldSpaceCntOfSecondLine) {\n\t\t\t\t\tconst spaceCntOffset = newSpaceCntOfSecondLine - oldSpaceCntOfSecondLine;\n\t\t\t\t\tfor (let i = startLineNumber + 1; i <= range.endLineNumber; i++) {\n\t\t\t\t\t\tconst lineContent = model.getLineContent(i);\n\t\t\t\t\t\tconst originalIndent = strings.getLeadingWhitespace(lineContent);\n\t\t\t\t\t\tconst originalSpacesCnt = indentUtils.getSpaceCnt(originalIndent, tabSize);\n\t\t\t\t\t\tconst newSpacesCnt = originalSpacesCnt + spaceCntOffset;\n\t\t\t\t\t\tconst newIndent = indentUtils.generateIndent(newSpacesCnt, tabSize, insertSpaces);\n\n\t\t\t\t\t\tif (newIndent !== originalIndent) {\n\t\t\t\t\t\t\ttextEdits.push({\n\t\t\t\t\t\t\t\trange: new Range(i, 1, i, originalIndent.length + 1),\n\t\t\t\t\t\t\t\ttext: newIndent\n\t\t\t\t\t\t\t});\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}\n\n\t\tif (textEdits.length > 0) {\n\t\t\tthis.editor.pushUndoStop();\n\t\t\tconst cmd = new AutoIndentOnPasteCommand(textEdits, this.editor.getSelection()!);\n\t\t\tthis.editor.executeCommand('autoIndentOnPaste', cmd);\n\t\t\tthis.editor.pushUndoStop();\n\t\t}\n\t}\n\n\tprivate shouldIgnoreLine(model: ITextModel, lineNumber: number): boolean {\n\t\tmodel.tokenization.forceTokenization(lineNumber);\n\t\tconst nonWhitespaceColumn = model.getLineFirstNonWhitespaceColumn(lineNumber);\n\t\tif (nonWhitespaceColumn === 0) {\n\t\t\treturn true;\n\t\t}\n\t\tconst tokens = model.tokenization.getLineTokens(lineNumber);\n\t\tif (tokens.getCount() > 0) {\n\t\t\tconst firstNonWhitespaceTokenIndex = tokens.findTokenIndexAtOffset(nonWhitespaceColumn);\n\t\t\tif (firstNonWhitespaceTokenIndex >= 0 && tokens.getStandardTokenType(firstNonWhitespaceTokenIndex) === StandardTokenType.Comment) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tpublic dispose(): void {\n\t\tthis.callOnDispose.dispose();\n\t\tthis.callOnModel.dispose();\n\t}\n}\n\nfunction getIndentationEditOperations(model: ITextModel, builder: IEditOperationBuilder, tabSize: number, tabsToSpaces: boolean): void {\n\tif (model.getLineCount() === 1 && model.getLineMaxColumn(1) === 1) {\n\t\t// Model is empty\n\t\treturn;\n\t}\n\n\tlet spaces = '';\n\tfor (let i = 0; i < tabSize; i++) {\n\t\tspaces += ' ';\n\t}\n\n\tconst spacesRegExp = new RegExp(spaces, 'gi');\n\n\tfor (let lineNumber = 1, lineCount = model.getLineCount(); lineNumber <= lineCount; lineNumber++) {\n\t\tlet lastIndentationColumn = model.getLineFirstNonWhitespaceColumn(lineNumber);\n\t\tif (lastIndentationColumn === 0) {\n\t\t\tlastIndentationColumn = model.getLineMaxColumn(lineNumber);\n\t\t}\n\n\t\tif (lastIndentationColumn === 1) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst originalIndentationRange = new Range(lineNumber, 1, lineNumber, lastIndentationColumn);\n\t\tconst originalIndentation = model.getValueInRange(originalIndentationRange);\n\t\tconst newIndentation = (\n\t\t\ttabsToSpaces\n\t\t\t\t? originalIndentation.replace(/\\t/ig, spaces)\n\t\t\t\t: originalIndentation.replace(spacesRegExp, '\\t')\n\t\t);\n\n\t\tbuilder.addEditOperation(originalIndentationRange, newIndentation);\n\t}\n}\n\nexport class IndentationToSpacesCommand implements ICommand {\n\n\tprivate selectionId: string | null = null;\n\n\tconstructor(private readonly selection: Selection, private tabSize: number) { }\n\n\tpublic getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {\n\t\tthis.selectionId = builder.trackSelection(this.selection);\n\t\tgetIndentationEditOperations(model, builder, this.tabSize, true);\n\t}\n\n\tpublic computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {\n\t\treturn helper.getTrackedSelection(this.selectionId!);\n\t}\n}\n\nexport class IndentationToTabsCommand implements ICommand {\n\n\tprivate selectionId: string | null = null;\n\n\tconstructor(private readonly selection: Selection, private tabSize: number) { }\n\n\tpublic getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {\n\t\tthis.selectionId = builder.trackSelection(this.selection);\n\t\tgetIndentationEditOperations(model, builder, this.tabSize, false);\n\t}\n\n\tpublic computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {\n\t\treturn helper.getTrackedSelection(this.selectionId!);\n\t}\n}\n\nregisterEditorContribution(AutoIndentOnPaste.ID, AutoIndentOnPaste, EditorContributionInstantiation.BeforeFirstInteraction);\nregisterEditorAction(IndentationToSpacesAction);\nregisterEditorAction(IndentationToTabsAction);\nregisterEditorAction(IndentUsingTabs);\nregisterEditorAction(IndentUsingSpaces);\nregisterEditorAction(ChangeTabDisplaySize);\nregisterEditorAction(DetectIndentation);\nregisterEditorAction(ReindentLinesAction);\nregisterEditorAction(ReindentSelectedLinesAction);\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\nimport { KeyCode, KeyMod } from 'vs/base/common/keyCodes';\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\nimport { EditorAction, registerEditorAction, ServicesAccessor } from 'vs/editor/browser/editorExtensions';\nimport { CursorChangeReason } from 'vs/editor/common/cursorEvents';\nimport { CursorMoveCommands } from 'vs/editor/common/cursor/cursorMoveCommands';\nimport { EditorContextKeys } from 'vs/editor/common/editorContextKeys';\nimport * as nls from 'vs/nls';\nimport { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';\n\nexport class ExpandLineSelectionAction extends EditorAction {\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'expandLineSelection',\n\t\t\tlabel: nls.localize('expandLineSelection', \"Expand Line Selection\"),\n\t\t\talias: 'Expand Line Selection',\n\t\t\tprecondition: undefined,\n\t\t\tkbOpts: {\n\t\t\t\tweight: KeybindingWeight.EditorCore,\n\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\t\tprimary: KeyMod.CtrlCmd | KeyCode.KeyL\n\t\t\t},\n\t\t});\n\t}\n\n\tpublic run(_accessor: ServicesAccessor, editor: ICodeEditor, args: any): void {\n\t\targs = args || {};\n\t\tif (!editor.hasModel()) {\n\t\t\treturn;\n\t\t}\n\t\tconst viewModel = editor._getViewModel();\n\t\tviewModel.model.pushStackElement();\n\t\tviewModel.setCursorStates(\n\t\t\targs.source,\n\t\t\tCursorChangeReason.Explicit,\n\t\t\tCursorMoveCommands.expandLineSelection(viewModel, viewModel.getCursorStates())\n\t\t);\n\t\tviewModel.revealAllCursors(args.source, true);\n\t}\n}\n\nregisterEditorAction(ExpandLineSelectionAction);\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\nimport { KeyChord, KeyCode, KeyMod } from 'vs/base/common/keyCodes';\nimport { CoreEditingCommands } from 'vs/editor/browser/coreCommands';\nimport { IActiveCodeEditor, ICodeEditor } from 'vs/editor/browser/editorBrowser';\nimport { EditorAction, IActionOptions, registerEditorAction, ServicesAccessor } from 'vs/editor/browser/editorExtensions';\nimport { ReplaceCommand, ReplaceCommandThatPreservesSelection, ReplaceCommandThatSelectsText } from 'vs/editor/common/commands/replaceCommand';\nimport { TrimTrailingWhitespaceCommand } from 'vs/editor/common/commands/trimTrailingWhitespaceCommand';\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\nimport { TypeOperations } from 'vs/editor/common/cursor/cursorTypeOperations';\nimport { EditOperation, ISingleEditOperation } from 'vs/editor/common/core/editOperation';\nimport { Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\nimport { Selection } from 'vs/editor/common/core/selection';\nimport { ICommand } from 'vs/editor/common/editorCommon';\nimport { EditorContextKeys } from 'vs/editor/common/editorContextKeys';\nimport { ITextModel } from 'vs/editor/common/model';\nimport { CopyLinesCommand } from 'vs/editor/contrib/linesOperations/browser/copyLinesCommand';\nimport { MoveLinesCommand } from 'vs/editor/contrib/linesOperations/browser/moveLinesCommand';\nimport { SortLinesCommand } from 'vs/editor/contrib/linesOperations/browser/sortLinesCommand';\nimport * as nls from 'vs/nls';\nimport { MenuId } from 'vs/platform/actions/common/actions';\nimport { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';\nimport { ILanguageConfigurationService } from 'vs/editor/common/languages/languageConfigurationRegistry';\nimport { IConfigurationService } from 'vs/platform/configuration/common/configuration';\n\n// copy lines\n\nabstract class AbstractCopyLinesAction extends EditorAction {\n\n\tprivate readonly down: boolean;\n\n\tconstructor(down: boolean, opts: IActionOptions) {\n\t\tsuper(opts);\n\t\tthis.down = down;\n\t}\n\n\tpublic run(_accessor: ServicesAccessor, editor: ICodeEditor): void {\n\t\tif (!editor.hasModel()) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst selections = editor.getSelections().map((selection, index) => ({ selection, index, ignore: false }));\n\t\tselections.sort((a, b) => Range.compareRangesUsingStarts(a.selection, b.selection));\n\n\t\t// Remove selections that would result in copying the same line\n\t\tlet prev = selections[0];\n\t\tfor (let i = 1; i < selections.length; i++) {\n\t\t\tconst curr = selections[i];\n\t\t\tif (prev.selection.endLineNumber === curr.selection.startLineNumber) {\n\t\t\t\t// these two selections would copy the same line\n\t\t\t\tif (prev.index < curr.index) {\n\t\t\t\t\t// prev wins\n\t\t\t\t\tcurr.ignore = true;\n\t\t\t\t} else {\n\t\t\t\t\t// curr wins\n\t\t\t\t\tprev.ignore = true;\n\t\t\t\t\tprev = curr;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst commands: ICommand[] = [];\n\t\tfor (const selection of selections) {\n\t\t\tcommands.push(new CopyLinesCommand(selection.selection, this.down, selection.ignore));\n\t\t}\n\n\t\teditor.pushUndoStop();\n\t\teditor.executeCommands(this.id, commands);\n\t\teditor.pushUndoStop();\n\t}\n}\n\nclass CopyLinesUpAction extends AbstractCopyLinesAction {\n\tconstructor() {\n\t\tsuper(false, {\n\t\t\tid: 'editor.action.copyLinesUpAction',\n\t\t\tlabel: nls.localize('lines.copyUp', \"Copy Line Up\"),\n\t\t\talias: 'Copy Line Up',\n\t\t\tprecondition: EditorContextKeys.writable,\n\t\t\tkbOpts: {\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\n\t\t\t\tprimary: KeyMod.Alt | KeyMod.Shift | KeyCode.UpArrow,\n\t\t\t\tlinux: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyMod.Shift | KeyCode.UpArrow },\n\t\t\t\tweight: KeybindingWeight.EditorContrib\n\t\t\t},\n\t\t\tmenuOpts: {\n\t\t\t\tmenuId: MenuId.MenubarSelectionMenu,\n\t\t\t\tgroup: '2_line',\n\t\t\t\ttitle: nls.localize({ key: 'miCopyLinesUp', comment: ['&& denotes a mnemonic'] }, \"&&Copy Line Up\"),\n\t\t\t\torder: 1\n\t\t\t}\n\t\t});\n\t}\n}\n\nclass CopyLinesDownAction extends AbstractCopyLinesAction {\n\tconstructor() {\n\t\tsuper(true, {\n\t\t\tid: 'editor.action.copyLinesDownAction',\n\t\t\tlabel: nls.localize('lines.copyDown', \"Copy Line Down\"),\n\t\t\talias: 'Copy Line Down',\n\t\t\tprecondition: EditorContextKeys.writable,\n\t\t\tkbOpts: {\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\n\t\t\t\tprimary: KeyMod.Alt | KeyMod.Shift | KeyCode.DownArrow,\n\t\t\t\tlinux: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyMod.Shift | KeyCode.DownArrow },\n\t\t\t\tweight: KeybindingWeight.EditorContrib\n\t\t\t},\n\t\t\tmenuOpts: {\n\t\t\t\tmenuId: MenuId.MenubarSelectionMenu,\n\t\t\t\tgroup: '2_line',\n\t\t\t\ttitle: nls.localize({ key: 'miCopyLinesDown', comment: ['&& denotes a mnemonic'] }, \"Co&&py Line Down\"),\n\t\t\t\torder: 2\n\t\t\t}\n\t\t});\n\t}\n}\n\nexport class DuplicateSelectionAction extends EditorAction {\n\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'editor.action.duplicateSelection',\n\t\t\tlabel: nls.localize('duplicateSelection', \"Duplicate Selection\"),\n\t\t\talias: 'Duplicate Selection',\n\t\t\tprecondition: EditorContextKeys.writable,\n\t\t\tmenuOpts: {\n\t\t\t\tmenuId: MenuId.MenubarSelectionMenu,\n\t\t\t\tgroup: '2_line',\n\t\t\t\ttitle: nls.localize({ key: 'miDuplicateSelection', comment: ['&& denotes a mnemonic'] }, \"&&Duplicate Selection\"),\n\t\t\t\torder: 5\n\t\t\t}\n\t\t});\n\t}\n\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void {\n\t\tif (!editor.hasModel()) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst commands: ICommand[] = [];\n\t\tconst selections = editor.getSelections();\n\t\tconst model = editor.getModel();\n\n\t\tfor (const selection of selections) {\n\t\t\tif (selection.isEmpty()) {\n\t\t\t\tcommands.push(new CopyLinesCommand(selection, true));\n\t\t\t} else {\n\t\t\t\tconst insertSelection = new Selection(selection.endLineNumber, selection.endColumn, selection.endLineNumber, selection.endColumn);\n\t\t\t\tcommands.push(new ReplaceCommandThatSelectsText(insertSelection, model.getValueInRange(selection)));\n\t\t\t}\n\t\t}\n\n\t\teditor.pushUndoStop();\n\t\teditor.executeCommands(this.id, commands);\n\t\teditor.pushUndoStop();\n\t}\n}\n\n// move lines\n\nabstract class AbstractMoveLinesAction extends EditorAction {\n\n\tprivate readonly down: boolean;\n\n\tconstructor(down: boolean, opts: IActionOptions) {\n\t\tsuper(opts);\n\t\tthis.down = down;\n\t}\n\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor): void {\n\t\tconst languageConfigurationService = accessor.get(ILanguageConfigurationService);\n\n\t\tconst commands: ICommand[] = [];\n\t\tconst selections = editor.getSelections() || [];\n\t\tconst autoIndent = editor.getOption(EditorOption.autoIndent);\n\n\t\tfor (const selection of selections) {\n\t\t\tcommands.push(new MoveLinesCommand(selection, this.down, autoIndent, languageConfigurationService));\n\t\t}\n\n\t\teditor.pushUndoStop();\n\t\teditor.executeCommands(this.id, commands);\n\t\teditor.pushUndoStop();\n\t}\n}\n\nclass MoveLinesUpAction extends AbstractMoveLinesAction {\n\tconstructor() {\n\t\tsuper(false, {\n\t\t\tid: 'editor.action.moveLinesUpAction',\n\t\t\tlabel: nls.localize('lines.moveUp', \"Move Line Up\"),\n\t\t\talias: 'Move Line Up',\n\t\t\tprecondition: EditorContextKeys.writable,\n\t\t\tkbOpts: {\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\n\t\t\t\tprimary: KeyMod.Alt | KeyCode.UpArrow,\n\t\t\t\tlinux: { primary: KeyMod.Alt | KeyCode.UpArrow },\n\t\t\t\tweight: KeybindingWeight.EditorContrib\n\t\t\t},\n\t\t\tmenuOpts: {\n\t\t\t\tmenuId: MenuId.MenubarSelectionMenu,\n\t\t\t\tgroup: '2_line',\n\t\t\t\ttitle: nls.localize({ key: 'miMoveLinesUp', comment: ['&& denotes a mnemonic'] }, \"Mo&&ve Line Up\"),\n\t\t\t\torder: 3\n\t\t\t}\n\t\t});\n\t}\n}\n\nclass MoveLinesDownAction extends AbstractMoveLinesAction {\n\tconstructor() {\n\t\tsuper(true, {\n\t\t\tid: 'editor.action.moveLinesDownAction',\n\t\t\tlabel: nls.localize('lines.moveDown', \"Move Line Down\"),\n\t\t\talias: 'Move Line Down',\n\t\t\tprecondition: EditorContextKeys.writable,\n\t\t\tkbOpts: {\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\n\t\t\t\tprimary: KeyMod.Alt | KeyCode.DownArrow,\n\t\t\t\tlinux: { primary: KeyMod.Alt | KeyCode.DownArrow },\n\t\t\t\tweight: KeybindingWeight.EditorContrib\n\t\t\t},\n\t\t\tmenuOpts: {\n\t\t\t\tmenuId: MenuId.MenubarSelectionMenu,\n\t\t\t\tgroup: '2_line',\n\t\t\t\ttitle: nls.localize({ key: 'miMoveLinesDown', comment: ['&& denotes a mnemonic'] }, \"Move &&Line Down\"),\n\t\t\t\torder: 4\n\t\t\t}\n\t\t});\n\t}\n}\n\nexport abstract class AbstractSortLinesAction extends EditorAction {\n\tprivate readonly descending: boolean;\n\n\tconstructor(descending: boolean, opts: IActionOptions) {\n\t\tsuper(opts);\n\t\tthis.descending = descending;\n\t}\n\n\tpublic run(_accessor: ServicesAccessor, editor: ICodeEditor): void {\n\t\tif (!editor.hasModel()) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst model = editor.getModel();\n\t\tlet selections = editor.getSelections();\n\t\tif (selections.length === 1 && selections[0].isEmpty()) {\n\t\t\t// Apply to whole document.\n\t\t\tselections = [new Selection(1, 1, model.getLineCount(), model.getLineMaxColumn(model.getLineCount()))];\n\t\t}\n\n\t\tfor (const selection of selections) {\n\t\t\tif (!SortLinesCommand.canRun(editor.getModel(), selection, this.descending)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tconst commands: ICommand[] = [];\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\n\t\t\tcommands[i] = new SortLinesCommand(selections[i], this.descending);\n\t\t}\n\n\t\teditor.pushUndoStop();\n\t\teditor.executeCommands(this.id, commands);\n\t\teditor.pushUndoStop();\n\t}\n}\n\nexport class SortLinesAscendingAction extends AbstractSortLinesAction {\n\tconstructor() {\n\t\tsuper(false, {\n\t\t\tid: 'editor.action.sortLinesAscending',\n\t\t\tlabel: nls.localize('lines.sortAscending', \"Sort Lines Ascending\"),\n\t\t\talias: 'Sort Lines Ascending',\n\t\t\tprecondition: EditorContextKeys.writable\n\t\t});\n\t}\n}\n\nexport class SortLinesDescendingAction extends AbstractSortLinesAction {\n\tconstructor() {\n\t\tsuper(true, {\n\t\t\tid: 'editor.action.sortLinesDescending',\n\t\t\tlabel: nls.localize('lines.sortDescending', \"Sort Lines Descending\"),\n\t\t\talias: 'Sort Lines Descending',\n\t\t\tprecondition: EditorContextKeys.writable\n\t\t});\n\t}\n}\n\nexport class DeleteDuplicateLinesAction extends EditorAction {\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'editor.action.removeDuplicateLines',\n\t\t\tlabel: nls.localize('lines.deleteDuplicates', \"Delete Duplicate Lines\"),\n\t\t\talias: 'Delete Duplicate Lines',\n\t\t\tprecondition: EditorContextKeys.writable\n\t\t});\n\t}\n\n\tpublic run(_accessor: ServicesAccessor, editor: ICodeEditor): void {\n\t\tif (!editor.hasModel()) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst model: ITextModel = editor.getModel();\n\t\tif (model.getLineCount() === 1 && model.getLineMaxColumn(1) === 1) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst edits: ISingleEditOperation[] = [];\n\t\tconst endCursorState: Selection[] = [];\n\n\t\tlet linesDeleted = 0;\n\t\tlet updateSelection = true;\n\n\t\tlet selections = editor.getSelections();\n\t\tif (selections.length === 1 && selections[0].isEmpty()) {\n\t\t\t// Apply to whole document.\n\t\t\tselections = [new Selection(1, 1, model.getLineCount(), model.getLineMaxColumn(model.getLineCount()))];\n\t\t\tupdateSelection = false;\n\t\t}\n\n\t\tfor (const selection of selections) {\n\t\t\tconst uniqueLines = new Set();\n\t\t\tconst lines = [];\n\n\t\t\tfor (let i = selection.startLineNumber; i <= selection.endLineNumber; i++) {\n\t\t\t\tconst line = model.getLineContent(i);\n\n\t\t\t\tif (uniqueLines.has(line)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tlines.push(line);\n\t\t\t\tuniqueLines.add(line);\n\t\t\t}\n\n\n\t\t\tconst selectionToReplace = new Selection(\n\t\t\t\tselection.startLineNumber,\n\t\t\t\t1,\n\t\t\t\tselection.endLineNumber,\n\t\t\t\tmodel.getLineMaxColumn(selection.endLineNumber)\n\t\t\t);\n\n\t\t\tconst adjustedSelectionStart = selection.startLineNumber - linesDeleted;\n\t\t\tconst finalSelection = new Selection(\n\t\t\t\tadjustedSelectionStart,\n\t\t\t\t1,\n\t\t\t\tadjustedSelectionStart + lines.length - 1,\n\t\t\t\tlines[lines.length - 1].length\n\t\t\t);\n\n\t\t\tedits.push(EditOperation.replace(selectionToReplace, lines.join('\\n')));\n\t\t\tendCursorState.push(finalSelection);\n\n\t\t\tlinesDeleted += (selection.endLineNumber - selection.startLineNumber + 1) - lines.length;\n\t\t}\n\n\t\teditor.pushUndoStop();\n\t\teditor.executeEdits(this.id, edits, updateSelection ? endCursorState : undefined);\n\t\teditor.pushUndoStop();\n\t}\n}\n\nexport class TrimTrailingWhitespaceAction extends EditorAction {\n\n\tpublic static readonly ID = 'editor.action.trimTrailingWhitespace';\n\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: TrimTrailingWhitespaceAction.ID,\n\t\t\tlabel: nls.localize('lines.trimTrailingWhitespace', \"Trim Trailing Whitespace\"),\n\t\t\talias: 'Trim Trailing Whitespace',\n\t\t\tprecondition: EditorContextKeys.writable,\n\t\t\tkbOpts: {\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\n\t\t\t\tprimary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyMod.CtrlCmd | KeyCode.KeyX),\n\t\t\t\tweight: KeybindingWeight.EditorContrib\n\t\t\t}\n\t\t});\n\t}\n\n\tpublic run(_accessor: ServicesAccessor, editor: ICodeEditor, args: any): void {\n\n\t\tlet cursors: Position[] = [];\n\t\tif (args.reason === 'auto-save') {\n\t\t\t// See https://github.com/editorconfig/editorconfig-vscode/issues/47\n\t\t\t// It is very convenient for the editor config extension to invoke this action.\n\t\t\t// So, if we get a reason:'auto-save' passed in, let's preserve cursor positions.\n\t\t\tcursors = (editor.getSelections() || []).map(s => new Position(s.positionLineNumber, s.positionColumn));\n\t\t}\n\n\t\tconst selection = editor.getSelection();\n\t\tif (selection === null) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst config = _accessor.get(IConfigurationService);\n\t\tconst model = editor.getModel();\n\t\tconst trimInRegexAndStrings = config.getValue('files.trimTrailingWhitespaceInRegexAndStrings', { overrideIdentifier: model?.getLanguageId(), resource: model?.uri });\n\n\t\tconst command = new TrimTrailingWhitespaceCommand(selection, cursors, trimInRegexAndStrings);\n\n\t\teditor.pushUndoStop();\n\t\teditor.executeCommands(this.id, [command]);\n\t\teditor.pushUndoStop();\n\t}\n}\n\n// delete lines\n\ninterface IDeleteLinesOperation {\n\tstartLineNumber: number;\n\tendLineNumber: number;\n\tpositionColumn: number;\n}\n\nexport class DeleteLinesAction extends EditorAction {\n\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'editor.action.deleteLines',\n\t\t\tlabel: nls.localize('lines.delete', \"Delete Line\"),\n\t\t\talias: 'Delete Line',\n\t\t\tprecondition: EditorContextKeys.writable,\n\t\t\tkbOpts: {\n\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\t\tprimary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KeyK,\n\t\t\t\tweight: KeybindingWeight.EditorContrib\n\t\t\t}\n\t\t});\n\t}\n\n\tpublic run(_accessor: ServicesAccessor, editor: ICodeEditor): void {\n\t\tif (!editor.hasModel()) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst ops = this._getLinesToRemove(editor);\n\n\t\tconst model: ITextModel = editor.getModel();\n\t\tif (model.getLineCount() === 1 && model.getLineMaxColumn(1) === 1) {\n\t\t\t// Model is empty\n\t\t\treturn;\n\t\t}\n\n\t\tlet linesDeleted = 0;\n\t\tconst edits: ISingleEditOperation[] = [];\n\t\tconst cursorState: Selection[] = [];\n\t\tfor (let i = 0, len = ops.length; i < len; i++) {\n\t\t\tconst op = ops[i];\n\n\t\t\tlet startLineNumber = op.startLineNumber;\n\t\t\tlet endLineNumber = op.endLineNumber;\n\n\t\t\tlet startColumn = 1;\n\t\t\tlet endColumn = model.getLineMaxColumn(endLineNumber);\n\t\t\tif (endLineNumber < model.getLineCount()) {\n\t\t\t\tendLineNumber += 1;\n\t\t\t\tendColumn = 1;\n\t\t\t} else if (startLineNumber > 1) {\n\t\t\t\tstartLineNumber -= 1;\n\t\t\t\tstartColumn = model.getLineMaxColumn(startLineNumber);\n\t\t\t}\n\n\t\t\tedits.push(EditOperation.replace(new Selection(startLineNumber, startColumn, endLineNumber, endColumn), ''));\n\t\t\tcursorState.push(new Selection(startLineNumber - linesDeleted, op.positionColumn, startLineNumber - linesDeleted, op.positionColumn));\n\t\t\tlinesDeleted += (op.endLineNumber - op.startLineNumber + 1);\n\t\t}\n\n\t\teditor.pushUndoStop();\n\t\teditor.executeEdits(this.id, edits, cursorState);\n\t\teditor.pushUndoStop();\n\t}\n\n\tprivate _getLinesToRemove(editor: IActiveCodeEditor): IDeleteLinesOperation[] {\n\t\t// Construct delete operations\n\t\tconst operations: IDeleteLinesOperation[] = editor.getSelections().map((s) => {\n\n\t\t\tlet endLineNumber = s.endLineNumber;\n\t\t\tif (s.startLineNumber < s.endLineNumber && s.endColumn === 1) {\n\t\t\t\tendLineNumber -= 1;\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tstartLineNumber: s.startLineNumber,\n\t\t\t\tselectionStartColumn: s.selectionStartColumn,\n\t\t\t\tendLineNumber: endLineNumber,\n\t\t\t\tpositionColumn: s.positionColumn\n\t\t\t};\n\t\t});\n\n\t\t// Sort delete operations\n\t\toperations.sort((a, b) => {\n\t\t\tif (a.startLineNumber === b.startLineNumber) {\n\t\t\t\treturn a.endLineNumber - b.endLineNumber;\n\t\t\t}\n\t\t\treturn a.startLineNumber - b.startLineNumber;\n\t\t});\n\n\t\t// Merge delete operations which are adjacent or overlapping\n\t\tconst mergedOperations: IDeleteLinesOperation[] = [];\n\t\tlet previousOperation = operations[0];\n\t\tfor (let i = 1; i < operations.length; i++) {\n\t\t\tif (previousOperation.endLineNumber + 1 >= operations[i].startLineNumber) {\n\t\t\t\t// Merge current operations into the previous one\n\t\t\t\tpreviousOperation.endLineNumber = operations[i].endLineNumber;\n\t\t\t} else {\n\t\t\t\t// Push previous operation\n\t\t\t\tmergedOperations.push(previousOperation);\n\t\t\t\tpreviousOperation = operations[i];\n\t\t\t}\n\t\t}\n\t\t// Push the last operation\n\t\tmergedOperations.push(previousOperation);\n\n\t\treturn mergedOperations;\n\t}\n}\n\nexport class IndentLinesAction extends EditorAction {\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'editor.action.indentLines',\n\t\t\tlabel: nls.localize('lines.indent', \"Indent Line\"),\n\t\t\talias: 'Indent Line',\n\t\t\tprecondition: EditorContextKeys.writable,\n\t\t\tkbOpts: {\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\n\t\t\t\tprimary: KeyMod.CtrlCmd | KeyCode.BracketRight,\n\t\t\t\tweight: KeybindingWeight.EditorContrib\n\t\t\t}\n\t\t});\n\t}\n\n\tpublic run(_accessor: ServicesAccessor, editor: ICodeEditor): void {\n\t\tconst viewModel = editor._getViewModel();\n\t\tif (!viewModel) {\n\t\t\treturn;\n\t\t}\n\t\teditor.pushUndoStop();\n\t\teditor.executeCommands(this.id, TypeOperations.indent(viewModel.cursorConfig, editor.getModel(), editor.getSelections()));\n\t\teditor.pushUndoStop();\n\t}\n}\n\nclass OutdentLinesAction extends EditorAction {\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'editor.action.outdentLines',\n\t\t\tlabel: nls.localize('lines.outdent', \"Outdent Line\"),\n\t\t\talias: 'Outdent Line',\n\t\t\tprecondition: EditorContextKeys.writable,\n\t\t\tkbOpts: {\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\n\t\t\t\tprimary: KeyMod.CtrlCmd | KeyCode.BracketLeft,\n\t\t\t\tweight: KeybindingWeight.EditorContrib\n\t\t\t}\n\t\t});\n\t}\n\n\tpublic run(_accessor: ServicesAccessor, editor: ICodeEditor): void {\n\t\tCoreEditingCommands.Outdent.runEditorCommand(_accessor, editor, null);\n\t}\n}\n\nexport class InsertLineBeforeAction extends EditorAction {\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'editor.action.insertLineBefore',\n\t\t\tlabel: nls.localize('lines.insertBefore', \"Insert Line Above\"),\n\t\t\talias: 'Insert Line Above',\n\t\t\tprecondition: EditorContextKeys.writable,\n\t\t\tkbOpts: {\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\n\t\t\t\tprimary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.Enter,\n\t\t\t\tweight: KeybindingWeight.EditorContrib\n\t\t\t}\n\t\t});\n\t}\n\n\tpublic run(_accessor: ServicesAccessor, editor: ICodeEditor): void {\n\t\tconst viewModel = editor._getViewModel();\n\t\tif (!viewModel) {\n\t\t\treturn;\n\t\t}\n\t\teditor.pushUndoStop();\n\t\teditor.executeCommands(this.id, TypeOperations.lineInsertBefore(viewModel.cursorConfig, editor.getModel(), editor.getSelections()));\n\t}\n}\n\nexport class InsertLineAfterAction extends EditorAction {\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'editor.action.insertLineAfter',\n\t\t\tlabel: nls.localize('lines.insertAfter', \"Insert Line Below\"),\n\t\t\talias: 'Insert Line Below',\n\t\t\tprecondition: EditorContextKeys.writable,\n\t\t\tkbOpts: {\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\n\t\t\t\tprimary: KeyMod.CtrlCmd | KeyCode.Enter,\n\t\t\t\tweight: KeybindingWeight.EditorContrib\n\t\t\t}\n\t\t});\n\t}\n\n\tpublic run(_accessor: ServicesAccessor, editor: ICodeEditor): void {\n\t\tconst viewModel = editor._getViewModel();\n\t\tif (!viewModel) {\n\t\t\treturn;\n\t\t}\n\t\teditor.pushUndoStop();\n\t\teditor.executeCommands(this.id, TypeOperations.lineInsertAfter(viewModel.cursorConfig, editor.getModel(), editor.getSelections()));\n\t}\n}\n\nexport abstract class AbstractDeleteAllToBoundaryAction extends EditorAction {\n\tpublic run(_accessor: ServicesAccessor, editor: ICodeEditor): void {\n\t\tif (!editor.hasModel()) {\n\t\t\treturn;\n\t\t}\n\t\tconst primaryCursor = editor.getSelection();\n\n\t\tconst rangesToDelete = this._getRangesToDelete(editor);\n\t\t// merge overlapping selections\n\t\tconst effectiveRanges: Range[] = [];\n\n\t\tfor (let i = 0, count = rangesToDelete.length - 1; i < count; i++) {\n\t\t\tconst range = rangesToDelete[i];\n\t\t\tconst nextRange = rangesToDelete[i + 1];\n\n\t\t\tif (Range.intersectRanges(range, nextRange) === null) {\n\t\t\t\teffectiveRanges.push(range);\n\t\t\t} else {\n\t\t\t\trangesToDelete[i + 1] = Range.plusRange(range, nextRange);\n\t\t\t}\n\t\t}\n\n\t\teffectiveRanges.push(rangesToDelete[rangesToDelete.length - 1]);\n\n\t\tconst endCursorState = this._getEndCursorState(primaryCursor, effectiveRanges);\n\n\t\tconst edits: ISingleEditOperation[] = effectiveRanges.map(range => {\n\t\t\treturn EditOperation.replace(range, '');\n\t\t});\n\n\t\teditor.pushUndoStop();\n\t\teditor.executeEdits(this.id, edits, endCursorState);\n\t\teditor.pushUndoStop();\n\t}\n\n\t/**\n\t * Compute the cursor state after the edit operations were applied.\n\t */\n\tprotected abstract _getEndCursorState(primaryCursor: Range, rangesToDelete: Range[]): Selection[];\n\n\tprotected abstract _getRangesToDelete(editor: IActiveCodeEditor): Range[];\n}\n\nexport class DeleteAllLeftAction extends AbstractDeleteAllToBoundaryAction {\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'deleteAllLeft',\n\t\t\tlabel: nls.localize('lines.deleteAllLeft', \"Delete All Left\"),\n\t\t\talias: 'Delete All Left',\n\t\t\tprecondition: EditorContextKeys.writable,\n\t\t\tkbOpts: {\n\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\t\tprimary: 0,\n\t\t\t\tmac: { primary: KeyMod.CtrlCmd | KeyCode.Backspace },\n\t\t\t\tweight: KeybindingWeight.EditorContrib\n\t\t\t}\n\t\t});\n\t}\n\n\tprotected _getEndCursorState(primaryCursor: Range, rangesToDelete: Range[]): Selection[] {\n\t\tlet endPrimaryCursor: Selection | null = null;\n\t\tconst endCursorState: Selection[] = [];\n\t\tlet deletedLines = 0;\n\n\t\trangesToDelete.forEach(range => {\n\t\t\tlet endCursor;\n\t\t\tif (range.endColumn === 1 && deletedLines > 0) {\n\t\t\t\tconst newStartLine = range.startLineNumber - deletedLines;\n\t\t\t\tendCursor = new Selection(newStartLine, range.startColumn, newStartLine, range.startColumn);\n\t\t\t} else {\n\t\t\t\tendCursor = new Selection(range.startLineNumber, range.startColumn, range.startLineNumber, range.startColumn);\n\t\t\t}\n\n\t\t\tdeletedLines += range.endLineNumber - range.startLineNumber;\n\n\t\t\tif (range.intersectRanges(primaryCursor)) {\n\t\t\t\tendPrimaryCursor = endCursor;\n\t\t\t} else {\n\t\t\t\tendCursorState.push(endCursor);\n\t\t\t}\n\t\t});\n\n\t\tif (endPrimaryCursor) {\n\t\t\tendCursorState.unshift(endPrimaryCursor);\n\t\t}\n\n\t\treturn endCursorState;\n\t}\n\n\tprotected _getRangesToDelete(editor: IActiveCodeEditor): Range[] {\n\t\tconst selections = editor.getSelections();\n\t\tif (selections === null) {\n\t\t\treturn [];\n\t\t}\n\n\t\tlet rangesToDelete: Range[] = selections;\n\t\tconst model = editor.getModel();\n\n\t\tif (model === null) {\n\t\t\treturn [];\n\t\t}\n\n\t\trangesToDelete.sort(Range.compareRangesUsingStarts);\n\t\trangesToDelete = rangesToDelete.map(selection => {\n\t\t\tif (selection.isEmpty()) {\n\t\t\t\tif (selection.startColumn === 1) {\n\t\t\t\t\tconst deleteFromLine = Math.max(1, selection.startLineNumber - 1);\n\t\t\t\t\tconst deleteFromColumn = selection.startLineNumber === 1 ? 1 : model.getLineLength(deleteFromLine) + 1;\n\t\t\t\t\treturn new Range(deleteFromLine, deleteFromColumn, selection.startLineNumber, 1);\n\t\t\t\t} else {\n\t\t\t\t\treturn new Range(selection.startLineNumber, 1, selection.startLineNumber, selection.startColumn);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturn new Range(selection.startLineNumber, 1, selection.endLineNumber, selection.endColumn);\n\t\t\t}\n\t\t});\n\n\t\treturn rangesToDelete;\n\t}\n}\n\nexport class DeleteAllRightAction extends AbstractDeleteAllToBoundaryAction {\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'deleteAllRight',\n\t\t\tlabel: nls.localize('lines.deleteAllRight', \"Delete All Right\"),\n\t\t\talias: 'Delete All Right',\n\t\t\tprecondition: EditorContextKeys.writable,\n\t\t\tkbOpts: {\n\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\t\tprimary: 0,\n\t\t\t\tmac: { primary: KeyMod.WinCtrl | KeyCode.KeyK, secondary: [KeyMod.CtrlCmd | KeyCode.Delete] },\n\t\t\t\tweight: KeybindingWeight.EditorContrib\n\t\t\t}\n\t\t});\n\t}\n\n\tprotected _getEndCursorState(primaryCursor: Range, rangesToDelete: Range[]): Selection[] {\n\t\tlet endPrimaryCursor: Selection | null = null;\n\t\tconst endCursorState: Selection[] = [];\n\t\tfor (let i = 0, len = rangesToDelete.length, offset = 0; i < len; i++) {\n\t\t\tconst range = rangesToDelete[i];\n\t\t\tconst endCursor = new Selection(range.startLineNumber - offset, range.startColumn, range.startLineNumber - offset, range.startColumn);\n\n\t\t\tif (range.intersectRanges(primaryCursor)) {\n\t\t\t\tendPrimaryCursor = endCursor;\n\t\t\t} else {\n\t\t\t\tendCursorState.push(endCursor);\n\t\t\t}\n\t\t}\n\n\t\tif (endPrimaryCursor) {\n\t\t\tendCursorState.unshift(endPrimaryCursor);\n\t\t}\n\n\t\treturn endCursorState;\n\t}\n\n\tprotected _getRangesToDelete(editor: IActiveCodeEditor): Range[] {\n\t\tconst model = editor.getModel();\n\t\tif (model === null) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst selections = editor.getSelections();\n\n\t\tif (selections === null) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst rangesToDelete: Range[] = selections.map((sel) => {\n\t\t\tif (sel.isEmpty()) {\n\t\t\t\tconst maxColumn = model.getLineMaxColumn(sel.startLineNumber);\n\n\t\t\t\tif (sel.startColumn === maxColumn) {\n\t\t\t\t\treturn new Range(sel.startLineNumber, sel.startColumn, sel.startLineNumber + 1, 1);\n\t\t\t\t} else {\n\t\t\t\t\treturn new Range(sel.startLineNumber, sel.startColumn, sel.startLineNumber, maxColumn);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn sel;\n\t\t});\n\n\t\trangesToDelete.sort(Range.compareRangesUsingStarts);\n\t\treturn rangesToDelete;\n\t}\n}\n\nexport class JoinLinesAction extends EditorAction {\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'editor.action.joinLines',\n\t\t\tlabel: nls.localize('lines.joinLines', \"Join Lines\"),\n\t\t\talias: 'Join Lines',\n\t\t\tprecondition: EditorContextKeys.writable,\n\t\t\tkbOpts: {\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\n\t\t\t\tprimary: 0,\n\t\t\t\tmac: { primary: KeyMod.WinCtrl | KeyCode.KeyJ },\n\t\t\t\tweight: KeybindingWeight.EditorContrib\n\t\t\t}\n\t\t});\n\t}\n\n\tpublic run(_accessor: ServicesAccessor, editor: ICodeEditor): void {\n\t\tconst selections = editor.getSelections();\n\t\tif (selections === null) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet primaryCursor = editor.getSelection();\n\t\tif (primaryCursor === null) {\n\t\t\treturn;\n\t\t}\n\n\t\tselections.sort(Range.compareRangesUsingStarts);\n\t\tconst reducedSelections: Selection[] = [];\n\n\t\tconst lastSelection = selections.reduce((previousValue, currentValue) => {\n\t\t\tif (previousValue.isEmpty()) {\n\t\t\t\tif (previousValue.endLineNumber === currentValue.startLineNumber) {\n\t\t\t\t\tif (primaryCursor!.equalsSelection(previousValue)) {\n\t\t\t\t\t\tprimaryCursor = currentValue;\n\t\t\t\t\t}\n\t\t\t\t\treturn currentValue;\n\t\t\t\t}\n\n\t\t\t\tif (currentValue.startLineNumber > previousValue.endLineNumber + 1) {\n\t\t\t\t\treducedSelections.push(previousValue);\n\t\t\t\t\treturn currentValue;\n\t\t\t\t} else {\n\t\t\t\t\treturn new Selection(previousValue.startLineNumber, previousValue.startColumn, currentValue.endLineNumber, currentValue.endColumn);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (currentValue.startLineNumber > previousValue.endLineNumber) {\n\t\t\t\t\treducedSelections.push(previousValue);\n\t\t\t\t\treturn currentValue;\n\t\t\t\t} else {\n\t\t\t\t\treturn new Selection(previousValue.startLineNumber, previousValue.startColumn, currentValue.endLineNumber, currentValue.endColumn);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\treducedSelections.push(lastSelection);\n\n\t\tconst model = editor.getModel();\n\t\tif (model === null) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst edits: ISingleEditOperation[] = [];\n\t\tconst endCursorState: Selection[] = [];\n\t\tlet endPrimaryCursor = primaryCursor;\n\t\tlet lineOffset = 0;\n\n\t\tfor (let i = 0, len = reducedSelections.length; i < len; i++) {\n\t\t\tconst selection = reducedSelections[i];\n\t\t\tconst startLineNumber = selection.startLineNumber;\n\t\t\tconst startColumn = 1;\n\t\t\tlet columnDeltaOffset = 0;\n\t\t\tlet endLineNumber: number,\n\t\t\t\tendColumn: number;\n\n\t\t\tconst selectionEndPositionOffset = model.getLineLength(selection.endLineNumber) - selection.endColumn;\n\n\t\t\tif (selection.isEmpty() || selection.startLineNumber === selection.endLineNumber) {\n\t\t\t\tconst position = selection.getStartPosition();\n\t\t\t\tif (position.lineNumber < model.getLineCount()) {\n\t\t\t\t\tendLineNumber = startLineNumber + 1;\n\t\t\t\t\tendColumn = model.getLineMaxColumn(endLineNumber);\n\t\t\t\t} else {\n\t\t\t\t\tendLineNumber = position.lineNumber;\n\t\t\t\t\tendColumn = model.getLineMaxColumn(position.lineNumber);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tendLineNumber = selection.endLineNumber;\n\t\t\t\tendColumn = model.getLineMaxColumn(endLineNumber);\n\t\t\t}\n\n\t\t\tlet trimmedLinesContent = model.getLineContent(startLineNumber);\n\n\t\t\tfor (let i = startLineNumber + 1; i <= endLineNumber; i++) {\n\t\t\t\tconst lineText = model.getLineContent(i);\n\t\t\t\tconst firstNonWhitespaceIdx = model.getLineFirstNonWhitespaceColumn(i);\n\n\t\t\t\tif (firstNonWhitespaceIdx >= 1) {\n\t\t\t\t\tlet insertSpace = true;\n\t\t\t\t\tif (trimmedLinesContent === '') {\n\t\t\t\t\t\tinsertSpace = false;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (insertSpace && (trimmedLinesContent.charAt(trimmedLinesContent.length - 1) === ' ' ||\n\t\t\t\t\t\ttrimmedLinesContent.charAt(trimmedLinesContent.length - 1) === '\\t')) {\n\t\t\t\t\t\tinsertSpace = false;\n\t\t\t\t\t\ttrimmedLinesContent = trimmedLinesContent.replace(/[\\s\\uFEFF\\xA0]+$/g, ' ');\n\t\t\t\t\t}\n\n\t\t\t\t\tconst lineTextWithoutIndent = lineText.substr(firstNonWhitespaceIdx - 1);\n\n\t\t\t\t\ttrimmedLinesContent += (insertSpace ? ' ' : '') + lineTextWithoutIndent;\n\n\t\t\t\t\tif (insertSpace) {\n\t\t\t\t\t\tcolumnDeltaOffset = lineTextWithoutIndent.length + 1;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tcolumnDeltaOffset = lineTextWithoutIndent.length;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tcolumnDeltaOffset = 0;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst deleteSelection = new Range(startLineNumber, startColumn, endLineNumber, endColumn);\n\n\t\t\tif (!deleteSelection.isEmpty()) {\n\t\t\t\tlet resultSelection: Selection;\n\n\t\t\t\tif (selection.isEmpty()) {\n\t\t\t\t\tedits.push(EditOperation.replace(deleteSelection, trimmedLinesContent));\n\t\t\t\t\tresultSelection = new Selection(deleteSelection.startLineNumber - lineOffset, trimmedLinesContent.length - columnDeltaOffset + 1, startLineNumber - lineOffset, trimmedLinesContent.length - columnDeltaOffset + 1);\n\t\t\t\t} else {\n\t\t\t\t\tif (selection.startLineNumber === selection.endLineNumber) {\n\t\t\t\t\t\tedits.push(EditOperation.replace(deleteSelection, trimmedLinesContent));\n\t\t\t\t\t\tresultSelection = new Selection(selection.startLineNumber - lineOffset, selection.startColumn,\n\t\t\t\t\t\t\tselection.endLineNumber - lineOffset, selection.endColumn);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tedits.push(EditOperation.replace(deleteSelection, trimmedLinesContent));\n\t\t\t\t\t\tresultSelection = new Selection(selection.startLineNumber - lineOffset, selection.startColumn,\n\t\t\t\t\t\t\tselection.startLineNumber - lineOffset, trimmedLinesContent.length - selectionEndPositionOffset);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (Range.intersectRanges(deleteSelection, primaryCursor) !== null) {\n\t\t\t\t\tendPrimaryCursor = resultSelection;\n\t\t\t\t} else {\n\t\t\t\t\tendCursorState.push(resultSelection);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlineOffset += deleteSelection.endLineNumber - deleteSelection.startLineNumber;\n\t\t}\n\n\t\tendCursorState.unshift(endPrimaryCursor);\n\t\teditor.pushUndoStop();\n\t\teditor.executeEdits(this.id, edits, endCursorState);\n\t\teditor.pushUndoStop();\n\t}\n}\n\nexport class TransposeAction extends EditorAction {\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'editor.action.transpose',\n\t\t\tlabel: nls.localize('editor.transpose', \"Transpose Characters around the Cursor\"),\n\t\t\talias: 'Transpose Characters around the Cursor',\n\t\t\tprecondition: EditorContextKeys.writable\n\t\t});\n\t}\n\n\tpublic run(_accessor: ServicesAccessor, editor: ICodeEditor): void {\n\t\tconst selections = editor.getSelections();\n\t\tif (selections === null) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst model = editor.getModel();\n\t\tif (model === null) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst commands: ICommand[] = [];\n\n\t\tfor (let i = 0, len = selections.length; i < len; i++) {\n\t\t\tconst selection = selections[i];\n\n\t\t\tif (!selection.isEmpty()) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst cursor = selection.getStartPosition();\n\t\t\tconst maxColumn = model.getLineMaxColumn(cursor.lineNumber);\n\n\t\t\tif (cursor.column >= maxColumn) {\n\t\t\t\tif (cursor.lineNumber === model.getLineCount()) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t// The cursor is at the end of current line and current line is not empty\n\t\t\t\t// then we transpose the character before the cursor and the line break if there is any following line.\n\t\t\t\tconst deleteSelection = new Range(cursor.lineNumber, Math.max(1, cursor.column - 1), cursor.lineNumber + 1, 1);\n\t\t\t\tconst chars = model.getValueInRange(deleteSelection).split('').reverse().join('');\n\n\t\t\t\tcommands.push(new ReplaceCommand(new Selection(cursor.lineNumber, Math.max(1, cursor.column - 1), cursor.lineNumber + 1, 1), chars));\n\t\t\t} else {\n\t\t\t\tconst deleteSelection = new Range(cursor.lineNumber, Math.max(1, cursor.column - 1), cursor.lineNumber, cursor.column + 1);\n\t\t\t\tconst chars = model.getValueInRange(deleteSelection).split('').reverse().join('');\n\t\t\t\tcommands.push(new ReplaceCommandThatPreservesSelection(deleteSelection, chars,\n\t\t\t\t\tnew Selection(cursor.lineNumber, cursor.column + 1, cursor.lineNumber, cursor.column + 1)));\n\t\t\t}\n\t\t}\n\n\t\teditor.pushUndoStop();\n\t\teditor.executeCommands(this.id, commands);\n\t\teditor.pushUndoStop();\n\t}\n}\n\nexport abstract class AbstractCaseAction extends EditorAction {\n\tpublic run(_accessor: ServicesAccessor, editor: ICodeEditor): void {\n\t\tconst selections = editor.getSelections();\n\t\tif (selections === null) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst model = editor.getModel();\n\t\tif (model === null) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst wordSeparators = editor.getOption(EditorOption.wordSeparators);\n\t\tconst textEdits: ISingleEditOperation[] = [];\n\n\t\tfor (const selection of selections) {\n\t\t\tif (selection.isEmpty()) {\n\t\t\t\tconst cursor = selection.getStartPosition();\n\t\t\t\tconst word = editor.getConfiguredWordAtPosition(cursor);\n\n\t\t\t\tif (!word) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst wordRange = new Range(cursor.lineNumber, word.startColumn, cursor.lineNumber, word.endColumn);\n\t\t\t\tconst text = model.getValueInRange(wordRange);\n\t\t\t\ttextEdits.push(EditOperation.replace(wordRange, this._modifyText(text, wordSeparators)));\n\t\t\t} else {\n\t\t\t\tconst text = model.getValueInRange(selection);\n\t\t\t\ttextEdits.push(EditOperation.replace(selection, this._modifyText(text, wordSeparators)));\n\t\t\t}\n\t\t}\n\n\t\teditor.pushUndoStop();\n\t\teditor.executeEdits(this.id, textEdits);\n\t\teditor.pushUndoStop();\n\t}\n\n\tprotected abstract _modifyText(text: string, wordSeparators: string): string;\n}\n\nexport class UpperCaseAction extends AbstractCaseAction {\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'editor.action.transformToUppercase',\n\t\t\tlabel: nls.localize('editor.transformToUppercase', \"Transform to Uppercase\"),\n\t\t\talias: 'Transform to Uppercase',\n\t\t\tprecondition: EditorContextKeys.writable\n\t\t});\n\t}\n\n\tprotected _modifyText(text: string, wordSeparators: string): string {\n\t\treturn text.toLocaleUpperCase();\n\t}\n}\n\nexport class LowerCaseAction extends AbstractCaseAction {\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'editor.action.transformToLowercase',\n\t\t\tlabel: nls.localize('editor.transformToLowercase', \"Transform to Lowercase\"),\n\t\t\talias: 'Transform to Lowercase',\n\t\t\tprecondition: EditorContextKeys.writable\n\t\t});\n\t}\n\n\tprotected _modifyText(text: string, wordSeparators: string): string {\n\t\treturn text.toLocaleLowerCase();\n\t}\n}\n\nclass BackwardsCompatibleRegExp {\n\n\tprivate _actual: RegExp | null;\n\tprivate _evaluated: boolean;\n\n\tconstructor(\n\t\tprivate readonly _pattern: string,\n\t\tprivate readonly _flags: string\n\t) {\n\t\tthis._actual = null;\n\t\tthis._evaluated = false;\n\t}\n\n\tpublic get(): RegExp | null {\n\t\tif (!this._evaluated) {\n\t\t\tthis._evaluated = true;\n\t\t\ttry {\n\t\t\t\tthis._actual = new RegExp(this._pattern, this._flags);\n\t\t\t} catch (err) {\n\t\t\t\t// this browser does not support this regular expression\n\t\t\t}\n\t\t}\n\t\treturn this._actual;\n\t}\n\n\tpublic isSupported(): boolean {\n\t\treturn (this.get() !== null);\n\t}\n}\n\nexport class TitleCaseAction extends AbstractCaseAction {\n\n\tpublic static titleBoundary = new BackwardsCompatibleRegExp('(^|[^\\\\p{L}\\\\p{N}\\']|((^|\\\\P{L})\\'))\\\\p{L}', 'gmu');\n\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'editor.action.transformToTitlecase',\n\t\t\tlabel: nls.localize('editor.transformToTitlecase', \"Transform to Title Case\"),\n\t\t\talias: 'Transform to Title Case',\n\t\t\tprecondition: EditorContextKeys.writable\n\t\t});\n\t}\n\n\tprotected _modifyText(text: string, wordSeparators: string): string {\n\t\tconst titleBoundary = TitleCaseAction.titleBoundary.get();\n\t\tif (!titleBoundary) {\n\t\t\t// cannot support this\n\t\t\treturn text;\n\t\t}\n\t\treturn text\n\t\t\t.toLocaleLowerCase()\n\t\t\t.replace(titleBoundary, (b) => b.toLocaleUpperCase());\n\t}\n}\n\nexport class SnakeCaseAction extends AbstractCaseAction {\n\n\tpublic static caseBoundary = new BackwardsCompatibleRegExp('(\\\\p{Ll})(\\\\p{Lu})', 'gmu');\n\tpublic static singleLetters = new BackwardsCompatibleRegExp('(\\\\p{Lu}|\\\\p{N})(\\\\p{Lu})(\\\\p{Ll})', 'gmu');\n\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'editor.action.transformToSnakecase',\n\t\t\tlabel: nls.localize('editor.transformToSnakecase', \"Transform to Snake Case\"),\n\t\t\talias: 'Transform to Snake Case',\n\t\t\tprecondition: EditorContextKeys.writable\n\t\t});\n\t}\n\n\tprotected _modifyText(text: string, wordSeparators: string): string {\n\t\tconst caseBoundary = SnakeCaseAction.caseBoundary.get();\n\t\tconst singleLetters = SnakeCaseAction.singleLetters.get();\n\t\tif (!caseBoundary || !singleLetters) {\n\t\t\t// cannot support this\n\t\t\treturn text;\n\t\t}\n\t\treturn (text\n\t\t\t.replace(caseBoundary, '$1_$2')\n\t\t\t.replace(singleLetters, '$1_$2$3')\n\t\t\t.toLocaleLowerCase()\n\t\t);\n\t}\n}\n\nexport class CamelCaseAction extends AbstractCaseAction {\n\tpublic static wordBoundary = new BackwardsCompatibleRegExp('[_\\\\s-]', 'gm');\n\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'editor.action.transformToCamelcase',\n\t\t\tlabel: nls.localize('editor.transformToCamelcase', \"Transform to Camel Case\"),\n\t\t\talias: 'Transform to Camel Case',\n\t\t\tprecondition: EditorContextKeys.writable\n\t\t});\n\t}\n\n\tprotected _modifyText(text: string, wordSeparators: string): string {\n\t\tconst wordBoundary = CamelCaseAction.wordBoundary.get();\n\t\tif (!wordBoundary) {\n\t\t\t// cannot support this\n\t\t\treturn text;\n\t\t}\n\t\tconst words = text.split(wordBoundary);\n\t\tconst firstWord = words.shift();\n\t\treturn firstWord + words.map((word: string) => word.substring(0, 1).toLocaleUpperCase() + word.substring(1))\n\t\t\t.join('');\n\t}\n}\n\nexport class PascalCaseAction extends AbstractCaseAction {\n\tpublic static wordBoundary = new BackwardsCompatibleRegExp('[_\\\\s-]', 'gm');\n\tpublic static wordBoundaryToMaintain = new BackwardsCompatibleRegExp('(?<=\\\\.)', 'gm');\n\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'editor.action.transformToPascalcase',\n\t\t\tlabel: nls.localize('editor.transformToPascalcase', \"Transform to Pascal Case\"),\n\t\t\talias: 'Transform to Pascal Case',\n\t\t\tprecondition: EditorContextKeys.writable\n\t\t});\n\t}\n\n\tprotected _modifyText(text: string, wordSeparators: string): string {\n\t\tconst wordBoundary = PascalCaseAction.wordBoundary.get();\n\t\tconst wordBoundaryToMaintain = PascalCaseAction.wordBoundaryToMaintain.get();\n\n\t\tif (!wordBoundary || !wordBoundaryToMaintain) {\n\t\t\t// cannot support this\n\t\t\treturn text;\n\t\t}\n\n\t\tconst wordsWithMaintainBoundaries = text.split(wordBoundaryToMaintain);\n\t\tconst words = wordsWithMaintainBoundaries.map((word: string) => word.split(wordBoundary)).flat();\n\t\treturn words.map((word: string) => word.substring(0, 1).toLocaleUpperCase() + word.substring(1))\n\t\t\t.join('');\n\t}\n}\n\nexport class KebabCaseAction extends AbstractCaseAction {\n\n\tpublic static isSupported(): boolean {\n\t\tconst areAllRegexpsSupported = [\n\t\t\tthis.caseBoundary,\n\t\t\tthis.singleLetters,\n\t\t\tthis.underscoreBoundary,\n\t\t].every((regexp) => regexp.isSupported());\n\n\t\treturn areAllRegexpsSupported;\n\t}\n\n\tprivate static caseBoundary = new BackwardsCompatibleRegExp('(\\\\p{Ll})(\\\\p{Lu})', 'gmu');\n\tprivate static singleLetters = new BackwardsCompatibleRegExp('(\\\\p{Lu}|\\\\p{N})(\\\\p{Lu}\\\\p{Ll})', 'gmu');\n\tprivate static underscoreBoundary = new BackwardsCompatibleRegExp('(\\\\S)(_)(\\\\S)', 'gm');\n\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'editor.action.transformToKebabcase',\n\t\t\tlabel: nls.localize('editor.transformToKebabcase', 'Transform to Kebab Case'),\n\t\t\talias: 'Transform to Kebab Case',\n\t\t\tprecondition: EditorContextKeys.writable\n\t\t});\n\t}\n\n\tprotected _modifyText(text: string, _: string): string {\n\t\tconst caseBoundary = KebabCaseAction.caseBoundary.get();\n\t\tconst singleLetters = KebabCaseAction.singleLetters.get();\n\t\tconst underscoreBoundary = KebabCaseAction.underscoreBoundary.get();\n\n\t\tif (!caseBoundary || !singleLetters || !underscoreBoundary) {\n\t\t\t// one or more regexps aren't supported\n\t\t\treturn text;\n\t\t}\n\n\t\treturn text\n\t\t\t.replace(underscoreBoundary, '$1-$3')\n\t\t\t.replace(caseBoundary, '$1-$2')\n\t\t\t.replace(singleLetters, '$1-$2')\n\t\t\t.toLocaleLowerCase();\n\t}\n}\n\nregisterEditorAction(CopyLinesUpAction);\nregisterEditorAction(CopyLinesDownAction);\nregisterEditorAction(DuplicateSelectionAction);\nregisterEditorAction(MoveLinesUpAction);\nregisterEditorAction(MoveLinesDownAction);\nregisterEditorAction(SortLinesAscendingAction);\nregisterEditorAction(SortLinesDescendingAction);\nregisterEditorAction(DeleteDuplicateLinesAction);\nregisterEditorAction(TrimTrailingWhitespaceAction);\nregisterEditorAction(DeleteLinesAction);\nregisterEditorAction(IndentLinesAction);\nregisterEditorAction(OutdentLinesAction);\nregisterEditorAction(InsertLineBeforeAction);\nregisterEditorAction(InsertLineAfterAction);\nregisterEditorAction(DeleteAllLeftAction);\nregisterEditorAction(DeleteAllRightAction);\nregisterEditorAction(JoinLinesAction);\nregisterEditorAction(TransposeAction);\nregisterEditorAction(UpperCaseAction);\nregisterEditorAction(LowerCaseAction);\n\nif (SnakeCaseAction.caseBoundary.isSupported() && SnakeCaseAction.singleLetters.isSupported()) {\n\tregisterEditorAction(SnakeCaseAction);\n}\nif (CamelCaseAction.wordBoundary.isSupported()) {\n\tregisterEditorAction(CamelCaseAction);\n}\nif (PascalCaseAction.wordBoundary.isSupported()) {\n\tregisterEditorAction(PascalCaseAction);\n}\nif (TitleCaseAction.titleBoundary.isSupported()) {\n\tregisterEditorAction(TitleCaseAction);\n}\n\nif (KebabCaseAction.isSupported()) {\n\tregisterEditorAction(KebabCaseAction);\n}\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\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport { ICodeEditor, MouseTargetType } from 'vs/editor/browser/editorBrowser';\nimport { EditorContributionInstantiation, registerEditorContribution } from 'vs/editor/browser/editorExtensions';\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\nimport { IEditorContribution } from 'vs/editor/common/editorCommon';\n\nclass LongLinesHelper extends Disposable implements IEditorContribution {\n\tpublic static readonly ID = 'editor.contrib.longLinesHelper';\n\n\tconstructor(\n\t\tprivate readonly _editor: ICodeEditor,\n\t) {\n\t\tsuper();\n\n\t\tthis._register(this._editor.onMouseDown((e) => {\n\t\t\tconst stopRenderingLineAfter = this._editor.getOption(EditorOption.stopRenderingLineAfter);\n\t\t\tif (stopRenderingLineAfter >= 0 && e.target.type === MouseTargetType.CONTENT_TEXT && e.target.position.column >= stopRenderingLineAfter) {\n\t\t\t\tthis._editor.updateOptions({\n\t\t\t\t\tstopRenderingLineAfter: -1\n\t\t\t\t});\n\t\t\t}\n\t\t}));\n\t}\n}\n\nregisterEditorContribution(LongLinesHelper.ID, LongLinesHelper, EditorContributionInstantiation.BeforeFirstInteraction);\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\nimport { renderMarkdown } from 'vs/base/browser/markdownRenderer';\nimport { alert } from 'vs/base/browser/ui/aria/aria';\nimport { Event } from 'vs/base/common/event';\nimport { IMarkdownString, isMarkdownString } from 'vs/base/common/htmlContent';\nimport { KeyCode } from 'vs/base/common/keyCodes';\nimport { DisposableStore, IDisposable, MutableDisposable } from 'vs/base/common/lifecycle';\nimport 'vs/css!./messageController';\nimport { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser';\nimport { EditorCommand, EditorContributionInstantiation, registerEditorCommand, registerEditorContribution } from 'vs/editor/browser/editorExtensions';\nimport { IPosition } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\nimport { IEditorContribution, ScrollType } from 'vs/editor/common/editorCommon';\nimport { PositionAffinity } from 'vs/editor/common/model';\nimport { openLinkFromMarkdown } from 'vs/editor/browser/widget/markdownRenderer/browser/markdownRenderer';\nimport * as nls from 'vs/nls';\nimport { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';\nimport { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';\nimport { IOpenerService } from 'vs/platform/opener/common/opener';\nimport * as dom from 'vs/base/browser/dom';\n\nexport class MessageController implements IEditorContribution {\n\n\tpublic static readonly ID = 'editor.contrib.messageController';\n\n\tstatic readonly MESSAGE_VISIBLE = new RawContextKey('messageVisible', false, nls.localize('messageVisible', 'Whether the editor is currently showing an inline message'));\n\n\tstatic get(editor: ICodeEditor): MessageController | null {\n\t\treturn editor.getContribution(MessageController.ID);\n\t}\n\n\tprivate readonly _editor: ICodeEditor;\n\tprivate readonly _visible: IContextKey;\n\tprivate readonly _messageWidget = new MutableDisposable();\n\tprivate readonly _messageListeners = new DisposableStore();\n\tprivate _message: { element: HTMLElement; dispose: () => void } | undefined;\n\tprivate _mouseOverMessage: boolean = false;\n\n\tconstructor(\n\t\teditor: ICodeEditor,\n\t\t@IContextKeyService contextKeyService: IContextKeyService,\n\t\t@IOpenerService private readonly _openerService: IOpenerService\n\t) {\n\n\t\tthis._editor = editor;\n\t\tthis._visible = MessageController.MESSAGE_VISIBLE.bindTo(contextKeyService);\n\t}\n\n\tdispose(): void {\n\t\tthis._message?.dispose();\n\t\tthis._messageListeners.dispose();\n\t\tthis._messageWidget.dispose();\n\t\tthis._visible.reset();\n\t}\n\n\tshowMessage(message: IMarkdownString | string, position: IPosition): void {\n\n\t\talert(isMarkdownString(message) ? message.value : message);\n\n\t\tthis._visible.set(true);\n\t\tthis._messageWidget.clear();\n\t\tthis._messageListeners.clear();\n\t\tthis._message = isMarkdownString(message) ? renderMarkdown(message, {\n\t\t\tactionHandler: {\n\t\t\t\tcallback: (url) => {\n\t\t\t\t\tthis.closeMessage();\n\t\t\t\t\topenLinkFromMarkdown(this._openerService, url, isMarkdownString(message) ? message.isTrusted : undefined);\n\t\t\t\t},\n\t\t\t\tdisposables: this._messageListeners\n\t\t\t},\n\t\t}) : undefined;\n\t\tthis._messageWidget.value = new MessageWidget(this._editor, position, typeof message === 'string' ? message : this._message!.element);\n\n\t\t// close on blur (debounced to allow to tab into the message), cursor, model change, dispose\n\t\tthis._messageListeners.add(Event.debounce(this._editor.onDidBlurEditorText, (last, event) => event, 0)(() => {\n\t\t\tif (this._mouseOverMessage) {\n\t\t\t\treturn; // override when mouse over message\n\t\t\t}\n\n\t\t\tif (this._messageWidget.value && dom.isAncestor(dom.getActiveElement(), this._messageWidget.value.getDomNode())) {\n\t\t\t\treturn; // override when focus is inside the message\n\t\t\t}\n\n\t\t\tthis.closeMessage();\n\t\t}\n\t\t));\n\t\tthis._messageListeners.add(this._editor.onDidChangeCursorPosition(() => this.closeMessage()));\n\t\tthis._messageListeners.add(this._editor.onDidDispose(() => this.closeMessage()));\n\t\tthis._messageListeners.add(this._editor.onDidChangeModel(() => this.closeMessage()));\n\t\tthis._messageListeners.add(dom.addDisposableListener(this._messageWidget.value.getDomNode(), dom.EventType.MOUSE_ENTER, () => this._mouseOverMessage = true, true));\n\t\tthis._messageListeners.add(dom.addDisposableListener(this._messageWidget.value.getDomNode(), dom.EventType.MOUSE_LEAVE, () => this._mouseOverMessage = false, true));\n\n\t\t// close on mouse move\n\t\tlet bounds: Range;\n\t\tthis._messageListeners.add(this._editor.onMouseMove(e => {\n\t\t\t// outside the text area\n\t\t\tif (!e.target.position) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (!bounds) {\n\t\t\t\t// define bounding box around position and first mouse occurance\n\t\t\t\tbounds = new Range(position.lineNumber - 3, 1, e.target.position.lineNumber + 3, 1);\n\t\t\t} else if (!bounds.containsPosition(e.target.position)) {\n\t\t\t\t// check if position is still in bounds\n\t\t\t\tthis.closeMessage();\n\t\t\t}\n\t\t}));\n\t}\n\n\tcloseMessage(): void {\n\t\tthis._visible.reset();\n\t\tthis._messageListeners.clear();\n\t\tif (this._messageWidget.value) {\n\t\t\tthis._messageListeners.add(MessageWidget.fadeOut(this._messageWidget.value));\n\t\t}\n\t}\n}\n\nconst MessageCommand = EditorCommand.bindToContribution(MessageController.get);\n\n\nregisterEditorCommand(new MessageCommand({\n\tid: 'leaveEditorMessage',\n\tprecondition: MessageController.MESSAGE_VISIBLE,\n\thandler: c => c.closeMessage(),\n\tkbOpts: {\n\t\tweight: KeybindingWeight.EditorContrib + 30,\n\t\tprimary: KeyCode.Escape\n\t}\n}));\n\nclass MessageWidget implements IContentWidget {\n\n\t// Editor.IContentWidget.allowEditorOverflow\n\treadonly allowEditorOverflow = true;\n\treadonly suppressMouseDown = false;\n\n\tprivate readonly _editor: ICodeEditor;\n\tprivate readonly _position: IPosition;\n\tprivate readonly _domNode: HTMLDivElement;\n\n\tstatic fadeOut(messageWidget: MessageWidget): IDisposable {\n\t\tconst dispose = () => {\n\t\t\tmessageWidget.dispose();\n\t\t\tclearTimeout(handle);\n\t\t\tmessageWidget.getDomNode().removeEventListener('animationend', dispose);\n\t\t};\n\t\tconst handle = setTimeout(dispose, 110);\n\t\tmessageWidget.getDomNode().addEventListener('animationend', dispose);\n\t\tmessageWidget.getDomNode().classList.add('fadeOut');\n\t\treturn { dispose };\n\t}\n\n\tconstructor(editor: ICodeEditor, { lineNumber, column }: IPosition, text: HTMLElement | string) {\n\n\t\tthis._editor = editor;\n\t\tthis._editor.revealLinesInCenterIfOutsideViewport(lineNumber, lineNumber, ScrollType.Smooth);\n\t\tthis._position = { lineNumber, column };\n\n\t\tthis._domNode = document.createElement('div');\n\t\tthis._domNode.classList.add('monaco-editor-overlaymessage');\n\t\tthis._domNode.style.marginLeft = '-6px';\n\n\t\tconst anchorTop = document.createElement('div');\n\t\tanchorTop.classList.add('anchor', 'top');\n\t\tthis._domNode.appendChild(anchorTop);\n\n\t\tconst message = document.createElement('div');\n\t\tif (typeof text === 'string') {\n\t\t\tmessage.classList.add('message');\n\t\t\tmessage.textContent = text;\n\t\t} else {\n\t\t\ttext.classList.add('message');\n\t\t\tmessage.appendChild(text);\n\t\t}\n\t\tthis._domNode.appendChild(message);\n\n\t\tconst anchorBottom = document.createElement('div');\n\t\tanchorBottom.classList.add('anchor', 'below');\n\t\tthis._domNode.appendChild(anchorBottom);\n\n\t\tthis._editor.addContentWidget(this);\n\t\tthis._domNode.classList.add('fadeIn');\n\t}\n\n\tdispose() {\n\t\tthis._editor.removeContentWidget(this);\n\t}\n\n\tgetId(): string {\n\t\treturn 'messageoverlay';\n\t}\n\n\tgetDomNode(): HTMLElement {\n\t\treturn this._domNode;\n\t}\n\n\tgetPosition(): IContentWidgetPosition {\n\t\treturn {\n\t\t\tposition: this._position,\n\t\t\tpreference: [\n\t\t\t\tContentWidgetPositionPreference.ABOVE,\n\t\t\t\tContentWidgetPositionPreference.BELOW,\n\t\t\t],\n\t\t\tpositionAffinity: PositionAffinity.Right,\n\t\t};\n\t}\n\n\tafterRender(position: ContentWidgetPositionPreference | null): void {\n\t\tthis._domNode.classList.toggle('below', position === ContentWidgetPositionPreference.BELOW);\n\t}\n\n}\n\nregisterEditorContribution(MessageController.ID, MessageController, EditorContributionInstantiation.Lazy);\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\nimport { MarkdownString } from 'vs/base/common/htmlContent';\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\nimport { EditorContributionInstantiation, registerEditorContribution } from 'vs/editor/browser/editorExtensions';\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\nimport { IEditorContribution } from 'vs/editor/common/editorCommon';\nimport { MessageController } from 'vs/editor/contrib/message/browser/messageController';\nimport * as nls from 'vs/nls';\n\nexport class ReadOnlyMessageController extends Disposable implements IEditorContribution {\n\n\tpublic static readonly ID = 'editor.contrib.readOnlyMessageController';\n\n\tconstructor(\n\t\tprivate readonly editor: ICodeEditor\n\t) {\n\t\tsuper();\n\t\tthis._register(this.editor.onDidAttemptReadOnlyEdit(() => this._onDidAttemptReadOnlyEdit()));\n\t}\n\n\tprivate _onDidAttemptReadOnlyEdit(): void {\n\t\tconst messageController = MessageController.get(this.editor);\n\t\tif (messageController && this.editor.hasModel()) {\n\t\t\tlet message = this.editor.getOptions().get(EditorOption.readOnlyMessage);\n\t\t\tif (!message) {\n\t\t\t\tif (this.editor.isSimpleWidget) {\n\t\t\t\t\tmessage = new MarkdownString(nls.localize('editor.simple.readonly', \"Cannot edit in read-only input\"));\n\t\t\t\t} else {\n\t\t\t\t\tmessage = new MarkdownString(nls.localize('editor.readonly', \"Cannot edit in read-only editor\"));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tmessageController.showMessage(message, this.editor.getPosition());\n\t\t}\n\t}\n}\n\nregisterEditorContribution(ReadOnlyMessageController.ID, ReadOnlyMessageController, EditorContributionInstantiation.BeforeFirstInteraction);\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\nimport * as arrays from 'vs/base/common/arrays';\nimport { CancellationToken } from 'vs/base/common/cancellation';\nimport { onUnexpectedExternalError } from 'vs/base/common/errors';\nimport { KeyCode, KeyMod } from 'vs/base/common/keyCodes';\nimport { IDisposable } from 'vs/base/common/lifecycle';\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\nimport { EditorAction, EditorContributionInstantiation, IActionOptions, registerEditorAction, registerEditorContribution, ServicesAccessor } from 'vs/editor/browser/editorExtensions';\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\nimport { Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\nimport { Selection } from 'vs/editor/common/core/selection';\nimport { IEditorContribution } from 'vs/editor/common/editorCommon';\nimport { EditorContextKeys } from 'vs/editor/common/editorContextKeys';\nimport { ITextModel } from 'vs/editor/common/model';\nimport * as languages from 'vs/editor/common/languages';\nimport { BracketSelectionRangeProvider } from 'vs/editor/contrib/smartSelect/browser/bracketSelections';\nimport { WordSelectionRangeProvider } from 'vs/editor/contrib/smartSelect/browser/wordSelections';\nimport * as nls from 'vs/nls';\nimport { MenuId } from 'vs/platform/actions/common/actions';\nimport { CommandsRegistry } from 'vs/platform/commands/common/commands';\nimport { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';\nimport { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';\nimport { LanguageFeatureRegistry } from 'vs/editor/common/languageFeatureRegistry';\nimport { ITextModelService } from 'vs/editor/common/services/resolverService';\nimport { assertType } from 'vs/base/common/types';\nimport { URI } from 'vs/base/common/uri';\n\nclass SelectionRanges {\n\n\tconstructor(\n\t\treadonly index: number,\n\t\treadonly ranges: Range[]\n\t) { }\n\n\tmov(fwd: boolean): SelectionRanges {\n\t\tconst index = this.index + (fwd ? 1 : -1);\n\t\tif (index < 0 || index >= this.ranges.length) {\n\t\t\treturn this;\n\t\t}\n\t\tconst res = new SelectionRanges(index, this.ranges);\n\t\tif (res.ranges[index].equalsRange(this.ranges[this.index])) {\n\t\t\t// next range equals this range, retry with next-next\n\t\t\treturn res.mov(fwd);\n\t\t}\n\t\treturn res;\n\t}\n}\n\nexport class SmartSelectController implements IEditorContribution {\n\n\tstatic readonly ID = 'editor.contrib.smartSelectController';\n\n\tstatic get(editor: ICodeEditor): SmartSelectController | null {\n\t\treturn editor.getContribution(SmartSelectController.ID);\n\t}\n\n\tprivate _state?: SelectionRanges[];\n\tprivate _selectionListener?: IDisposable;\n\tprivate _ignoreSelection: boolean = false;\n\n\tconstructor(\n\t\tprivate readonly _editor: ICodeEditor,\n\t\t@ILanguageFeaturesService private readonly _languageFeaturesService: ILanguageFeaturesService,\n\t) { }\n\n\tdispose(): void {\n\t\tthis._selectionListener?.dispose();\n\t}\n\n\tasync run(forward: boolean): Promise {\n\t\tif (!this._editor.hasModel()) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst selections = this._editor.getSelections();\n\t\tconst model = this._editor.getModel();\n\n\t\tif (!this._state) {\n\n\t\t\tawait provideSelectionRanges(this._languageFeaturesService.selectionRangeProvider, model, selections.map(s => s.getPosition()), this._editor.getOption(EditorOption.smartSelect), CancellationToken.None).then(ranges => {\n\t\t\t\tif (!arrays.isNonEmptyArray(ranges) || ranges.length !== selections.length) {\n\t\t\t\t\t// invalid result\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (!this._editor.hasModel() || !arrays.equals(this._editor.getSelections(), selections, (a, b) => a.equalsSelection(b))) {\n\t\t\t\t\t// invalid editor state\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tfor (let i = 0; i < ranges.length; i++) {\n\t\t\t\t\tranges[i] = ranges[i].filter(range => {\n\t\t\t\t\t\t// filter ranges inside the selection\n\t\t\t\t\t\treturn range.containsPosition(selections[i].getStartPosition()) && range.containsPosition(selections[i].getEndPosition());\n\t\t\t\t\t});\n\t\t\t\t\t// prepend current selection\n\t\t\t\t\tranges[i].unshift(selections[i]);\n\t\t\t\t}\n\n\n\t\t\t\tthis._state = ranges.map(ranges => new SelectionRanges(0, ranges));\n\n\t\t\t\t// listen to caret move and forget about state\n\t\t\t\tthis._selectionListener?.dispose();\n\t\t\t\tthis._selectionListener = this._editor.onDidChangeCursorPosition(() => {\n\t\t\t\t\tif (!this._ignoreSelection) {\n\t\t\t\t\t\tthis._selectionListener?.dispose();\n\t\t\t\t\t\tthis._state = undefined;\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\n\t\tif (!this._state) {\n\t\t\t// no state\n\t\t\treturn;\n\t\t}\n\t\tthis._state = this._state.map(state => state.mov(forward));\n\t\tconst newSelections = this._state.map(state => Selection.fromPositions(state.ranges[state.index].getStartPosition(), state.ranges[state.index].getEndPosition()));\n\t\tthis._ignoreSelection = true;\n\t\ttry {\n\t\t\tthis._editor.setSelections(newSelections);\n\t\t} finally {\n\t\t\tthis._ignoreSelection = false;\n\t\t}\n\t}\n}\n\nabstract class AbstractSmartSelect extends EditorAction {\n\n\tprivate readonly _forward: boolean;\n\n\tconstructor(forward: boolean, opts: IActionOptions) {\n\t\tsuper(opts);\n\t\tthis._forward = forward;\n\t}\n\n\tasync run(_accessor: ServicesAccessor, editor: ICodeEditor): Promise {\n\t\tconst controller = SmartSelectController.get(editor);\n\t\tif (controller) {\n\t\t\tawait controller.run(this._forward);\n\t\t}\n\t}\n}\n\nclass GrowSelectionAction extends AbstractSmartSelect {\n\tconstructor() {\n\t\tsuper(true, {\n\t\t\tid: 'editor.action.smartSelect.expand',\n\t\t\tlabel: nls.localize('smartSelect.expand', \"Expand Selection\"),\n\t\t\talias: 'Expand Selection',\n\t\t\tprecondition: undefined,\n\t\t\tkbOpts: {\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\n\t\t\t\tprimary: KeyMod.Shift | KeyMod.Alt | KeyCode.RightArrow,\n\t\t\t\tmac: {\n\t\t\t\t\tprimary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyMod.Shift | KeyCode.RightArrow,\n\t\t\t\t\tsecondary: [KeyMod.WinCtrl | KeyMod.Shift | KeyCode.RightArrow],\n\t\t\t\t},\n\t\t\t\tweight: KeybindingWeight.EditorContrib\n\t\t\t},\n\t\t\tmenuOpts: {\n\t\t\t\tmenuId: MenuId.MenubarSelectionMenu,\n\t\t\t\tgroup: '1_basic',\n\t\t\t\ttitle: nls.localize({ key: 'miSmartSelectGrow', comment: ['&& denotes a mnemonic'] }, \"&&Expand Selection\"),\n\t\t\t\torder: 2\n\t\t\t}\n\t\t});\n\t}\n}\n\n// renamed command id\nCommandsRegistry.registerCommandAlias('editor.action.smartSelect.grow', 'editor.action.smartSelect.expand');\n\nclass ShrinkSelectionAction extends AbstractSmartSelect {\n\tconstructor() {\n\t\tsuper(false, {\n\t\t\tid: 'editor.action.smartSelect.shrink',\n\t\t\tlabel: nls.localize('smartSelect.shrink', \"Shrink Selection\"),\n\t\t\talias: 'Shrink Selection',\n\t\t\tprecondition: undefined,\n\t\t\tkbOpts: {\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\n\t\t\t\tprimary: KeyMod.Shift | KeyMod.Alt | KeyCode.LeftArrow,\n\t\t\t\tmac: {\n\t\t\t\t\tprimary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyMod.Shift | KeyCode.LeftArrow,\n\t\t\t\t\tsecondary: [KeyMod.WinCtrl | KeyMod.Shift | KeyCode.LeftArrow],\n\t\t\t\t},\n\t\t\t\tweight: KeybindingWeight.EditorContrib\n\t\t\t},\n\t\t\tmenuOpts: {\n\t\t\t\tmenuId: MenuId.MenubarSelectionMenu,\n\t\t\t\tgroup: '1_basic',\n\t\t\t\ttitle: nls.localize({ key: 'miSmartSelectShrink', comment: ['&& denotes a mnemonic'] }, \"&&Shrink Selection\"),\n\t\t\t\torder: 3\n\t\t\t}\n\t\t});\n\t}\n}\n\nregisterEditorContribution(SmartSelectController.ID, SmartSelectController, EditorContributionInstantiation.Lazy);\nregisterEditorAction(GrowSelectionAction);\nregisterEditorAction(ShrinkSelectionAction);\n\nexport interface SelectionRangesOptions {\n\tselectLeadingAndTrailingWhitespace: boolean;\n\tselectSubwords: boolean;\n}\n\nexport async function provideSelectionRanges(registry: LanguageFeatureRegistry, model: ITextModel, positions: Position[], options: SelectionRangesOptions, token: CancellationToken): Promise {\n\n\tconst providers = registry.all(model)\n\t\t.concat(new WordSelectionRangeProvider(options.selectSubwords)); // ALWAYS have word based selection range\n\n\tif (providers.length === 1) {\n\t\t// add word selection and bracket selection when no provider exists\n\t\tproviders.unshift(new BracketSelectionRangeProvider());\n\t}\n\n\tconst work: Promise[] = [];\n\tconst allRawRanges: Range[][] = [];\n\n\tfor (const provider of providers) {\n\n\t\twork.push(Promise.resolve(provider.provideSelectionRanges(model, positions, token)).then(allProviderRanges => {\n\t\t\tif (arrays.isNonEmptyArray(allProviderRanges) && allProviderRanges.length === positions.length) {\n\t\t\t\tfor (let i = 0; i < positions.length; i++) {\n\t\t\t\t\tif (!allRawRanges[i]) {\n\t\t\t\t\t\tallRawRanges[i] = [];\n\t\t\t\t\t}\n\t\t\t\t\tfor (const oneProviderRanges of allProviderRanges[i]) {\n\t\t\t\t\t\tif (Range.isIRange(oneProviderRanges.range) && Range.containsPosition(oneProviderRanges.range, positions[i])) {\n\t\t\t\t\t\t\tallRawRanges[i].push(Range.lift(oneProviderRanges.range));\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}, onUnexpectedExternalError));\n\t}\n\n\tawait Promise.all(work);\n\n\treturn allRawRanges.map(oneRawRanges => {\n\n\t\tif (oneRawRanges.length === 0) {\n\t\t\treturn [];\n\t\t}\n\n\t\t// sort all by start/end position\n\t\toneRawRanges.sort((a, b) => {\n\t\t\tif (Position.isBefore(a.getStartPosition(), b.getStartPosition())) {\n\t\t\t\treturn 1;\n\t\t\t} else if (Position.isBefore(b.getStartPosition(), a.getStartPosition())) {\n\t\t\t\treturn -1;\n\t\t\t} else if (Position.isBefore(a.getEndPosition(), b.getEndPosition())) {\n\t\t\t\treturn -1;\n\t\t\t} else if (Position.isBefore(b.getEndPosition(), a.getEndPosition())) {\n\t\t\t\treturn 1;\n\t\t\t} else {\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t});\n\n\t\t// remove ranges that don't contain the former range or that are equal to the\n\t\t// former range\n\t\tconst oneRanges: Range[] = [];\n\t\tlet last: Range | undefined;\n\t\tfor (const range of oneRawRanges) {\n\t\t\tif (!last || (Range.containsRange(range, last) && !Range.equalsRange(range, last))) {\n\t\t\t\toneRanges.push(range);\n\t\t\t\tlast = range;\n\t\t\t}\n\t\t}\n\n\t\tif (!options.selectLeadingAndTrailingWhitespace) {\n\t\t\treturn oneRanges;\n\t\t}\n\n\t\t// add ranges that expand trivia at line starts and ends whenever a range\n\t\t// wraps onto the a new line\n\t\tconst oneRangesWithTrivia: Range[] = [oneRanges[0]];\n\t\tfor (let i = 1; i < oneRanges.length; i++) {\n\t\t\tconst prev = oneRanges[i - 1];\n\t\t\tconst cur = oneRanges[i];\n\t\t\tif (cur.startLineNumber !== prev.startLineNumber || cur.endLineNumber !== prev.endLineNumber) {\n\t\t\t\t// add line/block range without leading/failing whitespace\n\t\t\t\tconst rangeNoWhitespace = new Range(prev.startLineNumber, model.getLineFirstNonWhitespaceColumn(prev.startLineNumber), prev.endLineNumber, model.getLineLastNonWhitespaceColumn(prev.endLineNumber));\n\t\t\t\tif (rangeNoWhitespace.containsRange(prev) && !rangeNoWhitespace.equalsRange(prev) && cur.containsRange(rangeNoWhitespace) && !cur.equalsRange(rangeNoWhitespace)) {\n\t\t\t\t\toneRangesWithTrivia.push(rangeNoWhitespace);\n\t\t\t\t}\n\t\t\t\t// add line/block range\n\t\t\t\tconst rangeFull = new Range(prev.startLineNumber, 1, prev.endLineNumber, model.getLineMaxColumn(prev.endLineNumber));\n\t\t\t\tif (rangeFull.containsRange(prev) && !rangeFull.equalsRange(rangeNoWhitespace) && cur.containsRange(rangeFull) && !cur.equalsRange(rangeFull)) {\n\t\t\t\t\toneRangesWithTrivia.push(rangeFull);\n\t\t\t\t}\n\t\t\t}\n\t\t\toneRangesWithTrivia.push(cur);\n\t\t}\n\t\treturn oneRangesWithTrivia;\n\t});\n}\n\n\nCommandsRegistry.registerCommand('_executeSelectionRangeProvider', async function (accessor, ...args) {\n\n\tconst [resource, positions] = args;\n\tassertType(URI.isUri(resource));\n\n\tconst registry = accessor.get(ILanguageFeaturesService).selectionRangeProvider;\n\tconst reference = await accessor.get(ITextModelService).createModelReference(resource);\n\n\ttry {\n\t\treturn provideSelectionRanges(registry, reference.object.textEditorModel, positions, { selectLeadingAndTrailingWhitespace: true, selectSubwords: true }, CancellationToken.None);\n\t} finally {\n\t\treference.dispose();\n\t}\n});\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\nimport { StopWatch } from 'vs/base/common/stopwatch';\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\nimport { EditorAction, registerEditorAction, ServicesAccessor } from 'vs/editor/browser/editorExtensions';\nimport * as nls from 'vs/nls';\n\nclass ForceRetokenizeAction extends EditorAction {\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'editor.action.forceRetokenize',\n\t\t\tlabel: nls.localize('forceRetokenize', \"Developer: Force Retokenize\"),\n\t\t\talias: 'Developer: Force Retokenize',\n\t\t\tprecondition: undefined\n\t\t});\n\t}\n\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor): void {\n\t\tif (!editor.hasModel()) {\n\t\t\treturn;\n\t\t}\n\t\tconst model = editor.getModel();\n\t\tmodel.tokenization.resetTokenization();\n\t\tconst sw = new StopWatch();\n\t\tmodel.tokenization.forceTokenization(model.getLineCount());\n\t\tsw.stop();\n\t\tconsole.log(`tokenization took ${sw.elapsed()}`);\n\n\t}\n}\n\nregisterEditorAction(ForceRetokenizeAction);\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\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport { basename } from 'vs/base/common/resources';\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\nimport { EditorContributionInstantiation, registerEditorContribution } from 'vs/editor/browser/editorExtensions';\nimport { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\nimport { IEditorContribution } from 'vs/editor/common/editorCommon';\nimport { ITextModel } from 'vs/editor/common/model';\nimport * as nls from 'vs/nls';\nimport { IConfirmationResult, IDialogService } from 'vs/platform/dialogs/common/dialogs';\n\nconst ignoreUnusualLineTerminators = 'ignoreUnusualLineTerminators';\n\nfunction writeIgnoreState(codeEditorService: ICodeEditorService, model: ITextModel, state: boolean): void {\n\tcodeEditorService.setModelProperty(model.uri, ignoreUnusualLineTerminators, state);\n}\n\nfunction readIgnoreState(codeEditorService: ICodeEditorService, model: ITextModel): boolean | undefined {\n\treturn codeEditorService.getModelProperty(model.uri, ignoreUnusualLineTerminators);\n}\n\nexport class UnusualLineTerminatorsDetector extends Disposable implements IEditorContribution {\n\n\tpublic static readonly ID = 'editor.contrib.unusualLineTerminatorsDetector';\n\n\tprivate _config: 'auto' | 'off' | 'prompt';\n\tprivate _isPresentingDialog: boolean = false;\n\n\tconstructor(\n\t\tprivate readonly _editor: ICodeEditor,\n\t\t@IDialogService private readonly _dialogService: IDialogService,\n\t\t@ICodeEditorService private readonly _codeEditorService: ICodeEditorService\n\t) {\n\t\tsuper();\n\n\t\tthis._config = this._editor.getOption(EditorOption.unusualLineTerminators);\n\t\tthis._register(this._editor.onDidChangeConfiguration((e) => {\n\t\t\tif (e.hasChanged(EditorOption.unusualLineTerminators)) {\n\t\t\t\tthis._config = this._editor.getOption(EditorOption.unusualLineTerminators);\n\t\t\t\tthis._checkForUnusualLineTerminators();\n\t\t\t}\n\t\t}));\n\n\t\tthis._register(this._editor.onDidChangeModel(() => {\n\t\t\tthis._checkForUnusualLineTerminators();\n\t\t}));\n\n\t\tthis._register(this._editor.onDidChangeModelContent((e) => {\n\t\t\tif (e.isUndoing) {\n\t\t\t\t// skip checking in case of undoing\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis._checkForUnusualLineTerminators();\n\t\t}));\n\n\t\tthis._checkForUnusualLineTerminators();\n\t}\n\n\tprivate async _checkForUnusualLineTerminators(): Promise {\n\t\tif (this._config === 'off') {\n\t\t\treturn;\n\t\t}\n\t\tif (!this._editor.hasModel()) {\n\t\t\treturn;\n\t\t}\n\t\tconst model = this._editor.getModel();\n\t\tif (!model.mightContainUnusualLineTerminators()) {\n\t\t\treturn;\n\t\t}\n\t\tconst ignoreState = readIgnoreState(this._codeEditorService, model);\n\t\tif (ignoreState === true) {\n\t\t\t// this model should be ignored\n\t\t\treturn;\n\t\t}\n\t\tif (this._editor.getOption(EditorOption.readOnly)) {\n\t\t\t// read only editor => sorry!\n\t\t\treturn;\n\t\t}\n\n\t\tif (this._config === 'auto') {\n\t\t\t// just do it!\n\t\t\tmodel.removeUnusualLineTerminators(this._editor.getSelections());\n\t\t\treturn;\n\t\t}\n\n\t\tif (this._isPresentingDialog) {\n\t\t\t// we're currently showing the dialog, which is async.\n\t\t\t// avoid spamming the user\n\t\t\treturn;\n\t\t}\n\n\t\tlet result: IConfirmationResult;\n\t\ttry {\n\t\t\tthis._isPresentingDialog = true;\n\t\t\tresult = await this._dialogService.confirm({\n\t\t\t\ttitle: nls.localize('unusualLineTerminators.title', \"Unusual Line Terminators\"),\n\t\t\t\tmessage: nls.localize('unusualLineTerminators.message', \"Detected unusual line terminators\"),\n\t\t\t\tdetail: nls.localize('unusualLineTerminators.detail', \"The file '{0}' 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`.\", basename(model.uri)),\n\t\t\t\tprimaryButton: nls.localize({ key: 'unusualLineTerminators.fix', comment: ['&& denotes a mnemonic'] }, \"&&Remove Unusual Line Terminators\"),\n\t\t\t\tcancelButton: nls.localize('unusualLineTerminators.ignore', \"Ignore\")\n\t\t\t});\n\t\t} finally {\n\t\t\tthis._isPresentingDialog = false;\n\t\t}\n\n\t\tif (!result.confirmed) {\n\t\t\t// this model should be ignored\n\t\t\twriteIgnoreState(this._codeEditorService, model, true);\n\t\t\treturn;\n\t\t}\n\n\t\tmodel.removeUnusualLineTerminators(this._editor.getSelections());\n\t}\n}\n\nregisterEditorContribution(UnusualLineTerminatorsDetector.ID, UnusualLineTerminatorsDetector, EditorContributionInstantiation.AfterFirstRender);\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\nimport { KeyCode, KeyMod } from 'vs/base/common/keyCodes';\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\nimport { EditorAction, EditorCommand, ICommandOptions, registerEditorAction, registerEditorCommand, ServicesAccessor } from 'vs/editor/browser/editorExtensions';\nimport { ReplaceCommand } from 'vs/editor/common/commands/replaceCommand';\nimport { EditorOption, EditorOptions } from 'vs/editor/common/config/editorOptions';\nimport { CursorState } from 'vs/editor/common/cursorCommon';\nimport { CursorChangeReason } from 'vs/editor/common/cursorEvents';\nimport { DeleteWordContext, WordNavigationType, WordOperations } from 'vs/editor/common/cursor/cursorWordOperations';\nimport { getMapForWordSeparators, WordCharacterClassifier } from 'vs/editor/common/core/wordCharacterClassifier';\nimport { Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\nimport { Selection } from 'vs/editor/common/core/selection';\nimport { ScrollType } from 'vs/editor/common/editorCommon';\nimport { EditorContextKeys } from 'vs/editor/common/editorContextKeys';\nimport { ITextModel } from 'vs/editor/common/model';\nimport { ILanguageConfigurationService } from 'vs/editor/common/languages/languageConfigurationRegistry';\nimport * as nls from 'vs/nls';\nimport { CONTEXT_ACCESSIBILITY_MODE_ENABLED } from 'vs/platform/accessibility/common/accessibility';\nimport { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';\nimport { IsWindowsContext } from 'vs/platform/contextkey/common/contextkeys';\nimport { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';\n\nexport interface MoveWordOptions extends ICommandOptions {\n\tinSelectionMode: boolean;\n\twordNavigationType: WordNavigationType;\n}\n\nexport abstract class MoveWordCommand extends EditorCommand {\n\n\tprivate readonly _inSelectionMode: boolean;\n\tprivate readonly _wordNavigationType: WordNavigationType;\n\n\tconstructor(opts: MoveWordOptions) {\n\t\tsuper(opts);\n\t\tthis._inSelectionMode = opts.inSelectionMode;\n\t\tthis._wordNavigationType = opts.wordNavigationType;\n\t}\n\n\tpublic runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void {\n\t\tif (!editor.hasModel()) {\n\t\t\treturn;\n\t\t}\n\t\tconst wordSeparators = getMapForWordSeparators(editor.getOption(EditorOption.wordSeparators), editor.getOption(EditorOption.wordSegmenterLocales));\n\t\tconst model = editor.getModel();\n\t\tconst selections = editor.getSelections();\n\n\t\tconst result = selections.map((sel) => {\n\t\t\tconst inPosition = new Position(sel.positionLineNumber, sel.positionColumn);\n\t\t\tconst outPosition = this._move(wordSeparators, model, inPosition, this._wordNavigationType);\n\t\t\treturn this._moveTo(sel, outPosition, this._inSelectionMode);\n\t\t});\n\n\t\tmodel.pushStackElement();\n\t\teditor._getViewModel().setCursorStates('moveWordCommand', CursorChangeReason.Explicit, result.map(r => CursorState.fromModelSelection(r)));\n\t\tif (result.length === 1) {\n\t\t\tconst pos = new Position(result[0].positionLineNumber, result[0].positionColumn);\n\t\t\teditor.revealPosition(pos, ScrollType.Smooth);\n\t\t}\n\t}\n\n\tprivate _moveTo(from: Selection, to: Position, inSelectionMode: boolean): Selection {\n\t\tif (inSelectionMode) {\n\t\t\t// move just position\n\t\t\treturn new Selection(\n\t\t\t\tfrom.selectionStartLineNumber,\n\t\t\t\tfrom.selectionStartColumn,\n\t\t\t\tto.lineNumber,\n\t\t\t\tto.column\n\t\t\t);\n\t\t} else {\n\t\t\t// move everything\n\t\t\treturn new Selection(\n\t\t\t\tto.lineNumber,\n\t\t\t\tto.column,\n\t\t\t\tto.lineNumber,\n\t\t\t\tto.column\n\t\t\t);\n\t\t}\n\t}\n\n\tprotected abstract _move(wordSeparators: WordCharacterClassifier, model: ITextModel, position: Position, wordNavigationType: WordNavigationType): Position;\n}\n\nexport class WordLeftCommand extends MoveWordCommand {\n\tprotected _move(wordSeparators: WordCharacterClassifier, model: ITextModel, position: Position, wordNavigationType: WordNavigationType): Position {\n\t\treturn WordOperations.moveWordLeft(wordSeparators, model, position, wordNavigationType);\n\t}\n}\n\nexport class WordRightCommand extends MoveWordCommand {\n\tprotected _move(wordSeparators: WordCharacterClassifier, model: ITextModel, position: Position, wordNavigationType: WordNavigationType): Position {\n\t\treturn WordOperations.moveWordRight(wordSeparators, model, position, wordNavigationType);\n\t}\n}\n\nexport class CursorWordStartLeft extends WordLeftCommand {\n\tconstructor() {\n\t\tsuper({\n\t\t\tinSelectionMode: false,\n\t\t\twordNavigationType: WordNavigationType.WordStart,\n\t\t\tid: 'cursorWordStartLeft',\n\t\t\tprecondition: undefined\n\t\t});\n\t}\n}\n\nexport class CursorWordEndLeft extends WordLeftCommand {\n\tconstructor() {\n\t\tsuper({\n\t\t\tinSelectionMode: false,\n\t\t\twordNavigationType: WordNavigationType.WordEnd,\n\t\t\tid: 'cursorWordEndLeft',\n\t\t\tprecondition: undefined\n\t\t});\n\t}\n}\n\nexport class CursorWordLeft extends WordLeftCommand {\n\tconstructor() {\n\t\tsuper({\n\t\t\tinSelectionMode: false,\n\t\t\twordNavigationType: WordNavigationType.WordStartFast,\n\t\t\tid: 'cursorWordLeft',\n\t\t\tprecondition: undefined,\n\t\t\tkbOpts: {\n\t\t\t\tkbExpr: ContextKeyExpr.and(EditorContextKeys.textInputFocus, ContextKeyExpr.and(CONTEXT_ACCESSIBILITY_MODE_ENABLED, IsWindowsContext)?.negate()),\n\t\t\t\tprimary: KeyMod.CtrlCmd | KeyCode.LeftArrow,\n\t\t\t\tmac: { primary: KeyMod.Alt | KeyCode.LeftArrow },\n\t\t\t\tweight: KeybindingWeight.EditorContrib\n\t\t\t}\n\t\t});\n\t}\n}\n\nexport class CursorWordStartLeftSelect extends WordLeftCommand {\n\tconstructor() {\n\t\tsuper({\n\t\t\tinSelectionMode: true,\n\t\t\twordNavigationType: WordNavigationType.WordStart,\n\t\t\tid: 'cursorWordStartLeftSelect',\n\t\t\tprecondition: undefined\n\t\t});\n\t}\n}\n\nexport class CursorWordEndLeftSelect extends WordLeftCommand {\n\tconstructor() {\n\t\tsuper({\n\t\t\tinSelectionMode: true,\n\t\t\twordNavigationType: WordNavigationType.WordEnd,\n\t\t\tid: 'cursorWordEndLeftSelect',\n\t\t\tprecondition: undefined\n\t\t});\n\t}\n}\n\nexport class CursorWordLeftSelect extends WordLeftCommand {\n\tconstructor() {\n\t\tsuper({\n\t\t\tinSelectionMode: true,\n\t\t\twordNavigationType: WordNavigationType.WordStartFast,\n\t\t\tid: 'cursorWordLeftSelect',\n\t\t\tprecondition: undefined,\n\t\t\tkbOpts: {\n\t\t\t\tkbExpr: ContextKeyExpr.and(EditorContextKeys.textInputFocus, ContextKeyExpr.and(CONTEXT_ACCESSIBILITY_MODE_ENABLED, IsWindowsContext)?.negate()),\n\t\t\t\tprimary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.LeftArrow,\n\t\t\t\tmac: { primary: KeyMod.Alt | KeyMod.Shift | KeyCode.LeftArrow },\n\t\t\t\tweight: KeybindingWeight.EditorContrib\n\t\t\t}\n\t\t});\n\t}\n}\n\n// Accessibility navigation commands should only be enabled on windows since they are tuned to what NVDA expects\nexport class CursorWordAccessibilityLeft extends WordLeftCommand {\n\tconstructor() {\n\t\tsuper({\n\t\t\tinSelectionMode: false,\n\t\t\twordNavigationType: WordNavigationType.WordAccessibility,\n\t\t\tid: 'cursorWordAccessibilityLeft',\n\t\t\tprecondition: undefined\n\t\t});\n\t}\n\n\tprotected override _move(wordCharacterClassifier: WordCharacterClassifier, model: ITextModel, position: Position, wordNavigationType: WordNavigationType): Position {\n\t\treturn super._move(getMapForWordSeparators(EditorOptions.wordSeparators.defaultValue, wordCharacterClassifier.intlSegmenterLocales), model, position, wordNavigationType);\n\t}\n}\n\nexport class CursorWordAccessibilityLeftSelect extends WordLeftCommand {\n\tconstructor() {\n\t\tsuper({\n\t\t\tinSelectionMode: true,\n\t\t\twordNavigationType: WordNavigationType.WordAccessibility,\n\t\t\tid: 'cursorWordAccessibilityLeftSelect',\n\t\t\tprecondition: undefined\n\t\t});\n\t}\n\n\tprotected override _move(wordCharacterClassifier: WordCharacterClassifier, model: ITextModel, position: Position, wordNavigationType: WordNavigationType): Position {\n\t\treturn super._move(getMapForWordSeparators(EditorOptions.wordSeparators.defaultValue, wordCharacterClassifier.intlSegmenterLocales), model, position, wordNavigationType);\n\t}\n}\n\nexport class CursorWordStartRight extends WordRightCommand {\n\tconstructor() {\n\t\tsuper({\n\t\t\tinSelectionMode: false,\n\t\t\twordNavigationType: WordNavigationType.WordStart,\n\t\t\tid: 'cursorWordStartRight',\n\t\t\tprecondition: undefined\n\t\t});\n\t}\n}\n\nexport class CursorWordEndRight extends WordRightCommand {\n\tconstructor() {\n\t\tsuper({\n\t\t\tinSelectionMode: false,\n\t\t\twordNavigationType: WordNavigationType.WordEnd,\n\t\t\tid: 'cursorWordEndRight',\n\t\t\tprecondition: undefined,\n\t\t\tkbOpts: {\n\t\t\t\tkbExpr: ContextKeyExpr.and(EditorContextKeys.textInputFocus, ContextKeyExpr.and(CONTEXT_ACCESSIBILITY_MODE_ENABLED, IsWindowsContext)?.negate()),\n\t\t\t\tprimary: KeyMod.CtrlCmd | KeyCode.RightArrow,\n\t\t\t\tmac: { primary: KeyMod.Alt | KeyCode.RightArrow },\n\t\t\t\tweight: KeybindingWeight.EditorContrib\n\t\t\t}\n\t\t});\n\t}\n}\n\nexport class CursorWordRight extends WordRightCommand {\n\tconstructor() {\n\t\tsuper({\n\t\t\tinSelectionMode: false,\n\t\t\twordNavigationType: WordNavigationType.WordEnd,\n\t\t\tid: 'cursorWordRight',\n\t\t\tprecondition: undefined\n\t\t});\n\t}\n}\n\nexport class CursorWordStartRightSelect extends WordRightCommand {\n\tconstructor() {\n\t\tsuper({\n\t\t\tinSelectionMode: true,\n\t\t\twordNavigationType: WordNavigationType.WordStart,\n\t\t\tid: 'cursorWordStartRightSelect',\n\t\t\tprecondition: undefined\n\t\t});\n\t}\n}\n\nexport class CursorWordEndRightSelect extends WordRightCommand {\n\tconstructor() {\n\t\tsuper({\n\t\t\tinSelectionMode: true,\n\t\t\twordNavigationType: WordNavigationType.WordEnd,\n\t\t\tid: 'cursorWordEndRightSelect',\n\t\t\tprecondition: undefined,\n\t\t\tkbOpts: {\n\t\t\t\tkbExpr: ContextKeyExpr.and(EditorContextKeys.textInputFocus, ContextKeyExpr.and(CONTEXT_ACCESSIBILITY_MODE_ENABLED, IsWindowsContext)?.negate()),\n\t\t\t\tprimary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.RightArrow,\n\t\t\t\tmac: { primary: KeyMod.Alt | KeyMod.Shift | KeyCode.RightArrow },\n\t\t\t\tweight: KeybindingWeight.EditorContrib\n\t\t\t}\n\t\t});\n\t}\n}\n\nexport class CursorWordRightSelect extends WordRightCommand {\n\tconstructor() {\n\t\tsuper({\n\t\t\tinSelectionMode: true,\n\t\t\twordNavigationType: WordNavigationType.WordEnd,\n\t\t\tid: 'cursorWordRightSelect',\n\t\t\tprecondition: undefined\n\t\t});\n\t}\n}\n\nexport class CursorWordAccessibilityRight extends WordRightCommand {\n\tconstructor() {\n\t\tsuper({\n\t\t\tinSelectionMode: false,\n\t\t\twordNavigationType: WordNavigationType.WordAccessibility,\n\t\t\tid: 'cursorWordAccessibilityRight',\n\t\t\tprecondition: undefined\n\t\t});\n\t}\n\n\tprotected override _move(wordCharacterClassifier: WordCharacterClassifier, model: ITextModel, position: Position, wordNavigationType: WordNavigationType): Position {\n\t\treturn super._move(getMapForWordSeparators(EditorOptions.wordSeparators.defaultValue, wordCharacterClassifier.intlSegmenterLocales), model, position, wordNavigationType);\n\t}\n}\n\nexport class CursorWordAccessibilityRightSelect extends WordRightCommand {\n\tconstructor() {\n\t\tsuper({\n\t\t\tinSelectionMode: true,\n\t\t\twordNavigationType: WordNavigationType.WordAccessibility,\n\t\t\tid: 'cursorWordAccessibilityRightSelect',\n\t\t\tprecondition: undefined\n\t\t});\n\t}\n\n\tprotected override _move(wordCharacterClassifier: WordCharacterClassifier, model: ITextModel, position: Position, wordNavigationType: WordNavigationType): Position {\n\t\treturn super._move(getMapForWordSeparators(EditorOptions.wordSeparators.defaultValue, wordCharacterClassifier.intlSegmenterLocales), model, position, wordNavigationType);\n\t}\n}\n\nexport interface DeleteWordOptions extends ICommandOptions {\n\twhitespaceHeuristics: boolean;\n\twordNavigationType: WordNavigationType;\n}\n\nexport abstract class DeleteWordCommand extends EditorCommand {\n\tprivate readonly _whitespaceHeuristics: boolean;\n\tprivate readonly _wordNavigationType: WordNavigationType;\n\n\tconstructor(opts: DeleteWordOptions) {\n\t\tsuper(opts);\n\t\tthis._whitespaceHeuristics = opts.whitespaceHeuristics;\n\t\tthis._wordNavigationType = opts.wordNavigationType;\n\t}\n\n\tpublic runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void {\n\t\tconst languageConfigurationService = accessor.get(ILanguageConfigurationService);\n\n\t\tif (!editor.hasModel()) {\n\t\t\treturn;\n\t\t}\n\t\tconst wordSeparators = getMapForWordSeparators(editor.getOption(EditorOption.wordSeparators), editor.getOption(EditorOption.wordSegmenterLocales));\n\t\tconst model = editor.getModel();\n\t\tconst selections = editor.getSelections();\n\t\tconst autoClosingBrackets = editor.getOption(EditorOption.autoClosingBrackets);\n\t\tconst autoClosingQuotes = editor.getOption(EditorOption.autoClosingQuotes);\n\t\tconst autoClosingPairs = languageConfigurationService.getLanguageConfiguration(model.getLanguageId()).getAutoClosingPairs();\n\t\tconst viewModel = editor._getViewModel();\n\n\t\tconst commands = selections.map((sel) => {\n\t\t\tconst deleteRange = this._delete({\n\t\t\t\twordSeparators,\n\t\t\t\tmodel,\n\t\t\t\tselection: sel,\n\t\t\t\twhitespaceHeuristics: this._whitespaceHeuristics,\n\t\t\t\tautoClosingDelete: editor.getOption(EditorOption.autoClosingDelete),\n\t\t\t\tautoClosingBrackets,\n\t\t\t\tautoClosingQuotes,\n\t\t\t\tautoClosingPairs,\n\t\t\t\tautoClosedCharacters: viewModel.getCursorAutoClosedCharacters(),\n\t\t\t}, this._wordNavigationType);\n\t\t\treturn new ReplaceCommand(deleteRange, '');\n\t\t});\n\n\t\teditor.pushUndoStop();\n\t\teditor.executeCommands(this.id, commands);\n\t\teditor.pushUndoStop();\n\t}\n\n\tprotected abstract _delete(ctx: DeleteWordContext, wordNavigationType: WordNavigationType): Range;\n}\n\nexport class DeleteWordLeftCommand extends DeleteWordCommand {\n\tprotected _delete(ctx: DeleteWordContext, wordNavigationType: WordNavigationType): Range {\n\t\tconst r = WordOperations.deleteWordLeft(ctx, wordNavigationType);\n\t\tif (r) {\n\t\t\treturn r;\n\t\t}\n\t\treturn new Range(1, 1, 1, 1);\n\t}\n}\n\nexport class DeleteWordRightCommand extends DeleteWordCommand {\n\tprotected _delete(ctx: DeleteWordContext, wordNavigationType: WordNavigationType): Range {\n\t\tconst r = WordOperations.deleteWordRight(ctx, wordNavigationType);\n\t\tif (r) {\n\t\t\treturn r;\n\t\t}\n\t\tconst lineCount = ctx.model.getLineCount();\n\t\tconst maxColumn = ctx.model.getLineMaxColumn(lineCount);\n\t\treturn new Range(lineCount, maxColumn, lineCount, maxColumn);\n\t}\n}\n\nexport class DeleteWordStartLeft extends DeleteWordLeftCommand {\n\tconstructor() {\n\t\tsuper({\n\t\t\twhitespaceHeuristics: false,\n\t\t\twordNavigationType: WordNavigationType.WordStart,\n\t\t\tid: 'deleteWordStartLeft',\n\t\t\tprecondition: EditorContextKeys.writable\n\t\t});\n\t}\n}\n\nexport class DeleteWordEndLeft extends DeleteWordLeftCommand {\n\tconstructor() {\n\t\tsuper({\n\t\t\twhitespaceHeuristics: false,\n\t\t\twordNavigationType: WordNavigationType.WordEnd,\n\t\t\tid: 'deleteWordEndLeft',\n\t\t\tprecondition: EditorContextKeys.writable\n\t\t});\n\t}\n}\n\nexport class DeleteWordLeft extends DeleteWordLeftCommand {\n\tconstructor() {\n\t\tsuper({\n\t\t\twhitespaceHeuristics: true,\n\t\t\twordNavigationType: WordNavigationType.WordStart,\n\t\t\tid: 'deleteWordLeft',\n\t\t\tprecondition: EditorContextKeys.writable,\n\t\t\tkbOpts: {\n\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\t\tprimary: KeyMod.CtrlCmd | KeyCode.Backspace,\n\t\t\t\tmac: { primary: KeyMod.Alt | KeyCode.Backspace },\n\t\t\t\tweight: KeybindingWeight.EditorContrib\n\t\t\t}\n\t\t});\n\t}\n}\n\nexport class DeleteWordStartRight extends DeleteWordRightCommand {\n\tconstructor() {\n\t\tsuper({\n\t\t\twhitespaceHeuristics: false,\n\t\t\twordNavigationType: WordNavigationType.WordStart,\n\t\t\tid: 'deleteWordStartRight',\n\t\t\tprecondition: EditorContextKeys.writable\n\t\t});\n\t}\n}\n\nexport class DeleteWordEndRight extends DeleteWordRightCommand {\n\tconstructor() {\n\t\tsuper({\n\t\t\twhitespaceHeuristics: false,\n\t\t\twordNavigationType: WordNavigationType.WordEnd,\n\t\t\tid: 'deleteWordEndRight',\n\t\t\tprecondition: EditorContextKeys.writable\n\t\t});\n\t}\n}\n\nexport class DeleteWordRight extends DeleteWordRightCommand {\n\tconstructor() {\n\t\tsuper({\n\t\t\twhitespaceHeuristics: true,\n\t\t\twordNavigationType: WordNavigationType.WordEnd,\n\t\t\tid: 'deleteWordRight',\n\t\t\tprecondition: EditorContextKeys.writable,\n\t\t\tkbOpts: {\n\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\t\tprimary: KeyMod.CtrlCmd | KeyCode.Delete,\n\t\t\t\tmac: { primary: KeyMod.Alt | KeyCode.Delete },\n\t\t\t\tweight: KeybindingWeight.EditorContrib\n\t\t\t}\n\t\t});\n\t}\n}\n\nexport class DeleteInsideWord extends EditorAction {\n\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'deleteInsideWord',\n\t\t\tprecondition: EditorContextKeys.writable,\n\t\t\tlabel: nls.localize('deleteInsideWord', \"Delete Word\"),\n\t\t\talias: 'Delete Word'\n\t\t});\n\t}\n\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void {\n\t\tif (!editor.hasModel()) {\n\t\t\treturn;\n\t\t}\n\t\tconst wordSeparators = getMapForWordSeparators(editor.getOption(EditorOption.wordSeparators), editor.getOption(EditorOption.wordSegmenterLocales));\n\t\tconst model = editor.getModel();\n\t\tconst selections = editor.getSelections();\n\n\t\tconst commands = selections.map((sel) => {\n\t\t\tconst deleteRange = WordOperations.deleteInsideWord(wordSeparators, model, sel);\n\t\t\treturn new ReplaceCommand(deleteRange, '');\n\t\t});\n\n\t\teditor.pushUndoStop();\n\t\teditor.executeCommands(this.id, commands);\n\t\teditor.pushUndoStop();\n\t}\n}\n\nregisterEditorCommand(new CursorWordStartLeft());\nregisterEditorCommand(new CursorWordEndLeft());\nregisterEditorCommand(new CursorWordLeft());\nregisterEditorCommand(new CursorWordStartLeftSelect());\nregisterEditorCommand(new CursorWordEndLeftSelect());\nregisterEditorCommand(new CursorWordLeftSelect());\nregisterEditorCommand(new CursorWordStartRight());\nregisterEditorCommand(new CursorWordEndRight());\nregisterEditorCommand(new CursorWordRight());\nregisterEditorCommand(new CursorWordStartRightSelect());\nregisterEditorCommand(new CursorWordEndRightSelect());\nregisterEditorCommand(new CursorWordRightSelect());\nregisterEditorCommand(new CursorWordAccessibilityLeft());\nregisterEditorCommand(new CursorWordAccessibilityLeftSelect());\nregisterEditorCommand(new CursorWordAccessibilityRight());\nregisterEditorCommand(new CursorWordAccessibilityRightSelect());\nregisterEditorCommand(new DeleteWordStartLeft());\nregisterEditorCommand(new DeleteWordEndLeft());\nregisterEditorCommand(new DeleteWordLeft());\nregisterEditorCommand(new DeleteWordStartRight());\nregisterEditorCommand(new DeleteWordEndRight());\nregisterEditorCommand(new DeleteWordRight());\nregisterEditorAction(DeleteInsideWord);\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\nimport { KeyCode, KeyMod } from 'vs/base/common/keyCodes';\nimport { registerEditorCommand } from 'vs/editor/browser/editorExtensions';\nimport { DeleteWordContext, WordNavigationType, WordPartOperations } from 'vs/editor/common/cursor/cursorWordOperations';\nimport { WordCharacterClassifier } from 'vs/editor/common/core/wordCharacterClassifier';\nimport { Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\nimport { EditorContextKeys } from 'vs/editor/common/editorContextKeys';\nimport { ITextModel } from 'vs/editor/common/model';\nimport { DeleteWordCommand, MoveWordCommand } from 'vs/editor/contrib/wordOperations/browser/wordOperations';\nimport { CommandsRegistry } from 'vs/platform/commands/common/commands';\nimport { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';\n\nexport class DeleteWordPartLeft extends DeleteWordCommand {\n\tconstructor() {\n\t\tsuper({\n\t\t\twhitespaceHeuristics: true,\n\t\t\twordNavigationType: WordNavigationType.WordStart,\n\t\t\tid: 'deleteWordPartLeft',\n\t\t\tprecondition: EditorContextKeys.writable,\n\t\t\tkbOpts: {\n\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\t\tprimary: 0,\n\t\t\t\tmac: { primary: KeyMod.WinCtrl | KeyMod.Alt | KeyCode.Backspace },\n\t\t\t\tweight: KeybindingWeight.EditorContrib\n\t\t\t}\n\t\t});\n\t}\n\n\tprotected _delete(ctx: DeleteWordContext, wordNavigationType: WordNavigationType): Range {\n\t\tconst r = WordPartOperations.deleteWordPartLeft(ctx);\n\t\tif (r) {\n\t\t\treturn r;\n\t\t}\n\t\treturn new Range(1, 1, 1, 1);\n\t}\n}\n\nexport class DeleteWordPartRight extends DeleteWordCommand {\n\tconstructor() {\n\t\tsuper({\n\t\t\twhitespaceHeuristics: true,\n\t\t\twordNavigationType: WordNavigationType.WordEnd,\n\t\t\tid: 'deleteWordPartRight',\n\t\t\tprecondition: EditorContextKeys.writable,\n\t\t\tkbOpts: {\n\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\t\tprimary: 0,\n\t\t\t\tmac: { primary: KeyMod.WinCtrl | KeyMod.Alt | KeyCode.Delete },\n\t\t\t\tweight: KeybindingWeight.EditorContrib\n\t\t\t}\n\t\t});\n\t}\n\n\tprotected _delete(ctx: DeleteWordContext, wordNavigationType: WordNavigationType): Range {\n\t\tconst r = WordPartOperations.deleteWordPartRight(ctx);\n\t\tif (r) {\n\t\t\treturn r;\n\t\t}\n\t\tconst lineCount = ctx.model.getLineCount();\n\t\tconst maxColumn = ctx.model.getLineMaxColumn(lineCount);\n\t\treturn new Range(lineCount, maxColumn, lineCount, maxColumn);\n\t}\n}\n\nexport class WordPartLeftCommand extends MoveWordCommand {\n\tprotected _move(wordSeparators: WordCharacterClassifier, model: ITextModel, position: Position, wordNavigationType: WordNavigationType): Position {\n\t\treturn WordPartOperations.moveWordPartLeft(wordSeparators, model, position);\n\t}\n}\nexport class CursorWordPartLeft extends WordPartLeftCommand {\n\tconstructor() {\n\t\tsuper({\n\t\t\tinSelectionMode: false,\n\t\t\twordNavigationType: WordNavigationType.WordStart,\n\t\t\tid: 'cursorWordPartLeft',\n\t\t\tprecondition: undefined,\n\t\t\tkbOpts: {\n\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\t\tprimary: 0,\n\t\t\t\tmac: { primary: KeyMod.WinCtrl | KeyMod.Alt | KeyCode.LeftArrow },\n\t\t\t\tweight: KeybindingWeight.EditorContrib\n\t\t\t}\n\t\t});\n\t}\n}\n// Register previous id for compatibility purposes\nCommandsRegistry.registerCommandAlias('cursorWordPartStartLeft', 'cursorWordPartLeft');\n\nexport class CursorWordPartLeftSelect extends WordPartLeftCommand {\n\tconstructor() {\n\t\tsuper({\n\t\t\tinSelectionMode: true,\n\t\t\twordNavigationType: WordNavigationType.WordStart,\n\t\t\tid: 'cursorWordPartLeftSelect',\n\t\t\tprecondition: undefined,\n\t\t\tkbOpts: {\n\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\t\tprimary: 0,\n\t\t\t\tmac: { primary: KeyMod.WinCtrl | KeyMod.Alt | KeyMod.Shift | KeyCode.LeftArrow },\n\t\t\t\tweight: KeybindingWeight.EditorContrib\n\t\t\t}\n\t\t});\n\t}\n}\n// Register previous id for compatibility purposes\nCommandsRegistry.registerCommandAlias('cursorWordPartStartLeftSelect', 'cursorWordPartLeftSelect');\n\nexport class WordPartRightCommand extends MoveWordCommand {\n\tprotected _move(wordSeparators: WordCharacterClassifier, model: ITextModel, position: Position, wordNavigationType: WordNavigationType): Position {\n\t\treturn WordPartOperations.moveWordPartRight(wordSeparators, model, position);\n\t}\n}\nexport class CursorWordPartRight extends WordPartRightCommand {\n\tconstructor() {\n\t\tsuper({\n\t\t\tinSelectionMode: false,\n\t\t\twordNavigationType: WordNavigationType.WordEnd,\n\t\t\tid: 'cursorWordPartRight',\n\t\t\tprecondition: undefined,\n\t\t\tkbOpts: {\n\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\t\tprimary: 0,\n\t\t\t\tmac: { primary: KeyMod.WinCtrl | KeyMod.Alt | KeyCode.RightArrow },\n\t\t\t\tweight: KeybindingWeight.EditorContrib\n\t\t\t}\n\t\t});\n\t}\n}\nexport class CursorWordPartRightSelect extends WordPartRightCommand {\n\tconstructor() {\n\t\tsuper({\n\t\t\tinSelectionMode: true,\n\t\t\twordNavigationType: WordNavigationType.WordEnd,\n\t\t\tid: 'cursorWordPartRightSelect',\n\t\t\tprecondition: undefined,\n\t\t\tkbOpts: {\n\t\t\t\tkbExpr: EditorContextKeys.textInputFocus,\n\t\t\t\tprimary: 0,\n\t\t\t\tmac: { primary: KeyMod.WinCtrl | KeyMod.Alt | KeyMod.Shift | KeyCode.RightArrow },\n\t\t\t\tweight: KeybindingWeight.EditorContrib\n\t\t\t}\n\t\t});\n\t}\n}\n\n\nregisterEditorCommand(new DeleteWordPartLeft());\nregisterEditorCommand(new DeleteWordPartRight());\nregisterEditorCommand(new CursorWordPartLeft());\nregisterEditorCommand(new CursorWordPartLeftSelect());\nregisterEditorCommand(new CursorWordPartRight());\nregisterEditorCommand(new CursorWordPartRightSelect());\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\nimport 'vs/css!./iPadShowKeyboard';\nimport * as dom from 'vs/base/browser/dom';\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport { ICodeEditor, IOverlayWidget, IOverlayWidgetPosition, OverlayWidgetPositionPreference } from 'vs/editor/browser/editorBrowser';\nimport { EditorContributionInstantiation, registerEditorContribution } from 'vs/editor/browser/editorExtensions';\nimport { IEditorContribution } from 'vs/editor/common/editorCommon';\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\nimport { isIOS } from 'vs/base/common/platform';\n\nexport class IPadShowKeyboard extends Disposable implements IEditorContribution {\n\n\tpublic static readonly ID = 'editor.contrib.iPadShowKeyboard';\n\n\tprivate readonly editor: ICodeEditor;\n\tprivate widget: ShowKeyboardWidget | null;\n\n\tconstructor(editor: ICodeEditor) {\n\t\tsuper();\n\t\tthis.editor = editor;\n\t\tthis.widget = null;\n\t\tif (isIOS) {\n\t\t\tthis._register(editor.onDidChangeConfiguration(() => this.update()));\n\t\t\tthis.update();\n\t\t}\n\t}\n\n\tprivate update(): void {\n\t\tconst shouldHaveWidget = (!this.editor.getOption(EditorOption.readOnly));\n\n\t\tif (!this.widget && shouldHaveWidget) {\n\n\t\t\tthis.widget = new ShowKeyboardWidget(this.editor);\n\n\t\t} else if (this.widget && !shouldHaveWidget) {\n\n\t\t\tthis.widget.dispose();\n\t\t\tthis.widget = null;\n\n\t\t}\n\t}\n\n\tpublic override dispose(): void {\n\t\tsuper.dispose();\n\t\tif (this.widget) {\n\t\t\tthis.widget.dispose();\n\t\t\tthis.widget = null;\n\t\t}\n\t}\n}\n\nclass ShowKeyboardWidget extends Disposable implements IOverlayWidget {\n\n\tprivate static readonly ID = 'editor.contrib.ShowKeyboardWidget';\n\n\tprivate readonly editor: ICodeEditor;\n\n\tprivate readonly _domNode: HTMLElement;\n\n\tconstructor(editor: ICodeEditor) {\n\t\tsuper();\n\t\tthis.editor = editor;\n\t\tthis._domNode = document.createElement('textarea');\n\t\tthis._domNode.className = 'iPadShowKeyboard';\n\n\t\tthis._register(dom.addDisposableListener(this._domNode, 'touchstart', (e) => {\n\t\t\tthis.editor.focus();\n\t\t}));\n\t\tthis._register(dom.addDisposableListener(this._domNode, 'focus', (e) => {\n\t\t\tthis.editor.focus();\n\t\t}));\n\n\t\tthis.editor.addOverlayWidget(this);\n\t}\n\n\tpublic override dispose(): void {\n\t\tthis.editor.removeOverlayWidget(this);\n\t\tsuper.dispose();\n\t}\n\n\t// ----- IOverlayWidget API\n\n\tpublic getId(): string {\n\t\treturn ShowKeyboardWidget.ID;\n\t}\n\n\tpublic getDomNode(): HTMLElement {\n\t\treturn this._domNode;\n\t}\n\n\tpublic getPosition(): IOverlayWidgetPosition {\n\t\treturn {\n\t\t\tpreference: OverlayWidgetPositionPreference.BOTTOM_RIGHT_CORNER\n\t\t};\n\t}\n}\n\nregisterEditorContribution(IPadShowKeyboard.ID, IPadShowKeyboard, EditorContributionInstantiation.Eventually);\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\nimport 'vs/css!./inspectTokens';\nimport { $, append, reset } from 'vs/base/browser/dom';\nimport { CharCode } from 'vs/base/common/charCode';\nimport { Color } from 'vs/base/common/color';\nimport { KeyCode } from 'vs/base/common/keyCodes';\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport { ContentWidgetPositionPreference, IActiveCodeEditor, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser';\nimport { EditorAction, ServicesAccessor, registerEditorAction, registerEditorContribution, EditorContributionInstantiation } from 'vs/editor/browser/editorExtensions';\nimport { Position } from 'vs/editor/common/core/position';\nimport { IEditorContribution } from 'vs/editor/common/editorCommon';\nimport { ITextModel } from 'vs/editor/common/model';\nimport { IState, ITokenizationSupport, TokenizationRegistry, ILanguageIdCodec, Token } from 'vs/editor/common/languages';\nimport { FontStyle, StandardTokenType, TokenMetadata } from 'vs/editor/common/encodedTokenAttributes';\nimport { NullState, nullTokenize, nullTokenizeEncoded } from 'vs/editor/common/languages/nullTokenize';\nimport { ILanguageService } from 'vs/editor/common/languages/language';\nimport { IStandaloneThemeService } from 'vs/editor/standalone/common/standaloneTheme';\nimport { InspectTokensNLS } from 'vs/editor/common/standaloneStrings';\n\n\nclass InspectTokensController extends Disposable implements IEditorContribution {\n\n\tpublic static readonly ID = 'editor.contrib.inspectTokens';\n\n\tpublic static get(editor: ICodeEditor): InspectTokensController | null {\n\t\treturn editor.getContribution(InspectTokensController.ID);\n\t}\n\n\tprivate readonly _editor: ICodeEditor;\n\tprivate readonly _languageService: ILanguageService;\n\tprivate _widget: InspectTokensWidget | null;\n\n\tconstructor(\n\t\teditor: ICodeEditor,\n\t\t@IStandaloneThemeService standaloneColorService: IStandaloneThemeService,\n\t\t@ILanguageService languageService: ILanguageService\n\t) {\n\t\tsuper();\n\t\tthis._editor = editor;\n\t\tthis._languageService = languageService;\n\t\tthis._widget = null;\n\n\t\tthis._register(this._editor.onDidChangeModel((e) => this.stop()));\n\t\tthis._register(this._editor.onDidChangeModelLanguage((e) => this.stop()));\n\t\tthis._register(TokenizationRegistry.onDidChange((e) => this.stop()));\n\t\tthis._register(this._editor.onKeyUp((e) => e.keyCode === KeyCode.Escape && this.stop()));\n\t}\n\n\tpublic override dispose(): void {\n\t\tthis.stop();\n\t\tsuper.dispose();\n\t}\n\n\tpublic launch(): void {\n\t\tif (this._widget) {\n\t\t\treturn;\n\t\t}\n\t\tif (!this._editor.hasModel()) {\n\t\t\treturn;\n\t\t}\n\t\tthis._widget = new InspectTokensWidget(this._editor, this._languageService);\n\t}\n\n\tpublic stop(): void {\n\t\tif (this._widget) {\n\t\t\tthis._widget.dispose();\n\t\t\tthis._widget = null;\n\t\t}\n\t}\n}\n\nclass InspectTokens extends EditorAction {\n\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'editor.action.inspectTokens',\n\t\t\tlabel: InspectTokensNLS.inspectTokensAction,\n\t\t\talias: 'Developer: Inspect Tokens',\n\t\t\tprecondition: undefined\n\t\t});\n\t}\n\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor): void {\n\t\tconst controller = InspectTokensController.get(editor);\n\t\tcontroller?.launch();\n\t}\n}\n\ninterface ICompleteLineTokenization {\n\tstartState: IState;\n\ttokens1: Token[];\n\ttokens2: Uint32Array;\n\tendState: IState;\n}\n\ninterface IDecodedMetadata {\n\tlanguageId: string;\n\ttokenType: StandardTokenType;\n\tfontStyle: FontStyle;\n\tforeground: Color;\n\tbackground: Color;\n}\n\nfunction renderTokenText(tokenText: string): string {\n\tlet result: string = '';\n\tfor (let charIndex = 0, len = tokenText.length; charIndex < len; charIndex++) {\n\t\tconst charCode = tokenText.charCodeAt(charIndex);\n\t\tswitch (charCode) {\n\t\t\tcase CharCode.Tab:\n\t\t\t\tresult += '\\u2192'; // →\n\t\t\t\tbreak;\n\n\t\t\tcase CharCode.Space:\n\t\t\t\tresult += '\\u00B7'; // ·\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tresult += String.fromCharCode(charCode);\n\t\t}\n\t}\n\treturn result;\n}\n\nfunction getSafeTokenizationSupport(languageIdCodec: ILanguageIdCodec, languageId: string): ITokenizationSupport {\n\tconst tokenizationSupport = TokenizationRegistry.get(languageId);\n\tif (tokenizationSupport) {\n\t\treturn tokenizationSupport;\n\t}\n\tconst encodedLanguageId = languageIdCodec.encodeLanguageId(languageId);\n\treturn {\n\t\tgetInitialState: () => NullState,\n\t\ttokenize: (line: string, hasEOL: boolean, state: IState) => nullTokenize(languageId, state),\n\t\ttokenizeEncoded: (line: string, hasEOL: boolean, state: IState) => nullTokenizeEncoded(encodedLanguageId, state)\n\t};\n}\n\nclass InspectTokensWidget extends Disposable implements IContentWidget {\n\n\tprivate static readonly _ID = 'editor.contrib.inspectTokensWidget';\n\n\t// Editor.IContentWidget.allowEditorOverflow\n\tpublic allowEditorOverflow = true;\n\n\tprivate readonly _editor: IActiveCodeEditor;\n\tprivate readonly _languageService: ILanguageService;\n\tprivate readonly _tokenizationSupport: ITokenizationSupport;\n\tprivate readonly _model: ITextModel;\n\tprivate readonly _domNode: HTMLElement;\n\n\tconstructor(\n\t\teditor: IActiveCodeEditor,\n\t\tlanguageService: ILanguageService\n\t) {\n\t\tsuper();\n\t\tthis._editor = editor;\n\t\tthis._languageService = languageService;\n\t\tthis._model = this._editor.getModel();\n\t\tthis._domNode = document.createElement('div');\n\t\tthis._domNode.className = 'tokens-inspect-widget';\n\t\tthis._tokenizationSupport = getSafeTokenizationSupport(this._languageService.languageIdCodec, this._model.getLanguageId());\n\t\tthis._compute(this._editor.getPosition());\n\t\tthis._register(this._editor.onDidChangeCursorPosition((e) => this._compute(this._editor.getPosition())));\n\t\tthis._editor.addContentWidget(this);\n\t}\n\n\tpublic override dispose(): void {\n\t\tthis._editor.removeContentWidget(this);\n\t\tsuper.dispose();\n\t}\n\n\tpublic getId(): string {\n\t\treturn InspectTokensWidget._ID;\n\t}\n\n\tprivate _compute(position: Position): void {\n\t\tconst data = this._getTokensAtLine(position.lineNumber);\n\n\t\tlet token1Index = 0;\n\t\tfor (let i = data.tokens1.length - 1; i >= 0; i--) {\n\t\t\tconst t = data.tokens1[i];\n\t\t\tif (position.column - 1 >= t.offset) {\n\t\t\t\ttoken1Index = i;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tlet token2Index = 0;\n\t\tfor (let i = (data.tokens2.length >>> 1); i >= 0; i--) {\n\t\t\tif (position.column - 1 >= data.tokens2[(i << 1)]) {\n\t\t\t\ttoken2Index = i;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tconst lineContent = this._model.getLineContent(position.lineNumber);\n\t\tlet tokenText = '';\n\t\tif (token1Index < data.tokens1.length) {\n\t\t\tconst tokenStartIndex = data.tokens1[token1Index].offset;\n\t\t\tconst tokenEndIndex = token1Index + 1 < data.tokens1.length ? data.tokens1[token1Index + 1].offset : lineContent.length;\n\t\t\ttokenText = lineContent.substring(tokenStartIndex, tokenEndIndex);\n\t\t}\n\t\treset(this._domNode,\n\t\t\t$('h2.tm-token', undefined, renderTokenText(tokenText),\n\t\t\t\t$('span.tm-token-length', undefined, `${tokenText.length} ${tokenText.length === 1 ? 'char' : 'chars'}`)));\n\n\t\tappend(this._domNode, $('hr.tokens-inspect-separator', { 'style': 'clear:both' }));\n\n\t\tconst metadata = (token2Index << 1) + 1 < data.tokens2.length ? this._decodeMetadata(data.tokens2[(token2Index << 1) + 1]) : null;\n\t\tappend(this._domNode, $('table.tm-metadata-table', undefined,\n\t\t\t$('tbody', undefined,\n\t\t\t\t$('tr', undefined,\n\t\t\t\t\t$('td.tm-metadata-key', undefined, 'language'),\n\t\t\t\t\t$('td.tm-metadata-value', undefined, `${metadata ? metadata.languageId : '-?-'}`)\n\t\t\t\t),\n\t\t\t\t$('tr', undefined,\n\t\t\t\t\t$('td.tm-metadata-key', undefined, 'token type' as string),\n\t\t\t\t\t$('td.tm-metadata-value', undefined, `${metadata ? this._tokenTypeToString(metadata.tokenType) : '-?-'}`)\n\t\t\t\t),\n\t\t\t\t$('tr', undefined,\n\t\t\t\t\t$('td.tm-metadata-key', undefined, 'font style' as string),\n\t\t\t\t\t$('td.tm-metadata-value', undefined, `${metadata ? this._fontStyleToString(metadata.fontStyle) : '-?-'}`)\n\t\t\t\t),\n\t\t\t\t$('tr', undefined,\n\t\t\t\t\t$('td.tm-metadata-key', undefined, 'foreground'),\n\t\t\t\t\t$('td.tm-metadata-value', undefined, `${metadata ? Color.Format.CSS.formatHex(metadata.foreground) : '-?-'}`)\n\t\t\t\t),\n\t\t\t\t$('tr', undefined,\n\t\t\t\t\t$('td.tm-metadata-key', undefined, 'background'),\n\t\t\t\t\t$('td.tm-metadata-value', undefined, `${metadata ? Color.Format.CSS.formatHex(metadata.background) : '-?-'}`)\n\t\t\t\t)\n\t\t\t)\n\t\t));\n\t\tappend(this._domNode, $('hr.tokens-inspect-separator'));\n\n\t\tif (token1Index < data.tokens1.length) {\n\t\t\tappend(this._domNode, $('span.tm-token-type', undefined, data.tokens1[token1Index].type));\n\t\t}\n\n\t\tthis._editor.layoutContentWidget(this);\n\t}\n\n\tprivate _decodeMetadata(metadata: number): IDecodedMetadata {\n\t\tconst colorMap = TokenizationRegistry.getColorMap()!;\n\t\tconst languageId = TokenMetadata.getLanguageId(metadata);\n\t\tconst tokenType = TokenMetadata.getTokenType(metadata);\n\t\tconst fontStyle = TokenMetadata.getFontStyle(metadata);\n\t\tconst foreground = TokenMetadata.getForeground(metadata);\n\t\tconst background = TokenMetadata.getBackground(metadata);\n\t\treturn {\n\t\t\tlanguageId: this._languageService.languageIdCodec.decodeLanguageId(languageId),\n\t\t\ttokenType: tokenType,\n\t\t\tfontStyle: fontStyle,\n\t\t\tforeground: colorMap[foreground],\n\t\t\tbackground: colorMap[background]\n\t\t};\n\t}\n\n\tprivate _tokenTypeToString(tokenType: StandardTokenType): string {\n\t\tswitch (tokenType) {\n\t\t\tcase StandardTokenType.Other: return 'Other';\n\t\t\tcase StandardTokenType.Comment: return 'Comment';\n\t\t\tcase StandardTokenType.String: return 'String';\n\t\t\tcase StandardTokenType.RegEx: return 'RegEx';\n\t\t\tdefault: return '??';\n\t\t}\n\t}\n\n\tprivate _fontStyleToString(fontStyle: FontStyle): string {\n\t\tlet r = '';\n\t\tif (fontStyle & FontStyle.Italic) {\n\t\t\tr += 'italic ';\n\t\t}\n\t\tif (fontStyle & FontStyle.Bold) {\n\t\t\tr += 'bold ';\n\t\t}\n\t\tif (fontStyle & FontStyle.Underline) {\n\t\t\tr += 'underline ';\n\t\t}\n\t\tif (fontStyle & FontStyle.Strikethrough) {\n\t\t\tr += 'strikethrough ';\n\t\t}\n\t\tif (r.length === 0) {\n\t\t\tr = '---';\n\t\t}\n\t\treturn r;\n\t}\n\n\tprivate _getTokensAtLine(lineNumber: number): ICompleteLineTokenization {\n\t\tconst stateBeforeLine = this._getStateBeforeLine(lineNumber);\n\n\t\tconst tokenizationResult1 = this._tokenizationSupport.tokenize(this._model.getLineContent(lineNumber), true, stateBeforeLine);\n\t\tconst tokenizationResult2 = this._tokenizationSupport.tokenizeEncoded(this._model.getLineContent(lineNumber), true, stateBeforeLine);\n\n\t\treturn {\n\t\t\tstartState: stateBeforeLine,\n\t\t\ttokens1: tokenizationResult1.tokens,\n\t\t\ttokens2: tokenizationResult2.tokens,\n\t\t\tendState: tokenizationResult1.endState\n\t\t};\n\t}\n\n\tprivate _getStateBeforeLine(lineNumber: number): IState {\n\t\tlet state: IState = this._tokenizationSupport.getInitialState();\n\n\t\tfor (let i = 1; i < lineNumber; i++) {\n\t\t\tconst tokenizationResult = this._tokenizationSupport.tokenize(this._model.getLineContent(i), true, state);\n\t\t\tstate = tokenizationResult.endState;\n\t\t}\n\n\t\treturn state;\n\t}\n\n\tpublic getDomNode(): HTMLElement {\n\t\treturn this._domNode;\n\t}\n\n\tpublic getPosition(): IContentWidgetPosition {\n\t\treturn {\n\t\t\tposition: this._editor.getPosition(),\n\t\t\tpreference: [ContentWidgetPositionPreference.BELOW, ContentWidgetPositionPreference.ABOVE]\n\t\t};\n\t}\n}\n\nregisterEditorContribution(InspectTokensController.ID, InspectTokensController, EditorContributionInstantiation.Lazy);\nregisterEditorAction(InspectTokens);\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\nimport { WorkbenchActionExecutedClassification, WorkbenchActionExecutedEvent } from 'vs/base/common/actions';\nimport { CancellationToken } from 'vs/base/common/cancellation';\nimport { toErrorMessage } from 'vs/base/common/errorMessage';\nimport { isCancellationError } from 'vs/base/common/errors';\nimport { matchesContiguousSubString, matchesPrefix, matchesWords, or } from 'vs/base/common/filters';\nimport { createSingleCallFunction } from 'vs/base/common/functional';\nimport { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle';\nimport { LRUCache } from 'vs/base/common/map';\nimport { TfIdfCalculator, normalizeTfIdfScores } from 'vs/base/common/tfIdf';\nimport { localize } from 'vs/nls';\nimport { ILocalizedString } from 'vs/platform/action/common/action';\nimport { ICommandService } from 'vs/platform/commands/common/commands';\nimport { IConfigurationChangeEvent, IConfigurationService } from 'vs/platform/configuration/common/configuration';\nimport { IDialogService } from 'vs/platform/dialogs/common/dialogs';\nimport { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';\nimport { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';\nimport { ILogService } from 'vs/platform/log/common/log';\nimport { FastAndSlowPicks, IPickerQuickAccessItem, IPickerQuickAccessProviderOptions, PickerQuickAccessProvider, Picks } from 'vs/platform/quickinput/browser/pickerQuickAccess';\nimport { IQuickAccessProviderRunOptions } from 'vs/platform/quickinput/common/quickAccess';\nimport { IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput';\nimport { IStorageService, StorageScope, StorageTarget, WillSaveStateReason } from 'vs/platform/storage/common/storage';\nimport { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';\n\nexport interface ICommandQuickPick extends IPickerQuickAccessItem {\n\treadonly commandId: string;\n\treadonly commandAlias?: string;\n\treadonly commandDescription?: ILocalizedString;\n\ttfIdfScore?: number;\n\treadonly args?: any[];\n}\n\nexport interface ICommandsQuickAccessOptions extends IPickerQuickAccessProviderOptions {\n\treadonly showAlias: boolean;\n\tsuggestedCommandIds?: Set;\n}\n\nexport abstract class AbstractCommandsQuickAccessProvider extends PickerQuickAccessProvider implements IDisposable {\n\n\tstatic PREFIX = '>';\n\n\tprivate static readonly TFIDF_THRESHOLD = 0.5;\n\tprivate static readonly TFIDF_MAX_RESULTS = 5;\n\n\tprivate static WORD_FILTER = or(matchesPrefix, matchesWords, matchesContiguousSubString);\n\n\tprivate readonly commandsHistory = this._register(this.instantiationService.createInstance(CommandsHistory));\n\n\tprotected override readonly options: ICommandsQuickAccessOptions;\n\n\tconstructor(\n\t\toptions: ICommandsQuickAccessOptions,\n\t\t@IInstantiationService private readonly instantiationService: IInstantiationService,\n\t\t@IKeybindingService protected readonly keybindingService: IKeybindingService,\n\t\t@ICommandService private readonly commandService: ICommandService,\n\t\t@ITelemetryService private readonly telemetryService: ITelemetryService,\n\t\t@IDialogService private readonly dialogService: IDialogService\n\t) {\n\t\tsuper(AbstractCommandsQuickAccessProvider.PREFIX, options);\n\n\t\tthis.options = options;\n\t}\n\n\tprotected async _getPicks(filter: string, _disposables: DisposableStore, token: CancellationToken, runOptions?: IQuickAccessProviderRunOptions): Promise | FastAndSlowPicks> {\n\n\t\t// Ask subclass for all command picks\n\t\tconst allCommandPicks = await this.getCommandPicks(token);\n\n\t\tif (token.isCancellationRequested) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst runTfidf = createSingleCallFunction(() => {\n\t\t\tconst tfidf = new TfIdfCalculator();\n\t\t\ttfidf.updateDocuments(allCommandPicks.map(commandPick => ({\n\t\t\t\tkey: commandPick.commandId,\n\t\t\t\ttextChunks: [this.getTfIdfChunk(commandPick)]\n\t\t\t})));\n\t\t\tconst result = tfidf.calculateScores(filter, token);\n\n\t\t\treturn normalizeTfIdfScores(result)\n\t\t\t\t.filter(score => score.score > AbstractCommandsQuickAccessProvider.TFIDF_THRESHOLD)\n\t\t\t\t.slice(0, AbstractCommandsQuickAccessProvider.TFIDF_MAX_RESULTS);\n\t\t});\n\n\t\t// Filter\n\t\tconst filteredCommandPicks: ICommandQuickPick[] = [];\n\t\tfor (const commandPick of allCommandPicks) {\n\t\t\tconst labelHighlights = AbstractCommandsQuickAccessProvider.WORD_FILTER(filter, commandPick.label) ?? undefined;\n\t\t\tconst aliasHighlights = commandPick.commandAlias ? AbstractCommandsQuickAccessProvider.WORD_FILTER(filter, commandPick.commandAlias) ?? undefined : undefined;\n\n\t\t\t// Add if matching in label or alias\n\t\t\tif (labelHighlights || aliasHighlights) {\n\t\t\t\tcommandPick.highlights = {\n\t\t\t\t\tlabel: labelHighlights,\n\t\t\t\t\tdetail: this.options.showAlias ? aliasHighlights : undefined\n\t\t\t\t};\n\n\t\t\t\tfilteredCommandPicks.push(commandPick);\n\t\t\t}\n\n\t\t\t// Also add if we have a 100% command ID match\n\t\t\telse if (filter === commandPick.commandId) {\n\t\t\t\tfilteredCommandPicks.push(commandPick);\n\t\t\t}\n\n\t\t\t// Handle tf-idf scoring for the rest if there's a filter\n\t\t\telse if (filter.length >= 3) {\n\t\t\t\tconst tfidf = runTfidf();\n\t\t\t\tif (token.isCancellationRequested) {\n\t\t\t\t\treturn [];\n\t\t\t\t}\n\n\t\t\t\t// Add if we have a tf-idf score\n\t\t\t\tconst tfidfScore = tfidf.find(score => score.key === commandPick.commandId);\n\t\t\t\tif (tfidfScore) {\n\t\t\t\t\tcommandPick.tfIdfScore = tfidfScore.score;\n\t\t\t\t\tfilteredCommandPicks.push(commandPick);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Add description to commands that have duplicate labels\n\t\tconst mapLabelToCommand = new Map();\n\t\tfor (const commandPick of filteredCommandPicks) {\n\t\t\tconst existingCommandForLabel = mapLabelToCommand.get(commandPick.label);\n\t\t\tif (existingCommandForLabel) {\n\t\t\t\tcommandPick.description = commandPick.commandId;\n\t\t\t\texistingCommandForLabel.description = existingCommandForLabel.commandId;\n\t\t\t} else {\n\t\t\t\tmapLabelToCommand.set(commandPick.label, commandPick);\n\t\t\t}\n\t\t}\n\n\t\t// Sort by MRU order and fallback to name otherwise\n\t\tfilteredCommandPicks.sort((commandPickA, commandPickB) => {\n\t\t\t// If a result came from tf-idf, we want to put that towards the bottom\n\t\t\tif (commandPickA.tfIdfScore && commandPickB.tfIdfScore) {\n\t\t\t\tif (commandPickA.tfIdfScore === commandPickB.tfIdfScore) {\n\t\t\t\t\treturn commandPickA.label.localeCompare(commandPickB.label); // prefer lexicographically smaller command\n\t\t\t\t}\n\t\t\t\treturn commandPickB.tfIdfScore - commandPickA.tfIdfScore; // prefer higher tf-idf score\n\t\t\t} else if (commandPickA.tfIdfScore) {\n\t\t\t\treturn 1; // first command has a score but other doesn't so other wins\n\t\t\t} else if (commandPickB.tfIdfScore) {\n\t\t\t\treturn -1; // other command has a score but first doesn't so first wins\n\t\t\t}\n\n\t\t\tconst commandACounter = this.commandsHistory.peek(commandPickA.commandId);\n\t\t\tconst commandBCounter = this.commandsHistory.peek(commandPickB.commandId);\n\n\t\t\tif (commandACounter && commandBCounter) {\n\t\t\t\treturn commandACounter > commandBCounter ? -1 : 1; // use more recently used command before older\n\t\t\t}\n\n\t\t\tif (commandACounter) {\n\t\t\t\treturn -1; // first command was used, so it wins over the non used one\n\t\t\t}\n\n\t\t\tif (commandBCounter) {\n\t\t\t\treturn 1; // other command was used so it wins over the command\n\t\t\t}\n\n\t\t\tif (this.options.suggestedCommandIds) {\n\t\t\t\tconst commandASuggestion = this.options.suggestedCommandIds.has(commandPickA.commandId);\n\t\t\t\tconst commandBSuggestion = this.options.suggestedCommandIds.has(commandPickB.commandId);\n\t\t\t\tif (commandASuggestion && commandBSuggestion) {\n\t\t\t\t\treturn 0; // honor the order of the array\n\t\t\t\t}\n\n\t\t\t\tif (commandASuggestion) {\n\t\t\t\t\treturn -1; // first command was suggested, so it wins over the non suggested one\n\t\t\t\t}\n\n\t\t\t\tif (commandBSuggestion) {\n\t\t\t\t\treturn 1; // other command was suggested so it wins over the command\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// both commands were never used, so we sort by name\n\t\t\treturn commandPickA.label.localeCompare(commandPickB.label);\n\t\t});\n\n\t\tconst commandPicks: Array = [];\n\n\t\tlet addOtherSeparator = false;\n\t\tlet addSuggestedSeparator = true;\n\t\tlet addCommonlyUsedSeparator = !!this.options.suggestedCommandIds;\n\t\tfor (let i = 0; i < filteredCommandPicks.length; i++) {\n\t\t\tconst commandPick = filteredCommandPicks[i];\n\n\t\t\t// Separator: recently used\n\t\t\tif (i === 0 && this.commandsHistory.peek(commandPick.commandId)) {\n\t\t\t\tcommandPicks.push({ type: 'separator', label: localize('recentlyUsed', \"recently used\") });\n\t\t\t\taddOtherSeparator = true;\n\t\t\t}\n\n\t\t\tif (addSuggestedSeparator && commandPick.tfIdfScore !== undefined) {\n\t\t\t\tcommandPicks.push({ type: 'separator', label: localize('suggested', \"similar commands\") });\n\t\t\t\taddSuggestedSeparator = false;\n\t\t\t}\n\n\t\t\t// Separator: commonly used\n\t\t\tif (addCommonlyUsedSeparator && commandPick.tfIdfScore === undefined && !this.commandsHistory.peek(commandPick.commandId) && this.options.suggestedCommandIds?.has(commandPick.commandId)) {\n\t\t\t\tcommandPicks.push({ type: 'separator', label: localize('commonlyUsed', \"commonly used\") });\n\t\t\t\taddOtherSeparator = true;\n\t\t\t\taddCommonlyUsedSeparator = false;\n\t\t\t}\n\n\t\t\t// Separator: other commands\n\t\t\tif (addOtherSeparator && commandPick.tfIdfScore === undefined && !this.commandsHistory.peek(commandPick.commandId) && !this.options.suggestedCommandIds?.has(commandPick.commandId)) {\n\t\t\t\tcommandPicks.push({ type: 'separator', label: localize('morecCommands', \"other commands\") });\n\t\t\t\taddOtherSeparator = false;\n\t\t\t}\n\n\t\t\t// Command\n\t\t\tcommandPicks.push(this.toCommandPick(commandPick, runOptions));\n\t\t}\n\n\t\tif (!this.hasAdditionalCommandPicks(filter, token)) {\n\t\t\treturn commandPicks;\n\t\t}\n\n\t\treturn {\n\t\t\tpicks: commandPicks,\n\t\t\tadditionalPicks: (async (): Promise> => {\n\t\t\t\tconst additionalCommandPicks = await this.getAdditionalCommandPicks(allCommandPicks, filteredCommandPicks, filter, token);\n\t\t\t\tif (token.isCancellationRequested) {\n\t\t\t\t\treturn [];\n\t\t\t\t}\n\n\t\t\t\tconst commandPicks: Array = additionalCommandPicks.map(commandPick => this.toCommandPick(commandPick, runOptions));\n\t\t\t\t// Basically, if we haven't already added a separator, we add one before the additional picks so long\n\t\t\t\t// as one hasn't been added to the start of the array.\n\t\t\t\tif (addSuggestedSeparator && commandPicks[0]?.type !== 'separator') {\n\t\t\t\t\tcommandPicks.unshift({ type: 'separator', label: localize('suggested', \"similar commands\") });\n\t\t\t\t}\n\t\t\t\treturn commandPicks;\n\t\t\t})()\n\t\t};\n\t}\n\n\tprivate toCommandPick(commandPick: ICommandQuickPick | IQuickPickSeparator, runOptions?: IQuickAccessProviderRunOptions): ICommandQuickPick | IQuickPickSeparator {\n\t\tif (commandPick.type === 'separator') {\n\t\t\treturn commandPick;\n\t\t}\n\n\t\tconst keybinding = this.keybindingService.lookupKeybinding(commandPick.commandId);\n\t\tconst ariaLabel = keybinding ?\n\t\t\tlocalize('commandPickAriaLabelWithKeybinding', \"{0}, {1}\", commandPick.label, keybinding.getAriaLabel()) :\n\t\t\tcommandPick.label;\n\n\t\treturn {\n\t\t\t...commandPick,\n\t\t\tariaLabel,\n\t\t\tdetail: this.options.showAlias && commandPick.commandAlias !== commandPick.label ? commandPick.commandAlias : undefined,\n\t\t\tkeybinding,\n\t\t\taccept: async () => {\n\n\t\t\t\t// Add to history\n\t\t\t\tthis.commandsHistory.push(commandPick.commandId);\n\n\t\t\t\t// Telementry\n\t\t\t\tthis.telemetryService.publicLog2('workbenchActionExecuted', {\n\t\t\t\t\tid: commandPick.commandId,\n\t\t\t\t\tfrom: runOptions?.from ?? 'quick open'\n\t\t\t\t});\n\n\t\t\t\t// Run\n\t\t\t\ttry {\n\t\t\t\t\tcommandPick.args?.length\n\t\t\t\t\t\t? await this.commandService.executeCommand(commandPick.commandId, ...commandPick.args)\n\t\t\t\t\t\t: await this.commandService.executeCommand(commandPick.commandId);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (!isCancellationError(error)) {\n\t\t\t\t\t\tthis.dialogService.error(localize('canNotRun', \"Command '{0}' resulted in an error\", commandPick.label), toErrorMessage(error));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n\n\t// TF-IDF string to be indexed\n\tprivate getTfIdfChunk({ label, commandAlias, commandDescription }: ICommandQuickPick) {\n\t\tlet chunk = label;\n\t\tif (commandAlias && commandAlias !== label) {\n\t\t\tchunk += ` - ${commandAlias}`;\n\t\t}\n\t\tif (commandDescription && commandDescription.value !== label) {\n\t\t\t// If the original is the same as the value, don't add it\n\t\t\tchunk += ` - ${commandDescription.value === commandDescription.original ? commandDescription.value : `${commandDescription.value} (${commandDescription.original})`}`;\n\t\t}\n\t\treturn chunk;\n\t}\n\n\tprotected abstract getCommandPicks(token: CancellationToken): Promise>;\n\n\tprotected abstract hasAdditionalCommandPicks(filter: string, token: CancellationToken): boolean;\n\tprotected abstract getAdditionalCommandPicks(allPicks: ICommandQuickPick[], picksSoFar: ICommandQuickPick[], filter: string, token: CancellationToken): Promise>;\n}\n\ninterface ISerializedCommandHistory {\n\treadonly usesLRU?: boolean;\n\treadonly entries: { key: string; value: number }[];\n}\n\ninterface ICommandsQuickAccessConfiguration {\n\treadonly workbench: {\n\t\treadonly commandPalette: {\n\t\t\treadonly history: number;\n\t\t\treadonly preserveInput: boolean;\n\t\t};\n\t};\n}\n\nexport class CommandsHistory extends Disposable {\n\n\tstatic readonly DEFAULT_COMMANDS_HISTORY_LENGTH = 50;\n\n\tprivate static readonly PREF_KEY_CACHE = 'commandPalette.mru.cache';\n\tprivate static readonly PREF_KEY_COUNTER = 'commandPalette.mru.counter';\n\n\tprivate static cache: LRUCache | undefined;\n\tprivate static counter = 1;\n\tprivate static hasChanges = false;\n\n\tprivate configuredCommandsHistoryLength = 0;\n\n\tconstructor(\n\t\t@IStorageService private readonly storageService: IStorageService,\n\t\t@IConfigurationService private readonly configurationService: IConfigurationService,\n\t\t@ILogService private readonly logService: ILogService\n\t) {\n\t\tsuper();\n\n\t\tthis.updateConfiguration();\n\t\tthis.load();\n\n\t\tthis.registerListeners();\n\t}\n\n\tprivate registerListeners(): void {\n\t\tthis._register(this.configurationService.onDidChangeConfiguration(e => this.updateConfiguration(e)));\n\t\tthis._register(this.storageService.onWillSaveState(e => {\n\t\t\tif (e.reason === WillSaveStateReason.SHUTDOWN) {\n\t\t\t\t// Commands history is very dynamic and so we limit impact\n\t\t\t\t// on storage to only save on shutdown. This helps reduce\n\t\t\t\t// the overhead of syncing this data across machines.\n\t\t\t\tthis.saveState();\n\t\t\t}\n\t\t}));\n\t}\n\n\tprivate updateConfiguration(e?: IConfigurationChangeEvent): void {\n\t\tif (e && !e.affectsConfiguration('workbench.commandPalette.history')) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.configuredCommandsHistoryLength = CommandsHistory.getConfiguredCommandHistoryLength(this.configurationService);\n\n\t\tif (CommandsHistory.cache && CommandsHistory.cache.limit !== this.configuredCommandsHistoryLength) {\n\t\t\tCommandsHistory.cache.limit = this.configuredCommandsHistoryLength;\n\t\t\tCommandsHistory.hasChanges = true;\n\t\t}\n\t}\n\n\tprivate load(): void {\n\t\tconst raw = this.storageService.get(CommandsHistory.PREF_KEY_CACHE, StorageScope.PROFILE);\n\t\tlet serializedCache: ISerializedCommandHistory | undefined;\n\t\tif (raw) {\n\t\t\ttry {\n\t\t\t\tserializedCache = JSON.parse(raw);\n\t\t\t} catch (error) {\n\t\t\t\tthis.logService.error(`[CommandsHistory] invalid data: ${error}`);\n\t\t\t}\n\t\t}\n\n\t\tconst cache = CommandsHistory.cache = new LRUCache(this.configuredCommandsHistoryLength, 1);\n\t\tif (serializedCache) {\n\t\t\tlet entries: { key: string; value: number }[];\n\t\t\tif (serializedCache.usesLRU) {\n\t\t\t\tentries = serializedCache.entries;\n\t\t\t} else {\n\t\t\t\tentries = serializedCache.entries.sort((a, b) => a.value - b.value);\n\t\t\t}\n\t\t\tentries.forEach(entry => cache.set(entry.key, entry.value));\n\t\t}\n\n\t\tCommandsHistory.counter = this.storageService.getNumber(CommandsHistory.PREF_KEY_COUNTER, StorageScope.PROFILE, CommandsHistory.counter);\n\t}\n\n\tpush(commandId: string): void {\n\t\tif (!CommandsHistory.cache) {\n\t\t\treturn;\n\t\t}\n\n\t\tCommandsHistory.cache.set(commandId, CommandsHistory.counter++); // set counter to command\n\t\tCommandsHistory.hasChanges = true;\n\t}\n\n\tpeek(commandId: string): number | undefined {\n\t\treturn CommandsHistory.cache?.peek(commandId);\n\t}\n\n\tprivate saveState(): void {\n\t\tif (!CommandsHistory.cache) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (!CommandsHistory.hasChanges) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst serializedCache: ISerializedCommandHistory = { usesLRU: true, entries: [] };\n\t\tCommandsHistory.cache.forEach((value, key) => serializedCache.entries.push({ key, value }));\n\n\t\tthis.storageService.store(CommandsHistory.PREF_KEY_CACHE, JSON.stringify(serializedCache), StorageScope.PROFILE, StorageTarget.USER);\n\t\tthis.storageService.store(CommandsHistory.PREF_KEY_COUNTER, CommandsHistory.counter, StorageScope.PROFILE, StorageTarget.USER);\n\t\tCommandsHistory.hasChanges = false;\n\t}\n\n\tstatic getConfiguredCommandHistoryLength(configurationService: IConfigurationService): number {\n\t\tconst config = configurationService.getValue();\n\n\t\tconst configuredCommandHistoryLength = config.workbench?.commandPalette?.history;\n\t\tif (typeof configuredCommandHistoryLength === 'number') {\n\t\t\treturn configuredCommandHistoryLength;\n\t\t}\n\n\t\treturn CommandsHistory.DEFAULT_COMMANDS_HISTORY_LENGTH;\n\t}\n}\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\nimport { stripIcons } from 'vs/base/common/iconLabels';\nimport { IEditor } from 'vs/editor/common/editorCommon';\nimport { ILocalizedString } from 'vs/nls';\nimport { isLocalizedString } from 'vs/platform/action/common/action';\nimport { ICommandService } from 'vs/platform/commands/common/commands';\nimport { IDialogService } from 'vs/platform/dialogs/common/dialogs';\nimport { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';\nimport { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';\nimport { AbstractCommandsQuickAccessProvider, ICommandQuickPick, ICommandsQuickAccessOptions } from 'vs/platform/quickinput/browser/commandsQuickAccess';\nimport { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';\n\nexport abstract class AbstractEditorCommandsQuickAccessProvider extends AbstractCommandsQuickAccessProvider {\n\n\tconstructor(\n\t\toptions: ICommandsQuickAccessOptions,\n\t\tinstantiationService: IInstantiationService,\n\t\tkeybindingService: IKeybindingService,\n\t\tcommandService: ICommandService,\n\t\ttelemetryService: ITelemetryService,\n\t\tdialogService: IDialogService\n\t) {\n\t\tsuper(options, instantiationService, keybindingService, commandService, telemetryService, dialogService);\n\t}\n\n\t/**\n\t * Subclasses to provide the current active editor control.\n\t */\n\tprotected abstract activeTextEditorControl: IEditor | undefined;\n\n\tprotected getCodeEditorCommandPicks(): ICommandQuickPick[] {\n\t\tconst activeTextEditorControl = this.activeTextEditorControl;\n\t\tif (!activeTextEditorControl) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst editorCommandPicks: ICommandQuickPick[] = [];\n\t\tfor (const editorAction of activeTextEditorControl.getSupportedActions()) {\n\t\t\tlet commandDescription: undefined | ILocalizedString;\n\t\t\tif (editorAction.metadata?.description) {\n\t\t\t\tif (isLocalizedString(editorAction.metadata.description)) {\n\t\t\t\t\tcommandDescription = editorAction.metadata.description;\n\t\t\t\t} else {\n\t\t\t\t\tcommandDescription = { original: editorAction.metadata.description, value: editorAction.metadata.description };\n\t\t\t\t}\n\t\t\t}\n\t\t\teditorCommandPicks.push({\n\t\t\t\tcommandId: editorAction.id,\n\t\t\t\tcommandAlias: editorAction.alias,\n\t\t\t\tcommandDescription,\n\t\t\t\tlabel: stripIcons(editorAction.label) || editorAction.id,\n\t\t\t});\n\t\t}\n\n\t\treturn editorCommandPicks;\n\t}\n}\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\nimport { Registry } from 'vs/platform/registry/common/platform';\nimport { IQuickAccessRegistry, Extensions } from 'vs/platform/quickinput/common/quickAccess';\nimport { QuickCommandNLS } from 'vs/editor/common/standaloneStrings';\nimport { ICommandQuickPick } from 'vs/platform/quickinput/browser/commandsQuickAccess';\nimport { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';\nimport { AbstractEditorCommandsQuickAccessProvider } from 'vs/editor/contrib/quickAccess/browser/commandsQuickAccess';\nimport { IEditor } from 'vs/editor/common/editorCommon';\nimport { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';\nimport { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';\nimport { ICommandService } from 'vs/platform/commands/common/commands';\nimport { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';\nimport { IDialogService } from 'vs/platform/dialogs/common/dialogs';\nimport { EditorAction, registerEditorAction } from 'vs/editor/browser/editorExtensions';\nimport { EditorContextKeys } from 'vs/editor/common/editorContextKeys';\nimport { KeyCode } from 'vs/base/common/keyCodes';\nimport { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';\nimport { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';\n\nexport class StandaloneCommandsQuickAccessProvider extends AbstractEditorCommandsQuickAccessProvider {\n\n\tprotected get activeTextEditorControl(): IEditor | undefined { return this.codeEditorService.getFocusedCodeEditor() ?? undefined; }\n\n\tconstructor(\n\t\t@IInstantiationService instantiationService: IInstantiationService,\n\t\t@ICodeEditorService private readonly codeEditorService: ICodeEditorService,\n\t\t@IKeybindingService keybindingService: IKeybindingService,\n\t\t@ICommandService commandService: ICommandService,\n\t\t@ITelemetryService telemetryService: ITelemetryService,\n\t\t@IDialogService dialogService: IDialogService\n\t) {\n\t\tsuper({ showAlias: false }, instantiationService, keybindingService, commandService, telemetryService, dialogService);\n\t}\n\n\tprotected async getCommandPicks(): Promise> {\n\t\treturn this.getCodeEditorCommandPicks();\n\t}\n\n\tprotected hasAdditionalCommandPicks(): boolean {\n\t\treturn false;\n\t}\n\n\tprotected async getAdditionalCommandPicks(): Promise {\n\t\treturn [];\n\t}\n}\n\nexport class GotoLineAction extends EditorAction {\n\n\tstatic readonly ID = 'editor.action.quickCommand';\n\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: GotoLineAction.ID,\n\t\t\tlabel: QuickCommandNLS.quickCommandActionLabel,\n\t\t\talias: 'Command Palette',\n\t\t\tprecondition: undefined,\n\t\t\tkbOpts: {\n\t\t\t\tkbExpr: EditorContextKeys.focus,\n\t\t\t\tprimary: KeyCode.F1,\n\t\t\t\tweight: KeybindingWeight.EditorContrib\n\t\t\t},\n\t\t\tcontextMenuOpts: {\n\t\t\t\tgroup: 'z_commands',\n\t\t\t\torder: 1\n\t\t\t}\n\t\t});\n\t}\n\n\trun(accessor: ServicesAccessor): void {\n\t\taccessor.get(IQuickInputService).quickAccess.show(StandaloneCommandsQuickAccessProvider.PREFIX);\n\t}\n}\n\nregisterEditorAction(GotoLineAction);\n\nRegistry.as(Extensions.Quickaccess).registerQuickAccessProvider({\n\tctor: StandaloneCommandsQuickAccessProvider,\n\tprefix: StandaloneCommandsQuickAccessProvider.PREFIX,\n\thelpEntries: [{ description: QuickCommandNLS.quickCommandHelp, commandId: GotoLineAction.ID }]\n});\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\nimport { assertNever } from 'vs/base/common/assert';\nimport { RunOnceScheduler } from 'vs/base/common/async';\nimport { Color } from 'vs/base/common/color';\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { IJSONSchema, IJSONSchemaMap } from 'vs/base/common/jsonSchema';\nimport { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/platform/jsonschemas/common/jsonContributionRegistry';\nimport * as platform from 'vs/platform/registry/common/platform';\nimport { IColorTheme } from 'vs/platform/theme/common/themeService';\n\n// ------ API types\n\nexport type ColorIdentifier = string;\n\nexport interface ColorContribution {\n\treadonly id: ColorIdentifier;\n\treadonly description: string;\n\treadonly defaults: ColorDefaults | null;\n\treadonly needsTransparency: boolean;\n\treadonly deprecationMessage: string | undefined;\n}\n\n/**\n * Returns the css variable name for the given color identifier. Dots (`.`) are replaced with hyphens (`-`) and\n * everything is prefixed with `--vscode-`.\n *\n * @sample `editorSuggestWidget.background` is `--vscode-editorSuggestWidget-background`.\n */\nexport function asCssVariableName(colorIdent: ColorIdentifier): string {\n\treturn `--vscode-${colorIdent.replace(/\\./g, '-')}`;\n}\n\nexport function asCssVariable(color: ColorIdentifier): string {\n\treturn `var(${asCssVariableName(color)})`;\n}\n\nexport function asCssVariableWithDefault(color: ColorIdentifier, defaultCssValue: string): string {\n\treturn `var(${asCssVariableName(color)}, ${defaultCssValue})`;\n}\n\nexport const enum ColorTransformType {\n\tDarken,\n\tLighten,\n\tTransparent,\n\tOpaque,\n\tOneOf,\n\tLessProminent,\n\tIfDefinedThenElse\n}\n\nexport type ColorTransform =\n\t| { op: ColorTransformType.Darken; value: ColorValue; factor: number }\n\t| { op: ColorTransformType.Lighten; value: ColorValue; factor: number }\n\t| { op: ColorTransformType.Transparent; value: ColorValue; factor: number }\n\t| { op: ColorTransformType.Opaque; value: ColorValue; background: ColorValue }\n\t| { op: ColorTransformType.OneOf; values: readonly ColorValue[] }\n\t| { op: ColorTransformType.LessProminent; value: ColorValue; background: ColorValue; factor: number; transparency: number }\n\t| { op: ColorTransformType.IfDefinedThenElse; if: ColorIdentifier; then: ColorValue; else: ColorValue };\n\nexport interface ColorDefaults {\n\tlight: ColorValue | null;\n\tdark: ColorValue | null;\n\thcDark: ColorValue | null;\n\thcLight: ColorValue | null;\n}\n\n\n/**\n * A Color Value is either a color literal, a reference to an other color or a derived color\n */\nexport type ColorValue = Color | string | ColorIdentifier | ColorTransform;\n\n// color registry\nexport const Extensions = {\n\tColorContribution: 'base.contributions.colors'\n};\n\nexport interface IColorRegistry {\n\n\t/**\n\t * Get all color contributions\n\t */\n\tgetColors(): ColorContribution[];\n\n\t/**\n\t * Gets the default color of the given id\n\t */\n\tresolveDefaultColor(id: ColorIdentifier, theme: IColorTheme): Color | undefined;\n\n}\n\nclass ColorRegistry implements IColorRegistry {\n\n\tprivate readonly _onDidChangeSchema = new Emitter();\n\treadonly onDidChangeSchema: Event = this._onDidChangeSchema.event;\n\n\tprivate colorsById: { [key: string]: ColorContribution };\n\tprivate colorSchema: IJSONSchema & { properties: IJSONSchemaMap } = { type: 'object', properties: {} };\n\tprivate colorReferenceSchema: IJSONSchema & { enum: string[]; enumDescriptions: string[] } = { type: 'string', enum: [], enumDescriptions: [] };\n\n\tconstructor() {\n\t\tthis.colorsById = {};\n\t}\n\n\tpublic registerColor(id: string, defaults: ColorDefaults | null, description: string, needsTransparency = false, deprecationMessage?: string): ColorIdentifier {\n\t\tconst colorContribution: ColorContribution = { id, description, defaults, needsTransparency, deprecationMessage };\n\t\tthis.colorsById[id] = colorContribution;\n\t\tconst propertySchema: IJSONSchema = { type: 'string', description, format: 'color-hex', defaultSnippets: [{ body: '${1:#ff0000}' }] };\n\t\tif (deprecationMessage) {\n\t\t\tpropertySchema.deprecationMessage = deprecationMessage;\n\t\t}\n\t\tif (needsTransparency) {\n\t\t\tpropertySchema.pattern = '^#(?:(?[0-9a-fA-f]{3}[0-9a-eA-E])|(?:[0-9a-fA-F]{6}(?:(?![fF]{2})(?:[0-9a-fA-F]{2}))))?$';\n\t\t\tpropertySchema.patternErrorMessage = 'This color must be transparent or it will obscure content';\n\t\t}\n\t\tthis.colorSchema.properties[id] = propertySchema;\n\t\tthis.colorReferenceSchema.enum.push(id);\n\t\tthis.colorReferenceSchema.enumDescriptions.push(description);\n\n\t\tthis._onDidChangeSchema.fire();\n\t\treturn id;\n\t}\n\n\tpublic getColors(): ColorContribution[] {\n\t\treturn Object.keys(this.colorsById).map(id => this.colorsById[id]);\n\t}\n\n\tpublic resolveDefaultColor(id: ColorIdentifier, theme: IColorTheme): Color | undefined {\n\t\tconst colorDesc = this.colorsById[id];\n\t\tif (colorDesc && colorDesc.defaults) {\n\t\t\tconst colorValue = colorDesc.defaults[theme.type];\n\t\t\treturn resolveColorValue(colorValue, theme);\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tpublic getColorSchema(): IJSONSchema {\n\t\treturn this.colorSchema;\n\t}\n\n\tpublic toString() {\n\t\tconst sorter = (a: string, b: string) => {\n\t\t\tconst cat1 = a.indexOf('.') === -1 ? 0 : 1;\n\t\t\tconst cat2 = b.indexOf('.') === -1 ? 0 : 1;\n\t\t\tif (cat1 !== cat2) {\n\t\t\t\treturn cat1 - cat2;\n\t\t\t}\n\t\t\treturn a.localeCompare(b);\n\t\t};\n\n\t\treturn Object.keys(this.colorsById).sort(sorter).map(k => `- \\`${k}\\`: ${this.colorsById[k].description}`).join('\\n');\n\t}\n\n}\n\nconst colorRegistry = new ColorRegistry();\nplatform.Registry.add(Extensions.ColorContribution, colorRegistry);\n\n\nexport function registerColor(id: string, defaults: ColorDefaults | null, description: string, needsTransparency?: boolean, deprecationMessage?: string): ColorIdentifier {\n\treturn colorRegistry.registerColor(id, defaults, description, needsTransparency, deprecationMessage);\n}\n\n// ----- color functions\n\nexport function executeTransform(transform: ColorTransform, theme: IColorTheme): Color | undefined {\n\tswitch (transform.op) {\n\t\tcase ColorTransformType.Darken:\n\t\t\treturn resolveColorValue(transform.value, theme)?.darken(transform.factor);\n\n\t\tcase ColorTransformType.Lighten:\n\t\t\treturn resolveColorValue(transform.value, theme)?.lighten(transform.factor);\n\n\t\tcase ColorTransformType.Transparent:\n\t\t\treturn resolveColorValue(transform.value, theme)?.transparent(transform.factor);\n\n\t\tcase ColorTransformType.Opaque: {\n\t\t\tconst backgroundColor = resolveColorValue(transform.background, theme);\n\t\t\tif (!backgroundColor) {\n\t\t\t\treturn resolveColorValue(transform.value, theme);\n\t\t\t}\n\t\t\treturn resolveColorValue(transform.value, theme)?.makeOpaque(backgroundColor);\n\t\t}\n\n\t\tcase ColorTransformType.OneOf:\n\t\t\tfor (const candidate of transform.values) {\n\t\t\t\tconst color = resolveColorValue(candidate, theme);\n\t\t\t\tif (color) {\n\t\t\t\t\treturn color;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn undefined;\n\n\t\tcase ColorTransformType.IfDefinedThenElse:\n\t\t\treturn resolveColorValue(theme.defines(transform.if) ? transform.then : transform.else, theme);\n\n\t\tcase ColorTransformType.LessProminent: {\n\t\t\tconst from = resolveColorValue(transform.value, theme);\n\t\t\tif (!from) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\n\t\t\tconst backgroundColor = resolveColorValue(transform.background, theme);\n\t\t\tif (!backgroundColor) {\n\t\t\t\treturn from.transparent(transform.factor * transform.transparency);\n\t\t\t}\n\n\t\t\treturn from.isDarkerThan(backgroundColor)\n\t\t\t\t? Color.getLighterColor(from, backgroundColor, transform.factor).transparent(transform.transparency)\n\t\t\t\t: Color.getDarkerColor(from, backgroundColor, transform.factor).transparent(transform.transparency);\n\t\t}\n\t\tdefault:\n\t\t\tthrow assertNever(transform);\n\t}\n}\n\nexport function darken(colorValue: ColorValue, factor: number): ColorTransform {\n\treturn { op: ColorTransformType.Darken, value: colorValue, factor };\n}\n\nexport function lighten(colorValue: ColorValue, factor: number): ColorTransform {\n\treturn { op: ColorTransformType.Lighten, value: colorValue, factor };\n}\n\nexport function transparent(colorValue: ColorValue, factor: number): ColorTransform {\n\treturn { op: ColorTransformType.Transparent, value: colorValue, factor };\n}\n\nexport function oneOf(...colorValues: ColorValue[]): ColorTransform {\n\treturn { op: ColorTransformType.OneOf, values: colorValues };\n}\n\nexport function ifDefinedThenElse(ifArg: ColorIdentifier, thenArg: ColorValue, elseArg: ColorValue): ColorTransform {\n\treturn { op: ColorTransformType.IfDefinedThenElse, if: ifArg, then: thenArg, else: elseArg };\n}\n\nexport function lessProminent(colorValue: ColorValue, backgroundColorValue: ColorValue, factor: number, transparency: number): ColorTransform {\n\treturn { op: ColorTransformType.LessProminent, value: colorValue, background: backgroundColorValue, factor, transparency };\n}\n\n// ----- implementation\n\n/**\n * @param colorValue Resolve a color value in the context of a theme\n */\nexport function resolveColorValue(colorValue: ColorValue | null, theme: IColorTheme): Color | undefined {\n\tif (colorValue === null) {\n\t\treturn undefined;\n\t} else if (typeof colorValue === 'string') {\n\t\tif (colorValue[0] === '#') {\n\t\t\treturn Color.fromHex(colorValue);\n\t\t}\n\t\treturn theme.getColor(colorValue);\n\t} else if (colorValue instanceof Color) {\n\t\treturn colorValue;\n\t} else if (typeof colorValue === 'object') {\n\t\treturn executeTransform(colorValue, theme);\n\t}\n\treturn undefined;\n}\n\nexport const workbenchColorsSchemaId = 'vscode://schemas/workbench-colors';\n\nconst schemaRegistry = platform.Registry.as(JSONExtensions.JSONContribution);\nschemaRegistry.registerSchema(workbenchColorsSchemaId, colorRegistry.getColorSchema());\n\nconst delayer = new RunOnceScheduler(() => schemaRegistry.notifySchemaChanged(workbenchColorsSchemaId), 200);\ncolorRegistry.onDidChangeSchema(() => {\n\tif (!delayer.isScheduled()) {\n\t\tdelayer.schedule();\n\t}\n});\n\n// setTimeout(_ => console.log(colorRegistry.toString()), 5000);\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\nimport * as nls from 'vs/nls';\n\n// Import the effects we need\nimport { Color } from 'vs/base/common/color';\nimport { registerColor, transparent } from 'vs/platform/theme/common/colorUtils';\n\n\nexport const foreground = registerColor('foreground',\n\t{ dark: '#CCCCCC', light: '#616161', hcDark: '#FFFFFF', hcLight: '#292929' },\n\tnls.localize('foreground', \"Overall foreground color. This color is only used if not overridden by a component.\"));\n\nexport const disabledForeground = registerColor('disabledForeground',\n\t{ dark: '#CCCCCC80', light: '#61616180', hcDark: '#A5A5A5', hcLight: '#7F7F7F' },\n\tnls.localize('disabledForeground', \"Overall foreground for disabled elements. This color is only used if not overridden by a component.\"));\n\nexport const errorForeground = registerColor('errorForeground',\n\t{ dark: '#F48771', light: '#A1260D', hcDark: '#F48771', hcLight: '#B5200D' },\n\tnls.localize('errorForeground', \"Overall foreground color for error messages. This color is only used if not overridden by a component.\"));\n\nexport const descriptionForeground = registerColor('descriptionForeground',\n\t{ light: '#717171', dark: transparent(foreground, 0.7), hcDark: transparent(foreground, 0.7), hcLight: transparent(foreground, 0.7) },\n\tnls.localize('descriptionForeground', \"Foreground color for description text providing additional information, for example for a label.\"));\n\nexport const iconForeground = registerColor('icon.foreground',\n\t{ dark: '#C5C5C5', light: '#424242', hcDark: '#FFFFFF', hcLight: '#292929' },\n\tnls.localize('iconForeground', \"The default color for icons in the workbench.\"));\n\nexport const focusBorder = registerColor('focusBorder',\n\t{ dark: '#007FD4', light: '#0090F1', hcDark: '#F38518', hcLight: '#006BBD' },\n\tnls.localize('focusBorder', \"Overall border color for focused elements. This color is only used if not overridden by a component.\"));\n\nexport const contrastBorder = registerColor('contrastBorder',\n\t{ light: null, dark: null, hcDark: '#6FC3DF', hcLight: '#0F4A85' },\n\tnls.localize('contrastBorder', \"An extra border around elements to separate them from others for greater contrast.\"));\n\nexport const activeContrastBorder = registerColor('contrastActiveBorder',\n\t{ light: null, dark: null, hcDark: focusBorder, hcLight: focusBorder },\n\tnls.localize('activeContrastBorder', \"An extra border around active elements to separate them from others for greater contrast.\"));\n\nexport const selectionBackground = registerColor('selection.background',\n\t{ light: null, dark: null, hcDark: null, hcLight: null },\n\tnls.localize('selectionBackground', \"The background color of text selections in the workbench (e.g. for input fields or text areas). Note that this does not apply to selections within the editor.\"));\n\n\n// ------ text link\n\nexport const textLinkForeground = registerColor('textLink.foreground',\n\t{ light: '#006AB1', dark: '#3794FF', hcDark: '#21A6FF', hcLight: '#0F4A85' },\n\tnls.localize('textLinkForeground', \"Foreground color for links in text.\"));\n\nexport const textLinkActiveForeground = registerColor('textLink.activeForeground',\n\t{ light: '#006AB1', dark: '#3794FF', hcDark: '#21A6FF', hcLight: '#0F4A85' },\n\tnls.localize('textLinkActiveForeground', \"Foreground color for links in text when clicked on and on mouse hover.\"));\n\nexport const textSeparatorForeground = registerColor('textSeparator.foreground',\n\t{ light: '#0000002e', dark: '#ffffff2e', hcDark: Color.black, hcLight: '#292929' },\n\tnls.localize('textSeparatorForeground', \"Color for text separators.\"));\n\n\n// ------ text preformat\n\nexport const textPreformatForeground = registerColor('textPreformat.foreground',\n\t{ light: '#A31515', dark: '#D7BA7D', hcDark: '#000000', hcLight: '#FFFFFF' },\n\tnls.localize('textPreformatForeground', \"Foreground color for preformatted text segments.\"));\n\nexport const textPreformatBackground = registerColor('textPreformat.background',\n\t{ light: '#0000001A', dark: '#FFFFFF1A', hcDark: '#FFFFFF', hcLight: '#09345f' },\n\tnls.localize('textPreformatBackground', \"Background color for preformatted text segments.\"));\n\n\n// ------ text block quote\n\nexport const textBlockQuoteBackground = registerColor('textBlockQuote.background',\n\t{ light: '#f2f2f2', dark: '#222222', hcDark: null, hcLight: '#F2F2F2' },\n\tnls.localize('textBlockQuoteBackground', \"Background color for block quotes in text.\"));\n\nexport const textBlockQuoteBorder = registerColor('textBlockQuote.border',\n\t{ light: '#007acc80', dark: '#007acc80', hcDark: Color.white, hcLight: '#292929' },\n\tnls.localize('textBlockQuoteBorder', \"Border color for block quotes in text.\"));\n\n\n// ------ text code block\n\nexport const textCodeBlockBackground = registerColor('textCodeBlock.background',\n\t{ light: '#dcdcdc66', dark: '#0a0a0a66', hcDark: Color.black, hcLight: '#F2F2F2' },\n\tnls.localize('textCodeBlockBackground', \"Background color for code blocks in text.\"));\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\nimport * as nls from 'vs/nls';\n\n// Import the effects we need\nimport { Color } from 'vs/base/common/color';\nimport { registerColor, transparent } from 'vs/platform/theme/common/colorUtils';\n\n// Import the colors we need\nimport { contrastBorder, focusBorder } from 'vs/platform/theme/common/colors/baseColors';\n\n\n// ----- sash\n\nexport const sashHoverBorder = registerColor('sash.hoverBorder',\n\t{ dark: focusBorder, light: focusBorder, hcDark: focusBorder, hcLight: focusBorder },\n\tnls.localize('sashActiveBorder', \"Border color of active sashes.\"));\n\n\n// ----- badge\n\nexport const badgeBackground = registerColor('badge.background',\n\t{ dark: '#4D4D4D', light: '#C4C4C4', hcDark: Color.black, hcLight: '#0F4A85' },\n\tnls.localize('badgeBackground', \"Badge background color. Badges are small information labels, e.g. for search results count.\"));\n\nexport const badgeForeground = registerColor('badge.foreground',\n\t{ dark: Color.white, light: '#333', hcDark: Color.white, hcLight: Color.white },\n\tnls.localize('badgeForeground', \"Badge foreground color. Badges are small information labels, e.g. for search results count.\"));\n\n\n// ----- scrollbar\n\nexport const scrollbarShadow = registerColor('scrollbar.shadow',\n\t{ dark: '#000000', light: '#DDDDDD', hcDark: null, hcLight: null },\n\tnls.localize('scrollbarShadow', \"Scrollbar shadow to indicate that the view is scrolled.\"));\n\nexport const scrollbarSliderBackground = registerColor('scrollbarSlider.background',\n\t{ dark: Color.fromHex('#797979').transparent(0.4), light: Color.fromHex('#646464').transparent(0.4), hcDark: transparent(contrastBorder, 0.6), hcLight: transparent(contrastBorder, 0.4) },\n\tnls.localize('scrollbarSliderBackground', \"Scrollbar slider background color.\"));\n\nexport const scrollbarSliderHoverBackground = registerColor('scrollbarSlider.hoverBackground',\n\t{ dark: Color.fromHex('#646464').transparent(0.7), light: Color.fromHex('#646464').transparent(0.7), hcDark: transparent(contrastBorder, 0.8), hcLight: transparent(contrastBorder, 0.8) },\n\tnls.localize('scrollbarSliderHoverBackground', \"Scrollbar slider background color when hovering.\"));\n\nexport const scrollbarSliderActiveBackground = registerColor('scrollbarSlider.activeBackground',\n\t{ dark: Color.fromHex('#BFBFBF').transparent(0.4), light: Color.fromHex('#000000').transparent(0.6), hcDark: contrastBorder, hcLight: contrastBorder },\n\tnls.localize('scrollbarSliderActiveBackground', \"Scrollbar slider background color when clicked on.\"));\n\n\n// ----- progress bar\n\nexport const progressBarBackground = registerColor('progressBar.background',\n\t{ dark: Color.fromHex('#0E70C0'), light: Color.fromHex('#0E70C0'), hcDark: contrastBorder, hcLight: contrastBorder },\n\tnls.localize('progressBarBackground', \"Background color of the progress bar that can show for long running operations.\"));\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\nimport * as nls from 'vs/nls';\n\n// Import the effects we need\nimport { Color, RGBA } from 'vs/base/common/color';\nimport { registerColor, transparent, lessProminent, darken, lighten } from 'vs/platform/theme/common/colorUtils';\n\n// Import the colors we need\nimport { foreground, contrastBorder, activeContrastBorder } from 'vs/platform/theme/common/colors/baseColors';\nimport { scrollbarShadow, badgeBackground } from 'vs/platform/theme/common/colors/miscColors';\n\n\n// ----- editor\n\nexport const editorBackground = registerColor('editor.background',\n\t{ light: '#ffffff', dark: '#1E1E1E', hcDark: Color.black, hcLight: Color.white },\n\tnls.localize('editorBackground', \"Editor background color.\"));\n\nexport const editorForeground = registerColor('editor.foreground',\n\t{ light: '#333333', dark: '#BBBBBB', hcDark: Color.white, hcLight: foreground },\n\tnls.localize('editorForeground', \"Editor default foreground color.\"));\n\n\nexport const editorStickyScrollBackground = registerColor('editorStickyScroll.background',\n\t{ light: editorBackground, dark: editorBackground, hcDark: editorBackground, hcLight: editorBackground },\n\tnls.localize('editorStickyScrollBackground', \"Background color of sticky scroll in the editor\"));\n\nexport const editorStickyScrollHoverBackground = registerColor('editorStickyScrollHover.background',\n\t{ dark: '#2A2D2E', light: '#F0F0F0', hcDark: null, hcLight: Color.fromHex('#0F4A85').transparent(0.1) },\n\tnls.localize('editorStickyScrollHoverBackground', \"Background color of sticky scroll on hover in the editor\"));\n\nexport const editorStickyScrollBorder = registerColor('editorStickyScroll.border',\n\t{ dark: null, light: null, hcDark: contrastBorder, hcLight: contrastBorder },\n\tnls.localize('editorStickyScrollBorder', \"Border color of sticky scroll in the editor\"));\n\nexport const editorStickyScrollShadow = registerColor('editorStickyScroll.shadow',\n\t{ dark: scrollbarShadow, light: scrollbarShadow, hcDark: scrollbarShadow, hcLight: scrollbarShadow },\n\tnls.localize('editorStickyScrollShadow', \" Shadow color of sticky scroll in the editor\"));\n\n\nexport const editorWidgetBackground = registerColor('editorWidget.background',\n\t{ dark: '#252526', light: '#F3F3F3', hcDark: '#0C141F', hcLight: Color.white },\n\tnls.localize('editorWidgetBackground', 'Background color of editor widgets, such as find/replace.'));\n\nexport const editorWidgetForeground = registerColor('editorWidget.foreground',\n\t{ dark: foreground, light: foreground, hcDark: foreground, hcLight: foreground },\n\tnls.localize('editorWidgetForeground', 'Foreground color of editor widgets, such as find/replace.'));\n\nexport const editorWidgetBorder = registerColor('editorWidget.border',\n\t{ dark: '#454545', light: '#C8C8C8', hcDark: contrastBorder, hcLight: contrastBorder },\n\tnls.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.'));\n\nexport const editorWidgetResizeBorder = registerColor('editorWidget.resizeBorder',\n\t{ light: null, dark: null, hcDark: null, hcLight: null },\n\tnls.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.\"));\n\n\nexport const editorErrorBackground = registerColor('editorError.background',\n\t{ dark: null, light: null, hcDark: null, hcLight: null },\n\tnls.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);\n\nexport const editorErrorForeground = registerColor('editorError.foreground',\n\t{ dark: '#F14C4C', light: '#E51400', hcDark: '#F48771', hcLight: '#B5200D' },\n\tnls.localize('editorError.foreground', 'Foreground color of error squigglies in the editor.'));\n\nexport const editorErrorBorder = registerColor('editorError.border',\n\t{ dark: null, light: null, hcDark: Color.fromHex('#E47777').transparent(0.8), hcLight: '#B5200D' },\n\tnls.localize('errorBorder', 'If set, color of double underlines for errors in the editor.'));\n\n\nexport const editorWarningBackground = registerColor('editorWarning.background',\n\t{ dark: null, light: null, hcDark: null, hcLight: null },\n\tnls.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);\n\nexport const editorWarningForeground = registerColor('editorWarning.foreground',\n\t{ dark: '#CCA700', light: '#BF8803', hcDark: '#FFD370', hcLight: '#895503' },\n\tnls.localize('editorWarning.foreground', 'Foreground color of warning squigglies in the editor.'));\n\nexport const editorWarningBorder = registerColor('editorWarning.border',\n\t{ dark: null, light: null, hcDark: Color.fromHex('#FFCC00').transparent(0.8), hcLight: Color.fromHex('#FFCC00').transparent(0.8) },\n\tnls.localize('warningBorder', 'If set, color of double underlines for warnings in the editor.'));\n\n\nexport const editorInfoBackground = registerColor('editorInfo.background',\n\t{ dark: null, light: null, hcDark: null, hcLight: null },\n\tnls.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);\n\nexport const editorInfoForeground = registerColor('editorInfo.foreground',\n\t{ dark: '#3794FF', light: '#1a85ff', hcDark: '#3794FF', hcLight: '#1a85ff' },\n\tnls.localize('editorInfo.foreground', 'Foreground color of info squigglies in the editor.'));\n\nexport const editorInfoBorder = registerColor('editorInfo.border',\n\t{ dark: null, light: null, hcDark: Color.fromHex('#3794FF').transparent(0.8), hcLight: '#292929' },\n\tnls.localize('infoBorder', 'If set, color of double underlines for infos in the editor.'));\n\n\nexport const editorHintForeground = registerColor('editorHint.foreground',\n\t{ dark: Color.fromHex('#eeeeee').transparent(0.7), light: '#6c6c6c', hcDark: null, hcLight: null },\n\tnls.localize('editorHint.foreground', 'Foreground color of hint squigglies in the editor.'));\n\nexport const editorHintBorder = registerColor('editorHint.border',\n\t{ dark: null, light: null, hcDark: Color.fromHex('#eeeeee').transparent(0.8), hcLight: '#292929' },\n\tnls.localize('hintBorder', 'If set, color of double underlines for hints in the editor.'));\n\n\nexport const editorActiveLinkForeground = registerColor('editorLink.activeForeground',\n\t{ dark: '#4E94CE', light: Color.blue, hcDark: Color.cyan, hcLight: '#292929' },\n\tnls.localize('activeLinkForeground', 'Color of active links.'));\n\n\n// ----- editor selection\n\nexport const editorSelectionBackground = registerColor('editor.selectionBackground',\n\t{ light: '#ADD6FF', dark: '#264F78', hcDark: '#f3f518', hcLight: '#0F4A85' },\n\tnls.localize('editorSelectionBackground', \"Color of the editor selection.\"));\n\nexport const editorSelectionForeground = registerColor('editor.selectionForeground',\n\t{ light: null, dark: null, hcDark: '#000000', hcLight: Color.white },\n\tnls.localize('editorSelectionForeground', \"Color of the selected text for high contrast.\"));\n\nexport const editorInactiveSelection = registerColor('editor.inactiveSelectionBackground',\n\t{ light: transparent(editorSelectionBackground, 0.5), dark: transparent(editorSelectionBackground, 0.5), hcDark: transparent(editorSelectionBackground, 0.7), hcLight: transparent(editorSelectionBackground, 0.5) },\n\tnls.localize('editorInactiveSelection', \"Color of the selection in an inactive editor. The color must not be opaque so as not to hide underlying decorations.\"), true);\n\nexport const editorSelectionHighlight = registerColor('editor.selectionHighlightBackground',\n\t{ light: lessProminent(editorSelectionBackground, editorBackground, 0.3, 0.6), dark: lessProminent(editorSelectionBackground, editorBackground, 0.3, 0.6), hcDark: null, hcLight: null },\n\tnls.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);\n\nexport const editorSelectionHighlightBorder = registerColor('editor.selectionHighlightBorder',\n\t{ light: null, dark: null, hcDark: activeContrastBorder, hcLight: activeContrastBorder },\n\tnls.localize('editorSelectionHighlightBorder', \"Border color for regions with the same content as the selection.\"));\n\n\n// ----- editor find\n\nexport const editorFindMatch = registerColor('editor.findMatchBackground',\n\t{ light: '#A8AC94', dark: '#515C6A', hcDark: null, hcLight: null },\n\tnls.localize('editorFindMatch', \"Color of the current search match.\"));\n\nexport const editorFindMatchHighlight = registerColor('editor.findMatchHighlightBackground',\n\t{ light: '#EA5C0055', dark: '#EA5C0055', hcDark: null, hcLight: null },\n\tnls.localize('findMatchHighlight', \"Color of the other search matches. The color must not be opaque so as not to hide underlying decorations.\"), true);\n\nexport const editorFindRangeHighlight = registerColor('editor.findRangeHighlightBackground',\n\t{ dark: '#3a3d4166', light: '#b4b4b44d', hcDark: null, hcLight: null },\n\tnls.localize('findRangeHighlight', \"Color of the range limiting the search. The color must not be opaque so as not to hide underlying decorations.\"), true);\n\nexport const editorFindMatchBorder = registerColor('editor.findMatchBorder',\n\t{ light: null, dark: null, hcDark: activeContrastBorder, hcLight: activeContrastBorder },\n\tnls.localize('editorFindMatchBorder', \"Border color of the current search match.\"));\n\nexport const editorFindMatchHighlightBorder = registerColor('editor.findMatchHighlightBorder',\n\t{ light: null, dark: null, hcDark: activeContrastBorder, hcLight: activeContrastBorder },\n\tnls.localize('findMatchHighlightBorder', \"Border color of the other search matches.\"));\n\nexport const editorFindRangeHighlightBorder = registerColor('editor.findRangeHighlightBorder',\n\t{ dark: null, light: null, hcDark: transparent(activeContrastBorder, 0.4), hcLight: transparent(activeContrastBorder, 0.4) },\n\tnls.localize('findRangeHighlightBorder', \"Border color of the range limiting the search. The color must not be opaque so as not to hide underlying decorations.\"), true);\n\n\n// ----- editor hover\n\nexport const editorHoverHighlight = registerColor('editor.hoverHighlightBackground',\n\t{ light: '#ADD6FF26', dark: '#264f7840', hcDark: '#ADD6FF26', hcLight: null },\n\tnls.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);\n\nexport const editorHoverBackground = registerColor('editorHoverWidget.background',\n\t{ light: editorWidgetBackground, dark: editorWidgetBackground, hcDark: editorWidgetBackground, hcLight: editorWidgetBackground },\n\tnls.localize('hoverBackground', 'Background color of the editor hover.'));\n\nexport const editorHoverForeground = registerColor('editorHoverWidget.foreground',\n\t{ light: editorWidgetForeground, dark: editorWidgetForeground, hcDark: editorWidgetForeground, hcLight: editorWidgetForeground },\n\tnls.localize('hoverForeground', 'Foreground color of the editor hover.'));\n\nexport const editorHoverBorder = registerColor('editorHoverWidget.border',\n\t{ light: editorWidgetBorder, dark: editorWidgetBorder, hcDark: editorWidgetBorder, hcLight: editorWidgetBorder },\n\tnls.localize('hoverBorder', 'Border color of the editor hover.'));\n\nexport const editorHoverStatusBarBackground = registerColor('editorHoverWidget.statusBarBackground',\n\t{ dark: lighten(editorHoverBackground, 0.2), light: darken(editorHoverBackground, 0.05), hcDark: editorWidgetBackground, hcLight: editorWidgetBackground },\n\tnls.localize('statusBarBackground', \"Background color of the editor hover status bar.\"));\n\n\n// ----- editor inlay hint\n\nexport const editorInlayHintForeground = registerColor('editorInlayHint.foreground',\n\t{ dark: '#969696', light: '#969696', hcDark: Color.white, hcLight: Color.black },\n\tnls.localize('editorInlayHintForeground', 'Foreground color of inline hints'));\n\nexport const editorInlayHintBackground = registerColor('editorInlayHint.background',\n\t{ dark: transparent(badgeBackground, .10), light: transparent(badgeBackground, .10), hcDark: transparent(Color.white, .10), hcLight: transparent(badgeBackground, .10) },\n\tnls.localize('editorInlayHintBackground', 'Background color of inline hints'));\n\nexport const editorInlayHintTypeForeground = registerColor('editorInlayHint.typeForeground',\n\t{ dark: editorInlayHintForeground, light: editorInlayHintForeground, hcDark: editorInlayHintForeground, hcLight: editorInlayHintForeground },\n\tnls.localize('editorInlayHintForegroundTypes', 'Foreground color of inline hints for types'));\n\nexport const editorInlayHintTypeBackground = registerColor('editorInlayHint.typeBackground',\n\t{ dark: editorInlayHintBackground, light: editorInlayHintBackground, hcDark: editorInlayHintBackground, hcLight: editorInlayHintBackground },\n\tnls.localize('editorInlayHintBackgroundTypes', 'Background color of inline hints for types'));\n\nexport const editorInlayHintParameterForeground = registerColor('editorInlayHint.parameterForeground',\n\t{ dark: editorInlayHintForeground, light: editorInlayHintForeground, hcDark: editorInlayHintForeground, hcLight: editorInlayHintForeground },\n\tnls.localize('editorInlayHintForegroundParameter', 'Foreground color of inline hints for parameters'));\n\nexport const editorInlayHintParameterBackground = registerColor('editorInlayHint.parameterBackground',\n\t{ dark: editorInlayHintBackground, light: editorInlayHintBackground, hcDark: editorInlayHintBackground, hcLight: editorInlayHintBackground },\n\tnls.localize('editorInlayHintBackgroundParameter', 'Background color of inline hints for parameters'));\n\n\n// ----- editor lightbulb\n\nexport const editorLightBulbForeground = registerColor('editorLightBulb.foreground',\n\t{ dark: '#FFCC00', light: '#DDB100', hcDark: '#FFCC00', hcLight: '#007ACC' },\n\tnls.localize('editorLightBulbForeground', \"The color used for the lightbulb actions icon.\"));\n\nexport const editorLightBulbAutoFixForeground = registerColor('editorLightBulbAutoFix.foreground',\n\t{ dark: '#75BEFF', light: '#007ACC', hcDark: '#75BEFF', hcLight: '#007ACC' },\n\tnls.localize('editorLightBulbAutoFixForeground', \"The color used for the lightbulb auto fix actions icon.\"));\n\nexport const editorLightBulbAiForeground = registerColor('editorLightBulbAi.foreground',\n\t{ dark: editorLightBulbForeground, light: editorLightBulbForeground, hcDark: editorLightBulbForeground, hcLight: editorLightBulbForeground },\n\tnls.localize('editorLightBulbAiForeground', \"The color used for the lightbulb AI icon.\"));\n\n\n// ----- editor snippet\n\nexport const snippetTabstopHighlightBackground = registerColor('editor.snippetTabstopHighlightBackground',\n\t{ dark: new Color(new RGBA(124, 124, 124, 0.3)), light: new Color(new RGBA(10, 50, 100, 0.2)), hcDark: new Color(new RGBA(124, 124, 124, 0.3)), hcLight: new Color(new RGBA(10, 50, 100, 0.2)) },\n\tnls.localize('snippetTabstopHighlightBackground', \"Highlight background color of a snippet tabstop.\"));\n\nexport const snippetTabstopHighlightBorder = registerColor('editor.snippetTabstopHighlightBorder',\n\t{ dark: null, light: null, hcDark: null, hcLight: null },\n\tnls.localize('snippetTabstopHighlightBorder', \"Highlight border color of a snippet tabstop.\"));\n\nexport const snippetFinalTabstopHighlightBackground = registerColor('editor.snippetFinalTabstopHighlightBackground',\n\t{ dark: null, light: null, hcDark: null, hcLight: null },\n\tnls.localize('snippetFinalTabstopHighlightBackground', \"Highlight background color of the final tabstop of a snippet.\"));\n\nexport const snippetFinalTabstopHighlightBorder = registerColor('editor.snippetFinalTabstopHighlightBorder',\n\t{ dark: '#525252', light: new Color(new RGBA(10, 50, 100, 0.5)), hcDark: '#525252', hcLight: '#292929' },\n\tnls.localize('snippetFinalTabstopHighlightBorder', \"Highlight border color of the final tabstop of a snippet.\"));\n\n\n// ----- diff editor\n\nexport const defaultInsertColor = new Color(new RGBA(155, 185, 85, .2));\nexport const defaultRemoveColor = new Color(new RGBA(255, 0, 0, .2));\n\nexport const diffInserted = registerColor('diffEditor.insertedTextBackground',\n\t{ dark: '#9ccc2c33', light: '#9ccc2c40', hcDark: null, hcLight: null },\n\tnls.localize('diffEditorInserted', 'Background color for text that got inserted. The color must not be opaque so as not to hide underlying decorations.'), true);\n\nexport const diffRemoved = registerColor('diffEditor.removedTextBackground',\n\t{ dark: '#ff000033', light: '#ff000033', hcDark: null, hcLight: null },\n\tnls.localize('diffEditorRemoved', 'Background color for text that got removed. The color must not be opaque so as not to hide underlying decorations.'), true);\n\n\nexport const diffInsertedLine = registerColor('diffEditor.insertedLineBackground',\n\t{ dark: defaultInsertColor, light: defaultInsertColor, hcDark: null, hcLight: null },\n\tnls.localize('diffEditorInsertedLines', 'Background color for lines that got inserted. The color must not be opaque so as not to hide underlying decorations.'), true);\n\nexport const diffRemovedLine = registerColor('diffEditor.removedLineBackground',\n\t{ dark: defaultRemoveColor, light: defaultRemoveColor, hcDark: null, hcLight: null },\n\tnls.localize('diffEditorRemovedLines', 'Background color for lines that got removed. The color must not be opaque so as not to hide underlying decorations.'), true);\n\n\nexport const diffInsertedLineGutter = registerColor('diffEditorGutter.insertedLineBackground',\n\t{ dark: null, light: null, hcDark: null, hcLight: null },\n\tnls.localize('diffEditorInsertedLineGutter', 'Background color for the margin where lines got inserted.'));\n\nexport const diffRemovedLineGutter = registerColor('diffEditorGutter.removedLineBackground',\n\t{ dark: null, light: null, hcDark: null, hcLight: null },\n\tnls.localize('diffEditorRemovedLineGutter', 'Background color for the margin where lines got removed.'));\n\n\nexport const diffOverviewRulerInserted = registerColor('diffEditorOverview.insertedForeground',\n\t{ dark: null, light: null, hcDark: null, hcLight: null },\n\tnls.localize('diffEditorOverviewInserted', 'Diff overview ruler foreground for inserted content.'));\n\nexport const diffOverviewRulerRemoved = registerColor('diffEditorOverview.removedForeground',\n\t{ dark: null, light: null, hcDark: null, hcLight: null },\n\tnls.localize('diffEditorOverviewRemoved', 'Diff overview ruler foreground for removed content.'));\n\n\nexport const diffInsertedOutline = registerColor('diffEditor.insertedTextBorder',\n\t{ dark: null, light: null, hcDark: '#33ff2eff', hcLight: '#374E06' },\n\tnls.localize('diffEditorInsertedOutline', 'Outline color for the text that got inserted.'));\n\nexport const diffRemovedOutline = registerColor('diffEditor.removedTextBorder',\n\t{ dark: null, light: null, hcDark: '#FF008F', hcLight: '#AD0707' },\n\tnls.localize('diffEditorRemovedOutline', 'Outline color for text that got removed.'));\n\n\nexport const diffBorder = registerColor('diffEditor.border',\n\t{ dark: null, light: null, hcDark: contrastBorder, hcLight: contrastBorder },\n\tnls.localize('diffEditorBorder', 'Border color between the two text editors.'));\n\nexport const diffDiagonalFill = registerColor('diffEditor.diagonalFill',\n\t{ dark: '#cccccc33', light: '#22222233', hcDark: null, hcLight: null },\n\tnls.localize('diffDiagonalFill', \"Color of the diff editor's diagonal fill. The diagonal fill is used in side-by-side diff views.\"));\n\n\nexport const diffUnchangedRegionBackground = registerColor('diffEditor.unchangedRegionBackground',\n\t{ dark: 'sideBar.background', light: 'sideBar.background', hcDark: 'sideBar.background', hcLight: 'sideBar.background' },\n\tnls.localize('diffEditor.unchangedRegionBackground', \"The background color of unchanged blocks in the diff editor.\"));\n\nexport const diffUnchangedRegionForeground = registerColor('diffEditor.unchangedRegionForeground',\n\t{ dark: 'foreground', light: 'foreground', hcDark: 'foreground', hcLight: 'foreground' },\n\tnls.localize('diffEditor.unchangedRegionForeground', \"The foreground color of unchanged blocks in the diff editor.\"));\n\nexport const diffUnchangedTextBackground = registerColor('diffEditor.unchangedCodeBackground',\n\t{ dark: '#74747429', light: '#b8b8b829', hcDark: null, hcLight: null },\n\tnls.localize('diffEditor.unchangedCodeBackground', \"The background color of unchanged code in the diff editor.\"));\n\n\n// ----- widget\n\nexport const widgetShadow = registerColor('widget.shadow',\n\t{ dark: transparent(Color.black, .36), light: transparent(Color.black, .16), hcDark: null, hcLight: null },\n\tnls.localize('widgetShadow', 'Shadow color of widgets such as find/replace inside the editor.'));\n\nexport const widgetBorder = registerColor('widget.border',\n\t{ dark: null, light: null, hcDark: contrastBorder, hcLight: contrastBorder },\n\tnls.localize('widgetBorder', 'Border color of widgets such as find/replace inside the editor.'));\n\n\n// ----- toolbar\n\nexport const toolbarHoverBackground = registerColor('toolbar.hoverBackground',\n\t{ dark: '#5a5d5e50', light: '#b8b8b850', hcDark: null, hcLight: null },\n\tnls.localize('toolbarHoverBackground', \"Toolbar background when hovering over actions using the mouse\"));\n\nexport const toolbarHoverOutline = registerColor('toolbar.hoverOutline',\n\t{ dark: null, light: null, hcDark: activeContrastBorder, hcLight: activeContrastBorder },\n\tnls.localize('toolbarHoverOutline', \"Toolbar outline when hovering over actions using the mouse\"));\n\nexport const toolbarActiveBackground = registerColor('toolbar.activeBackground',\n\t{ dark: lighten(toolbarHoverBackground, 0.1), light: darken(toolbarHoverBackground, 0.1), hcDark: null, hcLight: null },\n\tnls.localize('toolbarActiveBackground', \"Toolbar background when holding the mouse over actions\"));\n\n\n// ----- breadcumbs\n\nexport const breadcrumbsForeground = registerColor('breadcrumb.foreground',\n\t{ light: transparent(foreground, 0.8), dark: transparent(foreground, 0.8), hcDark: transparent(foreground, 0.8), hcLight: transparent(foreground, 0.8) },\n\tnls.localize('breadcrumbsFocusForeground', \"Color of focused breadcrumb items.\"));\n\nexport const breadcrumbsBackground = registerColor('breadcrumb.background',\n\t{ light: editorBackground, dark: editorBackground, hcDark: editorBackground, hcLight: editorBackground },\n\tnls.localize('breadcrumbsBackground', \"Background color of breadcrumb items.\"));\n\nexport const breadcrumbsFocusForeground = registerColor('breadcrumb.focusForeground',\n\t{ light: darken(foreground, 0.2), dark: lighten(foreground, 0.1), hcDark: lighten(foreground, 0.1), hcLight: lighten(foreground, 0.1) },\n\tnls.localize('breadcrumbsFocusForeground', \"Color of focused breadcrumb items.\"));\n\nexport const breadcrumbsActiveSelectionForeground = registerColor('breadcrumb.activeSelectionForeground',\n\t{ light: darken(foreground, 0.2), dark: lighten(foreground, 0.1), hcDark: lighten(foreground, 0.1), hcLight: lighten(foreground, 0.1) },\n\tnls.localize('breadcrumbsSelectedForeground', \"Color of selected breadcrumb items.\"));\n\nexport const breadcrumbsPickerBackground = registerColor('breadcrumbPicker.background',\n\t{ light: editorWidgetBackground, dark: editorWidgetBackground, hcDark: editorWidgetBackground, hcLight: editorWidgetBackground },\n\tnls.localize('breadcrumbsSelectedBackground', \"Background color of breadcrumb item picker.\"));\n\n\n// ----- merge\n\nconst headerTransparency = 0.5;\nconst currentBaseColor = Color.fromHex('#40C8AE').transparent(headerTransparency);\nconst incomingBaseColor = Color.fromHex('#40A6FF').transparent(headerTransparency);\nconst commonBaseColor = Color.fromHex('#606060').transparent(0.4);\nconst contentTransparency = 0.4;\nconst rulerTransparency = 1;\n\nexport const mergeCurrentHeaderBackground = registerColor('merge.currentHeaderBackground',\n\t{ dark: currentBaseColor, light: currentBaseColor, hcDark: null, hcLight: null },\n\tnls.localize('mergeCurrentHeaderBackground', 'Current header background in inline merge-conflicts. The color must not be opaque so as not to hide underlying decorations.'), true);\n\nexport const mergeCurrentContentBackground = registerColor('merge.currentContentBackground',\n\t{ dark: transparent(mergeCurrentHeaderBackground, contentTransparency), light: transparent(mergeCurrentHeaderBackground, contentTransparency), hcDark: transparent(mergeCurrentHeaderBackground, contentTransparency), hcLight: transparent(mergeCurrentHeaderBackground, contentTransparency) },\n\tnls.localize('mergeCurrentContentBackground', 'Current content background in inline merge-conflicts. The color must not be opaque so as not to hide underlying decorations.'), true);\n\nexport const mergeIncomingHeaderBackground = registerColor('merge.incomingHeaderBackground',\n\t{ dark: incomingBaseColor, light: incomingBaseColor, hcDark: null, hcLight: null },\n\tnls.localize('mergeIncomingHeaderBackground', 'Incoming header background in inline merge-conflicts. The color must not be opaque so as not to hide underlying decorations.'), true);\n\nexport const mergeIncomingContentBackground = registerColor('merge.incomingContentBackground',\n\t{ dark: transparent(mergeIncomingHeaderBackground, contentTransparency), light: transparent(mergeIncomingHeaderBackground, contentTransparency), hcDark: transparent(mergeIncomingHeaderBackground, contentTransparency), hcLight: transparent(mergeIncomingHeaderBackground, contentTransparency) },\n\tnls.localize('mergeIncomingContentBackground', 'Incoming content background in inline merge-conflicts. The color must not be opaque so as not to hide underlying decorations.'), true);\n\nexport const mergeCommonHeaderBackground = registerColor('merge.commonHeaderBackground',\n\t{ dark: commonBaseColor, light: commonBaseColor, hcDark: null, hcLight: null },\n\tnls.localize('mergeCommonHeaderBackground', 'Common ancestor header background in inline merge-conflicts. The color must not be opaque so as not to hide underlying decorations.'), true);\n\nexport const mergeCommonContentBackground = registerColor('merge.commonContentBackground',\n\t{ dark: transparent(mergeCommonHeaderBackground, contentTransparency), light: transparent(mergeCommonHeaderBackground, contentTransparency), hcDark: transparent(mergeCommonHeaderBackground, contentTransparency), hcLight: transparent(mergeCommonHeaderBackground, contentTransparency) },\n\tnls.localize('mergeCommonContentBackground', 'Common ancestor content background in inline merge-conflicts. The color must not be opaque so as not to hide underlying decorations.'), true);\n\nexport const mergeBorder = registerColor('merge.border',\n\t{ dark: null, light: null, hcDark: '#C3DF6F', hcLight: '#007ACC' },\n\tnls.localize('mergeBorder', 'Border color on headers and the splitter in inline merge-conflicts.'));\n\n\nexport const overviewRulerCurrentContentForeground = registerColor('editorOverviewRuler.currentContentForeground',\n\t{ dark: transparent(mergeCurrentHeaderBackground, rulerTransparency), light: transparent(mergeCurrentHeaderBackground, rulerTransparency), hcDark: mergeBorder, hcLight: mergeBorder },\n\tnls.localize('overviewRulerCurrentContentForeground', 'Current overview ruler foreground for inline merge-conflicts.'));\n\nexport const overviewRulerIncomingContentForeground = registerColor('editorOverviewRuler.incomingContentForeground',\n\t{ dark: transparent(mergeIncomingHeaderBackground, rulerTransparency), light: transparent(mergeIncomingHeaderBackground, rulerTransparency), hcDark: mergeBorder, hcLight: mergeBorder },\n\tnls.localize('overviewRulerIncomingContentForeground', 'Incoming overview ruler foreground for inline merge-conflicts.'));\n\nexport const overviewRulerCommonContentForeground = registerColor('editorOverviewRuler.commonContentForeground',\n\t{ dark: transparent(mergeCommonHeaderBackground, rulerTransparency), light: transparent(mergeCommonHeaderBackground, rulerTransparency), hcDark: mergeBorder, hcLight: mergeBorder },\n\tnls.localize('overviewRulerCommonContentForeground', 'Common ancestor overview ruler foreground for inline merge-conflicts.'));\n\nexport const overviewRulerFindMatchForeground = registerColor('editorOverviewRuler.findMatchForeground',\n\t{ dark: '#d186167e', light: '#d186167e', hcDark: '#AB5A00', hcLight: '' },\n\tnls.localize('overviewRulerFindMatchForeground', 'Overview ruler marker color for find matches. The color must not be opaque so as not to hide underlying decorations.'), true);\n\nexport const overviewRulerSelectionHighlightForeground = registerColor('editorOverviewRuler.selectionHighlightForeground',\n\t{ dark: '#A0A0A0CC', light: '#A0A0A0CC', hcDark: '#A0A0A0CC', hcLight: '#A0A0A0CC' },\n\tnls.localize('overviewRulerSelectionHighlightForeground', 'Overview ruler marker color for selection highlights. The color must not be opaque so as not to hide underlying decorations.'), true);\n\n\n// ----- problems\n\nexport const problemsErrorIconForeground = registerColor('problemsErrorIcon.foreground',\n\t{ dark: editorErrorForeground, light: editorErrorForeground, hcDark: editorErrorForeground, hcLight: editorErrorForeground },\n\tnls.localize('problemsErrorIconForeground', \"The color used for the problems error icon.\"));\n\nexport const problemsWarningIconForeground = registerColor('problemsWarningIcon.foreground',\n\t{ dark: editorWarningForeground, light: editorWarningForeground, hcDark: editorWarningForeground, hcLight: editorWarningForeground },\n\tnls.localize('problemsWarningIconForeground', \"The color used for the problems warning icon.\"));\n\nexport const problemsInfoIconForeground = registerColor('problemsInfoIcon.foreground',\n\t{ dark: editorInfoForeground, light: editorInfoForeground, hcDark: editorInfoForeground, hcLight: editorInfoForeground },\n\tnls.localize('problemsInfoIconForeground', \"The color used for the problems info icon.\"));\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\nimport * as nls from 'vs/nls';\n\n// Import the effects we need\nimport { Color, RGBA } from 'vs/base/common/color';\nimport { registerColor, transparent, lighten, darken } from 'vs/platform/theme/common/colorUtils';\n\n// Import the colors we need\nimport { foreground, contrastBorder, focusBorder, iconForeground } from 'vs/platform/theme/common/colors/baseColors';\nimport { editorWidgetBackground } from 'vs/platform/theme/common/colors/editorColors';\n\n\n// ----- input\n\nexport const inputBackground = registerColor('input.background',\n\t{ dark: '#3C3C3C', light: Color.white, hcDark: Color.black, hcLight: Color.white },\n\tnls.localize('inputBoxBackground', \"Input box background.\"));\n\nexport const inputForeground = registerColor('input.foreground',\n\t{ dark: foreground, light: foreground, hcDark: foreground, hcLight: foreground },\n\tnls.localize('inputBoxForeground', \"Input box foreground.\"));\n\nexport const inputBorder = registerColor('input.border',\n\t{ dark: null, light: null, hcDark: contrastBorder, hcLight: contrastBorder },\n\tnls.localize('inputBoxBorder', \"Input box border.\"));\n\nexport const inputActiveOptionBorder = registerColor('inputOption.activeBorder',\n\t{ dark: '#007ACC', light: '#007ACC', hcDark: contrastBorder, hcLight: contrastBorder },\n\tnls.localize('inputBoxActiveOptionBorder', \"Border color of activated options in input fields.\"));\n\nexport const inputActiveOptionHoverBackground = registerColor('inputOption.hoverBackground',\n\t{ dark: '#5a5d5e80', light: '#b8b8b850', hcDark: null, hcLight: null },\n\tnls.localize('inputOption.hoverBackground', \"Background color of activated options in input fields.\"));\n\nexport const inputActiveOptionBackground = registerColor('inputOption.activeBackground',\n\t{ dark: transparent(focusBorder, 0.4), light: transparent(focusBorder, 0.2), hcDark: Color.transparent, hcLight: Color.transparent },\n\tnls.localize('inputOption.activeBackground', \"Background hover color of options in input fields.\"));\n\nexport const inputActiveOptionForeground = registerColor('inputOption.activeForeground',\n\t{ dark: Color.white, light: Color.black, hcDark: foreground, hcLight: foreground },\n\tnls.localize('inputOption.activeForeground', \"Foreground color of activated options in input fields.\"));\n\nexport const inputPlaceholderForeground = registerColor('input.placeholderForeground',\n\t{ light: transparent(foreground, 0.5), dark: transparent(foreground, 0.5), hcDark: transparent(foreground, 0.7), hcLight: transparent(foreground, 0.7) },\n\tnls.localize('inputPlaceholderForeground', \"Input box foreground color for placeholder text.\"));\n\n\n// ----- input validation\n\nexport const inputValidationInfoBackground = registerColor('inputValidation.infoBackground',\n\t{ dark: '#063B49', light: '#D6ECF2', hcDark: Color.black, hcLight: Color.white },\n\tnls.localize('inputValidationInfoBackground', \"Input validation background color for information severity.\"));\n\nexport const inputValidationInfoForeground = registerColor('inputValidation.infoForeground',\n\t{ dark: null, light: null, hcDark: null, hcLight: foreground },\n\tnls.localize('inputValidationInfoForeground', \"Input validation foreground color for information severity.\"));\n\nexport const inputValidationInfoBorder = registerColor('inputValidation.infoBorder',\n\t{ dark: '#007acc', light: '#007acc', hcDark: contrastBorder, hcLight: contrastBorder },\n\tnls.localize('inputValidationInfoBorder', \"Input validation border color for information severity.\"));\n\nexport const inputValidationWarningBackground = registerColor('inputValidation.warningBackground',\n\t{ dark: '#352A05', light: '#F6F5D2', hcDark: Color.black, hcLight: Color.white },\n\tnls.localize('inputValidationWarningBackground', \"Input validation background color for warning severity.\"));\n\nexport const inputValidationWarningForeground = registerColor('inputValidation.warningForeground',\n\t{ dark: null, light: null, hcDark: null, hcLight: foreground },\n\tnls.localize('inputValidationWarningForeground', \"Input validation foreground color for warning severity.\"));\n\nexport const inputValidationWarningBorder = registerColor('inputValidation.warningBorder',\n\t{ dark: '#B89500', light: '#B89500', hcDark: contrastBorder, hcLight: contrastBorder },\n\tnls.localize('inputValidationWarningBorder', \"Input validation border color for warning severity.\"));\n\nexport const inputValidationErrorBackground = registerColor('inputValidation.errorBackground',\n\t{ dark: '#5A1D1D', light: '#F2DEDE', hcDark: Color.black, hcLight: Color.white },\n\tnls.localize('inputValidationErrorBackground', \"Input validation background color for error severity.\"));\n\nexport const inputValidationErrorForeground = registerColor('inputValidation.errorForeground',\n\t{ dark: null, light: null, hcDark: null, hcLight: foreground },\n\tnls.localize('inputValidationErrorForeground', \"Input validation foreground color for error severity.\"));\n\nexport const inputValidationErrorBorder = registerColor('inputValidation.errorBorder',\n\t{ dark: '#BE1100', light: '#BE1100', hcDark: contrastBorder, hcLight: contrastBorder },\n\tnls.localize('inputValidationErrorBorder', \"Input validation border color for error severity.\"));\n\n\n// ----- select\n\nexport const selectBackground = registerColor('dropdown.background',\n\t{ dark: '#3C3C3C', light: Color.white, hcDark: Color.black, hcLight: Color.white },\n\tnls.localize('dropdownBackground', \"Dropdown background.\"));\n\nexport const selectListBackground = registerColor('dropdown.listBackground',\n\t{ dark: null, light: null, hcDark: Color.black, hcLight: Color.white },\n\tnls.localize('dropdownListBackground', \"Dropdown list background.\"));\n\nexport const selectForeground = registerColor('dropdown.foreground',\n\t{ dark: '#F0F0F0', light: foreground, hcDark: Color.white, hcLight: foreground },\n\tnls.localize('dropdownForeground', \"Dropdown foreground.\"));\n\nexport const selectBorder = registerColor('dropdown.border',\n\t{ dark: selectBackground, light: '#CECECE', hcDark: contrastBorder, hcLight: contrastBorder },\n\tnls.localize('dropdownBorder', \"Dropdown border.\"));\n\n\n// ------ button\n\nexport const buttonForeground = registerColor('button.foreground',\n\t{ dark: Color.white, light: Color.white, hcDark: Color.white, hcLight: Color.white },\n\tnls.localize('buttonForeground', \"Button foreground color.\"));\n\nexport const buttonSeparator = registerColor('button.separator',\n\t{ dark: transparent(buttonForeground, .4), light: transparent(buttonForeground, .4), hcDark: transparent(buttonForeground, .4), hcLight: transparent(buttonForeground, .4) },\n\tnls.localize('buttonSeparator', \"Button separator color.\"));\n\nexport const buttonBackground = registerColor('button.background',\n\t{ dark: '#0E639C', light: '#007ACC', hcDark: null, hcLight: '#0F4A85' },\n\tnls.localize('buttonBackground', \"Button background color.\"));\n\nexport const buttonHoverBackground = registerColor('button.hoverBackground',\n\t{ dark: lighten(buttonBackground, 0.2), light: darken(buttonBackground, 0.2), hcDark: buttonBackground, hcLight: buttonBackground },\n\tnls.localize('buttonHoverBackground', \"Button background color when hovering.\"));\n\nexport const buttonBorder = registerColor('button.border',\n\t{ dark: contrastBorder, light: contrastBorder, hcDark: contrastBorder, hcLight: contrastBorder },\n\tnls.localize('buttonBorder', \"Button border color.\"));\n\nexport const buttonSecondaryForeground = registerColor('button.secondaryForeground',\n\t{ dark: Color.white, light: Color.white, hcDark: Color.white, hcLight: foreground },\n\tnls.localize('buttonSecondaryForeground', \"Secondary button foreground color.\"));\n\nexport const buttonSecondaryBackground = registerColor('button.secondaryBackground',\n\t{ dark: '#3A3D41', light: '#5F6A79', hcDark: null, hcLight: Color.white },\n\tnls.localize('buttonSecondaryBackground', \"Secondary button background color.\"));\n\nexport const buttonSecondaryHoverBackground = registerColor('button.secondaryHoverBackground',\n\t{ dark: lighten(buttonSecondaryBackground, 0.2), light: darken(buttonSecondaryBackground, 0.2), hcDark: null, hcLight: null },\n\tnls.localize('buttonSecondaryHoverBackground', \"Secondary button background color when hovering.\"));\n\n\n// ------ checkbox\n\nexport const checkboxBackground = registerColor('checkbox.background',\n\t{ dark: selectBackground, light: selectBackground, hcDark: selectBackground, hcLight: selectBackground },\n\tnls.localize('checkbox.background', \"Background color of checkbox widget.\"));\n\nexport const checkboxSelectBackground = registerColor('checkbox.selectBackground',\n\t{ dark: editorWidgetBackground, light: editorWidgetBackground, hcDark: editorWidgetBackground, hcLight: editorWidgetBackground },\n\tnls.localize('checkbox.select.background', \"Background color of checkbox widget when the element it's in is selected.\"));\n\nexport const checkboxForeground = registerColor('checkbox.foreground',\n\t{ dark: selectForeground, light: selectForeground, hcDark: selectForeground, hcLight: selectForeground },\n\tnls.localize('checkbox.foreground', \"Foreground color of checkbox widget.\"));\n\nexport const checkboxBorder = registerColor('checkbox.border',\n\t{ dark: selectBorder, light: selectBorder, hcDark: selectBorder, hcLight: selectBorder },\n\tnls.localize('checkbox.border', \"Border color of checkbox widget.\"));\n\nexport const checkboxSelectBorder = registerColor('checkbox.selectBorder',\n\t{ dark: iconForeground, light: iconForeground, hcDark: iconForeground, hcLight: iconForeground },\n\tnls.localize('checkbox.select.border', \"Border color of checkbox widget when the element it's in is selected.\"));\n\n\n// ------ keybinding label\n\nexport const keybindingLabelBackground = registerColor('keybindingLabel.background',\n\t{ dark: new Color(new RGBA(128, 128, 128, 0.17)), light: new Color(new RGBA(221, 221, 221, 0.4)), hcDark: Color.transparent, hcLight: Color.transparent },\n\tnls.localize('keybindingLabelBackground', \"Keybinding label background color. The keybinding label is used to represent a keyboard shortcut.\"));\n\nexport const keybindingLabelForeground = registerColor('keybindingLabel.foreground',\n\t{ dark: Color.fromHex('#CCCCCC'), light: Color.fromHex('#555555'), hcDark: Color.white, hcLight: foreground },\n\tnls.localize('keybindingLabelForeground', \"Keybinding label foreground color. The keybinding label is used to represent a keyboard shortcut.\"));\n\nexport const keybindingLabelBorder = registerColor('keybindingLabel.border',\n\t{ dark: new Color(new RGBA(51, 51, 51, 0.6)), light: new Color(new RGBA(204, 204, 204, 0.4)), hcDark: new Color(new RGBA(111, 195, 223)), hcLight: contrastBorder },\n\tnls.localize('keybindingLabelBorder', \"Keybinding label border color. The keybinding label is used to represent a keyboard shortcut.\"));\n\nexport const keybindingLabelBottomBorder = registerColor('keybindingLabel.bottomBorder',\n\t{ dark: new Color(new RGBA(68, 68, 68, 0.6)), light: new Color(new RGBA(187, 187, 187, 0.4)), hcDark: new Color(new RGBA(111, 195, 223)), hcLight: foreground },\n\tnls.localize('keybindingLabelBottomBorder', \"Keybinding label border bottom color. The keybinding label is used to represent a keyboard shortcut.\"));\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\nimport * as nls from 'vs/nls';\n\n// Import the effects we need\nimport { Color } from 'vs/base/common/color';\nimport { registerColor, darken, lighten, transparent, ifDefinedThenElse } from 'vs/platform/theme/common/colorUtils';\n\n// Import the colors we need\nimport { foreground, contrastBorder, activeContrastBorder, focusBorder, iconForeground } from 'vs/platform/theme/common/colors/baseColors';\nimport { editorWidgetBackground, editorFindMatchHighlightBorder, editorFindMatchHighlight, widgetShadow } from 'vs/platform/theme/common/colors/editorColors';\n\n\nexport const listFocusBackground = registerColor('list.focusBackground',\n\t{ dark: null, light: null, hcDark: null, hcLight: null },\n\tnls.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.\"));\n\nexport const listFocusForeground = registerColor('list.focusForeground',\n\t{ dark: null, light: null, hcDark: null, hcLight: null },\n\tnls.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.\"));\n\nexport const listFocusOutline = registerColor('list.focusOutline',\n\t{ dark: focusBorder, light: focusBorder, hcDark: activeContrastBorder, hcLight: activeContrastBorder },\n\tnls.localize('listFocusOutline', \"List/Tree outline color for the focused item when the list/tree is active. An active list/tree has keyboard focus, an inactive does not.\"));\n\nexport const listFocusAndSelectionOutline = registerColor('list.focusAndSelectionOutline',\n\t{ dark: null, light: null, hcDark: null, hcLight: null },\n\tnls.localize('listFocusAndSelectionOutline', \"List/Tree outline color for the focused item when the list/tree is active and selected. An active list/tree has keyboard focus, an inactive does not.\"));\n\nexport const listActiveSelectionBackground = registerColor('list.activeSelectionBackground',\n\t{ dark: '#04395E', light: '#0060C0', hcDark: null, hcLight: Color.fromHex('#0F4A85').transparent(0.1) },\n\tnls.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.\"));\n\nexport const listActiveSelectionForeground = registerColor('list.activeSelectionForeground',\n\t{ dark: Color.white, light: Color.white, hcDark: null, hcLight: null },\n\tnls.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.\"));\n\nexport const listActiveSelectionIconForeground = registerColor('list.activeSelectionIconForeground',\n\t{ dark: null, light: null, hcDark: null, hcLight: null },\n\tnls.localize('listActiveSelectionIconForeground', \"List/Tree icon foreground color for the selected item when the list/tree is active. An active list/tree has keyboard focus, an inactive does not.\"));\n\nexport const listInactiveSelectionBackground = registerColor('list.inactiveSelectionBackground',\n\t{ dark: '#37373D', light: '#E4E6F1', hcDark: null, hcLight: Color.fromHex('#0F4A85').transparent(0.1) },\n\tnls.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.\"));\n\nexport const listInactiveSelectionForeground = registerColor('list.inactiveSelectionForeground',\n\t{ dark: null, light: null, hcDark: null, hcLight: null },\n\tnls.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.\"));\n\nexport const listInactiveSelectionIconForeground = registerColor('list.inactiveSelectionIconForeground',\n\t{ dark: null, light: null, hcDark: null, hcLight: null },\n\tnls.localize('listInactiveSelectionIconForeground', \"List/Tree icon foreground color for the selected item when the list/tree is inactive. An active list/tree has keyboard focus, an inactive does not.\"));\n\nexport const listInactiveFocusBackground = registerColor('list.inactiveFocusBackground',\n\t{ dark: null, light: null, hcDark: null, hcLight: null },\n\tnls.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.\"));\n\nexport const listInactiveFocusOutline = registerColor('list.inactiveFocusOutline',\n\t{ dark: null, light: null, hcDark: null, hcLight: null },\n\tnls.localize('listInactiveFocusOutline', \"List/Tree outline color for the focused item when the list/tree is inactive. An active list/tree has keyboard focus, an inactive does not.\"));\n\nexport const listHoverBackground = registerColor('list.hoverBackground',\n\t{ dark: '#2A2D2E', light: '#F0F0F0', hcDark: Color.white.transparent(0.1), hcLight: Color.fromHex('#0F4A85').transparent(0.1) },\n\tnls.localize('listHoverBackground', \"List/Tree background when hovering over items using the mouse.\"));\n\nexport const listHoverForeground = registerColor('list.hoverForeground',\n\t{ dark: null, light: null, hcDark: null, hcLight: null },\n\tnls.localize('listHoverForeground', \"List/Tree foreground when hovering over items using the mouse.\"));\n\nexport const listDropOverBackground = registerColor('list.dropBackground',\n\t{ dark: '#062F4A', light: '#D6EBFF', hcDark: null, hcLight: null },\n\tnls.localize('listDropBackground', \"List/Tree drag and drop background when moving items over other items when using the mouse.\"));\n\nexport const listDropBetweenBackground = registerColor('list.dropBetweenBackground',\n\t{ dark: iconForeground, light: iconForeground, hcDark: null, hcLight: null },\n\tnls.localize('listDropBetweenBackground', \"List/Tree drag and drop border color when moving items between items when using the mouse.\"));\n\nexport const listHighlightForeground = registerColor('list.highlightForeground',\n\t{ dark: '#2AAAFF', light: '#0066BF', hcDark: focusBorder, hcLight: focusBorder },\n\tnls.localize('highlight', 'List/Tree foreground color of the match highlights when searching inside the list/tree.'));\n\nexport const listFocusHighlightForeground = registerColor('list.focusHighlightForeground',\n\t{ dark: listHighlightForeground, light: ifDefinedThenElse(listActiveSelectionBackground, listHighlightForeground, '#BBE7FF'), hcDark: listHighlightForeground, hcLight: listHighlightForeground },\n\tnls.localize('listFocusHighlightForeground', 'List/Tree foreground color of the match highlights on actively focused items when searching inside the list/tree.'));\n\nexport const listInvalidItemForeground = registerColor('list.invalidItemForeground',\n\t{ dark: '#B89500', light: '#B89500', hcDark: '#B89500', hcLight: '#B5200D' },\n\tnls.localize('invalidItemForeground', 'List/Tree foreground color for invalid items, for example an unresolved root in explorer.'));\n\nexport const listErrorForeground = registerColor('list.errorForeground',\n\t{ dark: '#F88070', light: '#B01011', hcDark: null, hcLight: null }, nls.localize('listErrorForeground', 'Foreground color of list items containing errors.'));\n\nexport const listWarningForeground = registerColor('list.warningForeground',\n\t{ dark: '#CCA700', light: '#855F00', hcDark: null, hcLight: null }, nls.localize('listWarningForeground', 'Foreground color of list items containing warnings.'));\n\nexport const listFilterWidgetBackground = registerColor('listFilterWidget.background',\n\t{ light: darken(editorWidgetBackground, 0), dark: lighten(editorWidgetBackground, 0), hcDark: editorWidgetBackground, hcLight: editorWidgetBackground },\n\tnls.localize('listFilterWidgetBackground', 'Background color of the type filter widget in lists and trees.'));\n\nexport const listFilterWidgetOutline = registerColor('listFilterWidget.outline',\n\t{ dark: Color.transparent, light: Color.transparent, hcDark: '#f38518', hcLight: '#007ACC' },\n\tnls.localize('listFilterWidgetOutline', 'Outline color of the type filter widget in lists and trees.'));\n\nexport const listFilterWidgetNoMatchesOutline = registerColor('listFilterWidget.noMatchesOutline',\n\t{ dark: '#BE1100', light: '#BE1100', hcDark: contrastBorder, hcLight: contrastBorder },\n\tnls.localize('listFilterWidgetNoMatchesOutline', 'Outline color of the type filter widget in lists and trees, when there are no matches.'));\n\nexport const listFilterWidgetShadow = registerColor('listFilterWidget.shadow',\n\t{ dark: widgetShadow, light: widgetShadow, hcDark: widgetShadow, hcLight: widgetShadow },\n\tnls.localize('listFilterWidgetShadow', 'Shadow color of the type filter widget in lists and trees.'));\n\nexport const listFilterMatchHighlight = registerColor('list.filterMatchBackground',\n\t{ dark: editorFindMatchHighlight, light: editorFindMatchHighlight, hcDark: null, hcLight: null },\n\tnls.localize('listFilterMatchHighlight', 'Background color of the filtered match.'));\n\nexport const listFilterMatchHighlightBorder = registerColor('list.filterMatchBorder',\n\t{ dark: editorFindMatchHighlightBorder, light: editorFindMatchHighlightBorder, hcDark: contrastBorder, hcLight: activeContrastBorder },\n\tnls.localize('listFilterMatchHighlightBorder', 'Border color of the filtered match.'));\n\nexport const listDeemphasizedForeground = registerColor('list.deemphasizedForeground',\n\t{ dark: '#8C8C8C', light: '#8E8E90', hcDark: '#A7A8A9', hcLight: '#666666' },\n\tnls.localize('listDeemphasizedForeground', \"List/Tree foreground color for items that are deemphasized.\"));\n\n\n// ------ tree\n\nexport const treeIndentGuidesStroke = registerColor('tree.indentGuidesStroke',\n\t{ dark: '#585858', light: '#a9a9a9', hcDark: '#a9a9a9', hcLight: '#a5a5a5' },\n\tnls.localize('treeIndentGuidesStroke', \"Tree stroke color for the indentation guides.\"));\n\nexport const treeInactiveIndentGuidesStroke = registerColor('tree.inactiveIndentGuidesStroke',\n\t{ dark: transparent(treeIndentGuidesStroke, 0.4), light: transparent(treeIndentGuidesStroke, 0.4), hcDark: transparent(treeIndentGuidesStroke, 0.4), hcLight: transparent(treeIndentGuidesStroke, 0.4) },\n\tnls.localize('treeInactiveIndentGuidesStroke', \"Tree stroke color for the indentation guides that are not active.\"));\n\n\n// ------ table\n\nexport const tableColumnsBorder = registerColor('tree.tableColumnsBorder',\n\t{ dark: '#CCCCCC20', light: '#61616120', hcDark: null, hcLight: null },\n\tnls.localize('tableColumnsBorder', \"Table border color between columns.\"));\n\nexport const tableOddRowsBackgroundColor = registerColor('tree.tableOddRowsBackground',\n\t{ dark: transparent(foreground, 0.04), light: transparent(foreground, 0.04), hcDark: null, hcLight: null },\n\tnls.localize('tableOddRowsBackgroundColor', \"Background color for odd table rows.\"));\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\nimport * as nls from 'vs/nls';\n\n// Import the effects we need\nimport { registerColor } from 'vs/platform/theme/common/colorUtils';\n\n// Import the colors we need\nimport { contrastBorder, activeContrastBorder } from 'vs/platform/theme/common/colors/baseColors';\nimport { selectForeground, selectBackground } from 'vs/platform/theme/common/colors/inputColors';\nimport { listActiveSelectionBackground, listActiveSelectionForeground } from 'vs/platform/theme/common/colors/listColors';\n\n\nexport const menuBorder = registerColor('menu.border',\n\t{ dark: null, light: null, hcDark: contrastBorder, hcLight: contrastBorder },\n\tnls.localize('menuBorder', \"Border color of menus.\"));\n\nexport const menuForeground = registerColor('menu.foreground',\n\t{ dark: selectForeground, light: selectForeground, hcDark: selectForeground, hcLight: selectForeground },\n\tnls.localize('menuForeground', \"Foreground color of menu items.\"));\n\nexport const menuBackground = registerColor('menu.background',\n\t{ dark: selectBackground, light: selectBackground, hcDark: selectBackground, hcLight: selectBackground },\n\tnls.localize('menuBackground', \"Background color of menu items.\"));\n\nexport const menuSelectionForeground = registerColor('menu.selectionForeground',\n\t{ dark: listActiveSelectionForeground, light: listActiveSelectionForeground, hcDark: listActiveSelectionForeground, hcLight: listActiveSelectionForeground },\n\tnls.localize('menuSelectionForeground', \"Foreground color of the selected menu item in menus.\"));\n\nexport const menuSelectionBackground = registerColor('menu.selectionBackground',\n\t{ dark: listActiveSelectionBackground, light: listActiveSelectionBackground, hcDark: listActiveSelectionBackground, hcLight: listActiveSelectionBackground },\n\tnls.localize('menuSelectionBackground', \"Background color of the selected menu item in menus.\"));\n\nexport const menuSelectionBorder = registerColor('menu.selectionBorder',\n\t{ dark: null, light: null, hcDark: activeContrastBorder, hcLight: activeContrastBorder },\n\tnls.localize('menuSelectionBorder', \"Border color of the selected menu item in menus.\"));\n\nexport const menuSeparatorBackground = registerColor('menu.separatorBackground',\n\t{ dark: '#606060', light: '#D4D4D4', hcDark: contrastBorder, hcLight: contrastBorder },\n\tnls.localize('menuSeparatorBackground', \"Color of a separator menu item in menus.\"));\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\nimport * as nls from 'vs/nls';\n\n// Import the effects we need\nimport { Color, RGBA } from 'vs/base/common/color';\nimport { registerColor, transparent } from 'vs/platform/theme/common/colorUtils';\n\n// Import the colors we need\nimport { editorInfoForeground, editorWarningForeground, editorWarningBorder, editorInfoBorder } from 'vs/platform/theme/common/colors/editorColors';\nimport { scrollbarSliderBackground, scrollbarSliderHoverBackground, scrollbarSliderActiveBackground } from 'vs/platform/theme/common/colors/miscColors';\n\n\nexport const minimapFindMatch = registerColor('minimap.findMatchHighlight',\n\t{ light: '#d18616', dark: '#d18616', hcDark: '#AB5A00', hcLight: '#0F4A85' },\n\tnls.localize('minimapFindMatchHighlight', 'Minimap marker color for find matches.'), true);\n\nexport const minimapSelectionOccurrenceHighlight = registerColor('minimap.selectionOccurrenceHighlight',\n\t{ light: '#c9c9c9', dark: '#676767', hcDark: '#ffffff', hcLight: '#0F4A85' },\n\tnls.localize('minimapSelectionOccurrenceHighlight', 'Minimap marker color for repeating editor selections.'), true);\n\nexport const minimapSelection = registerColor('minimap.selectionHighlight',\n\t{ light: '#ADD6FF', dark: '#264F78', hcDark: '#ffffff', hcLight: '#0F4A85' },\n\tnls.localize('minimapSelectionHighlight', 'Minimap marker color for the editor selection.'), true);\n\nexport const minimapInfo = registerColor('minimap.infoHighlight',\n\t{ dark: editorInfoForeground, light: editorInfoForeground, hcDark: editorInfoBorder, hcLight: editorInfoBorder },\n\tnls.localize('minimapInfo', 'Minimap marker color for infos.'));\n\nexport const minimapWarning = registerColor('minimap.warningHighlight',\n\t{ dark: editorWarningForeground, light: editorWarningForeground, hcDark: editorWarningBorder, hcLight: editorWarningBorder },\n\tnls.localize('overviewRuleWarning', 'Minimap marker color for warnings.'));\n\nexport const minimapError = registerColor('minimap.errorHighlight',\n\t{ dark: new Color(new RGBA(255, 18, 18, 0.7)), light: new Color(new RGBA(255, 18, 18, 0.7)), hcDark: new Color(new RGBA(255, 50, 50, 1)), hcLight: '#B5200D' },\n\tnls.localize('minimapError', 'Minimap marker color for errors.'));\n\nexport const minimapBackground = registerColor('minimap.background',\n\t{ dark: null, light: null, hcDark: null, hcLight: null },\n\tnls.localize('minimapBackground', \"Minimap background color.\"));\n\nexport const minimapForegroundOpacity = registerColor('minimap.foregroundOpacity',\n\t{ dark: Color.fromHex('#000f'), light: Color.fromHex('#000f'), hcDark: Color.fromHex('#000f'), hcLight: Color.fromHex('#000f') },\n\tnls.localize('minimapForegroundOpacity', 'Opacity of foreground elements rendered in the minimap. For example, \"#000000c0\" will render the elements with 75% opacity.'));\n\nexport const minimapSliderBackground = registerColor('minimapSlider.background',\n\t{ light: transparent(scrollbarSliderBackground, 0.5), dark: transparent(scrollbarSliderBackground, 0.5), hcDark: transparent(scrollbarSliderBackground, 0.5), hcLight: transparent(scrollbarSliderBackground, 0.5) },\n\tnls.localize('minimapSliderBackground', \"Minimap slider background color.\"));\n\nexport const minimapSliderHoverBackground = registerColor('minimapSlider.hoverBackground',\n\t{ light: transparent(scrollbarSliderHoverBackground, 0.5), dark: transparent(scrollbarSliderHoverBackground, 0.5), hcDark: transparent(scrollbarSliderHoverBackground, 0.5), hcLight: transparent(scrollbarSliderHoverBackground, 0.5) },\n\tnls.localize('minimapSliderHoverBackground', \"Minimap slider background color when hovering.\"));\n\nexport const minimapSliderActiveBackground = registerColor('minimapSlider.activeBackground',\n\t{ light: transparent(scrollbarSliderActiveBackground, 0.5), dark: transparent(scrollbarSliderActiveBackground, 0.5), hcDark: transparent(scrollbarSliderActiveBackground, 0.5), hcLight: transparent(scrollbarSliderActiveBackground, 0.5) },\n\tnls.localize('minimapSliderActiveBackground', \"Minimap slider background color when clicked on.\"));\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\nimport * as nls from 'vs/nls';\nimport { registerColor, transparent } from 'vs/platform/theme/common/colorUtils';\n\nimport { foreground } from 'vs/platform/theme/common/colors/baseColors';\nimport { editorErrorForeground, editorInfoForeground, editorWarningForeground } from 'vs/platform/theme/common/colors/editorColors';\nimport { minimapFindMatch } from 'vs/platform/theme/common/colors/minimapColors';\n\n\nexport const chartsForeground = registerColor('charts.foreground',\n\t{ dark: foreground, light: foreground, hcDark: foreground, hcLight: foreground },\n\tnls.localize('chartsForeground', \"The foreground color used in charts.\"));\n\nexport const chartsLines = registerColor('charts.lines',\n\t{ dark: transparent(foreground, .5), light: transparent(foreground, .5), hcDark: transparent(foreground, .5), hcLight: transparent(foreground, .5) },\n\tnls.localize('chartsLines', \"The color used for horizontal lines in charts.\"));\n\nexport const chartsRed = registerColor('charts.red',\n\t{ dark: editorErrorForeground, light: editorErrorForeground, hcDark: editorErrorForeground, hcLight: editorErrorForeground },\n\tnls.localize('chartsRed', \"The red color used in chart visualizations.\"));\n\nexport const chartsBlue = registerColor('charts.blue',\n\t{ dark: editorInfoForeground, light: editorInfoForeground, hcDark: editorInfoForeground, hcLight: editorInfoForeground },\n\tnls.localize('chartsBlue', \"The blue color used in chart visualizations.\"));\n\nexport const chartsYellow = registerColor('charts.yellow',\n\t{ dark: editorWarningForeground, light: editorWarningForeground, hcDark: editorWarningForeground, hcLight: editorWarningForeground },\n\tnls.localize('chartsYellow', \"The yellow color used in chart visualizations.\"));\n\nexport const chartsOrange = registerColor('charts.orange',\n\t{ dark: minimapFindMatch, light: minimapFindMatch, hcDark: minimapFindMatch, hcLight: minimapFindMatch },\n\tnls.localize('chartsOrange', \"The orange color used in chart visualizations.\"));\n\nexport const chartsGreen = registerColor('charts.green',\n\t{ dark: '#89D185', light: '#388A34', hcDark: '#89D185', hcLight: '#374e06' },\n\tnls.localize('chartsGreen', \"The green color used in chart visualizations.\"));\n\nexport const chartsPurple = registerColor('charts.purple',\n\t{ dark: '#B180D7', light: '#652D90', hcDark: '#B180D7', hcLight: '#652D90' },\n\tnls.localize('chartsPurple', \"The purple color used in chart visualizations.\"));\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\nimport * as nls from 'vs/nls';\n\n// Import the effects we need\nimport { Color, RGBA } from 'vs/base/common/color';\nimport { registerColor, oneOf } from 'vs/platform/theme/common/colorUtils';\n\n// Import the colors we need\nimport { editorWidgetBackground, editorWidgetForeground } from 'vs/platform/theme/common/colors/editorColors';\nimport { listActiveSelectionBackground, listActiveSelectionForeground, listActiveSelectionIconForeground } from 'vs/platform/theme/common/colors/listColors';\n\n\nexport const quickInputBackground = registerColor('quickInput.background',\n\t{ dark: editorWidgetBackground, light: editorWidgetBackground, hcDark: editorWidgetBackground, hcLight: editorWidgetBackground },\n\tnls.localize('pickerBackground', \"Quick picker background color. The quick picker widget is the container for pickers like the command palette.\"));\n\nexport const quickInputForeground = registerColor('quickInput.foreground',\n\t{ dark: editorWidgetForeground, light: editorWidgetForeground, hcDark: editorWidgetForeground, hcLight: editorWidgetForeground },\n\tnls.localize('pickerForeground', \"Quick picker foreground color. The quick picker widget is the container for pickers like the command palette.\"));\n\nexport const quickInputTitleBackground = registerColor('quickInputTitle.background',\n\t{ dark: new Color(new RGBA(255, 255, 255, 0.105)), light: new Color(new RGBA(0, 0, 0, 0.06)), hcDark: '#000000', hcLight: Color.white },\n\tnls.localize('pickerTitleBackground', \"Quick picker title background color. The quick picker widget is the container for pickers like the command palette.\"));\n\nexport const pickerGroupForeground = registerColor('pickerGroup.foreground',\n\t{ dark: '#3794FF', light: '#0066BF', hcDark: Color.white, hcLight: '#0F4A85' },\n\tnls.localize('pickerGroupForeground', \"Quick picker color for grouping labels.\"));\n\nexport const pickerGroupBorder = registerColor('pickerGroup.border',\n\t{ dark: '#3F3F46', light: '#CCCEDB', hcDark: Color.white, hcLight: '#0F4A85' },\n\tnls.localize('pickerGroupBorder', \"Quick picker color for grouping borders.\"));\n\nexport const _deprecatedQuickInputListFocusBackground = registerColor('quickInput.list.focusBackground',\n\t{ dark: null, light: null, hcDark: null, hcLight: null }, '', undefined,\n\tnls.localize('quickInput.list.focusBackground deprecation', \"Please use quickInputList.focusBackground instead\"));\n\nexport const quickInputListFocusForeground = registerColor('quickInputList.focusForeground',\n\t{ dark: listActiveSelectionForeground, light: listActiveSelectionForeground, hcDark: listActiveSelectionForeground, hcLight: listActiveSelectionForeground },\n\tnls.localize('quickInput.listFocusForeground', \"Quick picker foreground color for the focused item.\"));\n\nexport const quickInputListFocusIconForeground = registerColor('quickInputList.focusIconForeground',\n\t{ dark: listActiveSelectionIconForeground, light: listActiveSelectionIconForeground, hcDark: listActiveSelectionIconForeground, hcLight: listActiveSelectionIconForeground },\n\tnls.localize('quickInput.listFocusIconForeground', \"Quick picker icon foreground color for the focused item.\"));\n\nexport const quickInputListFocusBackground = registerColor('quickInputList.focusBackground',\n\t{ dark: oneOf(_deprecatedQuickInputListFocusBackground, listActiveSelectionBackground), light: oneOf(_deprecatedQuickInputListFocusBackground, listActiveSelectionBackground), hcDark: null, hcLight: null },\n\tnls.localize('quickInput.listFocusBackground', \"Quick picker background color for the focused item.\"));\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\nimport * as nls from 'vs/nls';\n\n// Import the effects we need\nimport { registerColor, transparent } from 'vs/platform/theme/common/colorUtils';\n\n// Import the colors we need\nimport { foreground } from 'vs/platform/theme/common/colors/baseColors';\nimport { editorFindMatchHighlight, editorFindMatchHighlightBorder } from 'vs/platform/theme/common/colors/editorColors';\n\n\nexport const searchResultsInfoForeground = registerColor('search.resultsInfoForeground',\n\t{ light: foreground, dark: transparent(foreground, 0.65), hcDark: foreground, hcLight: foreground },\n\tnls.localize('search.resultsInfoForeground', \"Color of the text in the search viewlet's completion message.\"));\n\n\n// ----- search editor (Distinct from normal editor find match to allow for better differentiation)\n\nexport const searchEditorFindMatch = registerColor('searchEditor.findMatchBackground',\n\t{ light: transparent(editorFindMatchHighlight, 0.66), dark: transparent(editorFindMatchHighlight, 0.66), hcDark: editorFindMatchHighlight, hcLight: editorFindMatchHighlight },\n\tnls.localize('searchEditor.queryMatch', \"Color of the Search Editor query matches.\"));\n\nexport const searchEditorFindMatchBorder = registerColor('searchEditor.findMatchBorder',\n\t{ light: transparent(editorFindMatchHighlightBorder, 0.66), dark: transparent(editorFindMatchHighlightBorder, 0.66), hcDark: editorFindMatchHighlightBorder, hcLight: editorFindMatchHighlightBorder },\n\tnls.localize('searchEditor.editorFindMatchBorder', \"Border color of the Search Editor query matches.\"));\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\nexport * from 'vs/platform/theme/common/colorUtils';\n\n// Make sure all color files are exported\nexport * from 'vs/platform/theme/common/colors/baseColors';\nexport * from 'vs/platform/theme/common/colors/chartsColors';\nexport * from 'vs/platform/theme/common/colors/editorColors';\nexport * from 'vs/platform/theme/common/colors/inputColors';\nexport * from 'vs/platform/theme/common/colors/listColors';\nexport * from 'vs/platform/theme/common/colors/menuColors';\nexport * from 'vs/platform/theme/common/colors/minimapColors';\nexport * from 'vs/platform/theme/common/colors/miscColors';\nexport * from 'vs/platform/theme/common/colors/quickpickColors';\nexport * from 'vs/platform/theme/common/colors/searchColors';\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\nimport * as dom from 'vs/base/browser/dom';\nimport { GlobalPointerMoveMonitor } from 'vs/base/browser/globalPointerMoveMonitor';\nimport { StandardMouseEvent } from 'vs/base/browser/mouseEvent';\nimport { RunOnceScheduler } from 'vs/base/common/async';\nimport { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle';\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\nimport { asCssVariable } from 'vs/platform/theme/common/colorRegistry';\nimport { ThemeColor } from 'vs/base/common/themables';\n\n/**\n * Coordinates relative to the whole document (e.g. mouse event's pageX and pageY)\n */\nexport class PageCoordinates {\n\t_pageCoordinatesBrand: void = undefined;\n\n\tconstructor(\n\t\tpublic readonly x: number,\n\t\tpublic readonly y: number\n\t) { }\n\n\tpublic toClientCoordinates(targetWindow: Window): ClientCoordinates {\n\t\treturn new ClientCoordinates(this.x - targetWindow.scrollX, this.y - targetWindow.scrollY);\n\t}\n}\n\n/**\n * Coordinates within the application's client area (i.e. origin is document's scroll position).\n *\n * For example, clicking in the top-left corner of the client area will\n * always result in a mouse event with a client.x value of 0, regardless\n * of whether the page is scrolled horizontally.\n */\nexport class ClientCoordinates {\n\t_clientCoordinatesBrand: void = undefined;\n\n\tconstructor(\n\t\tpublic readonly clientX: number,\n\t\tpublic readonly clientY: number\n\t) { }\n\n\tpublic toPageCoordinates(targetWindow: Window): PageCoordinates {\n\t\treturn new PageCoordinates(this.clientX + targetWindow.scrollX, this.clientY + targetWindow.scrollY);\n\t}\n}\n\n/**\n * The position of the editor in the page.\n */\nexport class EditorPagePosition {\n\t_editorPagePositionBrand: void = undefined;\n\n\tconstructor(\n\t\tpublic readonly x: number,\n\t\tpublic readonly y: number,\n\t\tpublic readonly width: number,\n\t\tpublic readonly height: number\n\t) { }\n}\n\n/**\n * Coordinates relative to the the (top;left) of the editor that can be used safely with other internal editor metrics.\n * **NOTE**: This position is obtained by taking page coordinates and transforming them relative to the\n * editor's (top;left) position in a way in which scale transformations are taken into account.\n * **NOTE**: These coordinates could be negative if the mouse position is outside the editor.\n */\nexport class CoordinatesRelativeToEditor {\n\t_positionRelativeToEditorBrand: void = undefined;\n\n\tconstructor(\n\t\tpublic readonly x: number,\n\t\tpublic readonly y: number\n\t) { }\n}\n\nexport function createEditorPagePosition(editorViewDomNode: HTMLElement): EditorPagePosition {\n\tconst editorPos = dom.getDomNodePagePosition(editorViewDomNode);\n\treturn new EditorPagePosition(editorPos.left, editorPos.top, editorPos.width, editorPos.height);\n}\n\nexport function createCoordinatesRelativeToEditor(editorViewDomNode: HTMLElement, editorPagePosition: EditorPagePosition, pos: PageCoordinates) {\n\t// The editor's page position is read from the DOM using getBoundingClientRect().\n\t//\n\t// getBoundingClientRect() returns the actual dimensions, while offsetWidth and offsetHeight\n\t// reflect the unscaled size. We can use this difference to detect a transform:scale()\n\t// and we will apply the transformation in inverse to get mouse coordinates that make sense inside the editor.\n\t//\n\t// This could be expanded to cover rotation as well maybe by walking the DOM up from `editorViewDomNode`\n\t// and computing the effective transformation matrix using getComputedStyle(element).transform.\n\t//\n\tconst scaleX = editorPagePosition.width / editorViewDomNode.offsetWidth;\n\tconst scaleY = editorPagePosition.height / editorViewDomNode.offsetHeight;\n\n\t// Adjust mouse offsets if editor appears to be scaled via transforms\n\tconst relativeX = (pos.x - editorPagePosition.x) / scaleX;\n\tconst relativeY = (pos.y - editorPagePosition.y) / scaleY;\n\treturn new CoordinatesRelativeToEditor(relativeX, relativeY);\n}\n\nexport class EditorMouseEvent extends StandardMouseEvent {\n\t_editorMouseEventBrand: void = undefined;\n\n\t/**\n\t * If the event is a result of using `setPointerCapture`, the `event.target`\n\t * does not necessarily reflect the position in the editor.\n\t */\n\tpublic readonly isFromPointerCapture: boolean;\n\n\t/**\n\t * Coordinates relative to the whole document.\n\t */\n\tpublic readonly pos: PageCoordinates;\n\n\t/**\n\t * Editor's coordinates relative to the whole document.\n\t */\n\tpublic readonly editorPos: EditorPagePosition;\n\n\t/**\n\t * Coordinates relative to the (top;left) of the editor.\n\t * *NOTE*: These coordinates are preferred because they take into account transformations applied to the editor.\n\t * *NOTE*: These coordinates could be negative if the mouse position is outside the editor.\n\t */\n\tpublic readonly relativePos: CoordinatesRelativeToEditor;\n\n\tconstructor(e: MouseEvent, isFromPointerCapture: boolean, editorViewDomNode: HTMLElement) {\n\t\tsuper(dom.getWindow(editorViewDomNode), e);\n\t\tthis.isFromPointerCapture = isFromPointerCapture;\n\t\tthis.pos = new PageCoordinates(this.posx, this.posy);\n\t\tthis.editorPos = createEditorPagePosition(editorViewDomNode);\n\t\tthis.relativePos = createCoordinatesRelativeToEditor(editorViewDomNode, this.editorPos, this.pos);\n\t}\n}\n\nexport class EditorMouseEventFactory {\n\n\tprivate readonly _editorViewDomNode: HTMLElement;\n\n\tconstructor(editorViewDomNode: HTMLElement) {\n\t\tthis._editorViewDomNode = editorViewDomNode;\n\t}\n\n\tprivate _create(e: MouseEvent): EditorMouseEvent {\n\t\treturn new EditorMouseEvent(e, false, this._editorViewDomNode);\n\t}\n\n\tpublic onContextMenu(target: HTMLElement, callback: (e: EditorMouseEvent) => void): IDisposable {\n\t\treturn dom.addDisposableListener(target, 'contextmenu', (e: MouseEvent) => {\n\t\t\tcallback(this._create(e));\n\t\t});\n\t}\n\n\tpublic onMouseUp(target: HTMLElement, callback: (e: EditorMouseEvent) => void): IDisposable {\n\t\treturn dom.addDisposableListener(target, 'mouseup', (e: MouseEvent) => {\n\t\t\tcallback(this._create(e));\n\t\t});\n\t}\n\n\tpublic onMouseDown(target: HTMLElement, callback: (e: EditorMouseEvent) => void): IDisposable {\n\t\treturn dom.addDisposableListener(target, dom.EventType.MOUSE_DOWN, (e: MouseEvent) => {\n\t\t\tcallback(this._create(e));\n\t\t});\n\t}\n\n\tpublic onPointerDown(target: HTMLElement, callback: (e: EditorMouseEvent, pointerId: number) => void): IDisposable {\n\t\treturn dom.addDisposableListener(target, dom.EventType.POINTER_DOWN, (e: PointerEvent) => {\n\t\t\tcallback(this._create(e), e.pointerId);\n\t\t});\n\t}\n\n\tpublic onMouseLeave(target: HTMLElement, callback: (e: EditorMouseEvent) => void): IDisposable {\n\t\treturn dom.addDisposableListener(target, dom.EventType.MOUSE_LEAVE, (e: MouseEvent) => {\n\t\t\tcallback(this._create(e));\n\t\t});\n\t}\n\n\tpublic onMouseMove(target: HTMLElement, callback: (e: EditorMouseEvent) => void): IDisposable {\n\t\treturn dom.addDisposableListener(target, 'mousemove', (e) => callback(this._create(e)));\n\t}\n}\n\nexport class EditorPointerEventFactory {\n\n\tprivate readonly _editorViewDomNode: HTMLElement;\n\n\tconstructor(editorViewDomNode: HTMLElement) {\n\t\tthis._editorViewDomNode = editorViewDomNode;\n\t}\n\n\tprivate _create(e: MouseEvent): EditorMouseEvent {\n\t\treturn new EditorMouseEvent(e, false, this._editorViewDomNode);\n\t}\n\n\tpublic onPointerUp(target: HTMLElement, callback: (e: EditorMouseEvent) => void): IDisposable {\n\t\treturn dom.addDisposableListener(target, 'pointerup', (e: MouseEvent) => {\n\t\t\tcallback(this._create(e));\n\t\t});\n\t}\n\n\tpublic onPointerDown(target: HTMLElement, callback: (e: EditorMouseEvent, pointerId: number) => void): IDisposable {\n\t\treturn dom.addDisposableListener(target, dom.EventType.POINTER_DOWN, (e: PointerEvent) => {\n\t\t\tcallback(this._create(e), e.pointerId);\n\t\t});\n\t}\n\n\tpublic onPointerLeave(target: HTMLElement, callback: (e: EditorMouseEvent) => void): IDisposable {\n\t\treturn dom.addDisposableListener(target, dom.EventType.POINTER_LEAVE, (e: MouseEvent) => {\n\t\t\tcallback(this._create(e));\n\t\t});\n\t}\n\n\tpublic onPointerMove(target: HTMLElement, callback: (e: EditorMouseEvent) => void): IDisposable {\n\t\treturn dom.addDisposableListener(target, 'pointermove', (e) => callback(this._create(e)));\n\t}\n}\n\nexport class GlobalEditorPointerMoveMonitor extends Disposable {\n\n\tprivate readonly _editorViewDomNode: HTMLElement;\n\tprivate readonly _globalPointerMoveMonitor: GlobalPointerMoveMonitor;\n\tprivate _keydownListener: IDisposable | null;\n\n\tconstructor(editorViewDomNode: HTMLElement) {\n\t\tsuper();\n\t\tthis._editorViewDomNode = editorViewDomNode;\n\t\tthis._globalPointerMoveMonitor = this._register(new GlobalPointerMoveMonitor());\n\t\tthis._keydownListener = null;\n\t}\n\n\tpublic startMonitoring(\n\t\tinitialElement: Element,\n\t\tpointerId: number,\n\t\tinitialButtons: number,\n\t\tpointerMoveCallback: (e: EditorMouseEvent) => void,\n\t\tonStopCallback: (browserEvent?: PointerEvent | KeyboardEvent) => void\n\t): void {\n\n\t\t// Add a <> keydown event listener that will cancel the monitoring\n\t\t// if something other than a modifier key is pressed\n\t\tthis._keydownListener = dom.addStandardDisposableListener(initialElement.ownerDocument, 'keydown', (e) => {\n\t\t\tconst chord = e.toKeyCodeChord();\n\t\t\tif (chord.isModifierKey()) {\n\t\t\t\t// Allow modifier keys\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis._globalPointerMoveMonitor.stopMonitoring(true, e.browserEvent);\n\t\t}, true);\n\n\t\tthis._globalPointerMoveMonitor.startMonitoring(\n\t\t\tinitialElement,\n\t\t\tpointerId,\n\t\t\tinitialButtons,\n\t\t\t(e) => {\n\t\t\t\tpointerMoveCallback(new EditorMouseEvent(e, true, this._editorViewDomNode));\n\t\t\t},\n\t\t\t(e) => {\n\t\t\t\tthis._keydownListener!.dispose();\n\t\t\t\tonStopCallback(e);\n\t\t\t}\n\t\t);\n\t}\n\n\tpublic stopMonitoring(): void {\n\t\tthis._globalPointerMoveMonitor.stopMonitoring(true);\n\t}\n}\n\n\n/**\n * A helper to create dynamic css rules, bound to a class name.\n * Rules are reused.\n * Reference counting and delayed garbage collection ensure that no rules leak.\n*/\nexport class DynamicCssRules {\n\tprivate static _idPool = 0;\n\tprivate readonly _instanceId = ++DynamicCssRules._idPool;\n\tprivate _counter = 0;\n\tprivate readonly _rules = new Map();\n\n\t// We delay garbage collection so that hanging rules can be reused.\n\tprivate readonly _garbageCollectionScheduler = new RunOnceScheduler(() => this.garbageCollect(), 1000);\n\n\tconstructor(private readonly _editor: ICodeEditor) {\n\t}\n\n\tpublic createClassNameRef(options: CssProperties): ClassNameReference {\n\t\tconst rule = this.getOrCreateRule(options);\n\t\trule.increaseRefCount();\n\n\t\treturn {\n\t\t\tclassName: rule.className,\n\t\t\tdispose: () => {\n\t\t\t\trule.decreaseRefCount();\n\t\t\t\tthis._garbageCollectionScheduler.schedule();\n\t\t\t}\n\t\t};\n\t}\n\n\tprivate getOrCreateRule(properties: CssProperties): RefCountedCssRule {\n\t\tconst key = this.computeUniqueKey(properties);\n\t\tlet existingRule = this._rules.get(key);\n\t\tif (!existingRule) {\n\t\t\tconst counter = this._counter++;\n\t\t\texistingRule = new RefCountedCssRule(key, `dyn-rule-${this._instanceId}-${counter}`,\n\t\t\t\tdom.isInShadowDOM(this._editor.getContainerDomNode())\n\t\t\t\t\t? this._editor.getContainerDomNode()\n\t\t\t\t\t: undefined,\n\t\t\t\tproperties\n\t\t\t);\n\t\t\tthis._rules.set(key, existingRule);\n\t\t}\n\t\treturn existingRule;\n\t}\n\n\tprivate computeUniqueKey(properties: CssProperties): string {\n\t\treturn JSON.stringify(properties);\n\t}\n\n\tprivate garbageCollect() {\n\t\tfor (const rule of this._rules.values()) {\n\t\t\tif (!rule.hasReferences()) {\n\t\t\t\tthis._rules.delete(rule.key);\n\t\t\t\trule.dispose();\n\t\t\t}\n\t\t}\n\t}\n}\n\nexport interface ClassNameReference extends IDisposable {\n\tclassName: string;\n}\n\nexport interface CssProperties {\n\tborderRadius?: string;\n\tfontSize?: string;\n\tfontFamily?: string;\n\tunicodeBidi?: string;\n\ttextDecoration?: string;\n\tcolor?: string | ThemeColor;\n\tbackgroundColor?: string | ThemeColor;\n\tverticalAlign?: string;\n\tcursor?: string;\n\tpadding?: string;\n\twidth?: string;\n\tdisplay?: string;\n}\n\nclass RefCountedCssRule {\n\tprivate _referenceCount: number = 0;\n\tprivate _styleElement: HTMLStyleElement | undefined;\n\tprivate readonly _styleElementDisposables: DisposableStore;\n\n\tconstructor(\n\t\tpublic readonly key: string,\n\t\tpublic readonly className: string,\n\t\t_containerElement: HTMLElement | undefined,\n\t\tpublic readonly properties: CssProperties,\n\t) {\n\t\tthis._styleElementDisposables = new DisposableStore();\n\t\tthis._styleElement = dom.createStyleSheet(_containerElement, undefined, this._styleElementDisposables);\n\t\tthis._styleElement.textContent = this.getCssText(this.className, this.properties);\n\t}\n\n\tprivate getCssText(className: string, properties: CssProperties): string {\n\t\tlet str = `.${className} {`;\n\t\tfor (const prop in properties) {\n\t\t\tconst value = (properties as any)[prop] as string | ThemeColor;\n\t\t\tlet cssValue;\n\t\t\tif (typeof value === 'object') {\n\t\t\t\tcssValue = asCssVariable(value.id);\n\t\t\t} else {\n\t\t\t\tcssValue = value;\n\t\t\t}\n\n\t\t\tconst cssPropName = camelToDashes(prop);\n\t\t\tstr += `\\n\\t${cssPropName}: ${cssValue};`;\n\t\t}\n\t\tstr += `\\n}`;\n\t\treturn str;\n\t}\n\n\tpublic dispose(): void {\n\t\tthis._styleElementDisposables.dispose();\n\t\tthis._styleElement = undefined;\n\t}\n\n\tpublic increaseRefCount(): void {\n\t\tthis._referenceCount++;\n\t}\n\n\tpublic decreaseRefCount(): void {\n\t\tthis._referenceCount--;\n\t}\n\n\tpublic hasReferences(): boolean {\n\t\treturn this._referenceCount > 0;\n\t}\n}\n\nfunction camelToDashes(str: string): string {\n\treturn str.replace(/(^[A-Z])/, ([first]) => first.toLowerCase())\n\t\t.replace(/([A-Z])/g, ([letter]) => `-${letter.toLowerCase()}`);\n}\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\nimport 'vs/css!./minimap';\nimport * as dom from 'vs/base/browser/dom';\nimport { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';\nimport { GlobalPointerMoveMonitor } from 'vs/base/browser/globalPointerMoveMonitor';\nimport { CharCode } from 'vs/base/common/charCode';\nimport { IDisposable, Disposable } from 'vs/base/common/lifecycle';\nimport * as platform from 'vs/base/common/platform';\nimport * as strings from 'vs/base/common/strings';\nimport { ILine, RenderedLinesCollection } from 'vs/editor/browser/view/viewLayer';\nimport { PartFingerprint, PartFingerprints, ViewPart } from 'vs/editor/browser/view/viewPart';\nimport { RenderMinimap, EditorOption, MINIMAP_GUTTER_WIDTH, EditorLayoutInfoComputer } from 'vs/editor/common/config/editorOptions';\nimport { Range } from 'vs/editor/common/core/range';\nimport { RGBA8 } from 'vs/editor/common/core/rgba';\nimport { ScrollType } from 'vs/editor/common/editorCommon';\nimport { IEditorConfiguration } from 'vs/editor/common/config/editorConfiguration';\nimport { ColorId } from 'vs/editor/common/encodedTokenAttributes';\nimport { MinimapCharRenderer } from 'vs/editor/browser/viewParts/minimap/minimapCharRenderer';\nimport { Constants } from 'vs/editor/browser/viewParts/minimap/minimapCharSheet';\nimport { MinimapTokensColorTracker } from 'vs/editor/common/viewModel/minimapTokensColorTracker';\nimport { RenderingContext, RestrictedRenderingContext } from 'vs/editor/browser/view/renderingContext';\nimport { ViewContext } from 'vs/editor/common/viewModel/viewContext';\nimport { EditorTheme } from 'vs/editor/common/editorTheme';\nimport * as viewEvents from 'vs/editor/common/viewEvents';\nimport { ViewLineData, ViewModelDecoration } from 'vs/editor/common/viewModel';\nimport { minimapSelection, minimapBackground, minimapForegroundOpacity, editorForeground } from 'vs/platform/theme/common/colorRegistry';\nimport { ModelDecorationMinimapOptions } from 'vs/editor/common/model/textModel';\nimport { Selection } from 'vs/editor/common/core/selection';\nimport { Color } from 'vs/base/common/color';\nimport { GestureEvent, EventType, Gesture } from 'vs/base/browser/touch';\nimport { MinimapCharRendererFactory } from 'vs/editor/browser/viewParts/minimap/minimapCharRendererFactory';\nimport { MinimapPosition, MinimapSectionHeaderStyle, TextModelResolvedOptions } from 'vs/editor/common/model';\nimport { createSingleCallFunction } from 'vs/base/common/functional';\nimport { LRUCache } from 'vs/base/common/map';\nimport { DEFAULT_FONT_FAMILY } from 'vs/base/browser/fonts';\n\n/**\n * The orthogonal distance to the slider at which dragging \"resets\". This implements \"snapping\"\n */\nconst POINTER_DRAG_RESET_DISTANCE = 140;\n\nconst GUTTER_DECORATION_WIDTH = 2;\n\nclass MinimapOptions {\n\n\tpublic readonly renderMinimap: RenderMinimap;\n\tpublic readonly size: 'proportional' | 'fill' | 'fit';\n\tpublic readonly minimapHeightIsEditorHeight: boolean;\n\tpublic readonly scrollBeyondLastLine: boolean;\n\tpublic readonly paddingTop: number;\n\tpublic readonly paddingBottom: number;\n\tpublic readonly showSlider: 'always' | 'mouseover';\n\tpublic readonly autohide: boolean;\n\tpublic readonly pixelRatio: number;\n\tpublic readonly typicalHalfwidthCharacterWidth: number;\n\tpublic readonly lineHeight: number;\n\t/**\n\t * container dom node left position (in CSS px)\n\t */\n\tpublic readonly minimapLeft: number;\n\t/**\n\t * container dom node width (in CSS px)\n\t */\n\tpublic readonly minimapWidth: number;\n\t/**\n\t * container dom node height (in CSS px)\n\t */\n\tpublic readonly minimapHeight: number;\n\t/**\n\t * canvas backing store width (in device px)\n\t */\n\tpublic readonly canvasInnerWidth: number;\n\t/**\n\t * canvas backing store height (in device px)\n\t */\n\tpublic readonly canvasInnerHeight: number;\n\t/**\n\t * canvas width (in CSS px)\n\t */\n\tpublic readonly canvasOuterWidth: number;\n\t/**\n\t * canvas height (in CSS px)\n\t */\n\tpublic readonly canvasOuterHeight: number;\n\n\tpublic readonly isSampling: boolean;\n\tpublic readonly editorHeight: number;\n\tpublic readonly fontScale: number;\n\tpublic readonly minimapLineHeight: number;\n\tpublic readonly minimapCharWidth: number;\n\tpublic readonly sectionHeaderFontFamily: string;\n\tpublic readonly sectionHeaderFontSize: number;\n\tpublic readonly sectionHeaderFontColor: RGBA8;\n\n\tpublic readonly charRenderer: () => MinimapCharRenderer;\n\tpublic readonly defaultBackgroundColor: RGBA8;\n\tpublic readonly backgroundColor: RGBA8;\n\t/**\n\t * foreground alpha: integer in [0-255]\n\t */\n\tpublic readonly foregroundAlpha: number;\n\n\tconstructor(configuration: IEditorConfiguration, theme: EditorTheme, tokensColorTracker: MinimapTokensColorTracker) {\n\t\tconst options = configuration.options;\n\t\tconst pixelRatio = options.get(EditorOption.pixelRatio);\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\n\t\tconst minimapLayout = layoutInfo.minimap;\n\t\tconst fontInfo = options.get(EditorOption.fontInfo);\n\t\tconst minimapOpts = options.get(EditorOption.minimap);\n\n\t\tthis.renderMinimap = minimapLayout.renderMinimap;\n\t\tthis.size = minimapOpts.size;\n\t\tthis.minimapHeightIsEditorHeight = minimapLayout.minimapHeightIsEditorHeight;\n\t\tthis.scrollBeyondLastLine = options.get(EditorOption.scrollBeyondLastLine);\n\t\tthis.paddingTop = options.get(EditorOption.padding).top;\n\t\tthis.paddingBottom = options.get(EditorOption.padding).bottom;\n\t\tthis.showSlider = minimapOpts.showSlider;\n\t\tthis.autohide = minimapOpts.autohide;\n\t\tthis.pixelRatio = pixelRatio;\n\t\tthis.typicalHalfwidthCharacterWidth = fontInfo.typicalHalfwidthCharacterWidth;\n\t\tthis.lineHeight = options.get(EditorOption.lineHeight);\n\t\tthis.minimapLeft = minimapLayout.minimapLeft;\n\t\tthis.minimapWidth = minimapLayout.minimapWidth;\n\t\tthis.minimapHeight = layoutInfo.height;\n\n\t\tthis.canvasInnerWidth = minimapLayout.minimapCanvasInnerWidth;\n\t\tthis.canvasInnerHeight = minimapLayout.minimapCanvasInnerHeight;\n\t\tthis.canvasOuterWidth = minimapLayout.minimapCanvasOuterWidth;\n\t\tthis.canvasOuterHeight = minimapLayout.minimapCanvasOuterHeight;\n\n\t\tthis.isSampling = minimapLayout.minimapIsSampling;\n\t\tthis.editorHeight = layoutInfo.height;\n\t\tthis.fontScale = minimapLayout.minimapScale;\n\t\tthis.minimapLineHeight = minimapLayout.minimapLineHeight;\n\t\tthis.minimapCharWidth = Constants.BASE_CHAR_WIDTH * this.fontScale;\n\t\tthis.sectionHeaderFontFamily = DEFAULT_FONT_FAMILY;\n\t\tthis.sectionHeaderFontSize = minimapOpts.sectionHeaderFontSize * pixelRatio;\n\t\tthis.sectionHeaderFontColor = MinimapOptions._getSectionHeaderColor(theme, tokensColorTracker.getColor(ColorId.DefaultForeground));\n\n\t\tthis.charRenderer = createSingleCallFunction(() => MinimapCharRendererFactory.create(this.fontScale, fontInfo.fontFamily));\n\t\tthis.defaultBackgroundColor = tokensColorTracker.getColor(ColorId.DefaultBackground);\n\t\tthis.backgroundColor = MinimapOptions._getMinimapBackground(theme, this.defaultBackgroundColor);\n\t\tthis.foregroundAlpha = MinimapOptions._getMinimapForegroundOpacity(theme);\n\t}\n\n\tprivate static _getMinimapBackground(theme: EditorTheme, defaultBackgroundColor: RGBA8): RGBA8 {\n\t\tconst themeColor = theme.getColor(minimapBackground);\n\t\tif (themeColor) {\n\t\t\treturn new RGBA8(themeColor.rgba.r, themeColor.rgba.g, themeColor.rgba.b, Math.round(255 * themeColor.rgba.a));\n\t\t}\n\t\treturn defaultBackgroundColor;\n\t}\n\n\tprivate static _getMinimapForegroundOpacity(theme: EditorTheme): number {\n\t\tconst themeColor = theme.getColor(minimapForegroundOpacity);\n\t\tif (themeColor) {\n\t\t\treturn RGBA8._clamp(Math.round(255 * themeColor.rgba.a));\n\t\t}\n\t\treturn 255;\n\t}\n\n\tprivate static _getSectionHeaderColor(theme: EditorTheme, defaultForegroundColor: RGBA8): RGBA8 {\n\t\tconst themeColor = theme.getColor(editorForeground);\n\t\tif (themeColor) {\n\t\t\treturn new RGBA8(themeColor.rgba.r, themeColor.rgba.g, themeColor.rgba.b, Math.round(255 * themeColor.rgba.a));\n\t\t}\n\t\treturn defaultForegroundColor;\n\t}\n\n\tpublic equals(other: MinimapOptions): boolean {\n\t\treturn (this.renderMinimap === other.renderMinimap\n\t\t\t&& this.size === other.size\n\t\t\t&& this.minimapHeightIsEditorHeight === other.minimapHeightIsEditorHeight\n\t\t\t&& this.scrollBeyondLastLine === other.scrollBeyondLastLine\n\t\t\t&& this.paddingTop === other.paddingTop\n\t\t\t&& this.paddingBottom === other.paddingBottom\n\t\t\t&& this.showSlider === other.showSlider\n\t\t\t&& this.autohide === other.autohide\n\t\t\t&& this.pixelRatio === other.pixelRatio\n\t\t\t&& this.typicalHalfwidthCharacterWidth === other.typicalHalfwidthCharacterWidth\n\t\t\t&& this.lineHeight === other.lineHeight\n\t\t\t&& this.minimapLeft === other.minimapLeft\n\t\t\t&& this.minimapWidth === other.minimapWidth\n\t\t\t&& this.minimapHeight === other.minimapHeight\n\t\t\t&& this.canvasInnerWidth === other.canvasInnerWidth\n\t\t\t&& this.canvasInnerHeight === other.canvasInnerHeight\n\t\t\t&& this.canvasOuterWidth === other.canvasOuterWidth\n\t\t\t&& this.canvasOuterHeight === other.canvasOuterHeight\n\t\t\t&& this.isSampling === other.isSampling\n\t\t\t&& this.editorHeight === other.editorHeight\n\t\t\t&& this.fontScale === other.fontScale\n\t\t\t&& this.minimapLineHeight === other.minimapLineHeight\n\t\t\t&& this.minimapCharWidth === other.minimapCharWidth\n\t\t\t&& this.sectionHeaderFontSize === other.sectionHeaderFontSize\n\t\t\t&& this.defaultBackgroundColor && this.defaultBackgroundColor.equals(other.defaultBackgroundColor)\n\t\t\t&& this.backgroundColor && this.backgroundColor.equals(other.backgroundColor)\n\t\t\t&& this.foregroundAlpha === other.foregroundAlpha\n\t\t);\n\t}\n}\n\nclass MinimapLayout {\n\n\tconstructor(\n\t\t/**\n\t\t * The given editor scrollTop (input).\n\t\t */\n\t\tpublic readonly scrollTop: number,\n\t\t/**\n\t\t * The given editor scrollHeight (input).\n\t\t */\n\t\tpublic readonly scrollHeight: number,\n\t\tpublic readonly sliderNeeded: boolean,\n\t\tprivate readonly _computedSliderRatio: number,\n\t\t/**\n\t\t * slider dom node top (in CSS px)\n\t\t */\n\t\tpublic readonly sliderTop: number,\n\t\t/**\n\t\t * slider dom node height (in CSS px)\n\t\t */\n\t\tpublic readonly sliderHeight: number,\n\t\t/**\n\t\t * empty lines to reserve at the top of the minimap.\n\t\t */\n\t\tpublic readonly topPaddingLineCount: number,\n\t\t/**\n\t\t * minimap render start line number.\n\t\t */\n\t\tpublic readonly startLineNumber: number,\n\t\t/**\n\t\t * minimap render end line number.\n\t\t */\n\t\tpublic readonly endLineNumber: number\n\t) { }\n\n\t/**\n\t * Compute a desired `scrollPosition` such that the slider moves by `delta`.\n\t */\n\tpublic getDesiredScrollTopFromDelta(delta: number): number {\n\t\treturn Math.round(this.scrollTop + delta / this._computedSliderRatio);\n\t}\n\n\tpublic getDesiredScrollTopFromTouchLocation(pageY: number): number {\n\t\treturn Math.round((pageY - this.sliderHeight / 2) / this._computedSliderRatio);\n\t}\n\n\t/**\n\t * Intersect a line range with `this.startLineNumber` and `this.endLineNumber`.\n\t */\n\tpublic intersectWithViewport(range: Range): [number, number] | null {\n\t\tconst startLineNumber = Math.max(this.startLineNumber, range.startLineNumber);\n\t\tconst endLineNumber = Math.min(this.endLineNumber, range.endLineNumber);\n\t\tif (startLineNumber > endLineNumber) {\n\t\t\t// entirely outside minimap's viewport\n\t\t\treturn null;\n\t\t}\n\t\treturn [startLineNumber, endLineNumber];\n\t}\n\n\t/**\n\t * Get the inner minimap y coordinate for a line number.\n\t */\n\tpublic getYForLineNumber(lineNumber: number, minimapLineHeight: number): number {\n\t\treturn + (lineNumber - this.startLineNumber + this.topPaddingLineCount) * minimapLineHeight;\n\t}\n\n\tpublic static create(\n\t\toptions: MinimapOptions,\n\t\tviewportStartLineNumber: number,\n\t\tviewportEndLineNumber: number,\n\t\tviewportStartLineNumberVerticalOffset: number,\n\t\tviewportHeight: number,\n\t\tviewportContainsWhitespaceGaps: boolean,\n\t\tlineCount: number,\n\t\trealLineCount: number,\n\t\tscrollTop: number,\n\t\tscrollHeight: number,\n\t\tpreviousLayout: MinimapLayout | null\n\t): MinimapLayout {\n\t\tconst pixelRatio = options.pixelRatio;\n\t\tconst minimapLineHeight = options.minimapLineHeight;\n\t\tconst minimapLinesFitting = Math.floor(options.canvasInnerHeight / minimapLineHeight);\n\t\tconst lineHeight = options.lineHeight;\n\n\t\tif (options.minimapHeightIsEditorHeight) {\n\t\t\tlet logicalScrollHeight = (\n\t\t\t\trealLineCount * options.lineHeight\n\t\t\t\t+ options.paddingTop\n\t\t\t\t+ options.paddingBottom\n\t\t\t);\n\t\t\tif (options.scrollBeyondLastLine) {\n\t\t\t\tlogicalScrollHeight += Math.max(0, viewportHeight - options.lineHeight - options.paddingBottom);\n\t\t\t}\n\t\t\tconst sliderHeight = Math.max(1, Math.floor(viewportHeight * viewportHeight / logicalScrollHeight));\n\t\t\tconst maxMinimapSliderTop = Math.max(0, options.minimapHeight - sliderHeight);\n\t\t\t// The slider can move from 0 to `maxMinimapSliderTop`\n\t\t\t// in the same way `scrollTop` can move from 0 to `scrollHeight` - `viewportHeight`.\n\t\t\tconst computedSliderRatio = (maxMinimapSliderTop) / (scrollHeight - viewportHeight);\n\t\t\tconst sliderTop = (scrollTop * computedSliderRatio);\n\t\t\tconst sliderNeeded = (maxMinimapSliderTop > 0);\n\t\t\tconst maxLinesFitting = Math.floor(options.canvasInnerHeight / options.minimapLineHeight);\n\t\t\tconst topPaddingLineCount = Math.floor(options.paddingTop / options.lineHeight);\n\t\t\treturn new MinimapLayout(scrollTop, scrollHeight, sliderNeeded, computedSliderRatio, sliderTop, sliderHeight, topPaddingLineCount, 1, Math.min(lineCount, maxLinesFitting));\n\t\t}\n\n\t\t// The visible line count in a viewport can change due to a number of reasons:\n\t\t// a) with the same viewport width, different scroll positions can result in partial lines being visible:\n\t\t// e.g. for a line height of 20, and a viewport height of 600\n\t\t// * scrollTop = 0 => visible lines are [1, 30]\n\t\t// * scrollTop = 10 => visible lines are [1, 31] (with lines 1 and 31 partially visible)\n\t\t// * scrollTop = 20 => visible lines are [2, 31]\n\t\t// b) whitespace gaps might make their way in the viewport (which results in a decrease in the visible line count)\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)\n\n\t\t// We must first establish a desirable slider height.\n\t\tlet sliderHeight: number;\n\t\tif (viewportContainsWhitespaceGaps && viewportEndLineNumber !== lineCount) {\n\t\t\t// case b) from above: there are whitespace gaps in the viewport.\n\t\t\t// In this case, the height of the slider directly reflects the visible line count.\n\t\t\tconst viewportLineCount = viewportEndLineNumber - viewportStartLineNumber + 1;\n\t\t\tsliderHeight = Math.floor(viewportLineCount * minimapLineHeight / pixelRatio);\n\t\t} else {\n\t\t\t// The slider has a stable height\n\t\t\tconst expectedViewportLineCount = viewportHeight / lineHeight;\n\t\t\tsliderHeight = Math.floor(expectedViewportLineCount * minimapLineHeight / pixelRatio);\n\t\t}\n\n\t\tconst extraLinesAtTheTop = Math.floor(options.paddingTop / lineHeight);\n\t\tlet extraLinesAtTheBottom = Math.floor(options.paddingBottom / lineHeight);\n\t\tif (options.scrollBeyondLastLine) {\n\t\t\tconst expectedViewportLineCount = viewportHeight / lineHeight;\n\t\t\textraLinesAtTheBottom = Math.max(extraLinesAtTheBottom, expectedViewportLineCount - 1);\n\t\t}\n\n\t\tlet maxMinimapSliderTop: number;\n\t\tif (extraLinesAtTheBottom > 0) {\n\t\t\tconst expectedViewportLineCount = viewportHeight / lineHeight;\n\t\t\t// The minimap slider, when dragged all the way down, will contain the last line at its top\n\t\t\tmaxMinimapSliderTop = (extraLinesAtTheTop + lineCount + extraLinesAtTheBottom - expectedViewportLineCount - 1) * minimapLineHeight / pixelRatio;\n\t\t} else {\n\t\t\t// The minimap slider, when dragged all the way down, will contain the last line at its bottom\n\t\t\tmaxMinimapSliderTop = Math.max(0, (extraLinesAtTheTop + lineCount) * minimapLineHeight / pixelRatio - sliderHeight);\n\t\t}\n\t\tmaxMinimapSliderTop = Math.min(options.minimapHeight - sliderHeight, maxMinimapSliderTop);\n\n\t\t// The slider can move from 0 to `maxMinimapSliderTop`\n\t\t// in the same way `scrollTop` can move from 0 to `scrollHeight` - `viewportHeight`.\n\t\tconst computedSliderRatio = (maxMinimapSliderTop) / (scrollHeight - viewportHeight);\n\t\tconst sliderTop = (scrollTop * computedSliderRatio);\n\n\t\tif (minimapLinesFitting >= extraLinesAtTheTop + lineCount + extraLinesAtTheBottom) {\n\t\t\t// All lines fit in the minimap\n\t\t\tconst sliderNeeded = (maxMinimapSliderTop > 0);\n\t\t\treturn new MinimapLayout(scrollTop, scrollHeight, sliderNeeded, computedSliderRatio, sliderTop, sliderHeight, extraLinesAtTheTop, 1, lineCount);\n\t\t} else {\n\t\t\tlet consideringStartLineNumber: number;\n\t\t\tif (viewportStartLineNumber > 1) {\n\t\t\t\tconsideringStartLineNumber = viewportStartLineNumber + extraLinesAtTheTop;\n\t\t\t} else {\n\t\t\t\tconsideringStartLineNumber = Math.max(1, scrollTop / lineHeight);\n\t\t\t}\n\n\t\t\tlet topPaddingLineCount: number;\n\t\t\tlet startLineNumber = Math.max(1, Math.floor(consideringStartLineNumber - sliderTop * pixelRatio / minimapLineHeight));\n\t\t\tif (startLineNumber < extraLinesAtTheTop) {\n\t\t\t\ttopPaddingLineCount = extraLinesAtTheTop - startLineNumber + 1;\n\t\t\t\tstartLineNumber = 1;\n\t\t\t} else {\n\t\t\t\ttopPaddingLineCount = 0;\n\t\t\t\tstartLineNumber = Math.max(1, startLineNumber - extraLinesAtTheTop);\n\t\t\t}\n\n\t\t\t// Avoid flickering caused by a partial viewport start line\n\t\t\t// by being consistent w.r.t. the previous layout decision\n\t\t\tif (previousLayout && previousLayout.scrollHeight === scrollHeight) {\n\t\t\t\tif (previousLayout.scrollTop > scrollTop) {\n\t\t\t\t\t// Scrolling up => never increase `startLineNumber`\n\t\t\t\t\tstartLineNumber = Math.min(startLineNumber, previousLayout.startLineNumber);\n\t\t\t\t\ttopPaddingLineCount = Math.max(topPaddingLineCount, previousLayout.topPaddingLineCount);\n\t\t\t\t}\n\t\t\t\tif (previousLayout.scrollTop < scrollTop) {\n\t\t\t\t\t// Scrolling down => never decrease `startLineNumber`\n\t\t\t\t\tstartLineNumber = Math.max(startLineNumber, previousLayout.startLineNumber);\n\t\t\t\t\ttopPaddingLineCount = Math.min(topPaddingLineCount, previousLayout.topPaddingLineCount);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst endLineNumber = Math.min(lineCount, startLineNumber - topPaddingLineCount + minimapLinesFitting - 1);\n\t\t\tconst partialLine = (scrollTop - viewportStartLineNumberVerticalOffset) / lineHeight;\n\n\t\t\tlet sliderTopAligned: number;\n\t\t\tif (scrollTop >= options.paddingTop) {\n\t\t\t\tsliderTopAligned = (viewportStartLineNumber - startLineNumber + topPaddingLineCount + partialLine) * minimapLineHeight / pixelRatio;\n\t\t\t} else {\n\t\t\t\tsliderTopAligned = (scrollTop / options.paddingTop) * (topPaddingLineCount + partialLine) * minimapLineHeight / pixelRatio;\n\t\t\t}\n\n\t\t\treturn new MinimapLayout(scrollTop, scrollHeight, true, computedSliderRatio, sliderTopAligned, sliderHeight, topPaddingLineCount, startLineNumber, endLineNumber);\n\t\t}\n\t}\n}\n\nclass MinimapLine implements ILine {\n\n\tpublic static readonly INVALID = new MinimapLine(-1);\n\n\tdy: number;\n\n\tconstructor(dy: number) {\n\t\tthis.dy = dy;\n\t}\n\n\tpublic onContentChanged(): void {\n\t\tthis.dy = -1;\n\t}\n\n\tpublic onTokensChanged(): void {\n\t\tthis.dy = -1;\n\t}\n}\n\nclass RenderData {\n\t/**\n\t * last rendered layout.\n\t */\n\tpublic readonly renderedLayout: MinimapLayout;\n\tprivate readonly _imageData: ImageData;\n\tprivate readonly _renderedLines: RenderedLinesCollection;\n\n\tconstructor(\n\t\trenderedLayout: MinimapLayout,\n\t\timageData: ImageData,\n\t\tlines: MinimapLine[]\n\t) {\n\t\tthis.renderedLayout = renderedLayout;\n\t\tthis._imageData = imageData;\n\t\tthis._renderedLines = new RenderedLinesCollection(\n\t\t\t() => MinimapLine.INVALID\n\t\t);\n\t\tthis._renderedLines._set(renderedLayout.startLineNumber, lines);\n\t}\n\n\t/**\n\t * Check if the current RenderData matches accurately the new desired layout and no painting is needed.\n\t */\n\tpublic linesEquals(layout: MinimapLayout): boolean {\n\t\tif (!this.scrollEquals(layout)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst tmp = this._renderedLines._get();\n\t\tconst lines = tmp.lines;\n\t\tfor (let i = 0, len = lines.length; i < len; i++) {\n\t\t\tif (lines[i].dy === -1) {\n\t\t\t\t// This line is invalid\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Check if the current RenderData matches the new layout's scroll position\n\t */\n\tpublic scrollEquals(layout: MinimapLayout): boolean {\n\t\treturn this.renderedLayout.startLineNumber === layout.startLineNumber\n\t\t\t&& this.renderedLayout.endLineNumber === layout.endLineNumber;\n\t}\n\n\t_get(): { imageData: ImageData; rendLineNumberStart: number; lines: MinimapLine[] } {\n\t\tconst tmp = this._renderedLines._get();\n\t\treturn {\n\t\t\timageData: this._imageData,\n\t\t\trendLineNumberStart: tmp.rendLineNumberStart,\n\t\t\tlines: tmp.lines\n\t\t};\n\t}\n\n\tpublic onLinesChanged(changeFromLineNumber: number, changeCount: number): boolean {\n\t\treturn this._renderedLines.onLinesChanged(changeFromLineNumber, changeCount);\n\t}\n\tpublic onLinesDeleted(deleteFromLineNumber: number, deleteToLineNumber: number): void {\n\t\tthis._renderedLines.onLinesDeleted(deleteFromLineNumber, deleteToLineNumber);\n\t}\n\tpublic onLinesInserted(insertFromLineNumber: number, insertToLineNumber: number): void {\n\t\tthis._renderedLines.onLinesInserted(insertFromLineNumber, insertToLineNumber);\n\t}\n\tpublic onTokensChanged(ranges: { fromLineNumber: number; toLineNumber: number }[]): boolean {\n\t\treturn this._renderedLines.onTokensChanged(ranges);\n\t}\n}\n\n/**\n * Some sort of double buffering.\n *\n * Keeps two buffers around that will be rotated for painting.\n * Always gives a buffer that is filled with the background color.\n */\nclass MinimapBuffers {\n\n\tprivate readonly _backgroundFillData: Uint8ClampedArray;\n\tprivate readonly _buffers: [ImageData, ImageData];\n\tprivate _lastUsedBuffer: number;\n\n\tconstructor(ctx: CanvasRenderingContext2D, WIDTH: number, HEIGHT: number, background: RGBA8) {\n\t\tthis._backgroundFillData = MinimapBuffers._createBackgroundFillData(WIDTH, HEIGHT, background);\n\t\tthis._buffers = [\n\t\t\tctx.createImageData(WIDTH, HEIGHT),\n\t\t\tctx.createImageData(WIDTH, HEIGHT)\n\t\t];\n\t\tthis._lastUsedBuffer = 0;\n\t}\n\n\tpublic getBuffer(): ImageData {\n\t\t// rotate buffers\n\t\tthis._lastUsedBuffer = 1 - this._lastUsedBuffer;\n\t\tconst result = this._buffers[this._lastUsedBuffer];\n\n\t\t// fill with background color\n\t\tresult.data.set(this._backgroundFillData);\n\n\t\treturn result;\n\t}\n\n\tprivate static _createBackgroundFillData(WIDTH: number, HEIGHT: number, background: RGBA8): Uint8ClampedArray {\n\t\tconst backgroundR = background.r;\n\t\tconst backgroundG = background.g;\n\t\tconst backgroundB = background.b;\n\t\tconst backgroundA = background.a;\n\n\t\tconst result = new Uint8ClampedArray(WIDTH * HEIGHT * 4);\n\t\tlet offset = 0;\n\t\tfor (let i = 0; i < HEIGHT; i++) {\n\t\t\tfor (let j = 0; j < WIDTH; j++) {\n\t\t\t\tresult[offset] = backgroundR;\n\t\t\t\tresult[offset + 1] = backgroundG;\n\t\t\t\tresult[offset + 2] = backgroundB;\n\t\t\t\tresult[offset + 3] = backgroundA;\n\t\t\t\toffset += 4;\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n}\n\nexport interface IMinimapModel {\n\treadonly tokensColorTracker: MinimapTokensColorTracker;\n\treadonly options: MinimapOptions;\n\n\tgetLineCount(): number;\n\tgetRealLineCount(): number;\n\tgetLineContent(lineNumber: number): string;\n\tgetLineMaxColumn(lineNumber: number): number;\n\tgetMinimapLinesRenderingData(startLineNumber: number, endLineNumber: number, needed: boolean[]): (ViewLineData | null)[];\n\tgetSelections(): Selection[];\n\tgetMinimapDecorationsInViewport(startLineNumber: number, endLineNumber: number): ViewModelDecoration[];\n\tgetSectionHeaderDecorationsInViewport(startLineNumber: number, endLineNumber: number): ViewModelDecoration[];\n\tgetSectionHeaderText(decoration: ViewModelDecoration, fitWidth: (s: string) => string): string | null;\n\tgetOptions(): TextModelResolvedOptions;\n\trevealLineNumber(lineNumber: number): void;\n\tsetScrollTop(scrollTop: number): void;\n}\n\ninterface IMinimapRenderingContext {\n\treadonly viewportContainsWhitespaceGaps: boolean;\n\n\treadonly scrollWidth: number;\n\treadonly scrollHeight: number;\n\n\treadonly viewportStartLineNumber: number;\n\treadonly viewportEndLineNumber: number;\n\treadonly viewportStartLineNumberVerticalOffset: number;\n\n\treadonly scrollTop: number;\n\treadonly scrollLeft: number;\n\n\treadonly viewportWidth: number;\n\treadonly viewportHeight: number;\n}\n\ninterface SamplingStateLinesDeletedEvent {\n\ttype: 'deleted';\n\t_oldIndex: number;\n\tdeleteFromLineNumber: number;\n\tdeleteToLineNumber: number;\n}\n\ninterface SamplingStateLinesInsertedEvent {\n\ttype: 'inserted';\n\t_i: number;\n\tinsertFromLineNumber: number;\n\tinsertToLineNumber: number;\n}\n\ninterface SamplingStateFlushEvent {\n\ttype: 'flush';\n}\n\ntype SamplingStateEvent = SamplingStateLinesInsertedEvent | SamplingStateLinesDeletedEvent | SamplingStateFlushEvent;\n\nclass MinimapSamplingState {\n\n\tpublic static compute(options: MinimapOptions, viewLineCount: number, oldSamplingState: MinimapSamplingState | null): [MinimapSamplingState | null, SamplingStateEvent[]] {\n\t\tif (options.renderMinimap === RenderMinimap.None || !options.isSampling) {\n\t\t\treturn [null, []];\n\t\t}\n\n\t\t// ratio is intentionally not part of the layout to avoid the layout changing all the time\n\t\t// so we need to recompute it again...\n\t\tconst { minimapLineCount } = EditorLayoutInfoComputer.computeContainedMinimapLineCount({\n\t\t\tviewLineCount: viewLineCount,\n\t\t\tscrollBeyondLastLine: options.scrollBeyondLastLine,\n\t\t\tpaddingTop: options.paddingTop,\n\t\t\tpaddingBottom: options.paddingBottom,\n\t\t\theight: options.editorHeight,\n\t\t\tlineHeight: options.lineHeight,\n\t\t\tpixelRatio: options.pixelRatio\n\t\t});\n\t\tconst ratio = viewLineCount / minimapLineCount;\n\t\tconst halfRatio = ratio / 2;\n\n\t\tif (!oldSamplingState || oldSamplingState.minimapLines.length === 0) {\n\t\t\tconst result: number[] = [];\n\t\t\tresult[0] = 1;\n\t\t\tif (minimapLineCount > 1) {\n\t\t\t\tfor (let i = 0, lastIndex = minimapLineCount - 1; i < lastIndex; i++) {\n\t\t\t\t\tresult[i] = Math.round(i * ratio + halfRatio);\n\t\t\t\t}\n\t\t\t\tresult[minimapLineCount - 1] = viewLineCount;\n\t\t\t}\n\t\t\treturn [new MinimapSamplingState(ratio, result), []];\n\t\t}\n\n\t\tconst oldMinimapLines = oldSamplingState.minimapLines;\n\t\tconst oldLength = oldMinimapLines.length;\n\t\tconst result: number[] = [];\n\t\tlet oldIndex = 0;\n\t\tlet oldDeltaLineCount = 0;\n\t\tlet minViewLineNumber = 1;\n\t\tconst MAX_EVENT_COUNT = 10; // generate at most 10 events, if there are more than 10 changes, just flush all previous data\n\t\tlet events: SamplingStateEvent[] = [];\n\t\tlet lastEvent: SamplingStateEvent | null = null;\n\t\tfor (let i = 0; i < minimapLineCount; i++) {\n\t\t\tconst fromViewLineNumber = Math.max(minViewLineNumber, Math.round(i * ratio));\n\t\t\tconst toViewLineNumber = Math.max(fromViewLineNumber, Math.round((i + 1) * ratio));\n\n\t\t\twhile (oldIndex < oldLength && oldMinimapLines[oldIndex] < fromViewLineNumber) {\n\t\t\t\tif (events.length < MAX_EVENT_COUNT) {\n\t\t\t\t\tconst oldMinimapLineNumber = oldIndex + 1 + oldDeltaLineCount;\n\t\t\t\t\tif (lastEvent && lastEvent.type === 'deleted' && lastEvent._oldIndex === oldIndex - 1) {\n\t\t\t\t\t\tlastEvent.deleteToLineNumber++;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlastEvent = { type: 'deleted', _oldIndex: oldIndex, deleteFromLineNumber: oldMinimapLineNumber, deleteToLineNumber: oldMinimapLineNumber };\n\t\t\t\t\t\tevents.push(lastEvent);\n\t\t\t\t\t}\n\t\t\t\t\toldDeltaLineCount--;\n\t\t\t\t}\n\t\t\t\toldIndex++;\n\t\t\t}\n\n\t\t\tlet selectedViewLineNumber: number;\n\t\t\tif (oldIndex < oldLength && oldMinimapLines[oldIndex] <= toViewLineNumber) {\n\t\t\t\t// reuse the old sampled line\n\t\t\t\tselectedViewLineNumber = oldMinimapLines[oldIndex];\n\t\t\t\toldIndex++;\n\t\t\t} else {\n\t\t\t\tif (i === 0) {\n\t\t\t\t\tselectedViewLineNumber = 1;\n\t\t\t\t} else if (i + 1 === minimapLineCount) {\n\t\t\t\t\tselectedViewLineNumber = viewLineCount;\n\t\t\t\t} else {\n\t\t\t\t\tselectedViewLineNumber = Math.round(i * ratio + halfRatio);\n\t\t\t\t}\n\t\t\t\tif (events.length < MAX_EVENT_COUNT) {\n\t\t\t\t\tconst oldMinimapLineNumber = oldIndex + 1 + oldDeltaLineCount;\n\t\t\t\t\tif (lastEvent && lastEvent.type === 'inserted' && lastEvent._i === i - 1) {\n\t\t\t\t\t\tlastEvent.insertToLineNumber++;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlastEvent = { type: 'inserted', _i: i, insertFromLineNumber: oldMinimapLineNumber, insertToLineNumber: oldMinimapLineNumber };\n\t\t\t\t\t\tevents.push(lastEvent);\n\t\t\t\t\t}\n\t\t\t\t\toldDeltaLineCount++;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tresult[i] = selectedViewLineNumber;\n\t\t\tminViewLineNumber = selectedViewLineNumber;\n\t\t}\n\n\t\tif (events.length < MAX_EVENT_COUNT) {\n\t\t\twhile (oldIndex < oldLength) {\n\t\t\t\tconst oldMinimapLineNumber = oldIndex + 1 + oldDeltaLineCount;\n\t\t\t\tif (lastEvent && lastEvent.type === 'deleted' && lastEvent._oldIndex === oldIndex - 1) {\n\t\t\t\t\tlastEvent.deleteToLineNumber++;\n\t\t\t\t} else {\n\t\t\t\t\tlastEvent = { type: 'deleted', _oldIndex: oldIndex, deleteFromLineNumber: oldMinimapLineNumber, deleteToLineNumber: oldMinimapLineNumber };\n\t\t\t\t\tevents.push(lastEvent);\n\t\t\t\t}\n\t\t\t\toldDeltaLineCount--;\n\t\t\t\toldIndex++;\n\t\t\t}\n\t\t} else {\n\t\t\t// too many events, just give up\n\t\t\tevents = [{ type: 'flush' }];\n\t\t}\n\n\t\treturn [new MinimapSamplingState(ratio, result), events];\n\t}\n\n\tconstructor(\n\t\tpublic readonly samplingRatio: number,\n\t\tpublic readonly minimapLines: number[]\t// a map of 0-based minimap line indexes to 1-based view line numbers\n\t) {\n\t}\n\n\tpublic modelLineToMinimapLine(lineNumber: number): number {\n\t\treturn Math.min(this.minimapLines.length, Math.max(1, Math.round(lineNumber / this.samplingRatio)));\n\t}\n\n\t/**\n\t * Will return null if the model line ranges are not intersecting with a sampled model line.\n\t */\n\tpublic modelLineRangeToMinimapLineRange(fromLineNumber: number, toLineNumber: number): [number, number] | null {\n\t\tlet fromLineIndex = this.modelLineToMinimapLine(fromLineNumber) - 1;\n\t\twhile (fromLineIndex > 0 && this.minimapLines[fromLineIndex - 1] >= fromLineNumber) {\n\t\t\tfromLineIndex--;\n\t\t}\n\t\tlet toLineIndex = this.modelLineToMinimapLine(toLineNumber) - 1;\n\t\twhile (toLineIndex + 1 < this.minimapLines.length && this.minimapLines[toLineIndex + 1] <= toLineNumber) {\n\t\t\ttoLineIndex++;\n\t\t}\n\t\tif (fromLineIndex === toLineIndex) {\n\t\t\tconst sampledLineNumber = this.minimapLines[fromLineIndex];\n\t\t\tif (sampledLineNumber < fromLineNumber || sampledLineNumber > toLineNumber) {\n\t\t\t\t// This line is not part of the sampled lines ==> nothing to do\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}\n\t\treturn [fromLineIndex + 1, toLineIndex + 1];\n\t}\n\n\t/**\n\t * Will always return a range, even if it is not intersecting with a sampled model line.\n\t */\n\tpublic decorationLineRangeToMinimapLineRange(startLineNumber: number, endLineNumber: number): [number, number] {\n\t\tlet minimapLineStart = this.modelLineToMinimapLine(startLineNumber);\n\t\tlet minimapLineEnd = this.modelLineToMinimapLine(endLineNumber);\n\t\tif (startLineNumber !== endLineNumber && minimapLineEnd === minimapLineStart) {\n\t\t\tif (minimapLineEnd === this.minimapLines.length) {\n\t\t\t\tif (minimapLineStart > 1) {\n\t\t\t\t\tminimapLineStart--;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tminimapLineEnd++;\n\t\t\t}\n\t\t}\n\t\treturn [minimapLineStart, minimapLineEnd];\n\t}\n\n\tpublic onLinesDeleted(e: viewEvents.ViewLinesDeletedEvent): [number, number] {\n\t\t// have the mapping be sticky\n\t\tconst deletedLineCount = e.toLineNumber - e.fromLineNumber + 1;\n\t\tlet changeStartIndex = this.minimapLines.length;\n\t\tlet changeEndIndex = 0;\n\t\tfor (let i = this.minimapLines.length - 1; i >= 0; i--) {\n\t\t\tif (this.minimapLines[i] < e.fromLineNumber) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (this.minimapLines[i] <= e.toLineNumber) {\n\t\t\t\t// this line got deleted => move to previous available\n\t\t\t\tthis.minimapLines[i] = Math.max(1, e.fromLineNumber - 1);\n\t\t\t\tchangeStartIndex = Math.min(changeStartIndex, i);\n\t\t\t\tchangeEndIndex = Math.max(changeEndIndex, i);\n\t\t\t} else {\n\t\t\t\tthis.minimapLines[i] -= deletedLineCount;\n\t\t\t}\n\t\t}\n\t\treturn [changeStartIndex, changeEndIndex];\n\t}\n\n\tpublic onLinesInserted(e: viewEvents.ViewLinesInsertedEvent): void {\n\t\t// have the mapping be sticky\n\t\tconst insertedLineCount = e.toLineNumber - e.fromLineNumber + 1;\n\t\tfor (let i = this.minimapLines.length - 1; i >= 0; i--) {\n\t\t\tif (this.minimapLines[i] < e.fromLineNumber) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tthis.minimapLines[i] += insertedLineCount;\n\t\t}\n\t}\n}\n\nexport class Minimap extends ViewPart implements IMinimapModel {\n\n\tpublic readonly tokensColorTracker: MinimapTokensColorTracker;\n\n\tprivate _selections: Selection[];\n\tprivate _minimapSelections: Selection[] | null;\n\n\tpublic options: MinimapOptions;\n\n\tprivate _samplingState: MinimapSamplingState | null;\n\tprivate _shouldCheckSampling: boolean;\n\n\tprivate _sectionHeaderCache = new LRUCache(10, 1.5);\n\n\tprivate _actual: InnerMinimap;\n\n\tconstructor(context: ViewContext) {\n\t\tsuper(context);\n\n\t\tthis.tokensColorTracker = MinimapTokensColorTracker.getInstance();\n\n\t\tthis._selections = [];\n\t\tthis._minimapSelections = null;\n\n\t\tthis.options = new MinimapOptions(this._context.configuration, this._context.theme, this.tokensColorTracker);\n\t\tconst [samplingState,] = MinimapSamplingState.compute(this.options, this._context.viewModel.getLineCount(), null);\n\t\tthis._samplingState = samplingState;\n\t\tthis._shouldCheckSampling = false;\n\n\t\tthis._actual = new InnerMinimap(context.theme, this);\n\t}\n\n\tpublic override dispose(): void {\n\t\tthis._actual.dispose();\n\t\tsuper.dispose();\n\t}\n\n\tpublic getDomNode(): FastDomNode {\n\t\treturn this._actual.getDomNode();\n\t}\n\n\tprivate _onOptionsMaybeChanged(): boolean {\n\t\tconst opts = new MinimapOptions(this._context.configuration, this._context.theme, this.tokensColorTracker);\n\t\tif (this.options.equals(opts)) {\n\t\t\treturn false;\n\t\t}\n\t\tthis.options = opts;\n\t\tthis._recreateLineSampling();\n\t\tthis._actual.onDidChangeOptions();\n\t\treturn true;\n\t}\n\n\t// ---- begin view event handlers\n\n\tpublic override onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {\n\t\treturn this._onOptionsMaybeChanged();\n\t}\n\tpublic override onCursorStateChanged(e: viewEvents.ViewCursorStateChangedEvent): boolean {\n\t\tthis._selections = e.selections;\n\t\tthis._minimapSelections = null;\n\t\treturn this._actual.onSelectionChanged();\n\t}\n\tpublic override onDecorationsChanged(e: viewEvents.ViewDecorationsChangedEvent): boolean {\n\t\tif (e.affectsMinimap) {\n\t\t\treturn this._actual.onDecorationsChanged();\n\t\t}\n\t\treturn false;\n\t}\n\tpublic override onFlushed(e: viewEvents.ViewFlushedEvent): boolean {\n\t\tif (this._samplingState) {\n\t\t\tthis._shouldCheckSampling = true;\n\t\t}\n\t\treturn this._actual.onFlushed();\n\t}\n\tpublic override onLinesChanged(e: viewEvents.ViewLinesChangedEvent): boolean {\n\t\tif (this._samplingState) {\n\t\t\tconst minimapLineRange = this._samplingState.modelLineRangeToMinimapLineRange(e.fromLineNumber, e.fromLineNumber + e.count - 1);\n\t\t\tif (minimapLineRange) {\n\t\t\t\treturn this._actual.onLinesChanged(minimapLineRange[0], minimapLineRange[1] - minimapLineRange[0] + 1);\n\t\t\t} else {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t} else {\n\t\t\treturn this._actual.onLinesChanged(e.fromLineNumber, e.count);\n\t\t}\n\t}\n\tpublic override onLinesDeleted(e: viewEvents.ViewLinesDeletedEvent): boolean {\n\t\tif (this._samplingState) {\n\t\t\tconst [changeStartIndex, changeEndIndex] = this._samplingState.onLinesDeleted(e);\n\t\t\tif (changeStartIndex <= changeEndIndex) {\n\t\t\t\tthis._actual.onLinesChanged(changeStartIndex + 1, changeEndIndex - changeStartIndex + 1);\n\t\t\t}\n\t\t\tthis._shouldCheckSampling = true;\n\t\t\treturn true;\n\t\t} else {\n\t\t\treturn this._actual.onLinesDeleted(e.fromLineNumber, e.toLineNumber);\n\t\t}\n\t}\n\tpublic override onLinesInserted(e: viewEvents.ViewLinesInsertedEvent): boolean {\n\t\tif (this._samplingState) {\n\t\t\tthis._samplingState.onLinesInserted(e);\n\t\t\tthis._shouldCheckSampling = true;\n\t\t\treturn true;\n\t\t} else {\n\t\t\treturn this._actual.onLinesInserted(e.fromLineNumber, e.toLineNumber);\n\t\t}\n\t}\n\tpublic override onScrollChanged(e: viewEvents.ViewScrollChangedEvent): boolean {\n\t\treturn this._actual.onScrollChanged();\n\t}\n\tpublic override onThemeChanged(e: viewEvents.ViewThemeChangedEvent): boolean {\n\t\tthis._actual.onThemeChanged();\n\t\tthis._onOptionsMaybeChanged();\n\t\treturn true;\n\t}\n\tpublic override onTokensChanged(e: viewEvents.ViewTokensChangedEvent): boolean {\n\t\tif (this._samplingState) {\n\t\t\tconst ranges: { fromLineNumber: number; toLineNumber: number }[] = [];\n\t\t\tfor (const range of e.ranges) {\n\t\t\t\tconst minimapLineRange = this._samplingState.modelLineRangeToMinimapLineRange(range.fromLineNumber, range.toLineNumber);\n\t\t\t\tif (minimapLineRange) {\n\t\t\t\t\tranges.push({ fromLineNumber: minimapLineRange[0], toLineNumber: minimapLineRange[1] });\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (ranges.length) {\n\t\t\t\treturn this._actual.onTokensChanged(ranges);\n\t\t\t} else {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t} else {\n\t\t\treturn this._actual.onTokensChanged(e.ranges);\n\t\t}\n\t}\n\tpublic override onTokensColorsChanged(e: viewEvents.ViewTokensColorsChangedEvent): boolean {\n\t\tthis._onOptionsMaybeChanged();\n\t\treturn this._actual.onTokensColorsChanged();\n\t}\n\tpublic override onZonesChanged(e: viewEvents.ViewZonesChangedEvent): boolean {\n\t\treturn this._actual.onZonesChanged();\n\t}\n\n\t// --- end event handlers\n\n\tpublic prepareRender(ctx: RenderingContext): void {\n\t\tif (this._shouldCheckSampling) {\n\t\t\tthis._shouldCheckSampling = false;\n\t\t\tthis._recreateLineSampling();\n\t\t}\n\t}\n\n\tpublic render(ctx: RestrictedRenderingContext): void {\n\t\tlet viewportStartLineNumber = ctx.visibleRange.startLineNumber;\n\t\tlet viewportEndLineNumber = ctx.visibleRange.endLineNumber;\n\n\t\tif (this._samplingState) {\n\t\t\tviewportStartLineNumber = this._samplingState.modelLineToMinimapLine(viewportStartLineNumber);\n\t\t\tviewportEndLineNumber = this._samplingState.modelLineToMinimapLine(viewportEndLineNumber);\n\t\t}\n\n\t\tconst minimapCtx: IMinimapRenderingContext = {\n\t\t\tviewportContainsWhitespaceGaps: (ctx.viewportData.whitespaceViewportData.length > 0),\n\n\t\t\tscrollWidth: ctx.scrollWidth,\n\t\t\tscrollHeight: ctx.scrollHeight,\n\n\t\t\tviewportStartLineNumber: viewportStartLineNumber,\n\t\t\tviewportEndLineNumber: viewportEndLineNumber,\n\t\t\tviewportStartLineNumberVerticalOffset: ctx.getVerticalOffsetForLineNumber(viewportStartLineNumber),\n\n\t\t\tscrollTop: ctx.scrollTop,\n\t\t\tscrollLeft: ctx.scrollLeft,\n\n\t\t\tviewportWidth: ctx.viewportWidth,\n\t\t\tviewportHeight: ctx.viewportHeight,\n\t\t};\n\t\tthis._actual.render(minimapCtx);\n\t}\n\n\t//#region IMinimapModel\n\n\tprivate _recreateLineSampling(): void {\n\t\tthis._minimapSelections = null;\n\n\t\tconst wasSampling = Boolean(this._samplingState);\n\t\tconst [samplingState, events] = MinimapSamplingState.compute(this.options, this._context.viewModel.getLineCount(), this._samplingState);\n\t\tthis._samplingState = samplingState;\n\n\t\tif (wasSampling && this._samplingState) {\n\t\t\t// was sampling, is sampling\n\t\t\tfor (const event of events) {\n\t\t\t\tswitch (event.type) {\n\t\t\t\t\tcase 'deleted':\n\t\t\t\t\t\tthis._actual.onLinesDeleted(event.deleteFromLineNumber, event.deleteToLineNumber);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'inserted':\n\t\t\t\t\t\tthis._actual.onLinesInserted(event.insertFromLineNumber, event.insertToLineNumber);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'flush':\n\t\t\t\t\t\tthis._actual.onFlushed();\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic getLineCount(): number {\n\t\tif (this._samplingState) {\n\t\t\treturn this._samplingState.minimapLines.length;\n\t\t}\n\t\treturn this._context.viewModel.getLineCount();\n\t}\n\n\tpublic getRealLineCount(): number {\n\t\treturn this._context.viewModel.getLineCount();\n\t}\n\n\tpublic getLineContent(lineNumber: number): string {\n\t\tif (this._samplingState) {\n\t\t\treturn this._context.viewModel.getLineContent(this._samplingState.minimapLines[lineNumber - 1]);\n\t\t}\n\t\treturn this._context.viewModel.getLineContent(lineNumber);\n\t}\n\n\tpublic getLineMaxColumn(lineNumber: number): number {\n\t\tif (this._samplingState) {\n\t\t\treturn this._context.viewModel.getLineMaxColumn(this._samplingState.minimapLines[lineNumber - 1]);\n\t\t}\n\t\treturn this._context.viewModel.getLineMaxColumn(lineNumber);\n\t}\n\n\tpublic getMinimapLinesRenderingData(startLineNumber: number, endLineNumber: number, needed: boolean[]): (ViewLineData | null)[] {\n\t\tif (this._samplingState) {\n\t\t\tconst result: (ViewLineData | null)[] = [];\n\t\t\tfor (let lineIndex = 0, lineCount = endLineNumber - startLineNumber + 1; lineIndex < lineCount; lineIndex++) {\n\t\t\t\tif (needed[lineIndex]) {\n\t\t\t\t\tresult[lineIndex] = this._context.viewModel.getViewLineData(this._samplingState.minimapLines[startLineNumber + lineIndex - 1]);\n\t\t\t\t} else {\n\t\t\t\t\tresult[lineIndex] = null;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\t\treturn this._context.viewModel.getMinimapLinesRenderingData(startLineNumber, endLineNumber, needed).data;\n\t}\n\n\tpublic getSelections(): Selection[] {\n\t\tif (this._minimapSelections === null) {\n\t\t\tif (this._samplingState) {\n\t\t\t\tthis._minimapSelections = [];\n\t\t\t\tfor (const selection of this._selections) {\n\t\t\t\t\tconst [minimapLineStart, minimapLineEnd] = this._samplingState.decorationLineRangeToMinimapLineRange(selection.startLineNumber, selection.endLineNumber);\n\t\t\t\t\tthis._minimapSelections.push(new Selection(minimapLineStart, selection.startColumn, minimapLineEnd, selection.endColumn));\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis._minimapSelections = this._selections;\n\t\t\t}\n\t\t}\n\t\treturn this._minimapSelections;\n\t}\n\n\tpublic getMinimapDecorationsInViewport(startLineNumber: number, endLineNumber: number): ViewModelDecoration[] {\n\t\tconst decorations = this._getMinimapDecorationsInViewport(startLineNumber, endLineNumber)\n\t\t\t.filter(decoration => !decoration.options.minimap?.sectionHeaderStyle);\n\n\t\tif (this._samplingState) {\n\t\t\tconst result: ViewModelDecoration[] = [];\n\t\t\tfor (const decoration of decorations) {\n\t\t\t\tif (!decoration.options.minimap) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst range = decoration.range;\n\t\t\t\tconst minimapStartLineNumber = this._samplingState.modelLineToMinimapLine(range.startLineNumber);\n\t\t\t\tconst minimapEndLineNumber = this._samplingState.modelLineToMinimapLine(range.endLineNumber);\n\t\t\t\tresult.push(new ViewModelDecoration(new Range(minimapStartLineNumber, range.startColumn, minimapEndLineNumber, range.endColumn), decoration.options));\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\t\treturn decorations;\n\t}\n\n\tpublic getSectionHeaderDecorationsInViewport(startLineNumber: number, endLineNumber: number): ViewModelDecoration[] {\n\t\tconst minimapLineHeight = this.options.minimapLineHeight;\n\t\tconst sectionHeaderFontSize = this.options.sectionHeaderFontSize;\n\t\tconst headerHeightInMinimapLines = sectionHeaderFontSize / minimapLineHeight;\n\t\tstartLineNumber = Math.floor(Math.max(1, startLineNumber - headerHeightInMinimapLines));\n\t\treturn this._getMinimapDecorationsInViewport(startLineNumber, endLineNumber)\n\t\t\t.filter(decoration => !!decoration.options.minimap?.sectionHeaderStyle);\n\t}\n\n\tprivate _getMinimapDecorationsInViewport(startLineNumber: number, endLineNumber: number) {\n\t\tlet visibleRange: Range;\n\t\tif (this._samplingState) {\n\t\t\tconst modelStartLineNumber = this._samplingState.minimapLines[startLineNumber - 1];\n\t\t\tconst modelEndLineNumber = this._samplingState.minimapLines[endLineNumber - 1];\n\t\t\tvisibleRange = new Range(modelStartLineNumber, 1, modelEndLineNumber, this._context.viewModel.getLineMaxColumn(modelEndLineNumber));\n\t\t} else {\n\t\t\tvisibleRange = new Range(startLineNumber, 1, endLineNumber, this._context.viewModel.getLineMaxColumn(endLineNumber));\n\t\t}\n\t\treturn this._context.viewModel.getMinimapDecorationsInRange(visibleRange);\n\t}\n\n\tpublic getSectionHeaderText(decoration: ViewModelDecoration, fitWidth: (s: string) => string): string | null {\n\t\tconst headerText = decoration.options.minimap?.sectionHeaderText;\n\t\tif (!headerText) {\n\t\t\treturn null;\n\t\t}\n\t\tconst cachedText = this._sectionHeaderCache.get(headerText);\n\t\tif (cachedText) {\n\t\t\treturn cachedText;\n\t\t}\n\t\tconst fittedText = fitWidth(headerText);\n\t\tthis._sectionHeaderCache.set(headerText, fittedText);\n\t\treturn fittedText;\n\t}\n\n\tpublic getOptions(): TextModelResolvedOptions {\n\t\treturn this._context.viewModel.model.getOptions();\n\t}\n\n\tpublic revealLineNumber(lineNumber: number): void {\n\t\tif (this._samplingState) {\n\t\t\tlineNumber = this._samplingState.minimapLines[lineNumber - 1];\n\t\t}\n\t\tthis._context.viewModel.revealRange(\n\t\t\t'mouse',\n\t\t\tfalse,\n\t\t\tnew Range(lineNumber, 1, lineNumber, 1),\n\t\t\tviewEvents.VerticalRevealType.Center,\n\t\t\tScrollType.Smooth\n\t\t);\n\t}\n\n\tpublic setScrollTop(scrollTop: number): void {\n\t\tthis._context.viewModel.viewLayout.setScrollPosition({\n\t\t\tscrollTop: scrollTop\n\t\t}, ScrollType.Immediate);\n\t}\n\n\t//#endregion\n}\n\nclass InnerMinimap extends Disposable {\n\n\tprivate readonly _theme: EditorTheme;\n\tprivate readonly _model: IMinimapModel;\n\n\tprivate readonly _domNode: FastDomNode;\n\tprivate readonly _shadow: FastDomNode;\n\tprivate readonly _canvas: FastDomNode;\n\tprivate readonly _decorationsCanvas: FastDomNode;\n\tprivate readonly _slider: FastDomNode;\n\tprivate readonly _sliderHorizontal: FastDomNode;\n\tprivate readonly _pointerDownListener: IDisposable;\n\tprivate readonly _sliderPointerMoveMonitor: GlobalPointerMoveMonitor;\n\tprivate readonly _sliderPointerDownListener: IDisposable;\n\tprivate readonly _gestureDisposable: IDisposable;\n\tprivate readonly _sliderTouchStartListener: IDisposable;\n\tprivate readonly _sliderTouchMoveListener: IDisposable;\n\tprivate readonly _sliderTouchEndListener: IDisposable;\n\n\tprivate _lastRenderData: RenderData | null;\n\tprivate _selectionColor: Color | undefined;\n\tprivate _renderDecorations: boolean = false;\n\tprivate _gestureInProgress: boolean = false;\n\tprivate _buffers: MinimapBuffers | null;\n\n\tconstructor(\n\t\ttheme: EditorTheme,\n\t\tmodel: IMinimapModel\n\t) {\n\t\tsuper();\n\n\t\tthis._theme = theme;\n\t\tthis._model = model;\n\n\t\tthis._lastRenderData = null;\n\t\tthis._buffers = null;\n\t\tthis._selectionColor = this._theme.getColor(minimapSelection);\n\n\t\tthis._domNode = createFastDomNode(document.createElement('div'));\n\t\tPartFingerprints.write(this._domNode, PartFingerprint.Minimap);\n\t\tthis._domNode.setClassName(this._getMinimapDomNodeClassName());\n\t\tthis._domNode.setPosition('absolute');\n\t\tthis._domNode.setAttribute('role', 'presentation');\n\t\tthis._domNode.setAttribute('aria-hidden', 'true');\n\n\t\tthis._shadow = createFastDomNode(document.createElement('div'));\n\t\tthis._shadow.setClassName('minimap-shadow-hidden');\n\t\tthis._domNode.appendChild(this._shadow);\n\n\t\tthis._canvas = createFastDomNode(document.createElement('canvas'));\n\t\tthis._canvas.setPosition('absolute');\n\t\tthis._canvas.setLeft(0);\n\t\tthis._domNode.appendChild(this._canvas);\n\n\t\tthis._decorationsCanvas = createFastDomNode(document.createElement('canvas'));\n\t\tthis._decorationsCanvas.setPosition('absolute');\n\t\tthis._decorationsCanvas.setClassName('minimap-decorations-layer');\n\t\tthis._decorationsCanvas.setLeft(0);\n\t\tthis._domNode.appendChild(this._decorationsCanvas);\n\n\t\tthis._slider = createFastDomNode(document.createElement('div'));\n\t\tthis._slider.setPosition('absolute');\n\t\tthis._slider.setClassName('minimap-slider');\n\t\tthis._slider.setLayerHinting(true);\n\t\tthis._slider.setContain('strict');\n\t\tthis._domNode.appendChild(this._slider);\n\n\t\tthis._sliderHorizontal = createFastDomNode(document.createElement('div'));\n\t\tthis._sliderHorizontal.setPosition('absolute');\n\t\tthis._sliderHorizontal.setClassName('minimap-slider-horizontal');\n\t\tthis._slider.appendChild(this._sliderHorizontal);\n\n\t\tthis._applyLayout();\n\n\t\tthis._pointerDownListener = dom.addStandardDisposableListener(this._domNode.domNode, dom.EventType.POINTER_DOWN, (e) => {\n\t\t\te.preventDefault();\n\n\t\t\tconst renderMinimap = this._model.options.renderMinimap;\n\t\t\tif (renderMinimap === RenderMinimap.None) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (!this._lastRenderData) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (this._model.options.size !== 'proportional') {\n\t\t\t\tif (e.button === 0 && this._lastRenderData) {\n\t\t\t\t\t// pretend the click occurred in the center of the slider\n\t\t\t\t\tconst position = dom.getDomNodePagePosition(this._slider.domNode);\n\t\t\t\t\tconst initialPosY = position.top + position.height / 2;\n\t\t\t\t\tthis._startSliderDragging(e, initialPosY, this._lastRenderData.renderedLayout);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst minimapLineHeight = this._model.options.minimapLineHeight;\n\t\t\tconst internalOffsetY = (this._model.options.canvasInnerHeight / this._model.options.canvasOuterHeight) * e.offsetY;\n\t\t\tconst lineIndex = Math.floor(internalOffsetY / minimapLineHeight);\n\n\t\t\tlet lineNumber = lineIndex + this._lastRenderData.renderedLayout.startLineNumber - this._lastRenderData.renderedLayout.topPaddingLineCount;\n\t\t\tlineNumber = Math.min(lineNumber, this._model.getLineCount());\n\n\t\t\tthis._model.revealLineNumber(lineNumber);\n\t\t});\n\n\t\tthis._sliderPointerMoveMonitor = new GlobalPointerMoveMonitor();\n\n\t\tthis._sliderPointerDownListener = dom.addStandardDisposableListener(this._slider.domNode, dom.EventType.POINTER_DOWN, (e) => {\n\t\t\te.preventDefault();\n\t\t\te.stopPropagation();\n\t\t\tif (e.button === 0 && this._lastRenderData) {\n\t\t\t\tthis._startSliderDragging(e, e.pageY, this._lastRenderData.renderedLayout);\n\t\t\t}\n\t\t});\n\n\t\tthis._gestureDisposable = Gesture.addTarget(this._domNode.domNode);\n\t\tthis._sliderTouchStartListener = dom.addDisposableListener(this._domNode.domNode, EventType.Start, (e: GestureEvent) => {\n\t\t\te.preventDefault();\n\t\t\te.stopPropagation();\n\t\t\tif (this._lastRenderData) {\n\t\t\t\tthis._slider.toggleClassName('active', true);\n\t\t\t\tthis._gestureInProgress = true;\n\t\t\t\tthis.scrollDueToTouchEvent(e);\n\t\t\t}\n\t\t}, { passive: false });\n\n\t\tthis._sliderTouchMoveListener = dom.addDisposableListener(this._domNode.domNode, EventType.Change, (e: GestureEvent) => {\n\t\t\te.preventDefault();\n\t\t\te.stopPropagation();\n\t\t\tif (this._lastRenderData && this._gestureInProgress) {\n\t\t\t\tthis.scrollDueToTouchEvent(e);\n\t\t\t}\n\t\t}, { passive: false });\n\n\t\tthis._sliderTouchEndListener = dom.addStandardDisposableListener(this._domNode.domNode, EventType.End, (e: GestureEvent) => {\n\t\t\te.preventDefault();\n\t\t\te.stopPropagation();\n\t\t\tthis._gestureInProgress = false;\n\t\t\tthis._slider.toggleClassName('active', false);\n\t\t});\n\t}\n\n\tprivate _startSliderDragging(e: PointerEvent, initialPosY: number, initialSliderState: MinimapLayout): void {\n\t\tif (!e.target || !(e.target instanceof Element)) {\n\t\t\treturn;\n\t\t}\n\t\tconst initialPosX = e.pageX;\n\n\t\tthis._slider.toggleClassName('active', true);\n\n\t\tconst handlePointerMove = (posy: number, posx: number) => {\n\t\t\tconst minimapPosition = dom.getDomNodePagePosition(this._domNode.domNode);\n\t\t\tconst pointerOrthogonalDelta = Math.min(\n\t\t\t\tMath.abs(posx - initialPosX),\n\t\t\t\tMath.abs(posx - minimapPosition.left),\n\t\t\t\tMath.abs(posx - minimapPosition.left - minimapPosition.width)\n\t\t\t);\n\n\t\t\tif (platform.isWindows && pointerOrthogonalDelta > POINTER_DRAG_RESET_DISTANCE) {\n\t\t\t\t// The pointer has wondered away from the scrollbar => reset dragging\n\t\t\t\tthis._model.setScrollTop(initialSliderState.scrollTop);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst pointerDelta = posy - initialPosY;\n\t\t\tthis._model.setScrollTop(initialSliderState.getDesiredScrollTopFromDelta(pointerDelta));\n\t\t};\n\n\t\tif (e.pageY !== initialPosY) {\n\t\t\thandlePointerMove(e.pageY, initialPosX);\n\t\t}\n\n\t\tthis._sliderPointerMoveMonitor.startMonitoring(\n\t\t\te.target,\n\t\t\te.pointerId,\n\t\t\te.buttons,\n\t\t\tpointerMoveData => handlePointerMove(pointerMoveData.pageY, pointerMoveData.pageX),\n\t\t\t() => {\n\t\t\t\tthis._slider.toggleClassName('active', false);\n\t\t\t}\n\t\t);\n\t}\n\n\tprivate scrollDueToTouchEvent(touch: GestureEvent) {\n\t\tconst startY = this._domNode.domNode.getBoundingClientRect().top;\n\t\tconst scrollTop = this._lastRenderData!.renderedLayout.getDesiredScrollTopFromTouchLocation(touch.pageY - startY);\n\t\tthis._model.setScrollTop(scrollTop);\n\t}\n\n\tpublic override dispose(): void {\n\t\tthis._pointerDownListener.dispose();\n\t\tthis._sliderPointerMoveMonitor.dispose();\n\t\tthis._sliderPointerDownListener.dispose();\n\t\tthis._gestureDisposable.dispose();\n\t\tthis._sliderTouchStartListener.dispose();\n\t\tthis._sliderTouchMoveListener.dispose();\n\t\tthis._sliderTouchEndListener.dispose();\n\t\tsuper.dispose();\n\t}\n\n\tprivate _getMinimapDomNodeClassName(): string {\n\t\tconst class_ = ['minimap'];\n\t\tif (this._model.options.showSlider === 'always') {\n\t\t\tclass_.push('slider-always');\n\t\t} else {\n\t\t\tclass_.push('slider-mouseover');\n\t\t}\n\t\tif (this._model.options.autohide) {\n\t\t\tclass_.push('autohide');\n\t\t}\n\n\t\treturn class_.join(' ');\n\t}\n\n\tpublic getDomNode(): FastDomNode {\n\t\treturn this._domNode;\n\t}\n\n\tprivate _applyLayout(): void {\n\t\tthis._domNode.setLeft(this._model.options.minimapLeft);\n\t\tthis._domNode.setWidth(this._model.options.minimapWidth);\n\t\tthis._domNode.setHeight(this._model.options.minimapHeight);\n\t\tthis._shadow.setHeight(this._model.options.minimapHeight);\n\n\t\tthis._canvas.setWidth(this._model.options.canvasOuterWidth);\n\t\tthis._canvas.setHeight(this._model.options.canvasOuterHeight);\n\t\tthis._canvas.domNode.width = this._model.options.canvasInnerWidth;\n\t\tthis._canvas.domNode.height = this._model.options.canvasInnerHeight;\n\n\t\tthis._decorationsCanvas.setWidth(this._model.options.canvasOuterWidth);\n\t\tthis._decorationsCanvas.setHeight(this._model.options.canvasOuterHeight);\n\t\tthis._decorationsCanvas.domNode.width = this._model.options.canvasInnerWidth;\n\t\tthis._decorationsCanvas.domNode.height = this._model.options.canvasInnerHeight;\n\n\t\tthis._slider.setWidth(this._model.options.minimapWidth);\n\t}\n\n\tprivate _getBuffer(): ImageData | null {\n\t\tif (!this._buffers) {\n\t\t\tif (this._model.options.canvasInnerWidth > 0 && this._model.options.canvasInnerHeight > 0) {\n\t\t\t\tthis._buffers = new MinimapBuffers(\n\t\t\t\t\tthis._canvas.domNode.getContext('2d')!,\n\t\t\t\t\tthis._model.options.canvasInnerWidth,\n\t\t\t\t\tthis._model.options.canvasInnerHeight,\n\t\t\t\t\tthis._model.options.backgroundColor\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\treturn this._buffers ? this._buffers.getBuffer() : null;\n\t}\n\n\t// ---- begin view event handlers\n\n\tpublic onDidChangeOptions(): void {\n\t\tthis._lastRenderData = null;\n\t\tthis._buffers = null;\n\t\tthis._applyLayout();\n\t\tthis._domNode.setClassName(this._getMinimapDomNodeClassName());\n\t}\n\tpublic onSelectionChanged(): boolean {\n\t\tthis._renderDecorations = true;\n\t\treturn true;\n\t}\n\tpublic onDecorationsChanged(): boolean {\n\t\tthis._renderDecorations = true;\n\t\treturn true;\n\t}\n\tpublic onFlushed(): boolean {\n\t\tthis._lastRenderData = null;\n\t\treturn true;\n\t}\n\tpublic onLinesChanged(changeFromLineNumber: number, changeCount: number): boolean {\n\t\tif (this._lastRenderData) {\n\t\t\treturn this._lastRenderData.onLinesChanged(changeFromLineNumber, changeCount);\n\t\t}\n\t\treturn false;\n\t}\n\tpublic onLinesDeleted(deleteFromLineNumber: number, deleteToLineNumber: number): boolean {\n\t\tthis._lastRenderData?.onLinesDeleted(deleteFromLineNumber, deleteToLineNumber);\n\t\treturn true;\n\t}\n\tpublic onLinesInserted(insertFromLineNumber: number, insertToLineNumber: number): boolean {\n\t\tthis._lastRenderData?.onLinesInserted(insertFromLineNumber, insertToLineNumber);\n\t\treturn true;\n\t}\n\tpublic onScrollChanged(): boolean {\n\t\tthis._renderDecorations = true;\n\t\treturn true;\n\t}\n\tpublic onThemeChanged(): boolean {\n\t\tthis._selectionColor = this._theme.getColor(minimapSelection);\n\t\tthis._renderDecorations = true;\n\t\treturn true;\n\t}\n\tpublic onTokensChanged(ranges: { fromLineNumber: number; toLineNumber: number }[]): boolean {\n\t\tif (this._lastRenderData) {\n\t\t\treturn this._lastRenderData.onTokensChanged(ranges);\n\t\t}\n\t\treturn false;\n\t}\n\tpublic onTokensColorsChanged(): boolean {\n\t\tthis._lastRenderData = null;\n\t\tthis._buffers = null;\n\t\treturn true;\n\t}\n\tpublic onZonesChanged(): boolean {\n\t\tthis._lastRenderData = null;\n\t\treturn true;\n\t}\n\n\t// --- end event handlers\n\n\tpublic render(renderingCtx: IMinimapRenderingContext): void {\n\t\tconst renderMinimap = this._model.options.renderMinimap;\n\t\tif (renderMinimap === RenderMinimap.None) {\n\t\t\tthis._shadow.setClassName('minimap-shadow-hidden');\n\t\t\tthis._sliderHorizontal.setWidth(0);\n\t\t\tthis._sliderHorizontal.setHeight(0);\n\t\t\treturn;\n\t\t}\n\t\tif (renderingCtx.scrollLeft + renderingCtx.viewportWidth >= renderingCtx.scrollWidth) {\n\t\t\tthis._shadow.setClassName('minimap-shadow-hidden');\n\t\t} else {\n\t\t\tthis._shadow.setClassName('minimap-shadow-visible');\n\t\t}\n\n\t\tconst layout = MinimapLayout.create(\n\t\t\tthis._model.options,\n\t\t\trenderingCtx.viewportStartLineNumber,\n\t\t\trenderingCtx.viewportEndLineNumber,\n\t\t\trenderingCtx.viewportStartLineNumberVerticalOffset,\n\t\t\trenderingCtx.viewportHeight,\n\t\t\trenderingCtx.viewportContainsWhitespaceGaps,\n\t\t\tthis._model.getLineCount(),\n\t\t\tthis._model.getRealLineCount(),\n\t\t\trenderingCtx.scrollTop,\n\t\t\trenderingCtx.scrollHeight,\n\t\t\tthis._lastRenderData ? this._lastRenderData.renderedLayout : null\n\t\t);\n\t\tthis._slider.setDisplay(layout.sliderNeeded ? 'block' : 'none');\n\t\tthis._slider.setTop(layout.sliderTop);\n\t\tthis._slider.setHeight(layout.sliderHeight);\n\n\t\t// Compute horizontal slider coordinates\n\t\tthis._sliderHorizontal.setLeft(0);\n\t\tthis._sliderHorizontal.setWidth(this._model.options.minimapWidth);\n\t\tthis._sliderHorizontal.setTop(0);\n\t\tthis._sliderHorizontal.setHeight(layout.sliderHeight);\n\n\t\tthis.renderDecorations(layout);\n\t\tthis._lastRenderData = this.renderLines(layout);\n\t}\n\n\tprivate renderDecorations(layout: MinimapLayout) {\n\t\tif (this._renderDecorations) {\n\t\t\tthis._renderDecorations = false;\n\t\t\tconst selections = this._model.getSelections();\n\t\t\tselections.sort(Range.compareRangesUsingStarts);\n\n\t\t\tconst decorations = this._model.getMinimapDecorationsInViewport(layout.startLineNumber, layout.endLineNumber);\n\t\t\tdecorations.sort((a, b) => (a.options.zIndex || 0) - (b.options.zIndex || 0));\n\n\t\t\tconst { canvasInnerWidth, canvasInnerHeight } = this._model.options;\n\t\t\tconst minimapLineHeight = this._model.options.minimapLineHeight;\n\t\t\tconst minimapCharWidth = this._model.options.minimapCharWidth;\n\t\t\tconst tabSize = this._model.getOptions().tabSize;\n\t\t\tconst canvasContext = this._decorationsCanvas.domNode.getContext('2d')!;\n\n\t\t\tcanvasContext.clearRect(0, 0, canvasInnerWidth, canvasInnerHeight);\n\n\t\t\t// We first need to render line highlights and then render decorations on top of those.\n\t\t\t// But we need to pick a single color for each line, and use that as a line highlight.\n\t\t\t// This needs to be the color of the decoration with the highest `zIndex`, but priority\n\t\t\t// is given to the selection.\n\n\t\t\tconst highlightedLines = new ContiguousLineMap(layout.startLineNumber, layout.endLineNumber, false);\n\t\t\tthis._renderSelectionLineHighlights(canvasContext, selections, highlightedLines, layout, minimapLineHeight);\n\t\t\tthis._renderDecorationsLineHighlights(canvasContext, decorations, highlightedLines, layout, minimapLineHeight);\n\n\t\t\tconst lineOffsetMap = new ContiguousLineMap(layout.startLineNumber, layout.endLineNumber, null);\n\t\t\tthis._renderSelectionsHighlights(canvasContext, selections, lineOffsetMap, layout, minimapLineHeight, tabSize, minimapCharWidth, canvasInnerWidth);\n\t\t\tthis._renderDecorationsHighlights(canvasContext, decorations, lineOffsetMap, layout, minimapLineHeight, tabSize, minimapCharWidth, canvasInnerWidth);\n\t\t\tthis._renderSectionHeaders(layout);\n\t\t}\n\t}\n\n\tprivate _renderSelectionLineHighlights(\n\t\tcanvasContext: CanvasRenderingContext2D,\n\t\tselections: Selection[],\n\t\thighlightedLines: ContiguousLineMap,\n\t\tlayout: MinimapLayout,\n\t\tminimapLineHeight: number\n\t): void {\n\t\tif (!this._selectionColor || this._selectionColor.isTransparent()) {\n\t\t\treturn;\n\t\t}\n\n\t\tcanvasContext.fillStyle = this._selectionColor.transparent(0.5).toString();\n\n\t\tlet y1 = 0;\n\t\tlet y2 = 0;\n\n\t\tfor (const selection of selections) {\n\t\t\tconst intersection = layout.intersectWithViewport(selection);\n\t\t\tif (!intersection) {\n\t\t\t\t// entirely outside minimap's viewport\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst [startLineNumber, endLineNumber] = intersection;\n\n\t\t\tfor (let line = startLineNumber; line <= endLineNumber; line++) {\n\t\t\t\thighlightedLines.set(line, true);\n\t\t\t}\n\n\t\t\tconst yy1 = layout.getYForLineNumber(startLineNumber, minimapLineHeight);\n\t\t\tconst yy2 = layout.getYForLineNumber(endLineNumber, minimapLineHeight);\n\n\t\t\tif (y2 >= yy1) {\n\t\t\t\t// merge into previous\n\t\t\t\ty2 = yy2;\n\t\t\t} else {\n\t\t\t\tif (y2 > y1) {\n\t\t\t\t\t// flush\n\t\t\t\t\tcanvasContext.fillRect(MINIMAP_GUTTER_WIDTH, y1, canvasContext.canvas.width, y2 - y1);\n\t\t\t\t}\n\t\t\t\ty1 = yy1;\n\t\t\t\ty2 = yy2;\n\t\t\t}\n\t\t}\n\n\t\tif (y2 > y1) {\n\t\t\t// flush\n\t\t\tcanvasContext.fillRect(MINIMAP_GUTTER_WIDTH, y1, canvasContext.canvas.width, y2 - y1);\n\t\t}\n\t}\n\n\tprivate _renderDecorationsLineHighlights(\n\t\tcanvasContext: CanvasRenderingContext2D,\n\t\tdecorations: ViewModelDecoration[],\n\t\thighlightedLines: ContiguousLineMap,\n\t\tlayout: MinimapLayout,\n\t\tminimapLineHeight: number\n\t): void {\n\n\t\tconst highlightColors = new Map();\n\n\t\t// Loop backwards to hit first decorations with higher `zIndex`\n\t\tfor (let i = decorations.length - 1; i >= 0; i--) {\n\t\t\tconst decoration = decorations[i];\n\n\t\t\tconst minimapOptions = decoration.options.minimap;\n\t\t\tif (!minimapOptions || minimapOptions.position !== MinimapPosition.Inline) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst intersection = layout.intersectWithViewport(decoration.range);\n\t\t\tif (!intersection) {\n\t\t\t\t// entirely outside minimap's viewport\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst [startLineNumber, endLineNumber] = intersection;\n\n\t\t\tconst decorationColor = minimapOptions.getColor(this._theme.value);\n\t\t\tif (!decorationColor || decorationColor.isTransparent()) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tlet highlightColor = highlightColors.get(decorationColor.toString());\n\t\t\tif (!highlightColor) {\n\t\t\t\thighlightColor = decorationColor.transparent(0.5).toString();\n\t\t\t\thighlightColors.set(decorationColor.toString(), highlightColor);\n\t\t\t}\n\n\t\t\tcanvasContext.fillStyle = highlightColor;\n\t\t\tfor (let line = startLineNumber; line <= endLineNumber; line++) {\n\t\t\t\tif (highlightedLines.has(line)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\thighlightedLines.set(line, true);\n\t\t\t\tconst y = layout.getYForLineNumber(startLineNumber, minimapLineHeight);\n\t\t\t\tcanvasContext.fillRect(MINIMAP_GUTTER_WIDTH, y, canvasContext.canvas.width, minimapLineHeight);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate _renderSelectionsHighlights(\n\t\tcanvasContext: CanvasRenderingContext2D,\n\t\tselections: Selection[],\n\t\tlineOffsetMap: ContiguousLineMap,\n\t\tlayout: MinimapLayout,\n\t\tlineHeight: number,\n\t\ttabSize: number,\n\t\tcharacterWidth: number,\n\t\tcanvasInnerWidth: number\n\t): void {\n\t\tif (!this._selectionColor || this._selectionColor.isTransparent()) {\n\t\t\treturn;\n\t\t}\n\t\tfor (const selection of selections) {\n\t\t\tconst intersection = layout.intersectWithViewport(selection);\n\t\t\tif (!intersection) {\n\t\t\t\t// entirely outside minimap's viewport\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst [startLineNumber, endLineNumber] = intersection;\n\n\t\t\tfor (let line = startLineNumber; line <= endLineNumber; line++) {\n\t\t\t\tthis.renderDecorationOnLine(canvasContext, lineOffsetMap, selection, this._selectionColor, layout, line, lineHeight, lineHeight, tabSize, characterWidth, canvasInnerWidth);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate _renderDecorationsHighlights(\n\t\tcanvasContext: CanvasRenderingContext2D,\n\t\tdecorations: ViewModelDecoration[],\n\t\tlineOffsetMap: ContiguousLineMap,\n\t\tlayout: MinimapLayout,\n\t\tminimapLineHeight: number,\n\t\ttabSize: number,\n\t\tcharacterWidth: number,\n\t\tcanvasInnerWidth: number\n\t): void {\n\t\t// Loop forwards to hit first decorations with lower `zIndex`\n\t\tfor (const decoration of decorations) {\n\n\t\t\tconst minimapOptions = decoration.options.minimap;\n\t\t\tif (!minimapOptions) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst intersection = layout.intersectWithViewport(decoration.range);\n\t\t\tif (!intersection) {\n\t\t\t\t// entirely outside minimap's viewport\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst [startLineNumber, endLineNumber] = intersection;\n\n\t\t\tconst decorationColor = minimapOptions.getColor(this._theme.value);\n\t\t\tif (!decorationColor || decorationColor.isTransparent()) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tfor (let line = startLineNumber; line <= endLineNumber; line++) {\n\t\t\t\tswitch (minimapOptions.position) {\n\n\t\t\t\t\tcase MinimapPosition.Inline:\n\t\t\t\t\t\tthis.renderDecorationOnLine(canvasContext, lineOffsetMap, decoration.range, decorationColor, layout, line, minimapLineHeight, minimapLineHeight, tabSize, characterWidth, canvasInnerWidth);\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\tcase MinimapPosition.Gutter: {\n\t\t\t\t\t\tconst y = layout.getYForLineNumber(line, minimapLineHeight);\n\t\t\t\t\t\tconst x = 2;\n\t\t\t\t\t\tthis.renderDecoration(canvasContext, decorationColor, x, y, GUTTER_DECORATION_WIDTH, minimapLineHeight);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate renderDecorationOnLine(\n\t\tcanvasContext: CanvasRenderingContext2D,\n\t\tlineOffsetMap: ContiguousLineMap,\n\t\tdecorationRange: Range,\n\t\tdecorationColor: Color | undefined,\n\t\tlayout: MinimapLayout,\n\t\tlineNumber: number,\n\t\theight: number,\n\t\tminimapLineHeight: number,\n\t\ttabSize: number,\n\t\tcharWidth: number,\n\t\tcanvasInnerWidth: number\n\t): void {\n\t\tconst y = layout.getYForLineNumber(lineNumber, minimapLineHeight);\n\n\t\t// Skip rendering the line if it's vertically outside our viewport\n\t\tif (y + height < 0 || y > this._model.options.canvasInnerHeight) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst { startLineNumber, endLineNumber } = decorationRange;\n\t\tconst startColumn = (startLineNumber === lineNumber ? decorationRange.startColumn : 1);\n\t\tconst endColumn = (endLineNumber === lineNumber ? decorationRange.endColumn : this._model.getLineMaxColumn(lineNumber));\n\n\t\tconst x1 = this.getXOffsetForPosition(lineOffsetMap, lineNumber, startColumn, tabSize, charWidth, canvasInnerWidth);\n\t\tconst x2 = this.getXOffsetForPosition(lineOffsetMap, lineNumber, endColumn, tabSize, charWidth, canvasInnerWidth);\n\n\t\tthis.renderDecoration(canvasContext, decorationColor, x1, y, x2 - x1, height);\n\t}\n\n\tprivate getXOffsetForPosition(\n\t\tlineOffsetMap: ContiguousLineMap,\n\t\tlineNumber: number,\n\t\tcolumn: number,\n\t\ttabSize: number,\n\t\tcharWidth: number,\n\t\tcanvasInnerWidth: number\n\t): number {\n\t\tif (column === 1) {\n\t\t\treturn MINIMAP_GUTTER_WIDTH;\n\t\t}\n\n\t\tconst minimumXOffset = (column - 1) * charWidth;\n\t\tif (minimumXOffset >= canvasInnerWidth) {\n\t\t\t// there is no need to look at actual characters,\n\t\t\t// as this column is certainly after the minimap width\n\t\t\treturn canvasInnerWidth;\n\t\t}\n\n\t\t// Cache line offset data so that it is only read once per line\n\t\tlet lineIndexToXOffset = lineOffsetMap.get(lineNumber);\n\t\tif (!lineIndexToXOffset) {\n\t\t\tconst lineData = this._model.getLineContent(lineNumber);\n\t\t\tlineIndexToXOffset = [MINIMAP_GUTTER_WIDTH];\n\t\t\tlet prevx = MINIMAP_GUTTER_WIDTH;\n\t\t\tfor (let i = 1; i < lineData.length + 1; i++) {\n\t\t\t\tconst charCode = lineData.charCodeAt(i - 1);\n\t\t\t\tconst dx = charCode === CharCode.Tab\n\t\t\t\t\t? tabSize * charWidth\n\t\t\t\t\t: strings.isFullWidthCharacter(charCode)\n\t\t\t\t\t\t? 2 * charWidth\n\t\t\t\t\t\t: charWidth;\n\n\t\t\t\tconst x = prevx + dx;\n\t\t\t\tif (x >= canvasInnerWidth) {\n\t\t\t\t\t// no need to keep on going, as we've hit the canvas width\n\t\t\t\t\tlineIndexToXOffset[i] = canvasInnerWidth;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tlineIndexToXOffset[i] = x;\n\t\t\t\tprevx = x;\n\t\t\t}\n\n\t\t\tlineOffsetMap.set(lineNumber, lineIndexToXOffset);\n\t\t}\n\n\t\tif (column - 1 < lineIndexToXOffset.length) {\n\t\t\treturn lineIndexToXOffset[column - 1];\n\t\t}\n\t\t// goes over the canvas width\n\t\treturn canvasInnerWidth;\n\t}\n\n\tprivate renderDecoration(canvasContext: CanvasRenderingContext2D, decorationColor: Color | undefined, x: number, y: number, width: number, height: number) {\n\t\tcanvasContext.fillStyle = decorationColor && decorationColor.toString() || '';\n\t\tcanvasContext.fillRect(x, y, width, height);\n\t}\n\n\tprivate _renderSectionHeaders(layout: MinimapLayout) {\n\t\tconst minimapLineHeight = this._model.options.minimapLineHeight;\n\t\tconst sectionHeaderFontSize = this._model.options.sectionHeaderFontSize;\n\t\tconst backgroundFillHeight = sectionHeaderFontSize * 1.5;\n\t\tconst { canvasInnerWidth } = this._model.options;\n\n\t\tconst backgroundColor = this._model.options.backgroundColor;\n\t\tconst backgroundFill = `rgb(${backgroundColor.r} ${backgroundColor.g} ${backgroundColor.b} / .7)`;\n\t\tconst foregroundColor = this._model.options.sectionHeaderFontColor;\n\t\tconst foregroundFill = `rgb(${foregroundColor.r} ${foregroundColor.g} ${foregroundColor.b})`;\n\t\tconst separatorStroke = foregroundFill;\n\n\t\tconst canvasContext = this._decorationsCanvas.domNode.getContext('2d')!;\n\t\tcanvasContext.font = sectionHeaderFontSize + 'px ' + this._model.options.sectionHeaderFontFamily;\n\t\tcanvasContext.strokeStyle = separatorStroke;\n\t\tcanvasContext.lineWidth = 0.2;\n\n\t\tconst decorations = this._model.getSectionHeaderDecorationsInViewport(layout.startLineNumber, layout.endLineNumber);\n\t\tdecorations.sort((a, b) => a.range.startLineNumber - b.range.startLineNumber);\n\n\t\tconst fitWidth = InnerMinimap._fitSectionHeader.bind(null, canvasContext,\n\t\t\tcanvasInnerWidth - MINIMAP_GUTTER_WIDTH);\n\n\t\tfor (const decoration of decorations) {\n\t\t\tconst y = layout.getYForLineNumber(decoration.range.startLineNumber, minimapLineHeight) + sectionHeaderFontSize;\n\t\t\tconst backgroundFillY = y - sectionHeaderFontSize;\n\t\t\tconst separatorY = backgroundFillY + 2;\n\t\t\tconst headerText = this._model.getSectionHeaderText(decoration, fitWidth);\n\n\t\t\tInnerMinimap._renderSectionLabel(\n\t\t\t\tcanvasContext,\n\t\t\t\theaderText,\n\t\t\t\tdecoration.options.minimap?.sectionHeaderStyle === MinimapSectionHeaderStyle.Underlined,\n\t\t\t\tbackgroundFill,\n\t\t\t\tforegroundFill,\n\t\t\t\tcanvasInnerWidth,\n\t\t\t\tbackgroundFillY,\n\t\t\t\tbackgroundFillHeight,\n\t\t\t\ty,\n\t\t\t\tseparatorY);\n\t\t}\n\t}\n\n\tprivate static _fitSectionHeader(\n\t\ttarget: CanvasRenderingContext2D,\n\t\tmaxWidth: number,\n\t\theaderText: string,\n\t): string {\n\t\tif (!headerText) {\n\t\t\treturn headerText;\n\t\t}\n\n\t\tconst ellipsis = '…';\n\t\tconst width = target.measureText(headerText).width;\n\t\tconst ellipsisWidth = target.measureText(ellipsis).width;\n\n\t\tif (width <= maxWidth || width <= ellipsisWidth) {\n\t\t\treturn headerText;\n\t\t}\n\n\t\tconst len = headerText.length;\n\t\tconst averageCharWidth = width / headerText.length;\n\t\tconst maxCharCount = Math.floor((maxWidth - ellipsisWidth) / averageCharWidth) - 1;\n\n\t\t// Find a halfway point that isn't after whitespace\n\t\tlet halfCharCount = Math.ceil(maxCharCount / 2);\n\t\twhile (halfCharCount > 0 && /\\s/.test(headerText[halfCharCount - 1])) {\n\t\t\t--halfCharCount;\n\t\t}\n\n\t\t// Split with ellipsis\n\t\treturn headerText.substring(0, halfCharCount)\n\t\t\t+ ellipsis + headerText.substring(len - (maxCharCount - halfCharCount));\n\t}\n\n\tprivate static _renderSectionLabel(\n\t\ttarget: CanvasRenderingContext2D,\n\t\theaderText: string | null,\n\t\thasSeparatorLine: boolean,\n\t\tbackgroundFill: string,\n\t\tforegroundFill: string,\n\t\tminimapWidth: number,\n\t\tbackgroundFillY: number,\n\t\tbackgroundFillHeight: number,\n\t\ttextY: number,\n\t\tseparatorY: number\n\t): void {\n\t\tif (headerText) {\n\t\t\ttarget.fillStyle = backgroundFill;\n\t\t\ttarget.fillRect(0, backgroundFillY, minimapWidth, backgroundFillHeight);\n\n\t\t\ttarget.fillStyle = foregroundFill;\n\t\t\ttarget.fillText(headerText, MINIMAP_GUTTER_WIDTH, textY);\n\t\t}\n\n\t\tif (hasSeparatorLine) {\n\t\t\ttarget.beginPath();\n\t\t\ttarget.moveTo(0, separatorY);\n\t\t\ttarget.lineTo(minimapWidth, separatorY);\n\t\t\ttarget.closePath();\n\t\t\ttarget.stroke();\n\t\t}\n\t}\n\n\tprivate renderLines(layout: MinimapLayout): RenderData | null {\n\t\tconst startLineNumber = layout.startLineNumber;\n\t\tconst endLineNumber = layout.endLineNumber;\n\t\tconst minimapLineHeight = this._model.options.minimapLineHeight;\n\n\t\t// Check if nothing changed w.r.t. lines from last frame\n\t\tif (this._lastRenderData && this._lastRenderData.linesEquals(layout)) {\n\t\t\tconst _lastData = this._lastRenderData._get();\n\t\t\t// Nice!! Nothing changed from last frame\n\t\t\treturn new RenderData(layout, _lastData.imageData, _lastData.lines);\n\t\t}\n\n\t\t// Oh well!! We need to repaint some lines...\n\n\t\tconst imageData = this._getBuffer();\n\t\tif (!imageData) {\n\t\t\t// 0 width or 0 height canvas, nothing to do\n\t\t\treturn null;\n\t\t}\n\n\t\t// Render untouched lines by using last rendered data.\n\t\tconst [_dirtyY1, _dirtyY2, needed] = InnerMinimap._renderUntouchedLines(\n\t\t\timageData,\n\t\t\tlayout.topPaddingLineCount,\n\t\t\tstartLineNumber,\n\t\t\tendLineNumber,\n\t\t\tminimapLineHeight,\n\t\t\tthis._lastRenderData\n\t\t);\n\n\t\t// Fetch rendering info from view model for rest of lines that need rendering.\n\t\tconst lineInfo = this._model.getMinimapLinesRenderingData(startLineNumber, endLineNumber, needed);\n\t\tconst tabSize = this._model.getOptions().tabSize;\n\t\tconst defaultBackground = this._model.options.defaultBackgroundColor;\n\t\tconst background = this._model.options.backgroundColor;\n\t\tconst foregroundAlpha = this._model.options.foregroundAlpha;\n\t\tconst tokensColorTracker = this._model.tokensColorTracker;\n\t\tconst useLighterFont = tokensColorTracker.backgroundIsLight();\n\t\tconst renderMinimap = this._model.options.renderMinimap;\n\t\tconst charRenderer = this._model.options.charRenderer();\n\t\tconst fontScale = this._model.options.fontScale;\n\t\tconst minimapCharWidth = this._model.options.minimapCharWidth;\n\n\t\tconst baseCharHeight = (renderMinimap === RenderMinimap.Text ? Constants.BASE_CHAR_HEIGHT : Constants.BASE_CHAR_HEIGHT + 1);\n\t\tconst renderMinimapLineHeight = baseCharHeight * fontScale;\n\t\tconst innerLinePadding = (minimapLineHeight > renderMinimapLineHeight ? Math.floor((minimapLineHeight - renderMinimapLineHeight) / 2) : 0);\n\n\t\t// Render the rest of lines\n\t\tconst backgroundA = background.a / 255;\n\t\tconst renderBackground = new RGBA8(\n\t\t\tMath.round((background.r - defaultBackground.r) * backgroundA + defaultBackground.r),\n\t\t\tMath.round((background.g - defaultBackground.g) * backgroundA + defaultBackground.g),\n\t\t\tMath.round((background.b - defaultBackground.b) * backgroundA + defaultBackground.b),\n\t\t\t255\n\t\t);\n\t\tlet dy = layout.topPaddingLineCount * minimapLineHeight;\n\t\tconst renderedLines: MinimapLine[] = [];\n\t\tfor (let lineIndex = 0, lineCount = endLineNumber - startLineNumber + 1; lineIndex < lineCount; lineIndex++) {\n\t\t\tif (needed[lineIndex]) {\n\t\t\t\tInnerMinimap._renderLine(\n\t\t\t\t\timageData,\n\t\t\t\t\trenderBackground,\n\t\t\t\t\tbackground.a,\n\t\t\t\t\tuseLighterFont,\n\t\t\t\t\trenderMinimap,\n\t\t\t\t\tminimapCharWidth,\n\t\t\t\t\ttokensColorTracker,\n\t\t\t\t\tforegroundAlpha,\n\t\t\t\t\tcharRenderer,\n\t\t\t\t\tdy,\n\t\t\t\t\tinnerLinePadding,\n\t\t\t\t\ttabSize,\n\t\t\t\t\tlineInfo[lineIndex]!,\n\t\t\t\t\tfontScale,\n\t\t\t\t\tminimapLineHeight\n\t\t\t\t);\n\t\t\t}\n\t\t\trenderedLines[lineIndex] = new MinimapLine(dy);\n\t\t\tdy += minimapLineHeight;\n\t\t}\n\n\t\tconst dirtyY1 = (_dirtyY1 === -1 ? 0 : _dirtyY1);\n\t\tconst dirtyY2 = (_dirtyY2 === -1 ? imageData.height : _dirtyY2);\n\t\tconst dirtyHeight = dirtyY2 - dirtyY1;\n\n\t\t// Finally, paint to the canvas\n\t\tconst ctx = this._canvas.domNode.getContext('2d')!;\n\t\tctx.putImageData(imageData, 0, 0, 0, dirtyY1, imageData.width, dirtyHeight);\n\n\t\t// Save rendered data for reuse on next frame if possible\n\t\treturn new RenderData(\n\t\t\tlayout,\n\t\t\timageData,\n\t\t\trenderedLines\n\t\t);\n\t}\n\n\tprivate static _renderUntouchedLines(\n\t\ttarget: ImageData,\n\t\ttopPaddingLineCount: number,\n\t\tstartLineNumber: number,\n\t\tendLineNumber: number,\n\t\tminimapLineHeight: number,\n\t\tlastRenderData: RenderData | null,\n\t): [number, number, boolean[]] {\n\n\t\tconst needed: boolean[] = [];\n\t\tif (!lastRenderData) {\n\t\t\tfor (let i = 0, len = endLineNumber - startLineNumber + 1; i < len; i++) {\n\t\t\t\tneeded[i] = true;\n\t\t\t}\n\t\t\treturn [-1, -1, needed];\n\t\t}\n\n\t\tconst _lastData = lastRenderData._get();\n\t\tconst lastTargetData = _lastData.imageData.data;\n\t\tconst lastStartLineNumber = _lastData.rendLineNumberStart;\n\t\tconst lastLines = _lastData.lines;\n\t\tconst lastLinesLength = lastLines.length;\n\t\tconst WIDTH = target.width;\n\t\tconst targetData = target.data;\n\n\t\tconst maxDestPixel = (endLineNumber - startLineNumber + 1) * minimapLineHeight * WIDTH * 4;\n\t\tlet dirtyPixel1 = -1; // the pixel offset up to which all the data is equal to the prev frame\n\t\tlet dirtyPixel2 = -1; // the pixel offset after which all the data is equal to the prev frame\n\n\t\tlet copySourceStart = -1;\n\t\tlet copySourceEnd = -1;\n\t\tlet copyDestStart = -1;\n\t\tlet copyDestEnd = -1;\n\n\t\tlet dest_dy = topPaddingLineCount * minimapLineHeight;\n\t\tfor (let lineNumber = startLineNumber; lineNumber <= endLineNumber; lineNumber++) {\n\t\t\tconst lineIndex = lineNumber - startLineNumber;\n\t\t\tconst lastLineIndex = lineNumber - lastStartLineNumber;\n\t\t\tconst source_dy = (lastLineIndex >= 0 && lastLineIndex < lastLinesLength ? lastLines[lastLineIndex].dy : -1);\n\n\t\t\tif (source_dy === -1) {\n\t\t\t\tneeded[lineIndex] = true;\n\t\t\t\tdest_dy += minimapLineHeight;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst sourceStart = source_dy * WIDTH * 4;\n\t\t\tconst sourceEnd = (source_dy + minimapLineHeight) * WIDTH * 4;\n\t\t\tconst destStart = dest_dy * WIDTH * 4;\n\t\t\tconst destEnd = (dest_dy + minimapLineHeight) * WIDTH * 4;\n\n\t\t\tif (copySourceEnd === sourceStart && copyDestEnd === destStart) {\n\t\t\t\t// contiguous zone => extend copy request\n\t\t\t\tcopySourceEnd = sourceEnd;\n\t\t\t\tcopyDestEnd = destEnd;\n\t\t\t} else {\n\t\t\t\tif (copySourceStart !== -1) {\n\t\t\t\t\t// flush existing copy request\n\t\t\t\t\ttargetData.set(lastTargetData.subarray(copySourceStart, copySourceEnd), copyDestStart);\n\t\t\t\t\tif (dirtyPixel1 === -1 && copySourceStart === 0 && copySourceStart === copyDestStart) {\n\t\t\t\t\t\tdirtyPixel1 = copySourceEnd;\n\t\t\t\t\t}\n\t\t\t\t\tif (dirtyPixel2 === -1 && copySourceEnd === maxDestPixel && copySourceStart === copyDestStart) {\n\t\t\t\t\t\tdirtyPixel2 = copySourceStart;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcopySourceStart = sourceStart;\n\t\t\t\tcopySourceEnd = sourceEnd;\n\t\t\t\tcopyDestStart = destStart;\n\t\t\t\tcopyDestEnd = destEnd;\n\t\t\t}\n\n\t\t\tneeded[lineIndex] = false;\n\t\t\tdest_dy += minimapLineHeight;\n\t\t}\n\n\t\tif (copySourceStart !== -1) {\n\t\t\t// flush existing copy request\n\t\t\ttargetData.set(lastTargetData.subarray(copySourceStart, copySourceEnd), copyDestStart);\n\t\t\tif (dirtyPixel1 === -1 && copySourceStart === 0 && copySourceStart === copyDestStart) {\n\t\t\t\tdirtyPixel1 = copySourceEnd;\n\t\t\t}\n\t\t\tif (dirtyPixel2 === -1 && copySourceEnd === maxDestPixel && copySourceStart === copyDestStart) {\n\t\t\t\tdirtyPixel2 = copySourceStart;\n\t\t\t}\n\t\t}\n\n\t\tconst dirtyY1 = (dirtyPixel1 === -1 ? -1 : dirtyPixel1 / (WIDTH * 4));\n\t\tconst dirtyY2 = (dirtyPixel2 === -1 ? -1 : dirtyPixel2 / (WIDTH * 4));\n\n\t\treturn [dirtyY1, dirtyY2, needed];\n\t}\n\n\tprivate static _renderLine(\n\t\ttarget: ImageData,\n\t\tbackgroundColor: RGBA8,\n\t\tbackgroundAlpha: number,\n\t\tuseLighterFont: boolean,\n\t\trenderMinimap: RenderMinimap,\n\t\tcharWidth: number,\n\t\tcolorTracker: MinimapTokensColorTracker,\n\t\tforegroundAlpha: number,\n\t\tminimapCharRenderer: MinimapCharRenderer,\n\t\tdy: number,\n\t\tinnerLinePadding: number,\n\t\ttabSize: number,\n\t\tlineData: ViewLineData,\n\t\tfontScale: number,\n\t\tminimapLineHeight: number\n\t): void {\n\t\tconst content = lineData.content;\n\t\tconst tokens = lineData.tokens;\n\t\tconst maxDx = target.width - charWidth;\n\t\tconst force1pxHeight = (minimapLineHeight === 1);\n\n\t\tlet dx = MINIMAP_GUTTER_WIDTH;\n\t\tlet charIndex = 0;\n\t\tlet tabsCharDelta = 0;\n\n\t\tfor (let tokenIndex = 0, tokensLen = tokens.getCount(); tokenIndex < tokensLen; tokenIndex++) {\n\t\t\tconst tokenEndIndex = tokens.getEndOffset(tokenIndex);\n\t\t\tconst tokenColorId = tokens.getForeground(tokenIndex);\n\t\t\tconst tokenColor = colorTracker.getColor(tokenColorId);\n\n\t\t\tfor (; charIndex < tokenEndIndex; charIndex++) {\n\t\t\t\tif (dx > maxDx) {\n\t\t\t\t\t// hit edge of minimap\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst charCode = content.charCodeAt(charIndex);\n\n\t\t\t\tif (charCode === CharCode.Tab) {\n\t\t\t\t\tconst insertSpacesCount = tabSize - (charIndex + tabsCharDelta) % tabSize;\n\t\t\t\t\ttabsCharDelta += insertSpacesCount - 1;\n\t\t\t\t\t// No need to render anything since tab is invisible\n\t\t\t\t\tdx += insertSpacesCount * charWidth;\n\t\t\t\t} else if (charCode === CharCode.Space) {\n\t\t\t\t\t// No need to render anything since space is invisible\n\t\t\t\t\tdx += charWidth;\n\t\t\t\t} else {\n\t\t\t\t\t// Render twice for a full width character\n\t\t\t\t\tconst count = strings.isFullWidthCharacter(charCode) ? 2 : 1;\n\n\t\t\t\t\tfor (let i = 0; i < count; i++) {\n\t\t\t\t\t\tif (renderMinimap === RenderMinimap.Blocks) {\n\t\t\t\t\t\t\tminimapCharRenderer.blockRenderChar(target, dx, dy + innerLinePadding, tokenColor, foregroundAlpha, backgroundColor, backgroundAlpha, force1pxHeight);\n\t\t\t\t\t\t} else { // RenderMinimap.Text\n\t\t\t\t\t\t\tminimapCharRenderer.renderChar(target, dx, dy + innerLinePadding, charCode, tokenColor, foregroundAlpha, backgroundColor, backgroundAlpha, fontScale, useLighterFont, force1pxHeight);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tdx += charWidth;\n\n\t\t\t\t\t\tif (dx > maxDx) {\n\t\t\t\t\t\t\t// hit edge of minimap\n\t\t\t\t\t\t\treturn;\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}\n\t}\n}\n\nclass ContiguousLineMap {\n\n\tprivate readonly _startLineNumber: number;\n\tprivate readonly _endLineNumber: number;\n\tprivate readonly _defaultValue: T;\n\tprivate readonly _values: T[];\n\n\tconstructor(startLineNumber: number, endLineNumber: number, defaultValue: T) {\n\t\tthis._startLineNumber = startLineNumber;\n\t\tthis._endLineNumber = endLineNumber;\n\t\tthis._defaultValue = defaultValue;\n\t\tthis._values = [];\n\t\tfor (let i = 0, count = this._endLineNumber - this._startLineNumber + 1; i < count; i++) {\n\t\t\tthis._values[i] = defaultValue;\n\t\t}\n\t}\n\n\tpublic has(lineNumber: number): boolean {\n\t\treturn (this.get(lineNumber) !== this._defaultValue);\n\t}\n\n\tpublic set(lineNumber: number, value: T): void {\n\t\tif (lineNumber < this._startLineNumber || lineNumber > this._endLineNumber) {\n\t\t\treturn;\n\t\t}\n\t\tthis._values[lineNumber - this._startLineNumber] = value;\n\t}\n\n\tpublic get(lineNumber: number): T {\n\t\tif (lineNumber < this._startLineNumber || lineNumber > this._endLineNumber) {\n\t\t\treturn this._defaultValue;\n\t\t}\n\t\treturn this._values[lineNumber - this._startLineNumber];\n\t}\n}\n\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\nimport { localize } from 'vs/nls';\nimport { registerColor } from 'vs/platform/theme/common/colorRegistry';\n\nexport const multiDiffEditorHeaderBackground = registerColor(\n\t'multiDiffEditor.headerBackground',\n\t{ dark: '#262626', light: 'tab.inactiveBackground', hcDark: 'tab.inactiveBackground', hcLight: 'tab.inactiveBackground', },\n\tlocalize('multiDiffEditor.headerBackground', 'The background color of the diff editor\\'s header')\n);\n\nexport const multiDiffEditorBackground = registerColor(\n\t'multiDiffEditor.background',\n\t{ dark: 'editorBackground', light: 'editorBackground', hcDark: 'editorBackground', hcLight: 'editorBackground', },\n\tlocalize('multiDiffEditor.background', 'The background color of the multi file diff editor')\n);\n\nexport const multiDiffEditorBorder = registerColor(\n\t'multiDiffEditor.border',\n\t{ dark: 'sideBarSectionHeader.border', light: '#cccccc', hcDark: 'sideBarSectionHeader.border', hcLight: '#cccccc', },\n\tlocalize('multiDiffEditor.border', 'The border color of the multi file diff editor')\n);\n\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\nimport 'vs/css!./symbolIcons';\nimport { localize } from 'vs/nls';\nimport { foreground, registerColor } from 'vs/platform/theme/common/colorRegistry';\n\nexport const SYMBOL_ICON_ARRAY_FOREGROUND = registerColor('symbolIcon.arrayForeground', {\n\tdark: foreground,\n\tlight: foreground,\n\thcDark: foreground,\n\thcLight: foreground,\n}, localize('symbolIcon.arrayForeground', 'The foreground color for array symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\n\nexport const SYMBOL_ICON_BOOLEAN_FOREGROUND = registerColor('symbolIcon.booleanForeground', {\n\tdark: foreground,\n\tlight: foreground,\n\thcDark: foreground,\n\thcLight: foreground,\n}, localize('symbolIcon.booleanForeground', 'The foreground color for boolean symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\n\nexport const SYMBOL_ICON_CLASS_FOREGROUND = registerColor('symbolIcon.classForeground', {\n\tdark: '#EE9D28',\n\tlight: '#D67E00',\n\thcDark: '#EE9D28',\n\thcLight: '#D67E00'\n}, localize('symbolIcon.classForeground', 'The foreground color for class symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\n\nexport const SYMBOL_ICON_COLOR_FOREGROUND = registerColor('symbolIcon.colorForeground', {\n\tdark: foreground,\n\tlight: foreground,\n\thcDark: foreground,\n\thcLight: foreground\n}, localize('symbolIcon.colorForeground', 'The foreground color for color symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\n\nexport const SYMBOL_ICON_CONSTANT_FOREGROUND = registerColor('symbolIcon.constantForeground', {\n\tdark: foreground,\n\tlight: foreground,\n\thcDark: foreground,\n\thcLight: foreground\n}, localize('symbolIcon.constantForeground', 'The foreground color for constant symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\n\nexport const SYMBOL_ICON_CONSTRUCTOR_FOREGROUND = registerColor('symbolIcon.constructorForeground', {\n\tdark: '#B180D7',\n\tlight: '#652D90',\n\thcDark: '#B180D7',\n\thcLight: '#652D90'\n}, localize('symbolIcon.constructorForeground', 'The foreground color for constructor symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\n\nexport const SYMBOL_ICON_ENUMERATOR_FOREGROUND = registerColor('symbolIcon.enumeratorForeground', {\n\tdark: '#EE9D28',\n\tlight: '#D67E00',\n\thcDark: '#EE9D28',\n\thcLight: '#D67E00'\n}, localize('symbolIcon.enumeratorForeground', 'The foreground color for enumerator symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\n\nexport const SYMBOL_ICON_ENUMERATOR_MEMBER_FOREGROUND = registerColor('symbolIcon.enumeratorMemberForeground', {\n\tdark: '#75BEFF',\n\tlight: '#007ACC',\n\thcDark: '#75BEFF',\n\thcLight: '#007ACC'\n}, localize('symbolIcon.enumeratorMemberForeground', 'The foreground color for enumerator member symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\n\nexport const SYMBOL_ICON_EVENT_FOREGROUND = registerColor('symbolIcon.eventForeground', {\n\tdark: '#EE9D28',\n\tlight: '#D67E00',\n\thcDark: '#EE9D28',\n\thcLight: '#D67E00'\n}, localize('symbolIcon.eventForeground', 'The foreground color for event symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\n\nexport const SYMBOL_ICON_FIELD_FOREGROUND = registerColor('symbolIcon.fieldForeground', {\n\tdark: '#75BEFF',\n\tlight: '#007ACC',\n\thcDark: '#75BEFF',\n\thcLight: '#007ACC'\n}, localize('symbolIcon.fieldForeground', 'The foreground color for field symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\n\nexport const SYMBOL_ICON_FILE_FOREGROUND = registerColor('symbolIcon.fileForeground', {\n\tdark: foreground,\n\tlight: foreground,\n\thcDark: foreground,\n\thcLight: foreground\n}, localize('symbolIcon.fileForeground', 'The foreground color for file symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\n\nexport const SYMBOL_ICON_FOLDER_FOREGROUND = registerColor('symbolIcon.folderForeground', {\n\tdark: foreground,\n\tlight: foreground,\n\thcDark: foreground,\n\thcLight: foreground\n}, localize('symbolIcon.folderForeground', 'The foreground color for folder symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\n\nexport const SYMBOL_ICON_FUNCTION_FOREGROUND = registerColor('symbolIcon.functionForeground', {\n\tdark: '#B180D7',\n\tlight: '#652D90',\n\thcDark: '#B180D7',\n\thcLight: '#652D90'\n}, localize('symbolIcon.functionForeground', 'The foreground color for function symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\n\nexport const SYMBOL_ICON_INTERFACE_FOREGROUND = registerColor('symbolIcon.interfaceForeground', {\n\tdark: '#75BEFF',\n\tlight: '#007ACC',\n\thcDark: '#75BEFF',\n\thcLight: '#007ACC'\n}, localize('symbolIcon.interfaceForeground', 'The foreground color for interface symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\n\nexport const SYMBOL_ICON_KEY_FOREGROUND = registerColor('symbolIcon.keyForeground', {\n\tdark: foreground,\n\tlight: foreground,\n\thcDark: foreground,\n\thcLight: foreground\n}, localize('symbolIcon.keyForeground', 'The foreground color for key symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\n\nexport const SYMBOL_ICON_KEYWORD_FOREGROUND = registerColor('symbolIcon.keywordForeground', {\n\tdark: foreground,\n\tlight: foreground,\n\thcDark: foreground,\n\thcLight: foreground\n}, localize('symbolIcon.keywordForeground', 'The foreground color for keyword symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\n\nexport const SYMBOL_ICON_METHOD_FOREGROUND = registerColor('symbolIcon.methodForeground', {\n\tdark: '#B180D7',\n\tlight: '#652D90',\n\thcDark: '#B180D7',\n\thcLight: '#652D90'\n}, localize('symbolIcon.methodForeground', 'The foreground color for method symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\n\nexport const SYMBOL_ICON_MODULE_FOREGROUND = registerColor('symbolIcon.moduleForeground', {\n\tdark: foreground,\n\tlight: foreground,\n\thcDark: foreground,\n\thcLight: foreground\n}, localize('symbolIcon.moduleForeground', 'The foreground color for module symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\n\nexport const SYMBOL_ICON_NAMESPACE_FOREGROUND = registerColor('symbolIcon.namespaceForeground', {\n\tdark: foreground,\n\tlight: foreground,\n\thcDark: foreground,\n\thcLight: foreground\n}, localize('symbolIcon.namespaceForeground', 'The foreground color for namespace symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\n\nexport const SYMBOL_ICON_NULL_FOREGROUND = registerColor('symbolIcon.nullForeground', {\n\tdark: foreground,\n\tlight: foreground,\n\thcDark: foreground,\n\thcLight: foreground\n}, localize('symbolIcon.nullForeground', 'The foreground color for null symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\n\nexport const SYMBOL_ICON_NUMBER_FOREGROUND = registerColor('symbolIcon.numberForeground', {\n\tdark: foreground,\n\tlight: foreground,\n\thcDark: foreground,\n\thcLight: foreground\n}, localize('symbolIcon.numberForeground', 'The foreground color for number symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\n\nexport const SYMBOL_ICON_OBJECT_FOREGROUND = registerColor('symbolIcon.objectForeground', {\n\tdark: foreground,\n\tlight: foreground,\n\thcDark: foreground,\n\thcLight: foreground\n}, localize('symbolIcon.objectForeground', 'The foreground color for object symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\n\nexport const SYMBOL_ICON_OPERATOR_FOREGROUND = registerColor('symbolIcon.operatorForeground', {\n\tdark: foreground,\n\tlight: foreground,\n\thcDark: foreground,\n\thcLight: foreground\n}, localize('symbolIcon.operatorForeground', 'The foreground color for operator symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\n\nexport const SYMBOL_ICON_PACKAGE_FOREGROUND = registerColor('symbolIcon.packageForeground', {\n\tdark: foreground,\n\tlight: foreground,\n\thcDark: foreground,\n\thcLight: foreground\n}, localize('symbolIcon.packageForeground', 'The foreground color for package symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\n\nexport const SYMBOL_ICON_PROPERTY_FOREGROUND = registerColor('symbolIcon.propertyForeground', {\n\tdark: foreground,\n\tlight: foreground,\n\thcDark: foreground,\n\thcLight: foreground\n}, localize('symbolIcon.propertyForeground', 'The foreground color for property symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\n\nexport const SYMBOL_ICON_REFERENCE_FOREGROUND = registerColor('symbolIcon.referenceForeground', {\n\tdark: foreground,\n\tlight: foreground,\n\thcDark: foreground,\n\thcLight: foreground\n}, localize('symbolIcon.referenceForeground', 'The foreground color for reference symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\n\nexport const SYMBOL_ICON_SNIPPET_FOREGROUND = registerColor('symbolIcon.snippetForeground', {\n\tdark: foreground,\n\tlight: foreground,\n\thcDark: foreground,\n\thcLight: foreground\n}, localize('symbolIcon.snippetForeground', 'The foreground color for snippet symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\n\nexport const SYMBOL_ICON_STRING_FOREGROUND = registerColor('symbolIcon.stringForeground', {\n\tdark: foreground,\n\tlight: foreground,\n\thcDark: foreground,\n\thcLight: foreground\n}, localize('symbolIcon.stringForeground', 'The foreground color for string symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\n\nexport const SYMBOL_ICON_STRUCT_FOREGROUND = registerColor('symbolIcon.structForeground', {\n\tdark: foreground,\n\tlight: foreground,\n\thcDark: foreground,\n\thcLight: foreground,\n}, localize('symbolIcon.structForeground', 'The foreground color for struct symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\n\nexport const SYMBOL_ICON_TEXT_FOREGROUND = registerColor('symbolIcon.textForeground', {\n\tdark: foreground,\n\tlight: foreground,\n\thcDark: foreground,\n\thcLight: foreground\n}, localize('symbolIcon.textForeground', 'The foreground color for text symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\n\nexport const SYMBOL_ICON_TYPEPARAMETER_FOREGROUND = registerColor('symbolIcon.typeParameterForeground', {\n\tdark: foreground,\n\tlight: foreground,\n\thcDark: foreground,\n\thcLight: foreground\n}, localize('symbolIcon.typeParameterForeground', 'The foreground color for type parameter symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\n\nexport const SYMBOL_ICON_UNIT_FOREGROUND = registerColor('symbolIcon.unitForeground', {\n\tdark: foreground,\n\tlight: foreground,\n\thcDark: foreground,\n\thcLight: foreground\n}, localize('symbolIcon.unitForeground', 'The foreground color for unit symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\n\nexport const SYMBOL_ICON_VARIABLE_FOREGROUND = registerColor('symbolIcon.variableForeground', {\n\tdark: '#75BEFF',\n\tlight: '#007ACC',\n\thcDark: '#75BEFF',\n\thcLight: '#007ACC',\n}, localize('symbolIcon.variableForeground', 'The foreground color for variable symbols. These symbols appear in the outline, breadcrumb, and suggest widget.'));\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\nimport 'vs/base/browser/ui/codicons/codiconStyles'; // The codicon symbol styles are defined here and must be loaded\nimport { Codicon } from 'vs/base/common/codicons';\nimport { ThemeIcon } from 'vs/base/common/themables';\nimport { ResolvedKeybinding } from 'vs/base/common/keybindings';\nimport { CodeAction } from 'vs/editor/common/languages';\nimport { CodeActionItem, CodeActionKind } from 'vs/editor/contrib/codeAction/common/types';\nimport 'vs/editor/contrib/symbolIcons/browser/symbolIcons'; // The codicon symbol colors are defined here and must be loaded to get colors\nimport { localize } from 'vs/nls';\nimport { ActionListItemKind, IActionListItem } from 'vs/platform/actionWidget/browser/actionList';\nimport { HierarchicalKind } from 'vs/base/common/hierarchicalKind';\n\ninterface ActionGroup {\n\treadonly kind: HierarchicalKind;\n\treadonly title: string;\n\treadonly icon?: ThemeIcon;\n}\n\nconst uncategorizedCodeActionGroup = Object.freeze({ kind: HierarchicalKind.Empty, title: localize('codeAction.widget.id.more', 'More Actions...') });\n\nconst codeActionGroups = Object.freeze([\n\t{ kind: CodeActionKind.QuickFix, title: localize('codeAction.widget.id.quickfix', 'Quick Fix') },\n\t{ kind: CodeActionKind.RefactorExtract, title: localize('codeAction.widget.id.extract', 'Extract'), icon: Codicon.wrench },\n\t{ kind: CodeActionKind.RefactorInline, title: localize('codeAction.widget.id.inline', 'Inline'), icon: Codicon.wrench },\n\t{ kind: CodeActionKind.RefactorRewrite, title: localize('codeAction.widget.id.convert', 'Rewrite'), icon: Codicon.wrench },\n\t{ kind: CodeActionKind.RefactorMove, title: localize('codeAction.widget.id.move', 'Move'), icon: Codicon.wrench },\n\t{ kind: CodeActionKind.SurroundWith, title: localize('codeAction.widget.id.surround', 'Surround With'), icon: Codicon.surroundWith },\n\t{ kind: CodeActionKind.Source, title: localize('codeAction.widget.id.source', 'Source Action'), icon: Codicon.symbolFile },\n\tuncategorizedCodeActionGroup,\n]);\n\nexport function toMenuItems(\n\tinputCodeActions: readonly CodeActionItem[],\n\tshowHeaders: boolean,\n\tkeybindingResolver: (action: CodeAction) => ResolvedKeybinding | undefined\n): IActionListItem[] {\n\tif (!showHeaders) {\n\t\treturn inputCodeActions.map((action): IActionListItem => {\n\t\t\treturn {\n\t\t\t\tkind: ActionListItemKind.Action,\n\t\t\t\titem: action,\n\t\t\t\tgroup: uncategorizedCodeActionGroup,\n\t\t\t\tdisabled: !!action.action.disabled,\n\t\t\t\tlabel: action.action.disabled || action.action.title,\n\t\t\t\tcanPreview: !!action.action.edit?.edits.length,\n\t\t\t};\n\t\t});\n\t}\n\n\t// Group code actions\n\tconst menuEntries = codeActionGroups.map(group => ({ group, actions: [] as CodeActionItem[] }));\n\n\tfor (const action of inputCodeActions) {\n\t\tconst kind = action.action.kind ? new HierarchicalKind(action.action.kind) : HierarchicalKind.None;\n\t\tfor (const menuEntry of menuEntries) {\n\t\t\tif (menuEntry.group.kind.contains(kind)) {\n\t\t\t\tmenuEntry.actions.push(action);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tconst allMenuItems: IActionListItem[] = [];\n\tfor (const menuEntry of menuEntries) {\n\t\tif (menuEntry.actions.length) {\n\t\t\tallMenuItems.push({ kind: ActionListItemKind.Header, group: menuEntry.group });\n\t\t\tfor (const action of menuEntry.actions) {\n\t\t\t\tconst group = menuEntry.group;\n\t\t\t\tallMenuItems.push({\n\t\t\t\t\tkind: ActionListItemKind.Action,\n\t\t\t\t\titem: action,\n\t\t\t\t\tgroup: action.action.isAI ? { title: group.title, kind: group.kind, icon: Codicon.sparkle } : group,\n\t\t\t\t\tlabel: action.action.title,\n\t\t\t\t\tdisabled: !!action.action.disabled,\n\t\t\t\t\tkeybinding: keybindingResolver(action.action),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\treturn allMenuItems;\n}\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 *--------------------------------------------------------------------------------------------*/\nimport { IButtonStyles } from 'vs/base/browser/ui/button/button';\nimport { IKeybindingLabelStyles } from 'vs/base/browser/ui/keybindingLabel/keybindingLabel';\nimport { ColorIdentifier, keybindingLabelBackground, keybindingLabelBorder, keybindingLabelBottomBorder, keybindingLabelForeground, asCssVariable, widgetShadow, buttonForeground, buttonSeparator, buttonBackground, buttonHoverBackground, buttonSecondaryForeground, buttonSecondaryBackground, buttonSecondaryHoverBackground, buttonBorder, progressBarBackground, inputActiveOptionBorder, inputActiveOptionForeground, inputActiveOptionBackground, editorWidgetBackground, editorWidgetForeground, contrastBorder, checkboxBorder, checkboxBackground, checkboxForeground, problemsErrorIconForeground, problemsWarningIconForeground, problemsInfoIconForeground, inputBackground, inputForeground, inputBorder, textLinkForeground, inputValidationInfoBorder, inputValidationInfoBackground, inputValidationInfoForeground, inputValidationWarningBorder, inputValidationWarningBackground, inputValidationWarningForeground, inputValidationErrorBorder, inputValidationErrorBackground, inputValidationErrorForeground, listFilterWidgetBackground, listFilterWidgetNoMatchesOutline, listFilterWidgetOutline, listFilterWidgetShadow, badgeBackground, badgeForeground, breadcrumbsBackground, breadcrumbsForeground, breadcrumbsFocusForeground, breadcrumbsActiveSelectionForeground, activeContrastBorder, listActiveSelectionBackground, listActiveSelectionForeground, listActiveSelectionIconForeground, listDropOverBackground, listFocusAndSelectionOutline, listFocusBackground, listFocusForeground, listFocusOutline, listHoverBackground, listHoverForeground, listInactiveFocusBackground, listInactiveFocusOutline, listInactiveSelectionBackground, listInactiveSelectionForeground, listInactiveSelectionIconForeground, tableColumnsBorder, tableOddRowsBackgroundColor, treeIndentGuidesStroke, asCssVariableWithDefault, editorWidgetBorder, focusBorder, pickerGroupForeground, quickInputListFocusBackground, quickInputListFocusForeground, quickInputListFocusIconForeground, selectBackground, selectBorder, selectForeground, selectListBackground, treeInactiveIndentGuidesStroke, menuBorder, menuForeground, menuBackground, menuSelectionForeground, menuSelectionBackground, menuSelectionBorder, menuSeparatorBackground, scrollbarShadow, scrollbarSliderActiveBackground, scrollbarSliderBackground, scrollbarSliderHoverBackground, listDropBetweenBackground } from 'vs/platform/theme/common/colorRegistry';\nimport { IProgressBarStyles } from 'vs/base/browser/ui/progressbar/progressbar';\nimport { ICheckboxStyles, IToggleStyles } from 'vs/base/browser/ui/toggle/toggle';\nimport { IDialogStyles } from 'vs/base/browser/ui/dialog/dialog';\nimport { IInputBoxStyles } from 'vs/base/browser/ui/inputbox/inputBox';\nimport { IFindWidgetStyles } from 'vs/base/browser/ui/tree/abstractTree';\nimport { ICountBadgeStyles } from 'vs/base/browser/ui/countBadge/countBadge';\nimport { IBreadcrumbsWidgetStyles } from 'vs/base/browser/ui/breadcrumbs/breadcrumbsWidget';\nimport { IListStyles } from 'vs/base/browser/ui/list/listWidget';\nimport { ISelectBoxStyles } from 'vs/base/browser/ui/selectBox/selectBox';\nimport { Color } from 'vs/base/common/color';\nimport { IMenuStyles } from 'vs/base/browser/ui/menu/menu';\n\nexport type IStyleOverride = {\n\t[P in keyof T]?: ColorIdentifier | undefined;\n};\n\nfunction overrideStyles(override: IStyleOverride, styles: T): any {\n\tconst result: { [P in keyof T]: string | undefined } = { ...styles };\n\tfor (const key in override) {\n\t\tconst val = override[key];\n\t\tresult[key] = val !== undefined ? asCssVariable(val) : undefined;\n\t}\n\treturn result;\n}\n\nexport const defaultKeybindingLabelStyles: IKeybindingLabelStyles = {\n\tkeybindingLabelBackground: asCssVariable(keybindingLabelBackground),\n\tkeybindingLabelForeground: asCssVariable(keybindingLabelForeground),\n\tkeybindingLabelBorder: asCssVariable(keybindingLabelBorder),\n\tkeybindingLabelBottomBorder: asCssVariable(keybindingLabelBottomBorder),\n\tkeybindingLabelShadow: asCssVariable(widgetShadow)\n};\nexport const defaultButtonStyles: IButtonStyles = {\n\tbuttonForeground: asCssVariable(buttonForeground),\n\tbuttonSeparator: asCssVariable(buttonSeparator),\n\tbuttonBackground: asCssVariable(buttonBackground),\n\tbuttonHoverBackground: asCssVariable(buttonHoverBackground),\n\tbuttonSecondaryForeground: asCssVariable(buttonSecondaryForeground),\n\tbuttonSecondaryBackground: asCssVariable(buttonSecondaryBackground),\n\tbuttonSecondaryHoverBackground: asCssVariable(buttonSecondaryHoverBackground),\n\tbuttonBorder: asCssVariable(buttonBorder),\n};\n\nexport const defaultProgressBarStyles: IProgressBarStyles = {\n\tprogressBarBackground: asCssVariable(progressBarBackground)\n};\n\nexport const defaultToggleStyles: IToggleStyles = {\n\tinputActiveOptionBorder: asCssVariable(inputActiveOptionBorder),\n\tinputActiveOptionForeground: asCssVariable(inputActiveOptionForeground),\n\tinputActiveOptionBackground: asCssVariable(inputActiveOptionBackground)\n};\n\nexport const defaultCheckboxStyles: ICheckboxStyles = {\n\tcheckboxBackground: asCssVariable(checkboxBackground),\n\tcheckboxBorder: asCssVariable(checkboxBorder),\n\tcheckboxForeground: asCssVariable(checkboxForeground)\n};\n\nexport const defaultDialogStyles: IDialogStyles = {\n\tdialogBackground: asCssVariable(editorWidgetBackground),\n\tdialogForeground: asCssVariable(editorWidgetForeground),\n\tdialogShadow: asCssVariable(widgetShadow),\n\tdialogBorder: asCssVariable(contrastBorder),\n\terrorIconForeground: asCssVariable(problemsErrorIconForeground),\n\twarningIconForeground: asCssVariable(problemsWarningIconForeground),\n\tinfoIconForeground: asCssVariable(problemsInfoIconForeground),\n\ttextLinkForeground: asCssVariable(textLinkForeground)\n};\n\nexport const defaultInputBoxStyles: IInputBoxStyles = {\n\tinputBackground: asCssVariable(inputBackground),\n\tinputForeground: asCssVariable(inputForeground),\n\tinputBorder: asCssVariable(inputBorder),\n\tinputValidationInfoBorder: asCssVariable(inputValidationInfoBorder),\n\tinputValidationInfoBackground: asCssVariable(inputValidationInfoBackground),\n\tinputValidationInfoForeground: asCssVariable(inputValidationInfoForeground),\n\tinputValidationWarningBorder: asCssVariable(inputValidationWarningBorder),\n\tinputValidationWarningBackground: asCssVariable(inputValidationWarningBackground),\n\tinputValidationWarningForeground: asCssVariable(inputValidationWarningForeground),\n\tinputValidationErrorBorder: asCssVariable(inputValidationErrorBorder),\n\tinputValidationErrorBackground: asCssVariable(inputValidationErrorBackground),\n\tinputValidationErrorForeground: asCssVariable(inputValidationErrorForeground)\n};\n\nexport const defaultFindWidgetStyles: IFindWidgetStyles = {\n\tlistFilterWidgetBackground: asCssVariable(listFilterWidgetBackground),\n\tlistFilterWidgetOutline: asCssVariable(listFilterWidgetOutline),\n\tlistFilterWidgetNoMatchesOutline: asCssVariable(listFilterWidgetNoMatchesOutline),\n\tlistFilterWidgetShadow: asCssVariable(listFilterWidgetShadow),\n\tinputBoxStyles: defaultInputBoxStyles,\n\ttoggleStyles: defaultToggleStyles\n};\n\nexport const defaultCountBadgeStyles: ICountBadgeStyles = {\n\tbadgeBackground: asCssVariable(badgeBackground),\n\tbadgeForeground: asCssVariable(badgeForeground),\n\tbadgeBorder: asCssVariable(contrastBorder)\n};\n\nexport const defaultBreadcrumbsWidgetStyles: IBreadcrumbsWidgetStyles = {\n\tbreadcrumbsBackground: asCssVariable(breadcrumbsBackground),\n\tbreadcrumbsForeground: asCssVariable(breadcrumbsForeground),\n\tbreadcrumbsHoverForeground: asCssVariable(breadcrumbsFocusForeground),\n\tbreadcrumbsFocusForeground: asCssVariable(breadcrumbsFocusForeground),\n\tbreadcrumbsFocusAndSelectionForeground: asCssVariable(breadcrumbsActiveSelectionForeground)\n};\n\nexport const defaultListStyles: IListStyles = {\n\tlistBackground: undefined,\n\tlistInactiveFocusForeground: undefined,\n\tlistFocusBackground: asCssVariable(listFocusBackground),\n\tlistFocusForeground: asCssVariable(listFocusForeground),\n\tlistFocusOutline: asCssVariable(listFocusOutline),\n\tlistActiveSelectionBackground: asCssVariable(listActiveSelectionBackground),\n\tlistActiveSelectionForeground: asCssVariable(listActiveSelectionForeground),\n\tlistActiveSelectionIconForeground: asCssVariable(listActiveSelectionIconForeground),\n\tlistFocusAndSelectionOutline: asCssVariable(listFocusAndSelectionOutline),\n\tlistFocusAndSelectionBackground: asCssVariable(listActiveSelectionBackground),\n\tlistFocusAndSelectionForeground: asCssVariable(listActiveSelectionForeground),\n\tlistInactiveSelectionBackground: asCssVariable(listInactiveSelectionBackground),\n\tlistInactiveSelectionIconForeground: asCssVariable(listInactiveSelectionIconForeground),\n\tlistInactiveSelectionForeground: asCssVariable(listInactiveSelectionForeground),\n\tlistInactiveFocusBackground: asCssVariable(listInactiveFocusBackground),\n\tlistInactiveFocusOutline: asCssVariable(listInactiveFocusOutline),\n\tlistHoverBackground: asCssVariable(listHoverBackground),\n\tlistHoverForeground: asCssVariable(listHoverForeground),\n\tlistDropOverBackground: asCssVariable(listDropOverBackground),\n\tlistDropBetweenBackground: asCssVariable(listDropBetweenBackground),\n\tlistSelectionOutline: asCssVariable(activeContrastBorder),\n\tlistHoverOutline: asCssVariable(activeContrastBorder),\n\ttreeIndentGuidesStroke: asCssVariable(treeIndentGuidesStroke),\n\ttreeInactiveIndentGuidesStroke: asCssVariable(treeInactiveIndentGuidesStroke),\n\ttreeStickyScrollBackground: undefined,\n\ttreeStickyScrollBorder: undefined,\n\ttreeStickyScrollShadow: undefined,\n\ttableColumnsBorder: asCssVariable(tableColumnsBorder),\n\ttableOddRowsBackgroundColor: asCssVariable(tableOddRowsBackgroundColor),\n};\n\nexport function getListStyles(override: IStyleOverride): IListStyles {\n\treturn overrideStyles(override, defaultListStyles);\n}\n\nexport const defaultSelectBoxStyles: ISelectBoxStyles = {\n\tselectBackground: asCssVariable(selectBackground),\n\tselectListBackground: asCssVariable(selectListBackground),\n\tselectForeground: asCssVariable(selectForeground),\n\tdecoratorRightForeground: asCssVariable(pickerGroupForeground),\n\tselectBorder: asCssVariable(selectBorder),\n\tfocusBorder: asCssVariable(focusBorder),\n\tlistFocusBackground: asCssVariable(quickInputListFocusBackground),\n\tlistInactiveSelectionIconForeground: asCssVariable(quickInputListFocusIconForeground),\n\tlistFocusForeground: asCssVariable(quickInputListFocusForeground),\n\tlistFocusOutline: asCssVariableWithDefault(activeContrastBorder, Color.transparent.toString()),\n\tlistHoverBackground: asCssVariable(listHoverBackground),\n\tlistHoverForeground: asCssVariable(listHoverForeground),\n\tlistHoverOutline: asCssVariable(activeContrastBorder),\n\tselectListBorder: asCssVariable(editorWidgetBorder),\n\tlistBackground: undefined,\n\tlistActiveSelectionBackground: undefined,\n\tlistActiveSelectionForeground: undefined,\n\tlistActiveSelectionIconForeground: undefined,\n\tlistFocusAndSelectionBackground: undefined,\n\tlistDropOverBackground: undefined,\n\tlistDropBetweenBackground: undefined,\n\tlistInactiveSelectionBackground: undefined,\n\tlistInactiveSelectionForeground: undefined,\n\tlistInactiveFocusBackground: undefined,\n\tlistInactiveFocusOutline: undefined,\n\tlistSelectionOutline: undefined,\n\tlistFocusAndSelectionForeground: undefined,\n\tlistFocusAndSelectionOutline: undefined,\n\tlistInactiveFocusForeground: undefined,\n\ttableColumnsBorder: undefined,\n\ttableOddRowsBackgroundColor: undefined,\n\ttreeIndentGuidesStroke: undefined,\n\ttreeInactiveIndentGuidesStroke: undefined,\n\ttreeStickyScrollBackground: undefined,\n\ttreeStickyScrollBorder: undefined,\n\ttreeStickyScrollShadow: undefined\n};\n\nexport const defaultMenuStyles: IMenuStyles = {\n\tshadowColor: asCssVariable(widgetShadow),\n\tborderColor: asCssVariable(menuBorder),\n\tforegroundColor: asCssVariable(menuForeground),\n\tbackgroundColor: asCssVariable(menuBackground),\n\tselectionForegroundColor: asCssVariable(menuSelectionForeground),\n\tselectionBackgroundColor: asCssVariable(menuSelectionBackground),\n\tselectionBorderColor: asCssVariable(menuSelectionBorder),\n\tseparatorColor: asCssVariable(menuSeparatorBackground),\n\tscrollbarShadow: asCssVariable(scrollbarShadow),\n\tscrollbarSliderBackground: asCssVariable(scrollbarSliderBackground),\n\tscrollbarSliderHoverBackground: asCssVariable(scrollbarSliderHoverBackground),\n\tscrollbarSliderActiveBackground: asCssVariable(scrollbarSliderActiveBackground)\n};\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\nimport * as dom from 'vs/base/browser/dom';\nimport { CountBadge } from 'vs/base/browser/ui/countBadge/countBadge';\nimport { HighlightedLabel } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel';\nimport { IconLabel } from 'vs/base/browser/ui/iconLabel/iconLabel';\nimport { IIdentityProvider, IKeyboardNavigationLabelProvider, IListVirtualDelegate } from 'vs/base/browser/ui/list/list';\nimport { IListAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget';\nimport { IAsyncDataSource, ITreeNode, ITreeRenderer } from 'vs/base/browser/ui/tree/tree';\nimport { createMatches, FuzzyScore, IMatch } from 'vs/base/common/filters';\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport { basename, dirname } from 'vs/base/common/resources';\nimport { ITextModelService } from 'vs/editor/common/services/resolverService';\nimport { localize } from 'vs/nls';\nimport { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';\nimport { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';\nimport { ILabelService } from 'vs/platform/label/common/label';\nimport { defaultCountBadgeStyles } from 'vs/platform/theme/browser/defaultStyles';\nimport { FileReferences, OneReference, ReferencesModel } from '../referencesModel';\n\n//#region data source\n\nexport type TreeElement = FileReferences | OneReference;\n\nexport class DataSource implements IAsyncDataSource {\n\n\tconstructor(@ITextModelService private readonly _resolverService: ITextModelService) { }\n\n\thasChildren(element: ReferencesModel | FileReferences | TreeElement): boolean {\n\t\tif (element instanceof ReferencesModel) {\n\t\t\treturn true;\n\t\t}\n\t\tif (element instanceof FileReferences) {\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tgetChildren(element: ReferencesModel | FileReferences | TreeElement): TreeElement[] | Promise {\n\t\tif (element instanceof ReferencesModel) {\n\t\t\treturn element.groups;\n\t\t}\n\n\t\tif (element instanceof FileReferences) {\n\t\t\treturn element.resolve(this._resolverService).then(val => {\n\t\t\t\t// if (element.failure) {\n\t\t\t\t// \t// refresh the element on failure so that\n\t\t\t\t// \t// we can update its rendering\n\t\t\t\t// \treturn tree.refresh(element).then(() => val.children);\n\t\t\t\t// }\n\t\t\t\treturn val.children;\n\t\t\t});\n\t\t}\n\n\t\tthrow new Error('bad tree');\n\t}\n}\n\n//#endregion\n\nexport class Delegate implements IListVirtualDelegate {\n\tgetHeight(): number {\n\t\treturn 23;\n\t}\n\tgetTemplateId(element: FileReferences | OneReference): string {\n\t\tif (element instanceof FileReferences) {\n\t\t\treturn FileReferencesRenderer.id;\n\t\t} else {\n\t\t\treturn OneReferenceRenderer.id;\n\t\t}\n\t}\n}\n\nexport class StringRepresentationProvider implements IKeyboardNavigationLabelProvider {\n\n\tconstructor(@IKeybindingService private readonly _keybindingService: IKeybindingService) { }\n\n\tgetKeyboardNavigationLabel(element: TreeElement): { toString(): string } {\n\t\tif (element instanceof OneReference) {\n\t\t\tconst parts = element.parent.getPreview(element)?.preview(element.range);\n\t\t\tif (parts) {\n\t\t\t\treturn parts.value;\n\t\t\t}\n\t\t}\n\t\t// FileReferences or unresolved OneReference\n\t\treturn basename(element.uri);\n\t}\n}\n\nexport class IdentityProvider implements IIdentityProvider {\n\n\tgetId(element: TreeElement): { toString(): string } {\n\t\treturn element instanceof OneReference ? element.id : element.uri;\n\t}\n}\n\n//#region render: File\n\nclass FileReferencesTemplate extends Disposable {\n\n\treadonly file: IconLabel;\n\treadonly badge: CountBadge;\n\n\tconstructor(\n\t\tcontainer: HTMLElement,\n\t\t@ILabelService private readonly _labelService: ILabelService\n\t) {\n\t\tsuper();\n\t\tconst parent = document.createElement('div');\n\t\tparent.classList.add('reference-file');\n\t\tthis.file = this._register(new IconLabel(parent, { supportHighlights: true }));\n\n\t\tthis.badge = new CountBadge(dom.append(parent, dom.$('.count')), {}, defaultCountBadgeStyles);\n\n\t\tcontainer.appendChild(parent);\n\t}\n\n\tset(element: FileReferences, matches: IMatch[]) {\n\t\tconst parent = dirname(element.uri);\n\t\tthis.file.setLabel(\n\t\t\tthis._labelService.getUriBasenameLabel(element.uri),\n\t\t\tthis._labelService.getUriLabel(parent, { relative: true }),\n\t\t\t{ title: this._labelService.getUriLabel(element.uri), matches }\n\t\t);\n\t\tconst len = element.children.length;\n\t\tthis.badge.setCount(len);\n\t\tif (len > 1) {\n\t\t\tthis.badge.setTitleFormat(localize('referencesCount', \"{0} references\", len));\n\t\t} else {\n\t\t\tthis.badge.setTitleFormat(localize('referenceCount', \"{0} reference\", len));\n\t\t}\n\t}\n}\n\nexport class FileReferencesRenderer implements ITreeRenderer {\n\n\tstatic readonly id = 'FileReferencesRenderer';\n\n\treadonly templateId: string = FileReferencesRenderer.id;\n\n\tconstructor(@IInstantiationService private readonly _instantiationService: IInstantiationService) { }\n\n\trenderTemplate(container: HTMLElement): FileReferencesTemplate {\n\t\treturn this._instantiationService.createInstance(FileReferencesTemplate, container);\n\t}\n\trenderElement(node: ITreeNode, index: number, template: FileReferencesTemplate): void {\n\t\ttemplate.set(node.element, createMatches(node.filterData));\n\t}\n\tdisposeTemplate(templateData: FileReferencesTemplate): void {\n\t\ttemplateData.dispose();\n\t}\n}\n\n//#endregion\n\n//#region render: Reference\nclass OneReferenceTemplate extends Disposable {\n\n\treadonly label: HighlightedLabel;\n\n\tconstructor(container: HTMLElement) {\n\t\tsuper();\n\n\t\tthis.label = this._register(new HighlightedLabel(container));\n\t}\n\n\tset(element: OneReference, score?: FuzzyScore): void {\n\t\tconst preview = element.parent.getPreview(element)?.preview(element.range);\n\t\tif (!preview || !preview.value) {\n\t\t\t// this means we FAILED to resolve the document or the value is the empty string\n\t\t\tthis.label.set(`${basename(element.uri)}:${element.range.startLineNumber + 1}:${element.range.startColumn + 1}`);\n\t\t} else {\n\t\t\t// render search match as highlight unless\n\t\t\t// we have score, then render the score\n\t\t\tconst { value, highlight } = preview;\n\t\t\tif (score && !FuzzyScore.isDefault(score)) {\n\t\t\t\tthis.label.element.classList.toggle('referenceMatch', false);\n\t\t\t\tthis.label.set(value, createMatches(score));\n\t\t\t} else {\n\t\t\t\tthis.label.element.classList.toggle('referenceMatch', true);\n\t\t\t\tthis.label.set(value, [highlight]);\n\t\t\t}\n\t\t}\n\t}\n}\n\nexport class OneReferenceRenderer implements ITreeRenderer {\n\n\tstatic readonly id = 'OneReferenceRenderer';\n\n\treadonly templateId: string = OneReferenceRenderer.id;\n\n\trenderTemplate(container: HTMLElement): OneReferenceTemplate {\n\t\treturn new OneReferenceTemplate(container);\n\t}\n\trenderElement(node: ITreeNode, index: number, templateData: OneReferenceTemplate): void {\n\t\ttemplateData.set(node.element, node.filterData);\n\t}\n\tdisposeTemplate(templateData: OneReferenceTemplate): void {\n\t\ttemplateData.dispose();\n\t}\n}\n\n//#endregion\n\n\nexport class AccessibilityProvider implements IListAccessibilityProvider {\n\n\tgetWidgetAriaLabel(): string {\n\t\treturn localize('treeAriaLabel', \"References\");\n\t}\n\n\tgetAriaLabel(element: FileReferences | OneReference): string | null {\n\t\treturn element.ariaMessage;\n\t}\n}\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 *--------------------------------------------------------------------------------------------*/\nimport * as dom from 'vs/base/browser/dom';\nimport { KeybindingLabel } from 'vs/base/browser/ui/keybindingLabel/keybindingLabel';\nimport { IListEvent, IListMouseEvent, IListRenderer, IListVirtualDelegate } from 'vs/base/browser/ui/list/list';\nimport { List } from 'vs/base/browser/ui/list/listWidget';\nimport { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';\nimport { Codicon } from 'vs/base/common/codicons';\nimport { ResolvedKeybinding } from 'vs/base/common/keybindings';\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport { OS } from 'vs/base/common/platform';\nimport { ThemeIcon } from 'vs/base/common/themables';\nimport 'vs/css!./actionWidget';\nimport { localize } from 'vs/nls';\nimport { IContextViewService } from 'vs/platform/contextview/browser/contextView';\nimport { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';\nimport { defaultListStyles } from 'vs/platform/theme/browser/defaultStyles';\nimport { asCssVariable } from 'vs/platform/theme/common/colorRegistry';\n\nexport const acceptSelectedActionCommand = 'acceptSelectedCodeAction';\nexport const previewSelectedActionCommand = 'previewSelectedCodeAction';\n\nexport interface IActionListDelegate {\n\tonHide(didCancel?: boolean): void;\n\tonSelect(action: T, preview?: boolean): void;\n\tonHover?(action: T, cancellationToken: CancellationToken): Promise<{ canPreview: boolean } | void>;\n\tonFocus?(action: T | undefined): void;\n}\n\nexport interface IActionListItem {\n\treadonly item?: T;\n\treadonly kind: ActionListItemKind;\n\treadonly group?: { kind?: any; icon?: ThemeIcon; title: string };\n\treadonly disabled?: boolean;\n\treadonly label?: string;\n\treadonly keybinding?: ResolvedKeybinding;\n\tcanPreview?: boolean | undefined;\n}\n\ninterface IActionMenuTemplateData {\n\treadonly container: HTMLElement;\n\treadonly icon: HTMLElement;\n\treadonly text: HTMLElement;\n\treadonly keybinding: KeybindingLabel;\n}\n\nexport const enum ActionListItemKind {\n\tAction = 'action',\n\tHeader = 'header'\n}\n\ninterface IHeaderTemplateData {\n\treadonly container: HTMLElement;\n\treadonly text: HTMLElement;\n}\n\nclass HeaderRenderer implements IListRenderer, IHeaderTemplateData> {\n\n\tget templateId(): string { return ActionListItemKind.Header; }\n\n\trenderTemplate(container: HTMLElement): IHeaderTemplateData {\n\t\tcontainer.classList.add('group-header');\n\n\t\tconst text = document.createElement('span');\n\t\tcontainer.append(text);\n\n\t\treturn { container, text };\n\t}\n\n\trenderElement(element: IActionListItem, _index: number, templateData: IHeaderTemplateData): void {\n\t\ttemplateData.text.textContent = element.group?.title ?? '';\n\t}\n\n\tdisposeTemplate(_templateData: IHeaderTemplateData): void {\n\t\t// noop\n\t}\n}\n\nclass ActionItemRenderer implements IListRenderer, IActionMenuTemplateData> {\n\n\tget templateId(): string { return ActionListItemKind.Action; }\n\n\tconstructor(\n\t\tprivate readonly _supportsPreview: boolean,\n\t\t@IKeybindingService private readonly _keybindingService: IKeybindingService\n\t) { }\n\n\trenderTemplate(container: HTMLElement): IActionMenuTemplateData {\n\t\tcontainer.classList.add(this.templateId);\n\n\t\tconst icon = document.createElement('div');\n\t\ticon.className = 'icon';\n\t\tcontainer.append(icon);\n\n\t\tconst text = document.createElement('span');\n\t\ttext.className = 'title';\n\t\tcontainer.append(text);\n\n\t\tconst keybinding = new KeybindingLabel(container, OS);\n\n\t\treturn { container, icon, text, keybinding };\n\t}\n\n\trenderElement(element: IActionListItem, _index: number, data: IActionMenuTemplateData): void {\n\t\tif (element.group?.icon) {\n\t\t\tdata.icon.className = ThemeIcon.asClassName(element.group.icon);\n\t\t\tif (element.group.icon.color) {\n\t\t\t\tdata.icon.style.color = asCssVariable(element.group.icon.color.id);\n\t\t\t}\n\t\t} else {\n\t\t\tdata.icon.className = ThemeIcon.asClassName(Codicon.lightBulb);\n\t\t\tdata.icon.style.color = 'var(--vscode-editorLightBulb-foreground)';\n\t\t}\n\n\t\tif (!element.item || !element.label) {\n\t\t\treturn;\n\t\t}\n\n\t\tdata.text.textContent = stripNewlines(element.label);\n\n\t\tdata.keybinding.set(element.keybinding);\n\t\tdom.setVisibility(!!element.keybinding, data.keybinding.element);\n\n\t\tconst actionTitle = this._keybindingService.lookupKeybinding(acceptSelectedActionCommand)?.getLabel();\n\t\tconst previewTitle = this._keybindingService.lookupKeybinding(previewSelectedActionCommand)?.getLabel();\n\t\tdata.container.classList.toggle('option-disabled', element.disabled);\n\t\tif (element.disabled) {\n\t\t\tdata.container.title = element.label;\n\t\t} else if (actionTitle && previewTitle) {\n\t\t\tif (this._supportsPreview && element.canPreview) {\n\t\t\t\tdata.container.title = localize({ key: 'label-preview', comment: ['placeholders are keybindings, e.g \"F2 to Apply, Shift+F2 to Preview\"'] }, \"{0} to Apply, {1} to Preview\", actionTitle, previewTitle);\n\t\t\t} else {\n\t\t\t\tdata.container.title = localize({ key: 'label', comment: ['placeholder is a keybinding, e.g \"F2 to Apply\"'] }, \"{0} to Apply\", actionTitle);\n\t\t\t}\n\t\t} else {\n\t\t\tdata.container.title = '';\n\t\t}\n\t}\n\n\tdisposeTemplate(_templateData: IActionMenuTemplateData): void {\n\t\t_templateData.keybinding.dispose();\n\t}\n}\n\nclass AcceptSelectedEvent extends UIEvent {\n\tconstructor() { super('acceptSelectedAction'); }\n}\n\nclass PreviewSelectedEvent extends UIEvent {\n\tconstructor() { super('previewSelectedAction'); }\n}\n\nfunction getKeyboardNavigationLabel(item: IActionListItem): string | undefined {\n\t// Filter out header vs. action\n\tif (item.kind === 'action') {\n\t\treturn item.label;\n\t}\n\treturn undefined;\n}\n\nexport class ActionList extends Disposable {\n\n\tpublic readonly domNode: HTMLElement;\n\n\tprivate readonly _list: List>;\n\n\tprivate readonly _actionLineHeight = 24;\n\tprivate readonly _headerLineHeight = 26;\n\n\tprivate readonly _allMenuItems: readonly IActionListItem[];\n\n\tprivate readonly cts = this._register(new CancellationTokenSource());\n\n\tconstructor(\n\t\tuser: string,\n\t\tpreview: boolean,\n\t\titems: readonly IActionListItem[],\n\t\tprivate readonly _delegate: IActionListDelegate,\n\t\t@IContextViewService private readonly _contextViewService: IContextViewService,\n\t\t@IKeybindingService private readonly _keybindingService: IKeybindingService\n\t) {\n\t\tsuper();\n\n\t\tthis.domNode = document.createElement('div');\n\t\tthis.domNode.classList.add('actionList');\n\t\tconst virtualDelegate: IListVirtualDelegate> = {\n\t\t\tgetHeight: element => element.kind === ActionListItemKind.Header ? this._headerLineHeight : this._actionLineHeight,\n\t\t\tgetTemplateId: element => element.kind\n\t\t};\n\n\t\tthis._list = this._register(new List(user, this.domNode, virtualDelegate, [\n\t\t\tnew ActionItemRenderer>(preview, this._keybindingService),\n\t\t\tnew HeaderRenderer(),\n\t\t], {\n\t\t\tkeyboardSupport: false,\n\t\t\ttypeNavigationEnabled: true,\n\t\t\tkeyboardNavigationLabelProvider: { getKeyboardNavigationLabel },\n\t\t\taccessibilityProvider: {\n\t\t\t\tgetAriaLabel: element => {\n\t\t\t\t\tif (element.kind === ActionListItemKind.Action) {\n\t\t\t\t\t\tlet label = element.label ? stripNewlines(element?.label) : '';\n\t\t\t\t\t\tif (element.disabled) {\n\t\t\t\t\t\t\tlabel = localize({ key: 'customQuickFixWidget.labels', comment: [`Action widget labels for accessibility.`] }, \"{0}, Disabled Reason: {1}\", label, element.disabled);\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn label;\n\t\t\t\t\t}\n\t\t\t\t\treturn null;\n\t\t\t\t},\n\t\t\t\tgetWidgetAriaLabel: () => localize({ key: 'customQuickFixWidget', comment: [`An action widget option`] }, \"Action Widget\"),\n\t\t\t\tgetRole: (e) => e.kind === ActionListItemKind.Action ? 'option' : 'separator',\n\t\t\t\tgetWidgetRole: () => 'listbox',\n\t\t\t},\n\t\t}));\n\n\t\tthis._list.style(defaultListStyles);\n\n\t\tthis._register(this._list.onMouseClick(e => this.onListClick(e)));\n\t\tthis._register(this._list.onMouseOver(e => this.onListHover(e)));\n\t\tthis._register(this._list.onDidChangeFocus(() => this.onFocus()));\n\t\tthis._register(this._list.onDidChangeSelection(e => this.onListSelection(e)));\n\n\t\tthis._allMenuItems = items;\n\t\tthis._list.splice(0, this._list.length, this._allMenuItems);\n\n\t\tif (this._list.length) {\n\t\t\tthis.focusNext();\n\t\t}\n\t}\n\n\tprivate focusCondition(element: IActionListItem): boolean {\n\t\treturn !element.disabled && element.kind === ActionListItemKind.Action;\n\t}\n\n\thide(didCancel?: boolean): void {\n\t\tthis._delegate.onHide(didCancel);\n\t\tthis.cts.cancel();\n\t\tthis._contextViewService.hideContextView();\n\t}\n\n\tlayout(minWidth: number): number {\n\t\t// Updating list height, depending on how many separators and headers there are.\n\t\tconst numHeaders = this._allMenuItems.filter(item => item.kind === 'header').length;\n\t\tconst itemsHeight = this._allMenuItems.length * this._actionLineHeight;\n\t\tconst heightWithHeaders = itemsHeight + numHeaders * this._headerLineHeight - numHeaders * this._actionLineHeight;\n\t\tthis._list.layout(heightWithHeaders);\n\t\tlet maxWidth = minWidth;\n\n\t\tif (this._allMenuItems.length >= 50) {\n\t\t\tmaxWidth = 380;\n\t\t} else {\n\t\t\t// For finding width dynamically (not using resize observer)\n\t\t\tconst itemWidths: number[] = this._allMenuItems.map((_, index): number => {\n\t\t\t\tconst element = this.domNode.ownerDocument.getElementById(this._list.getElementID(index));\n\t\t\t\tif (element) {\n\t\t\t\t\telement.style.width = 'auto';\n\t\t\t\t\tconst width = element.getBoundingClientRect().width;\n\t\t\t\t\telement.style.width = '';\n\t\t\t\t\treturn width;\n\t\t\t\t}\n\t\t\t\treturn 0;\n\t\t\t});\n\n\t\t\t// resize observer - can be used in the future since list widget supports dynamic height but not width\n\t\t\tmaxWidth = Math.max(...itemWidths, minWidth);\n\t\t}\n\n\t\tconst maxVhPrecentage = 0.7;\n\t\tconst height = Math.min(heightWithHeaders, this.domNode.ownerDocument.body.clientHeight * maxVhPrecentage);\n\t\tthis._list.layout(height, maxWidth);\n\n\t\tthis.domNode.style.height = `${height}px`;\n\n\t\tthis._list.domFocus();\n\t\treturn maxWidth;\n\t}\n\n\tfocusPrevious() {\n\t\tthis._list.focusPrevious(1, true, undefined, this.focusCondition);\n\t}\n\n\tfocusNext() {\n\t\tthis._list.focusNext(1, true, undefined, this.focusCondition);\n\t}\n\n\tacceptSelected(preview?: boolean) {\n\t\tconst focused = this._list.getFocus();\n\t\tif (focused.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst focusIndex = focused[0];\n\t\tconst element = this._list.element(focusIndex);\n\t\tif (!this.focusCondition(element)) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst event = preview ? new PreviewSelectedEvent() : new AcceptSelectedEvent();\n\t\tthis._list.setSelection([focusIndex], event);\n\t}\n\n\tprivate onListSelection(e: IListEvent>): void {\n\t\tif (!e.elements.length) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst element = e.elements[0];\n\t\tif (element.item && this.focusCondition(element)) {\n\t\t\tthis._delegate.onSelect(element.item, e.browserEvent instanceof PreviewSelectedEvent);\n\t\t} else {\n\t\t\tthis._list.setSelection([]);\n\t\t}\n\t}\n\n\tprivate onFocus() {\n\t\tconst focused = this._list.getFocus();\n\t\tif (focused.length === 0) {\n\t\t\treturn;\n\t\t}\n\t\tconst focusIndex = focused[0];\n\t\tconst element = this._list.element(focusIndex);\n\t\tthis._delegate.onFocus?.(element.item);\n\t}\n\n\tprivate async onListHover(e: IListMouseEvent>) {\n\t\tconst element = e.element;\n\t\tif (element && element.item && this.focusCondition(element)) {\n\t\t\tif (this._delegate.onHover && !element.disabled && element.kind === ActionListItemKind.Action) {\n\t\t\t\tconst result = await this._delegate.onHover(element.item, this.cts.token);\n\t\t\t\telement.canPreview = result ? result.canPreview : undefined;\n\t\t\t}\n\t\t\tif (e.index) {\n\t\t\t\tthis._list.splice(e.index, 1, [element]);\n\t\t\t}\n\t\t}\n\n\t\tthis._list.setFocus(typeof e.index === 'number' ? [e.index] : []);\n\t}\n\n\tprivate onListClick(e: IListMouseEvent>): void {\n\t\tif (e.element && this.focusCondition(e.element)) {\n\t\t\tthis._list.setFocus([]);\n\t\t}\n\t}\n}\n\nfunction stripNewlines(str: string): string {\n\treturn str.replace(/\\r\\n|\\r|\\n/g, ' ');\n}\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 *--------------------------------------------------------------------------------------------*/\nimport * as dom from 'vs/base/browser/dom';\nimport { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';\nimport { IAnchor } from 'vs/base/browser/ui/contextview/contextview';\nimport { IAction } from 'vs/base/common/actions';\nimport { KeyCode, KeyMod } from 'vs/base/common/keyCodes';\nimport { Disposable, DisposableStore, IDisposable, MutableDisposable } from 'vs/base/common/lifecycle';\nimport 'vs/css!./actionWidget';\nimport { localize, localize2 } from 'vs/nls';\nimport { acceptSelectedActionCommand, ActionList, IActionListDelegate, IActionListItem, previewSelectedActionCommand } from 'vs/platform/actionWidget/browser/actionList';\nimport { Action2, registerAction2 } from 'vs/platform/actions/common/actions';\nimport { IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';\nimport { IContextViewService } from 'vs/platform/contextview/browser/contextView';\nimport { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions';\nimport { createDecorator, IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';\nimport { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';\nimport { inputActiveOptionBackground, registerColor } from 'vs/platform/theme/common/colorRegistry';\n\nregisterColor(\n\t'actionBar.toggledBackground',\n\t{ dark: inputActiveOptionBackground, light: inputActiveOptionBackground, hcDark: inputActiveOptionBackground, hcLight: inputActiveOptionBackground, },\n\tlocalize('actionBar.toggledBackground', 'Background color for toggled action items in action bar.')\n);\n\nconst ActionWidgetContextKeys = {\n\tVisible: new RawContextKey('codeActionMenuVisible', false, localize('codeActionMenuVisible', \"Whether the action widget list is visible\"))\n};\n\nexport const IActionWidgetService = createDecorator('actionWidgetService');\n\nexport interface IActionWidgetService {\n\treadonly _serviceBrand: undefined;\n\n\tshow(user: string, supportsPreview: boolean, items: readonly IActionListItem[], delegate: IActionListDelegate, anchor: IAnchor, container: HTMLElement | undefined, actionBarActions?: readonly IAction[]): void;\n\n\thide(didCancel?: boolean): void;\n\n\treadonly isVisible: boolean;\n}\n\nclass ActionWidgetService extends Disposable implements IActionWidgetService {\n\tdeclare readonly _serviceBrand: undefined;\n\n\tget isVisible() {\n\t\treturn ActionWidgetContextKeys.Visible.getValue(this._contextKeyService) || false;\n\t}\n\n\tprivate readonly _list = this._register(new MutableDisposable>());\n\n\tconstructor(\n\t\t@IContextViewService private readonly _contextViewService: IContextViewService,\n\t\t@IContextKeyService private readonly _contextKeyService: IContextKeyService,\n\t\t@IInstantiationService private readonly _instantiationService: IInstantiationService\n\t) {\n\t\tsuper();\n\t}\n\n\tshow(user: string, supportsPreview: boolean, items: readonly IActionListItem[], delegate: IActionListDelegate, anchor: IAnchor, container: HTMLElement | undefined, actionBarActions?: readonly IAction[]): void {\n\t\tconst visibleContext = ActionWidgetContextKeys.Visible.bindTo(this._contextKeyService);\n\n\t\tconst list = this._instantiationService.createInstance(ActionList, user, supportsPreview, items, delegate);\n\t\tthis._contextViewService.showContextView({\n\t\t\tgetAnchor: () => anchor,\n\t\t\trender: (container: HTMLElement) => {\n\t\t\t\tvisibleContext.set(true);\n\t\t\t\treturn this._renderWidget(container, list, actionBarActions ?? []);\n\t\t\t},\n\t\t\tonHide: (didCancel) => {\n\t\t\t\tvisibleContext.reset();\n\t\t\t\tthis._onWidgetClosed(didCancel);\n\t\t\t},\n\t\t}, container, false);\n\t}\n\n\tacceptSelected(preview?: boolean) {\n\t\tthis._list.value?.acceptSelected(preview);\n\t}\n\n\tfocusPrevious() {\n\t\tthis._list?.value?.focusPrevious();\n\t}\n\n\tfocusNext() {\n\t\tthis._list?.value?.focusNext();\n\t}\n\n\thide(didCancel?: boolean) {\n\t\tthis._list.value?.hide(didCancel);\n\t\tthis._list.clear();\n\t}\n\n\tprivate _renderWidget(element: HTMLElement, list: ActionList, actionBarActions: readonly IAction[]): IDisposable {\n\t\tconst widget = document.createElement('div');\n\t\twidget.classList.add('action-widget');\n\t\telement.appendChild(widget);\n\n\t\tthis._list.value = list;\n\t\tif (this._list.value) {\n\t\t\twidget.appendChild(this._list.value.domNode);\n\t\t} else {\n\t\t\tthrow new Error('List has no value');\n\t\t}\n\t\tconst renderDisposables = new DisposableStore();\n\n\t\t// Invisible div to block mouse interaction in the rest of the UI\n\t\tconst menuBlock = document.createElement('div');\n\t\tconst block = element.appendChild(menuBlock);\n\t\tblock.classList.add('context-view-block');\n\t\trenderDisposables.add(dom.addDisposableListener(block, dom.EventType.MOUSE_DOWN, e => e.stopPropagation()));\n\n\t\t// Invisible div to block mouse interaction with the menu\n\t\tconst pointerBlockDiv = document.createElement('div');\n\t\tconst pointerBlock = element.appendChild(pointerBlockDiv);\n\t\tpointerBlock.classList.add('context-view-pointerBlock');\n\n\t\t// Removes block on click INSIDE widget or ANY mouse movement\n\t\trenderDisposables.add(dom.addDisposableListener(pointerBlock, dom.EventType.POINTER_MOVE, () => pointerBlock.remove()));\n\t\trenderDisposables.add(dom.addDisposableListener(pointerBlock, dom.EventType.MOUSE_DOWN, () => pointerBlock.remove()));\n\n\t\t// Action bar\n\t\tlet actionBarWidth = 0;\n\t\tif (actionBarActions.length) {\n\t\t\tconst actionBar = this._createActionBar('.action-widget-action-bar', actionBarActions);\n\t\t\tif (actionBar) {\n\t\t\t\twidget.appendChild(actionBar.getContainer().parentElement!);\n\t\t\t\trenderDisposables.add(actionBar);\n\t\t\t\tactionBarWidth = actionBar.getContainer().offsetWidth;\n\t\t\t}\n\t\t}\n\n\t\tconst width = this._list.value?.layout(actionBarWidth);\n\t\twidget.style.width = `${width}px`;\n\n\t\tconst focusTracker = renderDisposables.add(dom.trackFocus(element));\n\t\trenderDisposables.add(focusTracker.onDidBlur(() => this.hide(true)));\n\n\t\treturn renderDisposables;\n\t}\n\n\tprivate _createActionBar(className: string, actions: readonly IAction[]): ActionBar | undefined {\n\t\tif (!actions.length) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst container = dom.$(className);\n\t\tconst actionBar = new ActionBar(container);\n\t\tactionBar.push(actions, { icon: false, label: true });\n\t\treturn actionBar;\n\t}\n\n\tprivate _onWidgetClosed(didCancel?: boolean): void {\n\t\tthis._list.value?.hide(didCancel);\n\t}\n}\n\nregisterSingleton(IActionWidgetService, ActionWidgetService, InstantiationType.Delayed);\n\nconst weight = KeybindingWeight.EditorContrib + 1000;\n\nregisterAction2(class extends Action2 {\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'hideCodeActionWidget',\n\t\t\ttitle: localize2('hideCodeActionWidget.title', \"Hide action widget\"),\n\t\t\tprecondition: ActionWidgetContextKeys.Visible,\n\t\t\tkeybinding: {\n\t\t\t\tweight,\n\t\t\t\tprimary: KeyCode.Escape,\n\t\t\t\tsecondary: [KeyMod.Shift | KeyCode.Escape]\n\t\t\t},\n\t\t});\n\t}\n\n\trun(accessor: ServicesAccessor): void {\n\t\taccessor.get(IActionWidgetService).hide(true);\n\t}\n});\n\nregisterAction2(class extends Action2 {\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'selectPrevCodeAction',\n\t\t\ttitle: localize2('selectPrevCodeAction.title', \"Select previous action\"),\n\t\t\tprecondition: ActionWidgetContextKeys.Visible,\n\t\t\tkeybinding: {\n\t\t\t\tweight,\n\t\t\t\tprimary: KeyCode.UpArrow,\n\t\t\t\tsecondary: [KeyMod.CtrlCmd | KeyCode.UpArrow],\n\t\t\t\tmac: { primary: KeyCode.UpArrow, secondary: [KeyMod.CtrlCmd | KeyCode.UpArrow, KeyMod.WinCtrl | KeyCode.KeyP] },\n\t\t\t}\n\t\t});\n\t}\n\n\trun(accessor: ServicesAccessor): void {\n\t\tconst widgetService = accessor.get(IActionWidgetService);\n\t\tif (widgetService instanceof ActionWidgetService) {\n\t\t\twidgetService.focusPrevious();\n\t\t}\n\t}\n});\n\nregisterAction2(class extends Action2 {\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'selectNextCodeAction',\n\t\t\ttitle: localize2('selectNextCodeAction.title', \"Select next action\"),\n\t\t\tprecondition: ActionWidgetContextKeys.Visible,\n\t\t\tkeybinding: {\n\t\t\t\tweight,\n\t\t\t\tprimary: KeyCode.DownArrow,\n\t\t\t\tsecondary: [KeyMod.CtrlCmd | KeyCode.DownArrow],\n\t\t\t\tmac: { primary: KeyCode.DownArrow, secondary: [KeyMod.CtrlCmd | KeyCode.DownArrow, KeyMod.WinCtrl | KeyCode.KeyN] }\n\t\t\t}\n\t\t});\n\t}\n\n\trun(accessor: ServicesAccessor): void {\n\t\tconst widgetService = accessor.get(IActionWidgetService);\n\t\tif (widgetService instanceof ActionWidgetService) {\n\t\t\twidgetService.focusNext();\n\t\t}\n\t}\n});\n\nregisterAction2(class extends Action2 {\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: acceptSelectedActionCommand,\n\t\t\ttitle: localize2('acceptSelected.title', \"Accept selected action\"),\n\t\t\tprecondition: ActionWidgetContextKeys.Visible,\n\t\t\tkeybinding: {\n\t\t\t\tweight,\n\t\t\t\tprimary: KeyCode.Enter,\n\t\t\t\tsecondary: [KeyMod.CtrlCmd | KeyCode.Period],\n\t\t\t}\n\t\t});\n\t}\n\n\trun(accessor: ServicesAccessor): void {\n\t\tconst widgetService = accessor.get(IActionWidgetService);\n\t\tif (widgetService instanceof ActionWidgetService) {\n\t\t\twidgetService.acceptSelected();\n\t\t}\n\t}\n});\n\nregisterAction2(class extends Action2 {\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: previewSelectedActionCommand,\n\t\t\ttitle: localize2('previewSelected.title', \"Preview selected action\"),\n\t\t\tprecondition: ActionWidgetContextKeys.Visible,\n\t\t\tkeybinding: {\n\t\t\t\tweight,\n\t\t\t\tprimary: KeyMod.CtrlCmd | KeyCode.Enter,\n\t\t\t}\n\t\t});\n\t}\n\n\trun(accessor: ServicesAccessor): void {\n\t\tconst widgetService = accessor.get(IActionWidgetService);\n\t\tif (widgetService instanceof ActionWidgetService) {\n\t\t\twidgetService.acceptSelected(true);\n\t\t}\n\t}\n});\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\nimport { IContextMenuDelegate } from 'vs/base/browser/contextmenu';\nimport { $, addDisposableListener, EventType, getActiveElement, getWindow, isAncestor } from 'vs/base/browser/dom';\nimport { StandardMouseEvent } from 'vs/base/browser/mouseEvent';\nimport { Menu } from 'vs/base/browser/ui/menu/menu';\nimport { ActionRunner, IRunEvent, WorkbenchActionExecutedClassification, WorkbenchActionExecutedEvent } from 'vs/base/common/actions';\nimport { isCancellationError } from 'vs/base/common/errors';\nimport { combinedDisposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle';\nimport { IContextViewService } from 'vs/platform/contextview/browser/contextView';\nimport { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';\nimport { INotificationService } from 'vs/platform/notification/common/notification';\nimport { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';\nimport { defaultMenuStyles } from 'vs/platform/theme/browser/defaultStyles';\n\n\nexport interface IContextMenuHandlerOptions {\n\tblockMouse: boolean;\n}\n\nexport class ContextMenuHandler {\n\tprivate focusToReturn: HTMLElement | null = null;\n\tprivate lastContainer: HTMLElement | null = null;\n\tprivate block: HTMLElement | null = null;\n\tprivate blockDisposable: IDisposable | null = null;\n\tprivate options: IContextMenuHandlerOptions = { blockMouse: true };\n\n\tconstructor(\n\t\tprivate contextViewService: IContextViewService,\n\t\tprivate telemetryService: ITelemetryService,\n\t\tprivate notificationService: INotificationService,\n\t\tprivate keybindingService: IKeybindingService,\n\t) { }\n\n\tconfigure(options: IContextMenuHandlerOptions): void {\n\t\tthis.options = options;\n\t}\n\n\tshowContextMenu(delegate: IContextMenuDelegate): void {\n\t\tconst actions = delegate.getActions();\n\t\tif (!actions.length) {\n\t\t\treturn; // Don't render an empty context menu\n\t\t}\n\n\t\tthis.focusToReturn = getActiveElement() as HTMLElement;\n\n\t\tlet menu: Menu | undefined;\n\n\t\tconst shadowRootElement = delegate.domForShadowRoot instanceof HTMLElement ? delegate.domForShadowRoot : undefined;\n\t\tthis.contextViewService.showContextView({\n\t\t\tgetAnchor: () => delegate.getAnchor(),\n\t\t\tcanRelayout: false,\n\t\t\tanchorAlignment: delegate.anchorAlignment,\n\t\t\tanchorAxisAlignment: delegate.anchorAxisAlignment,\n\n\t\t\trender: (container) => {\n\t\t\t\tthis.lastContainer = container;\n\t\t\t\tconst className = delegate.getMenuClassName ? delegate.getMenuClassName() : '';\n\n\t\t\t\tif (className) {\n\t\t\t\t\tcontainer.className += ' ' + className;\n\t\t\t\t}\n\n\t\t\t\t// Render invisible div to block mouse interaction in the rest of the UI\n\t\t\t\tif (this.options.blockMouse) {\n\t\t\t\t\tthis.block = container.appendChild($('.context-view-block'));\n\t\t\t\t\tthis.block.style.position = 'fixed';\n\t\t\t\t\tthis.block.style.cursor = 'initial';\n\t\t\t\t\tthis.block.style.left = '0';\n\t\t\t\t\tthis.block.style.top = '0';\n\t\t\t\t\tthis.block.style.width = '100%';\n\t\t\t\t\tthis.block.style.height = '100%';\n\t\t\t\t\tthis.block.style.zIndex = '-1';\n\n\t\t\t\t\tthis.blockDisposable?.dispose();\n\t\t\t\t\tthis.blockDisposable = addDisposableListener(this.block, EventType.MOUSE_DOWN, e => e.stopPropagation());\n\t\t\t\t}\n\n\t\t\t\tconst menuDisposables = new DisposableStore();\n\n\t\t\t\tconst actionRunner = delegate.actionRunner || new ActionRunner();\n\t\t\t\tactionRunner.onWillRun(evt => this.onActionRun(evt, !delegate.skipTelemetry), this, menuDisposables);\n\t\t\t\tactionRunner.onDidRun(this.onDidActionRun, this, menuDisposables);\n\t\t\t\tmenu = new Menu(container, actions, {\n\t\t\t\t\tactionViewItemProvider: delegate.getActionViewItem,\n\t\t\t\t\tcontext: delegate.getActionsContext ? delegate.getActionsContext() : null,\n\t\t\t\t\tactionRunner,\n\t\t\t\t\tgetKeyBinding: delegate.getKeyBinding ? delegate.getKeyBinding : action => this.keybindingService.lookupKeybinding(action.id)\n\t\t\t\t},\n\t\t\t\t\tdefaultMenuStyles\n\t\t\t\t);\n\n\t\t\t\tmenu.onDidCancel(() => this.contextViewService.hideContextView(true), null, menuDisposables);\n\t\t\t\tmenu.onDidBlur(() => this.contextViewService.hideContextView(true), null, menuDisposables);\n\t\t\t\tconst targetWindow = getWindow(container);\n\t\t\t\tmenuDisposables.add(addDisposableListener(targetWindow, EventType.BLUR, () => this.contextViewService.hideContextView(true)));\n\t\t\t\tmenuDisposables.add(addDisposableListener(targetWindow, EventType.MOUSE_DOWN, (e: MouseEvent) => {\n\t\t\t\t\tif (e.defaultPrevented) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst event = new StandardMouseEvent(targetWindow, e);\n\t\t\t\t\tlet element: HTMLElement | null = event.target;\n\n\t\t\t\t\t// Don't do anything as we are likely creating a context menu\n\t\t\t\t\tif (event.rightButton) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\twhile (element) {\n\t\t\t\t\t\tif (element === container) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\telement = element.parentElement;\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.contextViewService.hideContextView(true);\n\t\t\t\t}));\n\n\t\t\t\treturn combinedDisposable(menuDisposables, menu);\n\t\t\t},\n\n\t\t\tfocus: () => {\n\t\t\t\tmenu?.focus(!!delegate.autoSelectFirstItem);\n\t\t\t},\n\n\t\t\tonHide: (didCancel?: boolean) => {\n\t\t\t\tdelegate.onHide?.(!!didCancel);\n\n\t\t\t\tif (this.block) {\n\t\t\t\t\tthis.block.remove();\n\t\t\t\t\tthis.block = null;\n\t\t\t\t}\n\n\t\t\t\tthis.blockDisposable?.dispose();\n\t\t\t\tthis.blockDisposable = null;\n\n\t\t\t\tif (!!this.lastContainer && (getActiveElement() === this.lastContainer || isAncestor(getActiveElement(), this.lastContainer))) {\n\t\t\t\t\tthis.focusToReturn?.focus();\n\t\t\t\t}\n\n\t\t\t\tthis.lastContainer = null;\n\t\t\t}\n\t\t}, shadowRootElement, !!shadowRootElement);\n\t}\n\n\tprivate onActionRun(e: IRunEvent, logTelemetry: boolean): void {\n\t\tif (logTelemetry) {\n\t\t\tthis.telemetryService.publicLog2('workbenchActionExecuted', { id: e.action.id, from: 'contextMenu' });\n\t\t}\n\n\t\tthis.contextViewService.hideContextView(false);\n\t}\n\n\tprivate onDidActionRun(e: IRunEvent): void {\n\t\tif (e.error && !isCancellationError(e.error)) {\n\t\t\tthis.notificationService.error(e.error);\n\t\t}\n\t}\n}\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\nimport { createStyleSheet, isActiveElement, isKeyboardEvent } from 'vs/base/browser/dom';\nimport { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview';\nimport { IListMouseEvent, IListRenderer, IListTouchEvent, IListVirtualDelegate } from 'vs/base/browser/ui/list/list';\nimport { IPagedListOptions, IPagedRenderer, PagedList } from 'vs/base/browser/ui/list/listPaging';\nimport { DefaultStyleController, IKeyboardNavigationEventFilter, IListAccessibilityProvider, IListOptions, IListOptionsUpdate, IListStyles, IMultipleSelectionController, isSelectionRangeChangeEvent, isSelectionSingleChangeEvent, List, TypeNavigationMode } from 'vs/base/browser/ui/list/listWidget';\nimport { ITableColumn, ITableRenderer, ITableVirtualDelegate } from 'vs/base/browser/ui/table/table';\nimport { ITableOptions, ITableOptionsUpdate, ITableStyles, Table } from 'vs/base/browser/ui/table/tableWidget';\nimport { TreeFindMode, IAbstractTreeOptions, IAbstractTreeOptionsUpdate, RenderIndentGuides, TreeFindMatchType } from 'vs/base/browser/ui/tree/abstractTree';\nimport { AsyncDataTree, CompressibleAsyncDataTree, IAsyncDataTreeOptions, IAsyncDataTreeOptionsUpdate, ICompressibleAsyncDataTreeOptions, ICompressibleAsyncDataTreeOptionsUpdate, ITreeCompressionDelegate } from 'vs/base/browser/ui/tree/asyncDataTree';\nimport { DataTree, IDataTreeOptions } from 'vs/base/browser/ui/tree/dataTree';\nimport { CompressibleObjectTree, ICompressibleObjectTreeOptions, ICompressibleObjectTreeOptionsUpdate, ICompressibleTreeRenderer, IObjectTreeOptions, ObjectTree } from 'vs/base/browser/ui/tree/objectTree';\nimport { IAsyncDataSource, IDataSource, ITreeEvent, ITreeRenderer } from 'vs/base/browser/ui/tree/tree';\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { combinedDisposable, Disposable, DisposableStore, dispose, IDisposable, toDisposable } from 'vs/base/common/lifecycle';\nimport { localize } from 'vs/nls';\nimport { IConfigurationService } from 'vs/platform/configuration/common/configuration';\nimport { Extensions as ConfigurationExtensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry';\nimport { ContextKeyExpr, IContextKey, IContextKeyService, IScopedContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';\nimport { InputFocusedContextKey } from 'vs/platform/contextkey/common/contextkeys';\nimport { IContextViewService } from 'vs/platform/contextview/browser/contextView';\nimport { IEditorOptions } from 'vs/platform/editor/common/editor';\nimport { createDecorator, IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';\nimport { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';\nimport { ResultKind } from 'vs/platform/keybinding/common/keybindingResolver';\nimport { Registry } from 'vs/platform/registry/common/platform';\nimport { IStyleOverride, defaultFindWidgetStyles, defaultListStyles, getListStyles } from 'vs/platform/theme/browser/defaultStyles';\n\nexport type ListWidget = List | PagedList | ObjectTree | DataTree | AsyncDataTree | Table;\nexport type WorkbenchListWidget = WorkbenchList | WorkbenchPagedList | WorkbenchObjectTree | WorkbenchCompressibleObjectTree | WorkbenchDataTree | WorkbenchAsyncDataTree | WorkbenchCompressibleAsyncDataTree | WorkbenchTable;\n\nexport const IListService = createDecorator('listService');\n\nexport interface IListService {\n\n\treadonly _serviceBrand: undefined;\n\n\t/**\n\t * Returns the currently focused list widget if any.\n\t */\n\treadonly lastFocusedList: WorkbenchListWidget | undefined;\n}\n\ninterface IRegisteredList {\n\twidget: WorkbenchListWidget;\n\textraContextKeys?: (IContextKey)[];\n}\n\nexport class ListService implements IListService {\n\n\tdeclare readonly _serviceBrand: undefined;\n\n\tprivate readonly disposables = new DisposableStore();\n\tprivate lists: IRegisteredList[] = [];\n\tprivate _lastFocusedWidget: WorkbenchListWidget | undefined = undefined;\n\tprivate _hasCreatedStyleController: boolean = false;\n\n\tget lastFocusedList(): WorkbenchListWidget | undefined {\n\t\treturn this._lastFocusedWidget;\n\t}\n\n\tconstructor() { }\n\n\tprivate setLastFocusedList(widget: WorkbenchListWidget | undefined): void {\n\t\tif (widget === this._lastFocusedWidget) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._lastFocusedWidget?.getHTMLElement().classList.remove('last-focused');\n\t\tthis._lastFocusedWidget = widget;\n\t\tthis._lastFocusedWidget?.getHTMLElement().classList.add('last-focused');\n\t}\n\n\tregister(widget: WorkbenchListWidget, extraContextKeys?: (IContextKey)[]): IDisposable {\n\t\tif (!this._hasCreatedStyleController) {\n\t\t\tthis._hasCreatedStyleController = true;\n\t\t\t// create a shared default tree style sheet for performance reasons\n\t\t\tconst styleController = new DefaultStyleController(createStyleSheet(), '');\n\t\t\tstyleController.style(defaultListStyles);\n\t\t}\n\n\t\tif (this.lists.some(l => l.widget === widget)) {\n\t\t\tthrow new Error('Cannot register the same widget multiple times');\n\t\t}\n\n\t\t// Keep in our lists list\n\t\tconst registeredList: IRegisteredList = { widget, extraContextKeys };\n\t\tthis.lists.push(registeredList);\n\n\t\t// Check for currently being focused\n\t\tif (isActiveElement(widget.getHTMLElement())) {\n\t\t\tthis.setLastFocusedList(widget);\n\t\t}\n\n\t\treturn combinedDisposable(\n\t\t\twidget.onDidFocus(() => this.setLastFocusedList(widget)),\n\t\t\ttoDisposable(() => this.lists.splice(this.lists.indexOf(registeredList), 1)),\n\t\t\twidget.onDidDispose(() => {\n\t\t\t\tthis.lists = this.lists.filter(l => l !== registeredList);\n\t\t\t\tif (this._lastFocusedWidget === widget) {\n\t\t\t\t\tthis.setLastFocusedList(undefined);\n\t\t\t\t}\n\t\t\t})\n\t\t);\n\t}\n\n\tdispose(): void {\n\t\tthis.disposables.dispose();\n\t}\n}\n\nexport const RawWorkbenchListScrollAtBoundaryContextKey = new RawContextKey<'none' | 'top' | 'bottom' | 'both'>('listScrollAtBoundary', 'none');\nexport const WorkbenchListScrollAtTopContextKey = ContextKeyExpr.or(\n\tRawWorkbenchListScrollAtBoundaryContextKey.isEqualTo('top'),\n\tRawWorkbenchListScrollAtBoundaryContextKey.isEqualTo('both'));\nexport const WorkbenchListScrollAtBottomContextKey = ContextKeyExpr.or(\n\tRawWorkbenchListScrollAtBoundaryContextKey.isEqualTo('bottom'),\n\tRawWorkbenchListScrollAtBoundaryContextKey.isEqualTo('both'));\n\nexport const RawWorkbenchListFocusContextKey = new RawContextKey('listFocus', true);\nexport const WorkbenchTreeStickyScrollFocused = new RawContextKey('treestickyScrollFocused', false);\nexport const WorkbenchListSupportsMultiSelectContextKey = new RawContextKey('listSupportsMultiselect', true);\nexport const WorkbenchListFocusContextKey = ContextKeyExpr.and(RawWorkbenchListFocusContextKey, ContextKeyExpr.not(InputFocusedContextKey), WorkbenchTreeStickyScrollFocused.negate());\nexport const WorkbenchListHasSelectionOrFocus = new RawContextKey('listHasSelectionOrFocus', false);\nexport const WorkbenchListDoubleSelection = new RawContextKey('listDoubleSelection', false);\nexport const WorkbenchListMultiSelection = new RawContextKey('listMultiSelection', false);\nexport const WorkbenchListSelectionNavigation = new RawContextKey('listSelectionNavigation', false);\nexport const WorkbenchListSupportsFind = new RawContextKey('listSupportsFind', true);\nexport const WorkbenchTreeElementCanCollapse = new RawContextKey('treeElementCanCollapse', false);\nexport const WorkbenchTreeElementHasParent = new RawContextKey('treeElementHasParent', false);\nexport const WorkbenchTreeElementCanExpand = new RawContextKey('treeElementCanExpand', false);\nexport const WorkbenchTreeElementHasChild = new RawContextKey('treeElementHasChild', false);\nexport const WorkbenchTreeFindOpen = new RawContextKey('treeFindOpen', false);\nconst WorkbenchListTypeNavigationModeKey = 'listTypeNavigationMode';\n\n/**\n * @deprecated in favor of WorkbenchListTypeNavigationModeKey\n */\nconst WorkbenchListAutomaticKeyboardNavigationLegacyKey = 'listAutomaticKeyboardNavigation';\n\nfunction createScopedContextKeyService(contextKeyService: IContextKeyService, widget: ListWidget): IScopedContextKeyService {\n\tconst result = contextKeyService.createScoped(widget.getHTMLElement());\n\tRawWorkbenchListFocusContextKey.bindTo(result);\n\treturn result;\n}\n\n// Note: We must declare IScrollObservarable as the arithmetic of concrete classes,\n// instead of object type like { onDidScroll: Event; ... }. The latter will not mark\n// those properties as referenced during tree-shaking, causing them to be shaked away.\ntype IScrollObservarable = Exclude> | List;\n\nfunction createScrollObserver(contextKeyService: IContextKeyService, widget: IScrollObservarable): IDisposable {\n\tconst listScrollAt = RawWorkbenchListScrollAtBoundaryContextKey.bindTo(contextKeyService);\n\tconst update = () => {\n\t\tconst atTop = widget.scrollTop === 0;\n\n\t\t// We need a threshold `1` since scrollHeight is rounded.\n\t\t// https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight#determine_if_an_element_has_been_totally_scrolled\n\t\tconst atBottom = widget.scrollHeight - widget.renderHeight - widget.scrollTop < 1;\n\t\tif (atTop && atBottom) {\n\t\t\tlistScrollAt.set('both');\n\t\t} else if (atTop) {\n\t\t\tlistScrollAt.set('top');\n\t\t} else if (atBottom) {\n\t\t\tlistScrollAt.set('bottom');\n\t\t} else {\n\t\t\tlistScrollAt.set('none');\n\t\t}\n\t};\n\tupdate();\n\treturn widget.onDidScroll(update);\n}\n\nconst multiSelectModifierSettingKey = 'workbench.list.multiSelectModifier';\nconst openModeSettingKey = 'workbench.list.openMode';\nconst horizontalScrollingKey = 'workbench.list.horizontalScrolling';\nconst defaultFindModeSettingKey = 'workbench.list.defaultFindMode';\nconst typeNavigationModeSettingKey = 'workbench.list.typeNavigationMode';\n/** @deprecated in favor of `workbench.list.defaultFindMode` and `workbench.list.typeNavigationMode` */\nconst keyboardNavigationSettingKey = 'workbench.list.keyboardNavigation';\nconst scrollByPageKey = 'workbench.list.scrollByPage';\nconst defaultFindMatchTypeSettingKey = 'workbench.list.defaultFindMatchType';\nconst treeIndentKey = 'workbench.tree.indent';\nconst treeRenderIndentGuidesKey = 'workbench.tree.renderIndentGuides';\nconst listSmoothScrolling = 'workbench.list.smoothScrolling';\nconst mouseWheelScrollSensitivityKey = 'workbench.list.mouseWheelScrollSensitivity';\nconst fastScrollSensitivityKey = 'workbench.list.fastScrollSensitivity';\nconst treeExpandMode = 'workbench.tree.expandMode';\nconst treeStickyScroll = 'workbench.tree.enableStickyScroll';\nconst treeStickyScrollMaxElements = 'workbench.tree.stickyScrollMaxItemCount';\n\nfunction useAltAsMultipleSelectionModifier(configurationService: IConfigurationService): boolean {\n\treturn configurationService.getValue(multiSelectModifierSettingKey) === 'alt';\n}\n\nclass MultipleSelectionController extends Disposable implements IMultipleSelectionController {\n\tprivate useAltAsMultipleSelectionModifier: boolean;\n\n\tconstructor(private configurationService: IConfigurationService) {\n\t\tsuper();\n\n\t\tthis.useAltAsMultipleSelectionModifier = useAltAsMultipleSelectionModifier(configurationService);\n\n\t\tthis.registerListeners();\n\t}\n\n\tprivate registerListeners(): void {\n\t\tthis._register(this.configurationService.onDidChangeConfiguration(e => {\n\t\t\tif (e.affectsConfiguration(multiSelectModifierSettingKey)) {\n\t\t\t\tthis.useAltAsMultipleSelectionModifier = useAltAsMultipleSelectionModifier(this.configurationService);\n\t\t\t}\n\t\t}));\n\t}\n\n\tisSelectionSingleChangeEvent(event: IListMouseEvent | IListTouchEvent): boolean {\n\t\tif (this.useAltAsMultipleSelectionModifier) {\n\t\t\treturn event.browserEvent.altKey;\n\t\t}\n\n\t\treturn isSelectionSingleChangeEvent(event);\n\t}\n\n\tisSelectionRangeChangeEvent(event: IListMouseEvent | IListTouchEvent): boolean {\n\t\treturn isSelectionRangeChangeEvent(event);\n\t}\n}\n\nfunction toWorkbenchListOptions(\n\taccessor: ServicesAccessor,\n\toptions: IListOptions,\n): [IListOptions, IDisposable] {\n\tconst configurationService = accessor.get(IConfigurationService);\n\tconst keybindingService = accessor.get(IKeybindingService);\n\n\tconst disposables = new DisposableStore();\n\tconst result: IListOptions = {\n\t\t...options,\n\t\tkeyboardNavigationDelegate: { mightProducePrintableCharacter(e) { return keybindingService.mightProducePrintableCharacter(e); } },\n\t\tsmoothScrolling: Boolean(configurationService.getValue(listSmoothScrolling)),\n\t\tmouseWheelScrollSensitivity: configurationService.getValue(mouseWheelScrollSensitivityKey),\n\t\tfastScrollSensitivity: configurationService.getValue(fastScrollSensitivityKey),\n\t\tmultipleSelectionController: options.multipleSelectionController ?? disposables.add(new MultipleSelectionController(configurationService)),\n\t\tkeyboardNavigationEventFilter: createKeyboardNavigationEventFilter(keybindingService),\n\t\tscrollByPage: Boolean(configurationService.getValue(scrollByPageKey))\n\t};\n\n\treturn [result, disposables];\n}\n\nexport interface IWorkbenchListOptionsUpdate extends IListOptionsUpdate {\n\treadonly overrideStyles?: IStyleOverride;\n}\n\nexport interface IWorkbenchListOptions extends IWorkbenchListOptionsUpdate, IResourceNavigatorOptions, IListOptions {\n\treadonly selectionNavigation?: boolean;\n}\n\nexport class WorkbenchList extends List {\n\n\treadonly contextKeyService: IScopedContextKeyService;\n\tprivate listSupportsMultiSelect: IContextKey;\n\tprivate listHasSelectionOrFocus: IContextKey;\n\tprivate listDoubleSelection: IContextKey;\n\tprivate listMultiSelection: IContextKey;\n\tprivate horizontalScrolling: boolean | undefined;\n\tprivate _useAltAsMultipleSelectionModifier: boolean;\n\tprivate navigator: ListResourceNavigator;\n\n\tconstructor(\n\t\tuser: string,\n\t\tcontainer: HTMLElement,\n\t\tdelegate: IListVirtualDelegate,\n\t\trenderers: IListRenderer[],\n\t\toptions: IWorkbenchListOptions,\n\t\t@IContextKeyService contextKeyService: IContextKeyService,\n\t\t@IListService listService: IListService,\n\t\t@IConfigurationService configurationService: IConfigurationService,\n\t\t@IInstantiationService instantiationService: IInstantiationService\n\t) {\n\t\tconst horizontalScrolling = typeof options.horizontalScrolling !== 'undefined' ? options.horizontalScrolling : Boolean(configurationService.getValue(horizontalScrollingKey));\n\t\tconst [workbenchListOptions, workbenchListOptionsDisposable] = instantiationService.invokeFunction(toWorkbenchListOptions, options);\n\n\t\tsuper(user, container, delegate, renderers,\n\t\t\t{\n\t\t\t\tkeyboardSupport: false,\n\t\t\t\t...workbenchListOptions,\n\t\t\t\thorizontalScrolling,\n\t\t\t}\n\t\t);\n\n\t\tthis.disposables.add(workbenchListOptionsDisposable);\n\n\t\tthis.contextKeyService = createScopedContextKeyService(contextKeyService, this);\n\n\t\tthis.disposables.add(createScrollObserver(this.contextKeyService, this));\n\n\t\tthis.listSupportsMultiSelect = WorkbenchListSupportsMultiSelectContextKey.bindTo(this.contextKeyService);\n\t\tthis.listSupportsMultiSelect.set(options.multipleSelectionSupport !== false);\n\n\t\tconst listSelectionNavigation = WorkbenchListSelectionNavigation.bindTo(this.contextKeyService);\n\t\tlistSelectionNavigation.set(Boolean(options.selectionNavigation));\n\n\t\tthis.listHasSelectionOrFocus = WorkbenchListHasSelectionOrFocus.bindTo(this.contextKeyService);\n\t\tthis.listDoubleSelection = WorkbenchListDoubleSelection.bindTo(this.contextKeyService);\n\t\tthis.listMultiSelection = WorkbenchListMultiSelection.bindTo(this.contextKeyService);\n\t\tthis.horizontalScrolling = options.horizontalScrolling;\n\n\t\tthis._useAltAsMultipleSelectionModifier = useAltAsMultipleSelectionModifier(configurationService);\n\n\t\tthis.disposables.add(this.contextKeyService);\n\t\tthis.disposables.add((listService as ListService).register(this));\n\n\t\tthis.updateStyles(options.overrideStyles);\n\n\t\tthis.disposables.add(this.onDidChangeSelection(() => {\n\t\t\tconst selection = this.getSelection();\n\t\t\tconst focus = this.getFocus();\n\n\t\t\tthis.contextKeyService.bufferChangeEvents(() => {\n\t\t\t\tthis.listHasSelectionOrFocus.set(selection.length > 0 || focus.length > 0);\n\t\t\t\tthis.listMultiSelection.set(selection.length > 1);\n\t\t\t\tthis.listDoubleSelection.set(selection.length === 2);\n\t\t\t});\n\t\t}));\n\t\tthis.disposables.add(this.onDidChangeFocus(() => {\n\t\t\tconst selection = this.getSelection();\n\t\t\tconst focus = this.getFocus();\n\n\t\t\tthis.listHasSelectionOrFocus.set(selection.length > 0 || focus.length > 0);\n\t\t}));\n\t\tthis.disposables.add(configurationService.onDidChangeConfiguration(e => {\n\t\t\tif (e.affectsConfiguration(multiSelectModifierSettingKey)) {\n\t\t\t\tthis._useAltAsMultipleSelectionModifier = useAltAsMultipleSelectionModifier(configurationService);\n\t\t\t}\n\n\t\t\tlet options: IListOptionsUpdate = {};\n\n\t\t\tif (e.affectsConfiguration(horizontalScrollingKey) && this.horizontalScrolling === undefined) {\n\t\t\t\tconst horizontalScrolling = Boolean(configurationService.getValue(horizontalScrollingKey));\n\t\t\t\toptions = { ...options, horizontalScrolling };\n\t\t\t}\n\t\t\tif (e.affectsConfiguration(scrollByPageKey)) {\n\t\t\t\tconst scrollByPage = Boolean(configurationService.getValue(scrollByPageKey));\n\t\t\t\toptions = { ...options, scrollByPage };\n\t\t\t}\n\t\t\tif (e.affectsConfiguration(listSmoothScrolling)) {\n\t\t\t\tconst smoothScrolling = Boolean(configurationService.getValue(listSmoothScrolling));\n\t\t\t\toptions = { ...options, smoothScrolling };\n\t\t\t}\n\t\t\tif (e.affectsConfiguration(mouseWheelScrollSensitivityKey)) {\n\t\t\t\tconst mouseWheelScrollSensitivity = configurationService.getValue(mouseWheelScrollSensitivityKey);\n\t\t\t\toptions = { ...options, mouseWheelScrollSensitivity };\n\t\t\t}\n\t\t\tif (e.affectsConfiguration(fastScrollSensitivityKey)) {\n\t\t\t\tconst fastScrollSensitivity = configurationService.getValue(fastScrollSensitivityKey);\n\t\t\t\toptions = { ...options, fastScrollSensitivity };\n\t\t\t}\n\t\t\tif (Object.keys(options).length > 0) {\n\t\t\t\tthis.updateOptions(options);\n\t\t\t}\n\t\t}));\n\n\t\tthis.navigator = new ListResourceNavigator(this, { configurationService, ...options });\n\t\tthis.disposables.add(this.navigator);\n\t}\n\n\toverride updateOptions(options: IWorkbenchListOptionsUpdate): void {\n\t\tsuper.updateOptions(options);\n\n\t\tif (options.overrideStyles !== undefined) {\n\t\t\tthis.updateStyles(options.overrideStyles);\n\t\t}\n\n\t\tif (options.multipleSelectionSupport !== undefined) {\n\t\t\tthis.listSupportsMultiSelect.set(!!options.multipleSelectionSupport);\n\t\t}\n\t}\n\n\tprivate updateStyles(styles: IStyleOverride | undefined): void {\n\t\tthis.style(styles ? getListStyles(styles) : defaultListStyles);\n\t}\n}\n\nexport interface IWorkbenchPagedListOptions extends IWorkbenchListOptionsUpdate, IResourceNavigatorOptions, IPagedListOptions {\n\treadonly selectionNavigation?: boolean;\n}\n\nexport class WorkbenchPagedList extends PagedList {\n\n\treadonly contextKeyService: IScopedContextKeyService;\n\tprivate readonly disposables: DisposableStore;\n\tprivate listSupportsMultiSelect: IContextKey;\n\tprivate _useAltAsMultipleSelectionModifier: boolean;\n\tprivate horizontalScrolling: boolean | undefined;\n\tprivate navigator: ListResourceNavigator;\n\n\tconstructor(\n\t\tuser: string,\n\t\tcontainer: HTMLElement,\n\t\tdelegate: IListVirtualDelegate,\n\t\trenderers: IPagedRenderer[],\n\t\toptions: IWorkbenchPagedListOptions,\n\t\t@IContextKeyService contextKeyService: IContextKeyService,\n\t\t@IListService listService: IListService,\n\t\t@IConfigurationService configurationService: IConfigurationService,\n\t\t@IInstantiationService instantiationService: IInstantiationService\n\t) {\n\t\tconst horizontalScrolling = typeof options.horizontalScrolling !== 'undefined' ? options.horizontalScrolling : Boolean(configurationService.getValue(horizontalScrollingKey));\n\t\tconst [workbenchListOptions, workbenchListOptionsDisposable] = instantiationService.invokeFunction(toWorkbenchListOptions, options);\n\t\tsuper(user, container, delegate, renderers,\n\t\t\t{\n\t\t\t\tkeyboardSupport: false,\n\t\t\t\t...workbenchListOptions,\n\t\t\t\thorizontalScrolling,\n\t\t\t}\n\t\t);\n\n\t\tthis.disposables = new DisposableStore();\n\t\tthis.disposables.add(workbenchListOptionsDisposable);\n\n\t\tthis.contextKeyService = createScopedContextKeyService(contextKeyService, this);\n\n\t\tthis.disposables.add(createScrollObserver(this.contextKeyService, this.widget));\n\n\t\tthis.horizontalScrolling = options.horizontalScrolling;\n\n\t\tthis.listSupportsMultiSelect = WorkbenchListSupportsMultiSelectContextKey.bindTo(this.contextKeyService);\n\t\tthis.listSupportsMultiSelect.set(options.multipleSelectionSupport !== false);\n\n\t\tconst listSelectionNavigation = WorkbenchListSelectionNavigation.bindTo(this.contextKeyService);\n\t\tlistSelectionNavigation.set(Boolean(options.selectionNavigation));\n\n\t\tthis._useAltAsMultipleSelectionModifier = useAltAsMultipleSelectionModifier(configurationService);\n\n\t\tthis.disposables.add(this.contextKeyService);\n\t\tthis.disposables.add((listService as ListService).register(this));\n\n\t\tthis.updateStyles(options.overrideStyles);\n\n\t\tthis.disposables.add(configurationService.onDidChangeConfiguration(e => {\n\t\t\tif (e.affectsConfiguration(multiSelectModifierSettingKey)) {\n\t\t\t\tthis._useAltAsMultipleSelectionModifier = useAltAsMultipleSelectionModifier(configurationService);\n\t\t\t}\n\n\t\t\tlet options: IListOptionsUpdate = {};\n\n\t\t\tif (e.affectsConfiguration(horizontalScrollingKey) && this.horizontalScrolling === undefined) {\n\t\t\t\tconst horizontalScrolling = Boolean(configurationService.getValue(horizontalScrollingKey));\n\t\t\t\toptions = { ...options, horizontalScrolling };\n\t\t\t}\n\t\t\tif (e.affectsConfiguration(scrollByPageKey)) {\n\t\t\t\tconst scrollByPage = Boolean(configurationService.getValue(scrollByPageKey));\n\t\t\t\toptions = { ...options, scrollByPage };\n\t\t\t}\n\t\t\tif (e.affectsConfiguration(listSmoothScrolling)) {\n\t\t\t\tconst smoothScrolling = Boolean(configurationService.getValue(listSmoothScrolling));\n\t\t\t\toptions = { ...options, smoothScrolling };\n\t\t\t}\n\t\t\tif (e.affectsConfiguration(mouseWheelScrollSensitivityKey)) {\n\t\t\t\tconst mouseWheelScrollSensitivity = configurationService.getValue(mouseWheelScrollSensitivityKey);\n\t\t\t\toptions = { ...options, mouseWheelScrollSensitivity };\n\t\t\t}\n\t\t\tif (e.affectsConfiguration(fastScrollSensitivityKey)) {\n\t\t\t\tconst fastScrollSensitivity = configurationService.getValue(fastScrollSensitivityKey);\n\t\t\t\toptions = { ...options, fastScrollSensitivity };\n\t\t\t}\n\t\t\tif (Object.keys(options).length > 0) {\n\t\t\t\tthis.updateOptions(options);\n\t\t\t}\n\t\t}));\n\n\t\tthis.navigator = new ListResourceNavigator(this, { configurationService, ...options });\n\t\tthis.disposables.add(this.navigator);\n\t}\n\n\toverride updateOptions(options: IWorkbenchListOptionsUpdate): void {\n\t\tsuper.updateOptions(options);\n\n\t\tif (options.overrideStyles !== undefined) {\n\t\t\tthis.updateStyles(options.overrideStyles);\n\t\t}\n\n\t\tif (options.multipleSelectionSupport !== undefined) {\n\t\t\tthis.listSupportsMultiSelect.set(!!options.multipleSelectionSupport);\n\t\t}\n\t}\n\n\tprivate updateStyles(styles: IStyleOverride | undefined): void {\n\t\tthis.style(styles ? getListStyles(styles) : defaultListStyles);\n\t}\n\n\toverride dispose(): void {\n\t\tthis.disposables.dispose();\n\t\tsuper.dispose();\n\t}\n}\n\nexport interface IWorkbenchTableOptionsUpdate extends ITableOptionsUpdate {\n\treadonly overrideStyles?: IStyleOverride;\n}\n\nexport interface IWorkbenchTableOptions extends IWorkbenchTableOptionsUpdate, IResourceNavigatorOptions, ITableOptions {\n\treadonly selectionNavigation?: boolean;\n}\n\nexport class WorkbenchTable extends Table {\n\n\treadonly contextKeyService: IScopedContextKeyService;\n\tprivate listSupportsMultiSelect: IContextKey;\n\tprivate listHasSelectionOrFocus: IContextKey;\n\tprivate listDoubleSelection: IContextKey;\n\tprivate listMultiSelection: IContextKey;\n\tprivate horizontalScrolling: boolean | undefined;\n\tprivate _useAltAsMultipleSelectionModifier: boolean;\n\tprivate navigator: TableResourceNavigator;\n\n\tconstructor(\n\t\tuser: string,\n\t\tcontainer: HTMLElement,\n\t\tdelegate: ITableVirtualDelegate,\n\t\tcolumns: ITableColumn[],\n\t\trenderers: ITableRenderer[],\n\t\toptions: IWorkbenchTableOptions,\n\t\t@IContextKeyService contextKeyService: IContextKeyService,\n\t\t@IListService listService: IListService,\n\t\t@IConfigurationService configurationService: IConfigurationService,\n\t\t@IInstantiationService instantiationService: IInstantiationService\n\t) {\n\t\tconst horizontalScrolling = typeof options.horizontalScrolling !== 'undefined' ? options.horizontalScrolling : Boolean(configurationService.getValue(horizontalScrollingKey));\n\t\tconst [workbenchListOptions, workbenchListOptionsDisposable] = instantiationService.invokeFunction(toWorkbenchListOptions, options);\n\n\t\tsuper(user, container, delegate, columns, renderers,\n\t\t\t{\n\t\t\t\tkeyboardSupport: false,\n\t\t\t\t...workbenchListOptions,\n\t\t\t\thorizontalScrolling,\n\t\t\t}\n\t\t);\n\n\t\tthis.disposables.add(workbenchListOptionsDisposable);\n\n\t\tthis.contextKeyService = createScopedContextKeyService(contextKeyService, this);\n\n\t\tthis.disposables.add(createScrollObserver(this.contextKeyService, this));\n\n\t\tthis.listSupportsMultiSelect = WorkbenchListSupportsMultiSelectContextKey.bindTo(this.contextKeyService);\n\t\tthis.listSupportsMultiSelect.set(options.multipleSelectionSupport !== false);\n\n\t\tconst listSelectionNavigation = WorkbenchListSelectionNavigation.bindTo(this.contextKeyService);\n\t\tlistSelectionNavigation.set(Boolean(options.selectionNavigation));\n\n\t\tthis.listHasSelectionOrFocus = WorkbenchListHasSelectionOrFocus.bindTo(this.contextKeyService);\n\t\tthis.listDoubleSelection = WorkbenchListDoubleSelection.bindTo(this.contextKeyService);\n\t\tthis.listMultiSelection = WorkbenchListMultiSelection.bindTo(this.contextKeyService);\n\t\tthis.horizontalScrolling = options.horizontalScrolling;\n\n\t\tthis._useAltAsMultipleSelectionModifier = useAltAsMultipleSelectionModifier(configurationService);\n\n\t\tthis.disposables.add(this.contextKeyService);\n\t\tthis.disposables.add((listService as ListService).register(this));\n\n\t\tthis.updateStyles(options.overrideStyles);\n\n\t\tthis.disposables.add(this.onDidChangeSelection(() => {\n\t\t\tconst selection = this.getSelection();\n\t\t\tconst focus = this.getFocus();\n\n\t\t\tthis.contextKeyService.bufferChangeEvents(() => {\n\t\t\t\tthis.listHasSelectionOrFocus.set(selection.length > 0 || focus.length > 0);\n\t\t\t\tthis.listMultiSelection.set(selection.length > 1);\n\t\t\t\tthis.listDoubleSelection.set(selection.length === 2);\n\t\t\t});\n\t\t}));\n\t\tthis.disposables.add(this.onDidChangeFocus(() => {\n\t\t\tconst selection = this.getSelection();\n\t\t\tconst focus = this.getFocus();\n\n\t\t\tthis.listHasSelectionOrFocus.set(selection.length > 0 || focus.length > 0);\n\t\t}));\n\t\tthis.disposables.add(configurationService.onDidChangeConfiguration(e => {\n\t\t\tif (e.affectsConfiguration(multiSelectModifierSettingKey)) {\n\t\t\t\tthis._useAltAsMultipleSelectionModifier = useAltAsMultipleSelectionModifier(configurationService);\n\t\t\t}\n\n\t\t\tlet options: IListOptionsUpdate = {};\n\n\t\t\tif (e.affectsConfiguration(horizontalScrollingKey) && this.horizontalScrolling === undefined) {\n\t\t\t\tconst horizontalScrolling = Boolean(configurationService.getValue(horizontalScrollingKey));\n\t\t\t\toptions = { ...options, horizontalScrolling };\n\t\t\t}\n\t\t\tif (e.affectsConfiguration(scrollByPageKey)) {\n\t\t\t\tconst scrollByPage = Boolean(configurationService.getValue(scrollByPageKey));\n\t\t\t\toptions = { ...options, scrollByPage };\n\t\t\t}\n\t\t\tif (e.affectsConfiguration(listSmoothScrolling)) {\n\t\t\t\tconst smoothScrolling = Boolean(configurationService.getValue(listSmoothScrolling));\n\t\t\t\toptions = { ...options, smoothScrolling };\n\t\t\t}\n\t\t\tif (e.affectsConfiguration(mouseWheelScrollSensitivityKey)) {\n\t\t\t\tconst mouseWheelScrollSensitivity = configurationService.getValue(mouseWheelScrollSensitivityKey);\n\t\t\t\toptions = { ...options, mouseWheelScrollSensitivity };\n\t\t\t}\n\t\t\tif (e.affectsConfiguration(fastScrollSensitivityKey)) {\n\t\t\t\tconst fastScrollSensitivity = configurationService.getValue(fastScrollSensitivityKey);\n\t\t\t\toptions = { ...options, fastScrollSensitivity };\n\t\t\t}\n\t\t\tif (Object.keys(options).length > 0) {\n\t\t\t\tthis.updateOptions(options);\n\t\t\t}\n\t\t}));\n\n\t\tthis.navigator = new TableResourceNavigator(this, { configurationService, ...options });\n\t\tthis.disposables.add(this.navigator);\n\t}\n\n\toverride updateOptions(options: IWorkbenchTableOptionsUpdate): void {\n\t\tsuper.updateOptions(options);\n\n\t\tif (options.overrideStyles !== undefined) {\n\t\t\tthis.updateStyles(options.overrideStyles);\n\t\t}\n\n\t\tif (options.multipleSelectionSupport !== undefined) {\n\t\t\tthis.listSupportsMultiSelect.set(!!options.multipleSelectionSupport);\n\t\t}\n\t}\n\n\tprivate updateStyles(styles: IStyleOverride | undefined): void {\n\t\tthis.style(styles ? getListStyles(styles) : defaultListStyles);\n\t}\n\n\toverride dispose(): void {\n\t\tthis.disposables.dispose();\n\t\tsuper.dispose();\n\t}\n}\n\nexport interface IOpenEvent {\n\teditorOptions: IEditorOptions;\n\tsideBySide: boolean;\n\telement: T;\n\tbrowserEvent?: UIEvent;\n}\n\nexport interface IResourceNavigatorOptions {\n\treadonly configurationService?: IConfigurationService;\n\treadonly openOnSingleClick?: boolean;\n}\n\nexport interface SelectionKeyboardEvent extends KeyboardEvent {\n\tpreserveFocus?: boolean;\n\tpinned?: boolean;\n\t__forceEvent?: boolean;\n}\n\nabstract class ResourceNavigator extends Disposable {\n\n\tprivate openOnSingleClick: boolean;\n\n\tprivate readonly _onDidOpen = this._register(new Emitter>());\n\treadonly onDidOpen: Event> = this._onDidOpen.event;\n\n\tconstructor(\n\t\tprotected readonly widget: ListWidget,\n\t\toptions?: IResourceNavigatorOptions\n\t) {\n\t\tsuper();\n\n\t\tthis._register(Event.filter(this.widget.onDidChangeSelection, e => isKeyboardEvent(e.browserEvent))(e => this.onSelectionFromKeyboard(e)));\n\t\tthis._register(this.widget.onPointer((e: { browserEvent: MouseEvent; element: T | undefined }) => this.onPointer(e.element, e.browserEvent)));\n\t\tthis._register(this.widget.onMouseDblClick((e: { browserEvent: MouseEvent; element: T | undefined }) => this.onMouseDblClick(e.element, e.browserEvent)));\n\n\t\tif (typeof options?.openOnSingleClick !== 'boolean' && options?.configurationService) {\n\t\t\tthis.openOnSingleClick = options?.configurationService.getValue(openModeSettingKey) !== 'doubleClick';\n\t\t\tthis._register(options?.configurationService.onDidChangeConfiguration(e => {\n\t\t\t\tif (e.affectsConfiguration(openModeSettingKey)) {\n\t\t\t\t\tthis.openOnSingleClick = options?.configurationService!.getValue(openModeSettingKey) !== 'doubleClick';\n\t\t\t\t}\n\t\t\t}));\n\t\t} else {\n\t\t\tthis.openOnSingleClick = options?.openOnSingleClick ?? true;\n\t\t}\n\t}\n\n\tprivate onSelectionFromKeyboard(event: ITreeEvent): void {\n\t\tif (event.elements.length !== 1) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst selectionKeyboardEvent = event.browserEvent as SelectionKeyboardEvent;\n\t\tconst preserveFocus = typeof selectionKeyboardEvent.preserveFocus === 'boolean' ? selectionKeyboardEvent.preserveFocus : true;\n\t\tconst pinned = typeof selectionKeyboardEvent.pinned === 'boolean' ? selectionKeyboardEvent.pinned : !preserveFocus;\n\t\tconst sideBySide = false;\n\n\t\tthis._open(this.getSelectedElement(), preserveFocus, pinned, sideBySide, event.browserEvent);\n\t}\n\n\tprivate onPointer(element: T | undefined, browserEvent: MouseEvent): void {\n\t\tif (!this.openOnSingleClick) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst isDoubleClick = browserEvent.detail === 2;\n\n\t\tif (isDoubleClick) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst isMiddleClick = browserEvent.button === 1;\n\t\tconst preserveFocus = true;\n\t\tconst pinned = isMiddleClick;\n\t\tconst sideBySide = browserEvent.ctrlKey || browserEvent.metaKey || browserEvent.altKey;\n\n\t\tthis._open(element, preserveFocus, pinned, sideBySide, browserEvent);\n\t}\n\n\tprivate onMouseDblClick(element: T | undefined, browserEvent?: MouseEvent): void {\n\t\tif (!browserEvent) {\n\t\t\treturn;\n\t\t}\n\n\t\t// copied from AbstractTree\n\t\tconst target = browserEvent.target as HTMLElement;\n\t\tconst onTwistie = target.classList.contains('monaco-tl-twistie')\n\t\t\t|| (target.classList.contains('monaco-icon-label') && target.classList.contains('folder-icon') && browserEvent.offsetX < 16);\n\n\t\tif (onTwistie) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst preserveFocus = false;\n\t\tconst pinned = true;\n\t\tconst sideBySide = (browserEvent.ctrlKey || browserEvent.metaKey || browserEvent.altKey);\n\n\t\tthis._open(element, preserveFocus, pinned, sideBySide, browserEvent);\n\t}\n\n\tprivate _open(element: T | undefined, preserveFocus: boolean, pinned: boolean, sideBySide: boolean, browserEvent?: UIEvent): void {\n\t\tif (!element) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis._onDidOpen.fire({\n\t\t\teditorOptions: {\n\t\t\t\tpreserveFocus,\n\t\t\t\tpinned,\n\t\t\t\trevealIfVisible: true\n\t\t\t},\n\t\t\tsideBySide,\n\t\t\telement,\n\t\t\tbrowserEvent\n\t\t});\n\t}\n\n\tabstract getSelectedElement(): T | undefined;\n}\n\nclass ListResourceNavigator extends ResourceNavigator {\n\n\tprotected override readonly widget: List | PagedList;\n\n\tconstructor(\n\t\twidget: List | PagedList,\n\t\toptions: IResourceNavigatorOptions\n\t) {\n\t\tsuper(widget, options);\n\t\tthis.widget = widget;\n\t}\n\n\tgetSelectedElement(): T | undefined {\n\t\treturn this.widget.getSelectedElements()[0];\n\t}\n}\n\nclass TableResourceNavigator extends ResourceNavigator {\n\n\tprotected declare readonly widget: Table;\n\n\tconstructor(\n\t\twidget: Table,\n\t\toptions: IResourceNavigatorOptions\n\t) {\n\t\tsuper(widget, options);\n\t}\n\n\tgetSelectedElement(): TRow | undefined {\n\t\treturn this.widget.getSelectedElements()[0];\n\t}\n}\n\nclass TreeResourceNavigator extends ResourceNavigator {\n\n\tprotected declare readonly widget: ObjectTree | CompressibleObjectTree | DataTree | AsyncDataTree | CompressibleAsyncDataTree;\n\n\tconstructor(\n\t\twidget: ObjectTree | CompressibleObjectTree | DataTree | AsyncDataTree | CompressibleAsyncDataTree,\n\t\toptions: IResourceNavigatorOptions\n\t) {\n\t\tsuper(widget, options);\n\t}\n\n\tgetSelectedElement(): T | undefined {\n\t\treturn this.widget.getSelection()[0] ?? undefined;\n\t}\n}\n\nfunction createKeyboardNavigationEventFilter(keybindingService: IKeybindingService): IKeyboardNavigationEventFilter {\n\tlet inMultiChord = false;\n\n\treturn event => {\n\t\tif (event.toKeyCodeChord().isModifierKey()) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (inMultiChord) {\n\t\t\tinMultiChord = false;\n\t\t\treturn false;\n\t\t}\n\n\t\tconst result = keybindingService.softDispatch(event, event.target);\n\n\t\tif (result.kind === ResultKind.MoreChordsNeeded) {\n\t\t\tinMultiChord = true;\n\t\t\treturn false;\n\t\t}\n\n\t\tinMultiChord = false;\n\t\treturn result.kind === ResultKind.NoMatchingKb;\n\t};\n}\n\nexport interface IWorkbenchObjectTreeOptions extends IObjectTreeOptions, IResourceNavigatorOptions {\n\treadonly accessibilityProvider: IListAccessibilityProvider;\n\treadonly overrideStyles?: IStyleOverride;\n\treadonly selectionNavigation?: boolean;\n}\n\nexport class WorkbenchObjectTree, TFilterData = void> extends ObjectTree {\n\n\tprivate internals: WorkbenchTreeInternals;\n\n\tconstructor(\n\t\tuser: string,\n\t\tcontainer: HTMLElement,\n\t\tdelegate: IListVirtualDelegate,\n\t\trenderers: ITreeRenderer[],\n\t\toptions: IWorkbenchObjectTreeOptions,\n\t\t@IInstantiationService instantiationService: IInstantiationService,\n\t\t@IContextKeyService contextKeyService: IContextKeyService,\n\t\t@IListService listService: IListService,\n\t\t@IConfigurationService configurationService: IConfigurationService\n\t) {\n\t\tconst { options: treeOptions, getTypeNavigationMode, disposable } = instantiationService.invokeFunction(workbenchTreeDataPreamble, options as any);\n\t\tsuper(user, container, delegate, renderers, treeOptions);\n\t\tthis.disposables.add(disposable);\n\t\tthis.internals = new WorkbenchTreeInternals(this, options, getTypeNavigationMode, options.overrideStyles, contextKeyService, listService, configurationService);\n\t\tthis.disposables.add(this.internals);\n\t}\n\n\toverride updateOptions(options: IAbstractTreeOptionsUpdate): void {\n\t\tsuper.updateOptions(options);\n\t\tthis.internals.updateOptions(options);\n\t}\n}\n\nexport interface IWorkbenchCompressibleObjectTreeOptionsUpdate extends ICompressibleObjectTreeOptionsUpdate {\n\treadonly overrideStyles?: IStyleOverride;\n}\n\nexport interface IWorkbenchCompressibleObjectTreeOptions extends IWorkbenchCompressibleObjectTreeOptionsUpdate, ICompressibleObjectTreeOptions, IResourceNavigatorOptions {\n\treadonly selectionNavigation?: boolean;\n}\n\nexport class WorkbenchCompressibleObjectTree, TFilterData = void> extends CompressibleObjectTree {\n\n\tprivate internals: WorkbenchTreeInternals;\n\n\tconstructor(\n\t\tuser: string,\n\t\tcontainer: HTMLElement,\n\t\tdelegate: IListVirtualDelegate,\n\t\trenderers: ICompressibleTreeRenderer[],\n\t\toptions: IWorkbenchCompressibleObjectTreeOptions,\n\t\t@IInstantiationService instantiationService: IInstantiationService,\n\t\t@IContextKeyService contextKeyService: IContextKeyService,\n\t\t@IListService listService: IListService,\n\t\t@IConfigurationService configurationService: IConfigurationService\n\t) {\n\t\tconst { options: treeOptions, getTypeNavigationMode, disposable } = instantiationService.invokeFunction(workbenchTreeDataPreamble, options as any);\n\t\tsuper(user, container, delegate, renderers, treeOptions);\n\t\tthis.disposables.add(disposable);\n\t\tthis.internals = new WorkbenchTreeInternals(this, options, getTypeNavigationMode, options.overrideStyles, contextKeyService, listService, configurationService);\n\t\tthis.disposables.add(this.internals);\n\t}\n\n\toverride updateOptions(options: IWorkbenchCompressibleObjectTreeOptionsUpdate = {}): void {\n\t\tsuper.updateOptions(options);\n\n\t\tif (options.overrideStyles) {\n\t\t\tthis.internals.updateStyleOverrides(options.overrideStyles);\n\t\t}\n\n\t\tthis.internals.updateOptions(options);\n\t}\n}\n\nexport interface IWorkbenchDataTreeOptionsUpdate extends IAbstractTreeOptionsUpdate {\n\treadonly overrideStyles?: IStyleOverride;\n}\n\nexport interface IWorkbenchDataTreeOptions extends IWorkbenchDataTreeOptionsUpdate, IDataTreeOptions, IResourceNavigatorOptions {\n\treadonly selectionNavigation?: boolean;\n}\n\nexport class WorkbenchDataTree extends DataTree {\n\n\tprivate internals: WorkbenchTreeInternals;\n\n\tconstructor(\n\t\tuser: string,\n\t\tcontainer: HTMLElement,\n\t\tdelegate: IListVirtualDelegate,\n\t\trenderers: ITreeRenderer[],\n\t\tdataSource: IDataSource,\n\t\toptions: IWorkbenchDataTreeOptions,\n\t\t@IInstantiationService instantiationService: IInstantiationService,\n\t\t@IContextKeyService contextKeyService: IContextKeyService,\n\t\t@IListService listService: IListService,\n\t\t@IConfigurationService configurationService: IConfigurationService\n\t) {\n\t\tconst { options: treeOptions, getTypeNavigationMode, disposable } = instantiationService.invokeFunction(workbenchTreeDataPreamble, options as any);\n\t\tsuper(user, container, delegate, renderers, dataSource, treeOptions);\n\t\tthis.disposables.add(disposable);\n\t\tthis.internals = new WorkbenchTreeInternals(this, options, getTypeNavigationMode, options.overrideStyles, contextKeyService, listService, configurationService);\n\t\tthis.disposables.add(this.internals);\n\t}\n\n\toverride updateOptions(options: IWorkbenchDataTreeOptionsUpdate = {}): void {\n\t\tsuper.updateOptions(options);\n\n\t\tif (options.overrideStyles !== undefined) {\n\t\t\tthis.internals.updateStyleOverrides(options.overrideStyles);\n\t\t}\n\n\t\tthis.internals.updateOptions(options);\n\t}\n}\n\nexport interface IWorkbenchAsyncDataTreeOptionsUpdate extends IAsyncDataTreeOptionsUpdate {\n\treadonly overrideStyles?: IStyleOverride;\n}\n\nexport interface IWorkbenchAsyncDataTreeOptions extends IWorkbenchAsyncDataTreeOptionsUpdate, IAsyncDataTreeOptions, IResourceNavigatorOptions {\n\treadonly accessibilityProvider: IListAccessibilityProvider;\n\treadonly selectionNavigation?: boolean;\n}\n\nexport class WorkbenchAsyncDataTree extends AsyncDataTree {\n\n\tprivate internals: WorkbenchTreeInternals;\n\tget onDidOpen(): Event> { return this.internals.onDidOpen; }\n\n\tconstructor(\n\t\tuser: string,\n\t\tcontainer: HTMLElement,\n\t\tdelegate: IListVirtualDelegate,\n\t\trenderers: ITreeRenderer[],\n\t\tdataSource: IAsyncDataSource,\n\t\toptions: IWorkbenchAsyncDataTreeOptions,\n\t\t@IInstantiationService instantiationService: IInstantiationService,\n\t\t@IContextKeyService contextKeyService: IContextKeyService,\n\t\t@IListService listService: IListService,\n\t\t@IConfigurationService configurationService: IConfigurationService\n\t) {\n\t\tconst { options: treeOptions, getTypeNavigationMode, disposable } = instantiationService.invokeFunction(workbenchTreeDataPreamble, options as any);\n\t\tsuper(user, container, delegate, renderers, dataSource, treeOptions);\n\t\tthis.disposables.add(disposable);\n\t\tthis.internals = new WorkbenchTreeInternals(this, options, getTypeNavigationMode, options.overrideStyles, contextKeyService, listService, configurationService);\n\t\tthis.disposables.add(this.internals);\n\t}\n\n\toverride updateOptions(options: IWorkbenchAsyncDataTreeOptionsUpdate = {}): void {\n\t\tsuper.updateOptions(options);\n\n\t\tif (options.overrideStyles) {\n\t\t\tthis.internals.updateStyleOverrides(options.overrideStyles);\n\t\t}\n\n\t\tthis.internals.updateOptions(options);\n\t}\n}\n\nexport interface IWorkbenchCompressibleAsyncDataTreeOptions extends ICompressibleAsyncDataTreeOptions, IResourceNavigatorOptions {\n\treadonly overrideStyles?: IStyleOverride;\n\treadonly selectionNavigation?: boolean;\n}\n\nexport class WorkbenchCompressibleAsyncDataTree extends CompressibleAsyncDataTree {\n\n\tprivate internals: WorkbenchTreeInternals;\n\n\tconstructor(\n\t\tuser: string,\n\t\tcontainer: HTMLElement,\n\t\tvirtualDelegate: IListVirtualDelegate,\n\t\tcompressionDelegate: ITreeCompressionDelegate,\n\t\trenderers: ICompressibleTreeRenderer[],\n\t\tdataSource: IAsyncDataSource,\n\t\toptions: IWorkbenchCompressibleAsyncDataTreeOptions,\n\t\t@IInstantiationService instantiationService: IInstantiationService,\n\t\t@IContextKeyService contextKeyService: IContextKeyService,\n\t\t@IListService listService: IListService,\n\t\t@IConfigurationService configurationService: IConfigurationService\n\t) {\n\t\tconst { options: treeOptions, getTypeNavigationMode, disposable } = instantiationService.invokeFunction(workbenchTreeDataPreamble, options as any);\n\t\tsuper(user, container, virtualDelegate, compressionDelegate, renderers, dataSource, treeOptions);\n\t\tthis.disposables.add(disposable);\n\t\tthis.internals = new WorkbenchTreeInternals(this, options, getTypeNavigationMode, options.overrideStyles, contextKeyService, listService, configurationService);\n\t\tthis.disposables.add(this.internals);\n\t}\n\n\toverride updateOptions(options: ICompressibleAsyncDataTreeOptionsUpdate): void {\n\t\tsuper.updateOptions(options);\n\t\tthis.internals.updateOptions(options);\n\t}\n}\n\nfunction getDefaultTreeFindMode(configurationService: IConfigurationService) {\n\tconst value = configurationService.getValue<'highlight' | 'filter'>(defaultFindModeSettingKey);\n\n\tif (value === 'highlight') {\n\t\treturn TreeFindMode.Highlight;\n\t} else if (value === 'filter') {\n\t\treturn TreeFindMode.Filter;\n\t}\n\n\tconst deprecatedValue = configurationService.getValue<'simple' | 'highlight' | 'filter'>(keyboardNavigationSettingKey);\n\n\tif (deprecatedValue === 'simple' || deprecatedValue === 'highlight') {\n\t\treturn TreeFindMode.Highlight;\n\t} else if (deprecatedValue === 'filter') {\n\t\treturn TreeFindMode.Filter;\n\t}\n\n\treturn undefined;\n}\n\nfunction getDefaultTreeFindMatchType(configurationService: IConfigurationService) {\n\tconst value = configurationService.getValue<'fuzzy' | 'contiguous'>(defaultFindMatchTypeSettingKey);\n\n\tif (value === 'fuzzy') {\n\t\treturn TreeFindMatchType.Fuzzy;\n\t} else if (value === 'contiguous') {\n\t\treturn TreeFindMatchType.Contiguous;\n\t}\n\treturn undefined;\n}\n\nfunction workbenchTreeDataPreamble | IAsyncDataTreeOptions>(\n\taccessor: ServicesAccessor,\n\toptions: TOptions,\n): { options: TOptions; getTypeNavigationMode: () => TypeNavigationMode | undefined; disposable: IDisposable } {\n\tconst configurationService = accessor.get(IConfigurationService);\n\tconst contextViewService = accessor.get(IContextViewService);\n\tconst contextKeyService = accessor.get(IContextKeyService);\n\tconst instantiationService = accessor.get(IInstantiationService);\n\n\tconst getTypeNavigationMode = () => {\n\t\t// give priority to the context key value to specify a value\n\t\tconst modeString = contextKeyService.getContextKeyValue<'automatic' | 'trigger'>(WorkbenchListTypeNavigationModeKey);\n\n\t\tif (modeString === 'automatic') {\n\t\t\treturn TypeNavigationMode.Automatic;\n\t\t} else if (modeString === 'trigger') {\n\t\t\treturn TypeNavigationMode.Trigger;\n\t\t}\n\n\t\t// also check the deprecated context key to set the mode to 'trigger'\n\t\tconst modeBoolean = contextKeyService.getContextKeyValue(WorkbenchListAutomaticKeyboardNavigationLegacyKey);\n\n\t\tif (modeBoolean === false) {\n\t\t\treturn TypeNavigationMode.Trigger;\n\t\t}\n\n\t\t// finally, check the setting\n\t\tconst configString = configurationService.getValue<'automatic' | 'trigger'>(typeNavigationModeSettingKey);\n\n\t\tif (configString === 'automatic') {\n\t\t\treturn TypeNavigationMode.Automatic;\n\t\t} else if (configString === 'trigger') {\n\t\t\treturn TypeNavigationMode.Trigger;\n\t\t}\n\n\t\treturn undefined;\n\t};\n\n\tconst horizontalScrolling = options.horizontalScrolling !== undefined ? options.horizontalScrolling : Boolean(configurationService.getValue(horizontalScrollingKey));\n\tconst [workbenchListOptions, disposable] = instantiationService.invokeFunction(toWorkbenchListOptions, options);\n\tconst paddingBottom = options.paddingBottom;\n\tconst renderIndentGuides = options.renderIndentGuides !== undefined ? options.renderIndentGuides : configurationService.getValue(treeRenderIndentGuidesKey);\n\n\treturn {\n\t\tgetTypeNavigationMode,\n\t\tdisposable,\n\t\toptions: {\n\t\t\t// ...options, // TODO@Joao why is this not splatted here?\n\t\t\tkeyboardSupport: false,\n\t\t\t...workbenchListOptions,\n\t\t\tindent: typeof configurationService.getValue(treeIndentKey) === 'number' ? configurationService.getValue(treeIndentKey) : undefined,\n\t\t\trenderIndentGuides,\n\t\t\tsmoothScrolling: Boolean(configurationService.getValue(listSmoothScrolling)),\n\t\t\tdefaultFindMode: getDefaultTreeFindMode(configurationService),\n\t\t\tdefaultFindMatchType: getDefaultTreeFindMatchType(configurationService),\n\t\t\thorizontalScrolling,\n\t\t\tscrollByPage: Boolean(configurationService.getValue(scrollByPageKey)),\n\t\t\tpaddingBottom: paddingBottom,\n\t\t\thideTwistiesOfChildlessElements: options.hideTwistiesOfChildlessElements,\n\t\t\texpandOnlyOnTwistieClick: options.expandOnlyOnTwistieClick ?? (configurationService.getValue<'singleClick' | 'doubleClick'>(treeExpandMode) === 'doubleClick'),\n\t\t\tcontextViewProvider: contextViewService as IContextViewProvider,\n\t\t\tfindWidgetStyles: defaultFindWidgetStyles,\n\t\t\tenableStickyScroll: Boolean(configurationService.getValue(treeStickyScroll)),\n\t\t\tstickyScrollMaxItemCount: Number(configurationService.getValue(treeStickyScrollMaxElements)),\n\t\t} as TOptions\n\t};\n}\n\ninterface IWorkbenchTreeInternalsOptionsUpdate {\n\treadonly multipleSelectionSupport?: boolean;\n}\n\nclass WorkbenchTreeInternals {\n\n\treadonly contextKeyService: IScopedContextKeyService;\n\tprivate listSupportsMultiSelect: IContextKey;\n\tprivate listSupportFindWidget: IContextKey;\n\tprivate hasSelectionOrFocus: IContextKey;\n\tprivate hasDoubleSelection: IContextKey;\n\tprivate hasMultiSelection: IContextKey;\n\tprivate treeElementCanCollapse: IContextKey;\n\tprivate treeElementHasParent: IContextKey;\n\tprivate treeElementCanExpand: IContextKey;\n\tprivate treeElementHasChild: IContextKey;\n\tprivate treeFindOpen: IContextKey;\n\tprivate treeStickyScrollFocused: IContextKey;\n\tprivate _useAltAsMultipleSelectionModifier: boolean;\n\tprivate disposables: IDisposable[] = [];\n\n\tprivate navigator: TreeResourceNavigator;\n\n\tget onDidOpen(): Event> { return this.navigator.onDidOpen; }\n\n\tconstructor(\n\t\tprivate tree: WorkbenchObjectTree | WorkbenchCompressibleObjectTree | WorkbenchDataTree | WorkbenchAsyncDataTree | WorkbenchCompressibleAsyncDataTree,\n\t\toptions: IWorkbenchObjectTreeOptions | IWorkbenchCompressibleObjectTreeOptions | IWorkbenchDataTreeOptions | IWorkbenchAsyncDataTreeOptions | IWorkbenchCompressibleAsyncDataTreeOptions,\n\t\tgetTypeNavigationMode: () => TypeNavigationMode | undefined,\n\t\toverrideStyles: IStyleOverride | undefined,\n\t\t@IContextKeyService contextKeyService: IContextKeyService,\n\t\t@IListService listService: IListService,\n\t\t@IConfigurationService configurationService: IConfigurationService\n\t) {\n\t\tthis.contextKeyService = createScopedContextKeyService(contextKeyService, tree);\n\n\t\tthis.disposables.push(createScrollObserver(this.contextKeyService, tree));\n\n\t\tthis.listSupportsMultiSelect = WorkbenchListSupportsMultiSelectContextKey.bindTo(this.contextKeyService);\n\t\tthis.listSupportsMultiSelect.set(options.multipleSelectionSupport !== false);\n\n\t\tconst listSelectionNavigation = WorkbenchListSelectionNavigation.bindTo(this.contextKeyService);\n\t\tlistSelectionNavigation.set(Boolean(options.selectionNavigation));\n\n\t\tthis.listSupportFindWidget = WorkbenchListSupportsFind.bindTo(this.contextKeyService);\n\t\tthis.listSupportFindWidget.set(options.findWidgetEnabled ?? true);\n\n\t\tthis.hasSelectionOrFocus = WorkbenchListHasSelectionOrFocus.bindTo(this.contextKeyService);\n\t\tthis.hasDoubleSelection = WorkbenchListDoubleSelection.bindTo(this.contextKeyService);\n\t\tthis.hasMultiSelection = WorkbenchListMultiSelection.bindTo(this.contextKeyService);\n\n\t\tthis.treeElementCanCollapse = WorkbenchTreeElementCanCollapse.bindTo(this.contextKeyService);\n\t\tthis.treeElementHasParent = WorkbenchTreeElementHasParent.bindTo(this.contextKeyService);\n\t\tthis.treeElementCanExpand = WorkbenchTreeElementCanExpand.bindTo(this.contextKeyService);\n\t\tthis.treeElementHasChild = WorkbenchTreeElementHasChild.bindTo(this.contextKeyService);\n\n\t\tthis.treeFindOpen = WorkbenchTreeFindOpen.bindTo(this.contextKeyService);\n\t\tthis.treeStickyScrollFocused = WorkbenchTreeStickyScrollFocused.bindTo(this.contextKeyService);\n\n\t\tthis._useAltAsMultipleSelectionModifier = useAltAsMultipleSelectionModifier(configurationService);\n\n\t\tthis.updateStyleOverrides(overrideStyles);\n\n\t\tconst updateCollapseContextKeys = () => {\n\t\t\tconst focus = tree.getFocus()[0];\n\n\t\t\tif (!focus) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst node = tree.getNode(focus);\n\t\t\tthis.treeElementCanCollapse.set(node.collapsible && !node.collapsed);\n\t\t\tthis.treeElementHasParent.set(!!tree.getParentElement(focus));\n\t\t\tthis.treeElementCanExpand.set(node.collapsible && node.collapsed);\n\t\t\tthis.treeElementHasChild.set(!!tree.getFirstElementChild(focus));\n\t\t};\n\n\t\tconst interestingContextKeys = new Set();\n\t\tinterestingContextKeys.add(WorkbenchListTypeNavigationModeKey);\n\t\tinterestingContextKeys.add(WorkbenchListAutomaticKeyboardNavigationLegacyKey);\n\n\t\tthis.disposables.push(\n\t\t\tthis.contextKeyService,\n\t\t\t(listService as ListService).register(tree),\n\t\t\ttree.onDidChangeSelection(() => {\n\t\t\t\tconst selection = tree.getSelection();\n\t\t\t\tconst focus = tree.getFocus();\n\n\t\t\t\tthis.contextKeyService.bufferChangeEvents(() => {\n\t\t\t\t\tthis.hasSelectionOrFocus.set(selection.length > 0 || focus.length > 0);\n\t\t\t\t\tthis.hasMultiSelection.set(selection.length > 1);\n\t\t\t\t\tthis.hasDoubleSelection.set(selection.length === 2);\n\t\t\t\t});\n\t\t\t}),\n\t\t\ttree.onDidChangeFocus(() => {\n\t\t\t\tconst selection = tree.getSelection();\n\t\t\t\tconst focus = tree.getFocus();\n\n\t\t\t\tthis.hasSelectionOrFocus.set(selection.length > 0 || focus.length > 0);\n\t\t\t\tupdateCollapseContextKeys();\n\t\t\t}),\n\t\t\ttree.onDidChangeCollapseState(updateCollapseContextKeys),\n\t\t\ttree.onDidChangeModel(updateCollapseContextKeys),\n\t\t\ttree.onDidChangeFindOpenState(enabled => this.treeFindOpen.set(enabled)),\n\t\t\ttree.onDidChangeStickyScrollFocused(focused => this.treeStickyScrollFocused.set(focused)),\n\t\t\tconfigurationService.onDidChangeConfiguration(e => {\n\t\t\t\tlet newOptions: IAbstractTreeOptionsUpdate = {};\n\t\t\t\tif (e.affectsConfiguration(multiSelectModifierSettingKey)) {\n\t\t\t\t\tthis._useAltAsMultipleSelectionModifier = useAltAsMultipleSelectionModifier(configurationService);\n\t\t\t\t}\n\t\t\t\tif (e.affectsConfiguration(treeIndentKey)) {\n\t\t\t\t\tconst indent = configurationService.getValue(treeIndentKey);\n\t\t\t\t\tnewOptions = { ...newOptions, indent };\n\t\t\t\t}\n\t\t\t\tif (e.affectsConfiguration(treeRenderIndentGuidesKey) && options.renderIndentGuides === undefined) {\n\t\t\t\t\tconst renderIndentGuides = configurationService.getValue(treeRenderIndentGuidesKey);\n\t\t\t\t\tnewOptions = { ...newOptions, renderIndentGuides };\n\t\t\t\t}\n\t\t\t\tif (e.affectsConfiguration(listSmoothScrolling)) {\n\t\t\t\t\tconst smoothScrolling = Boolean(configurationService.getValue(listSmoothScrolling));\n\t\t\t\t\tnewOptions = { ...newOptions, smoothScrolling };\n\t\t\t\t}\n\t\t\t\tif (e.affectsConfiguration(defaultFindModeSettingKey) || e.affectsConfiguration(keyboardNavigationSettingKey)) {\n\t\t\t\t\tconst defaultFindMode = getDefaultTreeFindMode(configurationService);\n\t\t\t\t\tnewOptions = { ...newOptions, defaultFindMode };\n\t\t\t\t}\n\t\t\t\tif (e.affectsConfiguration(typeNavigationModeSettingKey) || e.affectsConfiguration(keyboardNavigationSettingKey)) {\n\t\t\t\t\tconst typeNavigationMode = getTypeNavigationMode();\n\t\t\t\t\tnewOptions = { ...newOptions, typeNavigationMode };\n\t\t\t\t}\n\t\t\t\tif (e.affectsConfiguration(defaultFindMatchTypeSettingKey)) {\n\t\t\t\t\tconst defaultFindMatchType = getDefaultTreeFindMatchType(configurationService);\n\t\t\t\t\tnewOptions = { ...newOptions, defaultFindMatchType };\n\t\t\t\t}\n\t\t\t\tif (e.affectsConfiguration(horizontalScrollingKey) && options.horizontalScrolling === undefined) {\n\t\t\t\t\tconst horizontalScrolling = Boolean(configurationService.getValue(horizontalScrollingKey));\n\t\t\t\t\tnewOptions = { ...newOptions, horizontalScrolling };\n\t\t\t\t}\n\t\t\t\tif (e.affectsConfiguration(scrollByPageKey)) {\n\t\t\t\t\tconst scrollByPage = Boolean(configurationService.getValue(scrollByPageKey));\n\t\t\t\t\tnewOptions = { ...newOptions, scrollByPage };\n\t\t\t\t}\n\t\t\t\tif (e.affectsConfiguration(treeExpandMode) && options.expandOnlyOnTwistieClick === undefined) {\n\t\t\t\t\tnewOptions = { ...newOptions, expandOnlyOnTwistieClick: configurationService.getValue<'singleClick' | 'doubleClick'>(treeExpandMode) === 'doubleClick' };\n\t\t\t\t}\n\t\t\t\tif (e.affectsConfiguration(treeStickyScroll)) {\n\t\t\t\t\tconst enableStickyScroll = configurationService.getValue(treeStickyScroll);\n\t\t\t\t\tnewOptions = { ...newOptions, enableStickyScroll };\n\t\t\t\t}\n\t\t\t\tif (e.affectsConfiguration(treeStickyScrollMaxElements)) {\n\t\t\t\t\tconst stickyScrollMaxItemCount = Math.max(1, configurationService.getValue(treeStickyScrollMaxElements));\n\t\t\t\t\tnewOptions = { ...newOptions, stickyScrollMaxItemCount };\n\t\t\t\t}\n\t\t\t\tif (e.affectsConfiguration(mouseWheelScrollSensitivityKey)) {\n\t\t\t\t\tconst mouseWheelScrollSensitivity = configurationService.getValue(mouseWheelScrollSensitivityKey);\n\t\t\t\t\tnewOptions = { ...newOptions, mouseWheelScrollSensitivity };\n\t\t\t\t}\n\t\t\t\tif (e.affectsConfiguration(fastScrollSensitivityKey)) {\n\t\t\t\t\tconst fastScrollSensitivity = configurationService.getValue(fastScrollSensitivityKey);\n\t\t\t\t\tnewOptions = { ...newOptions, fastScrollSensitivity };\n\t\t\t\t}\n\t\t\t\tif (Object.keys(newOptions).length > 0) {\n\t\t\t\t\ttree.updateOptions(newOptions);\n\t\t\t\t}\n\t\t\t}),\n\t\t\tthis.contextKeyService.onDidChangeContext(e => {\n\t\t\t\tif (e.affectsSome(interestingContextKeys)) {\n\t\t\t\t\ttree.updateOptions({ typeNavigationMode: getTypeNavigationMode() });\n\t\t\t\t}\n\t\t\t})\n\t\t);\n\n\t\tthis.navigator = new TreeResourceNavigator(tree, { configurationService, ...options });\n\t\tthis.disposables.push(this.navigator);\n\t}\n\n\tupdateOptions(options: IWorkbenchTreeInternalsOptionsUpdate): void {\n\t\tif (options.multipleSelectionSupport !== undefined) {\n\t\t\tthis.listSupportsMultiSelect.set(!!options.multipleSelectionSupport);\n\t\t}\n\t}\n\n\tupdateStyleOverrides(overrideStyles?: IStyleOverride): void {\n\t\tthis.tree.style(overrideStyles ? getListStyles(overrideStyles) : defaultListStyles);\n\t}\n\n\tdispose(): void {\n\t\tthis.disposables = dispose(this.disposables);\n\t}\n}\n\nconst configurationRegistry = Registry.as(ConfigurationExtensions.Configuration);\n\nconfigurationRegistry.registerConfiguration({\n\tid: 'workbench',\n\torder: 7,\n\ttitle: localize('workbenchConfigurationTitle', \"Workbench\"),\n\ttype: 'object',\n\tproperties: {\n\t\t[multiSelectModifierSettingKey]: {\n\t\t\ttype: 'string',\n\t\t\tenum: ['ctrlCmd', 'alt'],\n\t\t\tmarkdownEnumDescriptions: [\n\t\t\t\tlocalize('multiSelectModifier.ctrlCmd', \"Maps to `Control` on Windows and Linux and to `Command` on macOS.\"),\n\t\t\t\tlocalize('multiSelectModifier.alt', \"Maps to `Alt` on Windows and Linux and to `Option` on macOS.\")\n\t\t\t],\n\t\t\tdefault: 'ctrlCmd',\n\t\t\tdescription: localize({\n\t\t\t\tkey: 'multiSelectModifier',\n\t\t\t\tcomment: [\n\t\t\t\t\t'- `ctrlCmd` refers to a value the setting can take and should not be localized.',\n\t\t\t\t\t'- `Control` and `Command` refer to the modifier keys Ctrl or Cmd on the keyboard and can be localized.'\n\t\t\t\t]\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.\")\n\t\t},\n\t\t[openModeSettingKey]: {\n\t\t\ttype: 'string',\n\t\t\tenum: ['singleClick', 'doubleClick'],\n\t\t\tdefault: 'singleClick',\n\t\t\tdescription: localize({\n\t\t\t\tkey: 'openModeModifier',\n\t\t\t\tcomment: ['`singleClick` and `doubleClick` refers to a value the setting can take and should not be localized.']\n\t\t\t}, \"Controls how to open items in trees and lists using the mouse (if supported). Note that some trees and lists might choose to ignore this setting if it is not applicable.\")\n\t\t},\n\t\t[horizontalScrollingKey]: {\n\t\t\ttype: 'boolean',\n\t\t\tdefault: false,\n\t\t\tdescription: localize('horizontalScrolling setting', \"Controls whether lists and trees support horizontal scrolling in the workbench. Warning: turning on this setting has a performance implication.\")\n\t\t},\n\t\t[scrollByPageKey]: {\n\t\t\ttype: 'boolean',\n\t\t\tdefault: false,\n\t\t\tdescription: localize('list.scrollByPage', \"Controls whether clicks in the scrollbar scroll page by page.\")\n\t\t},\n\t\t[treeIndentKey]: {\n\t\t\ttype: 'number',\n\t\t\tdefault: 8,\n\t\t\tminimum: 4,\n\t\t\tmaximum: 40,\n\t\t\tdescription: localize('tree indent setting', \"Controls tree indentation in pixels.\")\n\t\t},\n\t\t[treeRenderIndentGuidesKey]: {\n\t\t\ttype: 'string',\n\t\t\tenum: ['none', 'onHover', 'always'],\n\t\t\tdefault: 'onHover',\n\t\t\tdescription: localize('render tree indent guides', \"Controls whether the tree should render indent guides.\")\n\t\t},\n\t\t[listSmoothScrolling]: {\n\t\t\ttype: 'boolean',\n\t\t\tdefault: false,\n\t\t\tdescription: localize('list smoothScrolling setting', \"Controls whether lists and trees have smooth scrolling.\"),\n\t\t},\n\t\t[mouseWheelScrollSensitivityKey]: {\n\t\t\ttype: 'number',\n\t\t\tdefault: 1,\n\t\t\tmarkdownDescription: localize('Mouse Wheel Scroll Sensitivity', \"A multiplier to be used on the `deltaX` and `deltaY` of mouse wheel scroll events.\")\n\t\t},\n\t\t[fastScrollSensitivityKey]: {\n\t\t\ttype: 'number',\n\t\t\tdefault: 5,\n\t\t\tmarkdownDescription: localize('Fast Scroll Sensitivity', \"Scrolling speed multiplier when pressing `Alt`.\")\n\t\t},\n\t\t[defaultFindModeSettingKey]: {\n\t\t\ttype: 'string',\n\t\t\tenum: ['highlight', 'filter'],\n\t\t\tenumDescriptions: [\n\t\t\t\tlocalize('defaultFindModeSettingKey.highlight', \"Highlight elements when searching. Further up and down navigation will traverse only the highlighted elements.\"),\n\t\t\t\tlocalize('defaultFindModeSettingKey.filter', \"Filter elements when searching.\")\n\t\t\t],\n\t\t\tdefault: 'highlight',\n\t\t\tdescription: localize('defaultFindModeSettingKey', \"Controls the default find mode for lists and trees in the workbench.\")\n\t\t},\n\t\t[keyboardNavigationSettingKey]: {\n\t\t\ttype: 'string',\n\t\t\tenum: ['simple', 'highlight', 'filter'],\n\t\t\tenumDescriptions: [\n\t\t\t\tlocalize('keyboardNavigationSettingKey.simple', \"Simple keyboard navigation focuses elements which match the keyboard input. Matching is done only on prefixes.\"),\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.\"),\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.\")\n\t\t\t],\n\t\t\tdefault: 'highlight',\n\t\t\tdescription: localize('keyboardNavigationSettingKey', \"Controls the keyboard navigation style for lists and trees in the workbench. Can be simple, highlight and filter.\"),\n\t\t\tdeprecated: true,\n\t\t\tdeprecationMessage: localize('keyboardNavigationSettingKeyDeprecated', \"Please use 'workbench.list.defaultFindMode' and\t'workbench.list.typeNavigationMode' instead.\")\n\t\t},\n\t\t[defaultFindMatchTypeSettingKey]: {\n\t\t\ttype: 'string',\n\t\t\tenum: ['fuzzy', 'contiguous'],\n\t\t\tenumDescriptions: [\n\t\t\t\tlocalize('defaultFindMatchTypeSettingKey.fuzzy', \"Use fuzzy matching when searching.\"),\n\t\t\t\tlocalize('defaultFindMatchTypeSettingKey.contiguous', \"Use contiguous matching when searching.\")\n\t\t\t],\n\t\t\tdefault: 'fuzzy',\n\t\t\tdescription: localize('defaultFindMatchTypeSettingKey', \"Controls the type of matching used when searching lists and trees in the workbench.\")\n\t\t},\n\t\t[treeExpandMode]: {\n\t\t\ttype: 'string',\n\t\t\tenum: ['singleClick', 'doubleClick'],\n\t\t\tdefault: 'singleClick',\n\t\t\tdescription: localize('expand mode', \"Controls how tree folders are expanded when clicking the folder names. Note that some trees and lists might choose to ignore this setting if it is not applicable.\"),\n\t\t},\n\t\t[treeStickyScroll]: {\n\t\t\ttype: 'boolean',\n\t\t\tdefault: true,\n\t\t\tdescription: localize('sticky scroll', \"Controls whether sticky scrolling is enabled in trees.\"),\n\t\t},\n\t\t[treeStickyScrollMaxElements]: {\n\t\t\ttype: 'number',\n\t\t\tminimum: 1,\n\t\t\tdefault: 7,\n\t\t\tmarkdownDescription: localize('sticky scroll maximum items', \"Controls the number of sticky elements displayed in the tree when `#workbench.tree.enableStickyScroll#` is enabled.\"),\n\t\t},\n\t\t[typeNavigationModeSettingKey]: {\n\t\t\ttype: 'string',\n\t\t\tenum: ['automatic', 'trigger'],\n\t\t\tdefault: 'automatic',\n\t\t\tmarkdownDescription: localize('typeNavigationMode2', \"Controls how type navigation works in lists and trees in the workbench. When set to `trigger`, type navigation begins once the `list.triggerTypeNavigation` command is run.\"),\n\t\t}\n\t}\n});\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\nimport { RunOnceScheduler } from 'vs/base/common/async';\nimport { Codicon } from 'vs/base/common/codicons';\nimport { getCodiconFontCharacters } from 'vs/base/common/codiconsUtil';\nimport { ThemeIcon, IconIdentifier } from 'vs/base/common/themables';\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { IJSONSchema, IJSONSchemaMap } from 'vs/base/common/jsonSchema';\nimport { isString } from 'vs/base/common/types';\nimport { URI } from 'vs/base/common/uri';\nimport { localize } from 'vs/nls';\nimport { Extensions as JSONExtensions, IJSONContributionRegistry } from 'vs/platform/jsonschemas/common/jsonContributionRegistry';\nimport * as platform from 'vs/platform/registry/common/platform';\n\n// ------ API types\n\n\n// icon registry\nexport const Extensions = {\n\tIconContribution: 'base.contributions.icons'\n};\n\nexport type IconDefaults = ThemeIcon | IconDefinition;\n\nexport interface IconDefinition {\n\tfont?: IconFontContribution; // undefined for the default font (codicon)\n\tfontCharacter: string;\n}\n\n\nexport interface IconContribution {\n\treadonly id: string;\n\tdescription: string | undefined;\n\tdeprecationMessage?: string;\n\treadonly defaults: IconDefaults;\n}\n\nexport namespace IconContribution {\n\texport function getDefinition(contribution: IconContribution, registry: IIconRegistry): IconDefinition | undefined {\n\t\tlet definition = contribution.defaults;\n\t\twhile (ThemeIcon.isThemeIcon(definition)) {\n\t\t\tconst c = iconRegistry.getIcon(definition.id);\n\t\t\tif (!c) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tdefinition = c.defaults;\n\t\t}\n\t\treturn definition;\n\t}\n}\n\nexport interface IconFontContribution {\n\treadonly id: string;\n\treadonly definition: IconFontDefinition;\n}\n\nexport interface IconFontDefinition {\n\treadonly weight?: string;\n\treadonly style?: string;\n\treadonly src: IconFontSource[];\n}\n\nexport namespace IconFontDefinition {\n\texport function toJSONObject(iconFont: IconFontDefinition): any {\n\t\treturn {\n\t\t\tweight: iconFont.weight,\n\t\t\tstyle: iconFont.style,\n\t\t\tsrc: iconFont.src.map(s => ({ format: s.format, location: s.location.toString() }))\n\t\t};\n\t}\n\texport function fromJSONObject(json: any): IconFontDefinition | undefined {\n\t\tconst stringOrUndef = (s: any) => isString(s) ? s : undefined;\n\t\tif (json && Array.isArray(json.src) && json.src.every((s: any) => isString(s.format) && isString(s.location))) {\n\t\t\treturn {\n\t\t\t\tweight: stringOrUndef(json.weight),\n\t\t\t\tstyle: stringOrUndef(json.style),\n\t\t\t\tsrc: json.src.map((s: any) => ({ format: s.format, location: URI.parse(s.location) }))\n\t\t\t};\n\t\t}\n\t\treturn undefined;\n\t}\n}\n\n\nexport interface IconFontSource {\n\treadonly location: URI;\n\treadonly format: string;\n}\n\nexport interface IIconRegistry {\n\n\treadonly onDidChange: Event;\n\n\t/**\n\t * Get all icon contributions\n\t */\n\tgetIcons(): IconContribution[];\n\n\t/**\n\t * Get the icon for the given id\n\t */\n\tgetIcon(id: IconIdentifier): IconContribution | undefined;\n}\n\nclass IconRegistry implements IIconRegistry {\n\n\tprivate readonly _onDidChange = new Emitter();\n\treadonly onDidChange: Event = this._onDidChange.event;\n\n\tprivate iconsById: { [key: string]: IconContribution };\n\tprivate iconSchema: IJSONSchema & { properties: IJSONSchemaMap } = {\n\t\tdefinitions: {\n\t\t\ticons: {\n\t\t\t\ttype: 'object',\n\t\t\t\tproperties: {\n\t\t\t\t\tfontId: { type: 'string', description: localize('iconDefinition.fontId', 'The id of the font to use. If not set, the font that is defined first is used.') },\n\t\t\t\t\tfontCharacter: { type: 'string', description: localize('iconDefinition.fontCharacter', 'The font character associated with the icon definition.') }\n\t\t\t\t},\n\t\t\t\tadditionalProperties: false,\n\t\t\t\tdefaultSnippets: [{ body: { fontCharacter: '\\\\\\\\e030' } }]\n\t\t\t}\n\t\t},\n\t\ttype: 'object',\n\t\tproperties: {}\n\t};\n\tprivate iconReferenceSchema: IJSONSchema & { enum: string[]; enumDescriptions: string[] } = { type: 'string', pattern: `^${ThemeIcon.iconNameExpression}$`, enum: [], enumDescriptions: [] };\n\n\tprivate iconFontsById: { [key: string]: IconFontDefinition };\n\n\tconstructor() {\n\t\tthis.iconsById = {};\n\t\tthis.iconFontsById = {};\n\t}\n\n\tpublic registerIcon(id: string, defaults: IconDefaults, description?: string, deprecationMessage?: string): ThemeIcon {\n\t\tconst existing = this.iconsById[id];\n\t\tif (existing) {\n\t\t\tif (description && !existing.description) {\n\t\t\t\texisting.description = description;\n\t\t\t\tthis.iconSchema.properties[id].markdownDescription = `${description} $(${id})`;\n\t\t\t\tconst enumIndex = this.iconReferenceSchema.enum.indexOf(id);\n\t\t\t\tif (enumIndex !== -1) {\n\t\t\t\t\tthis.iconReferenceSchema.enumDescriptions[enumIndex] = description;\n\t\t\t\t}\n\t\t\t\tthis._onDidChange.fire();\n\t\t\t}\n\t\t\treturn existing;\n\t\t}\n\t\tconst iconContribution: IconContribution = { id, description, defaults, deprecationMessage };\n\t\tthis.iconsById[id] = iconContribution;\n\t\tconst propertySchema: IJSONSchema = { $ref: '#/definitions/icons' };\n\t\tif (deprecationMessage) {\n\t\t\tpropertySchema.deprecationMessage = deprecationMessage;\n\t\t}\n\t\tif (description) {\n\t\t\tpropertySchema.markdownDescription = `${description}: $(${id})`;\n\t\t}\n\t\tthis.iconSchema.properties[id] = propertySchema;\n\t\tthis.iconReferenceSchema.enum.push(id);\n\t\tthis.iconReferenceSchema.enumDescriptions.push(description || '');\n\n\t\tthis._onDidChange.fire();\n\t\treturn { id };\n\t}\n\n\tpublic getIcons(): IconContribution[] {\n\t\treturn Object.keys(this.iconsById).map(id => this.iconsById[id]);\n\t}\n\n\tpublic getIcon(id: string): IconContribution | undefined {\n\t\treturn this.iconsById[id];\n\t}\n\n\tpublic getIconSchema(): IJSONSchema {\n\t\treturn this.iconSchema;\n\t}\n\n\tpublic toString() {\n\t\tconst sorter = (i1: IconContribution, i2: IconContribution) => {\n\t\t\treturn i1.id.localeCompare(i2.id);\n\t\t};\n\t\tconst classNames = (i: IconContribution) => {\n\t\t\twhile (ThemeIcon.isThemeIcon(i.defaults)) {\n\t\t\t\ti = this.iconsById[i.defaults.id];\n\t\t\t}\n\t\t\treturn `codicon codicon-${i ? i.id : ''}`;\n\t\t};\n\n\t\tconst reference = [];\n\n\t\treference.push(`| preview | identifier | default codicon ID | description`);\n\t\treference.push(`| ----------- | --------------------------------- | --------------------------------- | --------------------------------- |`);\n\t\tconst contributions = Object.keys(this.iconsById).map(key => this.iconsById[key]);\n\n\t\tfor (const i of contributions.filter(i => !!i.description).sort(sorter)) {\n\t\t\treference.push(`||${i.id}|${ThemeIcon.isThemeIcon(i.defaults) ? i.defaults.id : i.id}|${i.description || ''}|`);\n\t\t}\n\n\t\treference.push(`| preview | identifier `);\n\t\treference.push(`| ----------- | --------------------------------- |`);\n\n\t\tfor (const i of contributions.filter(i => !ThemeIcon.isThemeIcon(i.defaults)).sort(sorter)) {\n\t\t\treference.push(`||${i.id}|`);\n\n\t\t}\n\n\t\treturn reference.join('\\n');\n\t}\n\n}\n\nconst iconRegistry = new IconRegistry();\nplatform.Registry.add(Extensions.IconContribution, iconRegistry);\n\nexport function registerIcon(id: string, defaults: IconDefaults, description: string, deprecationMessage?: string): ThemeIcon {\n\treturn iconRegistry.registerIcon(id, defaults, description, deprecationMessage);\n}\n\nexport function getIconRegistry(): IIconRegistry {\n\treturn iconRegistry;\n}\n\nfunction initialize() {\n\tconst codiconFontCharacters = getCodiconFontCharacters();\n\tfor (const icon in codiconFontCharacters) {\n\t\tconst fontCharacter = '\\\\' + codiconFontCharacters[icon].toString(16);\n\t\ticonRegistry.registerIcon(icon, { fontCharacter });\n\t}\n}\ninitialize();\n\nexport const iconsSchemaId = 'vscode://schemas/icons';\n\nconst schemaRegistry = platform.Registry.as(JSONExtensions.JSONContribution);\nschemaRegistry.registerSchema(iconsSchemaId, iconRegistry.getIconSchema());\n\nconst delayer = new RunOnceScheduler(() => schemaRegistry.notifySchemaChanged(iconsSchemaId), 200);\niconRegistry.onDidChange(() => {\n\tif (!delayer.isScheduled()) {\n\t\tdelayer.schedule();\n\t}\n});\n\n\n//setTimeout(_ => console.log(iconRegistry.toString()), 5000);\n\n\n// common icons\n\nexport const widgetClose = registerIcon('widget-close', Codicon.close, localize('widgetClose', 'Icon for the close action in widgets.'));\n\nexport const gotoPreviousLocation = registerIcon('goto-previous-location', Codicon.arrowUp, localize('previousChangeIcon', 'Icon for goto previous editor location.'));\nexport const gotoNextLocation = registerIcon('goto-next-location', Codicon.arrowDown, localize('nextChangeIcon', 'Icon for goto next editor location.'));\n\nexport const syncing = ThemeIcon.modify(Codicon.sync, 'spin');\nexport const spinningLoading = ThemeIcon.modify(Codicon.loading, 'spin');\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\nimport { addDisposableListener, addStandardDisposableListener, reset } from 'vs/base/browser/dom';\nimport { createTrustedTypesPolicy } from 'vs/base/browser/trustedTypes';\nimport { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';\nimport { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';\nimport { Action } from 'vs/base/common/actions';\nimport { forEachAdjacent, groupAdjacentBy } from 'vs/base/common/arrays';\nimport { Codicon } from 'vs/base/common/codicons';\nimport { KeyCode, KeyMod } from 'vs/base/common/keyCodes';\nimport { Disposable, DisposableStore, toDisposable } from 'vs/base/common/lifecycle';\nimport { IObservable, ITransaction, autorun, autorunWithStore, derived, derivedWithStore, observableValue, subtransaction, transaction } from 'vs/base/common/observable';\nimport { ThemeIcon } from 'vs/base/common/themables';\nimport { applyFontInfo } from 'vs/editor/browser/config/domFontInfo';\nimport { applyStyle } from 'vs/editor/browser/widget/diffEditor/utils';\nimport { EditorFontLigatures, EditorOption, IComputedEditorOptions } from 'vs/editor/common/config/editorOptions';\nimport { LineRange } from 'vs/editor/common/core/lineRange';\nimport { OffsetRange } from 'vs/editor/common/core/offsetRange';\nimport { Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\nimport { DetailedLineRangeMapping, LineRangeMapping } from 'vs/editor/common/diff/rangeMapping';\nimport { ILanguageIdCodec } from 'vs/editor/common/languages';\nimport { ILanguageService } from 'vs/editor/common/languages/language';\nimport { ITextModel, TextModelResolvedOptions } from 'vs/editor/common/model';\nimport { LineTokens } from 'vs/editor/common/tokens/lineTokens';\nimport { RenderLineInput, renderViewLine2 } from 'vs/editor/common/viewLayout/viewLineRenderer';\nimport { ViewLineRenderingData } from 'vs/editor/common/viewModel';\nimport { localize } from 'vs/nls';\nimport { AccessibilitySignal, IAccessibilitySignalService } from 'vs/platform/accessibilitySignal/browser/accessibilitySignalService';\nimport { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';\nimport { registerIcon } from 'vs/platform/theme/common/iconRegistry';\nimport 'vs/css!./accessibleDiffViewer';\nimport { DiffEditorEditors } from 'vs/editor/browser/widget/diffEditor/components/diffEditorEditors';\n\nconst accessibleDiffViewerInsertIcon = registerIcon('diff-review-insert', Codicon.add, localize('accessibleDiffViewerInsertIcon', 'Icon for \\'Insert\\' in accessible diff viewer.'));\nconst accessibleDiffViewerRemoveIcon = registerIcon('diff-review-remove', Codicon.remove, localize('accessibleDiffViewerRemoveIcon', 'Icon for \\'Remove\\' in accessible diff viewer.'));\nconst accessibleDiffViewerCloseIcon = registerIcon('diff-review-close', Codicon.close, localize('accessibleDiffViewerCloseIcon', 'Icon for \\'Close\\' in accessible diff viewer.'));\n\nexport interface IAccessibleDiffViewerModel {\n\tgetOriginalModel(): ITextModel;\n\tgetOriginalOptions(): IComputedEditorOptions;\n\n\t/**\n\t * Should do: `setSelection`, `revealLine` and `focus`\n\t */\n\toriginalReveal(range: Range): void;\n\n\tgetModifiedModel(): ITextModel;\n\tgetModifiedOptions(): IComputedEditorOptions;\n\t/**\n\t * Should do: `setSelection`, `revealLine` and `focus`\n\t */\n\tmodifiedReveal(range?: Range): void;\n\tmodifiedSetSelection(range: Range): void;\n\tmodifiedFocus(): void;\n\n\tgetModifiedPosition(): Position | undefined;\n}\n\nexport class AccessibleDiffViewer extends Disposable {\n\tpublic static _ttPolicy = createTrustedTypesPolicy('diffReview', { createHTML: value => value });\n\n\tconstructor(\n\t\tprivate readonly _parentNode: HTMLElement,\n\t\tprivate readonly _visible: IObservable,\n\t\tprivate readonly _setVisible: (visible: boolean, tx: ITransaction | undefined) => void,\n\t\tprivate readonly _canClose: IObservable,\n\t\tprivate readonly _width: IObservable,\n\t\tprivate readonly _height: IObservable,\n\t\tprivate readonly _diffs: IObservable,\n\t\tprivate readonly _models: IAccessibleDiffViewerModel,\n\t\t@IInstantiationService private readonly _instantiationService: IInstantiationService,\n\t) {\n\t\tsuper();\n\t}\n\n\tprivate readonly _state = derivedWithStore(this, (reader, store) => {\n\t\tconst visible = this._visible.read(reader);\n\t\tthis._parentNode.style.visibility = visible ? 'visible' : 'hidden';\n\t\tif (!visible) {\n\t\t\treturn null;\n\t\t}\n\t\tconst model = store.add(this._instantiationService.createInstance(ViewModel, this._diffs, this._models, this._setVisible, this._canClose));\n\t\tconst view = store.add(this._instantiationService.createInstance(View, this._parentNode, model, this._width, this._height, this._models));\n\t\treturn { model, view, };\n\t}).recomputeInitiallyAndOnChange(this._store);\n\n\tnext(): void {\n\t\ttransaction(tx => {\n\t\t\tconst isVisible = this._visible.get();\n\t\t\tthis._setVisible(true, tx);\n\t\t\tif (isVisible) {\n\t\t\t\tthis._state.get()!.model.nextGroup(tx);\n\t\t\t}\n\t\t});\n\t}\n\n\tprev(): void {\n\t\ttransaction(tx => {\n\t\t\tthis._setVisible(true, tx);\n\t\t\tthis._state.get()!.model.previousGroup(tx);\n\t\t});\n\t}\n\n\tclose(): void {\n\t\ttransaction(tx => {\n\t\t\tthis._setVisible(false, tx);\n\t\t});\n\t}\n}\n\nclass ViewModel extends Disposable {\n\tprivate readonly _groups = observableValue(this, []);\n\tprivate readonly _currentGroupIdx = observableValue(this, 0);\n\tprivate readonly _currentElementIdx = observableValue(this, 0);\n\n\tpublic readonly groups: IObservable = this._groups;\n\tpublic readonly currentGroup: IObservable\n\t\t= this._currentGroupIdx.map((idx, r) => this._groups.read(r)[idx]);\n\tpublic readonly currentGroupIndex: IObservable = this._currentGroupIdx;\n\n\tpublic readonly currentElement: IObservable\n\t\t= this._currentElementIdx.map((idx, r) => this.currentGroup.read(r)?.lines[idx]);\n\n\tconstructor(\n\t\tprivate readonly _diffs: IObservable,\n\t\tprivate readonly _models: IAccessibleDiffViewerModel,\n\t\tprivate readonly _setVisible: (visible: boolean, tx: ITransaction | undefined) => void,\n\t\tpublic readonly canClose: IObservable,\n\t\t@IAccessibilitySignalService private readonly _accessibilitySignalService: IAccessibilitySignalService,\n\t) {\n\t\tsuper();\n\n\t\tthis._register(autorun(reader => {\n\t\t\t/** @description update groups */\n\t\t\tconst diffs = this._diffs.read(reader);\n\t\t\tif (!diffs) {\n\t\t\t\tthis._groups.set([], undefined);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst groups = computeViewElementGroups(\n\t\t\t\tdiffs,\n\t\t\t\tthis._models.getOriginalModel().getLineCount(),\n\t\t\t\tthis._models.getModifiedModel().getLineCount()\n\t\t\t);\n\n\t\t\ttransaction(tx => {\n\t\t\t\tconst p = this._models.getModifiedPosition();\n\t\t\t\tif (p) {\n\t\t\t\t\tconst nextGroup = groups.findIndex(g => p?.lineNumber < g.range.modified.endLineNumberExclusive);\n\t\t\t\t\tif (nextGroup !== -1) {\n\t\t\t\t\t\tthis._currentGroupIdx.set(nextGroup, tx);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tthis._groups.set(groups, tx);\n\t\t\t});\n\t\t}));\n\n\t\tthis._register(autorun(reader => {\n\t\t\t/** @description play audio-cue for diff */\n\t\t\tconst currentViewItem = this.currentElement.read(reader);\n\t\t\tif (currentViewItem?.type === LineType.Deleted) {\n\t\t\t\tthis._accessibilitySignalService.playSignal(AccessibilitySignal.diffLineDeleted, { source: 'accessibleDiffViewer.currentElementChanged' });\n\t\t\t} else if (currentViewItem?.type === LineType.Added) {\n\t\t\t\tthis._accessibilitySignalService.playSignal(AccessibilitySignal.diffLineInserted, { source: 'accessibleDiffViewer.currentElementChanged' });\n\t\t\t}\n\t\t}));\n\n\t\tthis._register(autorun(reader => {\n\t\t\t/** @description select lines in editor */\n\t\t\t// This ensures editor commands (like revert/stage) work\n\t\t\tconst currentViewItem = this.currentElement.read(reader);\n\t\t\tif (currentViewItem && currentViewItem.type !== LineType.Header) {\n\t\t\t\tconst lineNumber = currentViewItem.modifiedLineNumber ?? currentViewItem.diff.modified.startLineNumber;\n\t\t\t\tthis._models.modifiedSetSelection(Range.fromPositions(new Position(lineNumber, 1)));\n\t\t\t}\n\t\t}));\n\t}\n\n\tprivate _goToGroupDelta(delta: number, tx?: ITransaction): void {\n\t\tconst groups = this.groups.get();\n\t\tif (!groups || groups.length <= 1) { return; }\n\t\tsubtransaction(tx, tx => {\n\t\t\tthis._currentGroupIdx.set(OffsetRange.ofLength(groups.length).clipCyclic(this._currentGroupIdx.get() + delta), tx);\n\t\t\tthis._currentElementIdx.set(0, tx);\n\t\t});\n\t}\n\n\tnextGroup(tx?: ITransaction): void { this._goToGroupDelta(1, tx); }\n\tpreviousGroup(tx?: ITransaction): void { this._goToGroupDelta(-1, tx); }\n\n\tprivate _goToLineDelta(delta: number): void {\n\t\tconst group = this.currentGroup.get();\n\t\tif (!group || group.lines.length <= 1) { return; }\n\t\ttransaction(tx => {\n\t\t\tthis._currentElementIdx.set(OffsetRange.ofLength(group.lines.length).clip(this._currentElementIdx.get() + delta), tx);\n\t\t});\n\t}\n\n\tgoToNextLine(): void { this._goToLineDelta(1); }\n\tgoToPreviousLine(): void { this._goToLineDelta(-1); }\n\n\tgoToLine(line: ViewElement): void {\n\t\tconst group = this.currentGroup.get();\n\t\tif (!group) { return; }\n\t\tconst idx = group.lines.indexOf(line);\n\t\tif (idx === -1) { return; }\n\t\ttransaction(tx => {\n\t\t\tthis._currentElementIdx.set(idx, tx);\n\t\t});\n\t}\n\n\trevealCurrentElementInEditor(): void {\n\t\tif (!this.canClose.get()) { return; }\n\t\tthis._setVisible(false, undefined);\n\n\t\tconst curElem = this.currentElement.get();\n\t\tif (curElem) {\n\t\t\tif (curElem.type === LineType.Deleted) {\n\t\t\t\tthis._models.originalReveal(Range.fromPositions(new Position(curElem.originalLineNumber, 1)));\n\t\t\t} else {\n\t\t\t\tthis._models.modifiedReveal(\n\t\t\t\t\tcurElem.type !== LineType.Header\n\t\t\t\t\t\t? Range.fromPositions(new Position(curElem.modifiedLineNumber, 1))\n\t\t\t\t\t\t: undefined\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tclose(): void {\n\t\tif (!this.canClose.get()) { return; }\n\t\tthis._setVisible(false, undefined);\n\t\tthis._models.modifiedFocus();\n\t}\n}\n\n\nconst viewElementGroupLineMargin = 3;\n\nfunction computeViewElementGroups(diffs: DetailedLineRangeMapping[], originalLineCount: number, modifiedLineCount: number): ViewElementGroup[] {\n\tconst result: ViewElementGroup[] = [];\n\n\tfor (const g of groupAdjacentBy(diffs, (a, b) => (b.modified.startLineNumber - a.modified.endLineNumberExclusive < 2 * viewElementGroupLineMargin))) {\n\t\tconst viewElements: ViewElement[] = [];\n\t\tviewElements.push(new HeaderViewElement());\n\n\t\tconst origFullRange = new LineRange(\n\t\t\tMath.max(1, g[0].original.startLineNumber - viewElementGroupLineMargin),\n\t\t\tMath.min(g[g.length - 1].original.endLineNumberExclusive + viewElementGroupLineMargin, originalLineCount + 1)\n\t\t);\n\t\tconst modifiedFullRange = new LineRange(\n\t\t\tMath.max(1, g[0].modified.startLineNumber - viewElementGroupLineMargin),\n\t\t\tMath.min(g[g.length - 1].modified.endLineNumberExclusive + viewElementGroupLineMargin, modifiedLineCount + 1)\n\t\t);\n\n\t\tforEachAdjacent(g, (a, b) => {\n\t\t\tconst origRange = new LineRange(a ? a.original.endLineNumberExclusive : origFullRange.startLineNumber, b ? b.original.startLineNumber : origFullRange.endLineNumberExclusive);\n\t\t\tconst modifiedRange = new LineRange(a ? a.modified.endLineNumberExclusive : modifiedFullRange.startLineNumber, b ? b.modified.startLineNumber : modifiedFullRange.endLineNumberExclusive);\n\n\t\t\torigRange.forEach(origLineNumber => {\n\t\t\t\tviewElements.push(new UnchangedLineViewElement(origLineNumber, modifiedRange.startLineNumber + (origLineNumber - origRange.startLineNumber)));\n\t\t\t});\n\n\t\t\tif (b) {\n\t\t\t\tb.original.forEach(origLineNumber => {\n\t\t\t\t\tviewElements.push(new DeletedLineViewElement(b, origLineNumber));\n\t\t\t\t});\n\t\t\t\tb.modified.forEach(modifiedLineNumber => {\n\t\t\t\t\tviewElements.push(new AddedLineViewElement(b, modifiedLineNumber));\n\t\t\t\t});\n\t\t\t}\n\t\t});\n\n\t\tconst modifiedRange = g[0].modified.join(g[g.length - 1].modified);\n\t\tconst originalRange = g[0].original.join(g[g.length - 1].original);\n\n\t\tresult.push(new ViewElementGroup(new LineRangeMapping(modifiedRange, originalRange), viewElements));\n\t}\n\treturn result;\n}\n\nenum LineType {\n\tHeader,\n\tUnchanged,\n\tDeleted,\n\tAdded,\n}\n\nclass ViewElementGroup {\n\tconstructor(\n\t\tpublic readonly range: LineRangeMapping,\n\t\tpublic readonly lines: readonly ViewElement[],\n\t) { }\n}\n\ntype ViewElement = HeaderViewElement | UnchangedLineViewElement | DeletedLineViewElement | AddedLineViewElement;\n\nclass HeaderViewElement {\n\tpublic readonly type = LineType.Header;\n}\n\nclass DeletedLineViewElement {\n\tpublic readonly type = LineType.Deleted;\n\n\tpublic readonly modifiedLineNumber = undefined;\n\n\tconstructor(\n\t\tpublic readonly diff: DetailedLineRangeMapping,\n\t\tpublic readonly originalLineNumber: number,\n\t) {\n\t}\n}\n\nclass AddedLineViewElement {\n\tpublic readonly type = LineType.Added;\n\n\tpublic readonly originalLineNumber = undefined;\n\n\tconstructor(\n\t\tpublic readonly diff: DetailedLineRangeMapping,\n\t\tpublic readonly modifiedLineNumber: number,\n\t) {\n\t}\n}\n\nclass UnchangedLineViewElement {\n\tpublic readonly type = LineType.Unchanged;\n\tconstructor(\n\t\tpublic readonly originalLineNumber: number,\n\t\tpublic readonly modifiedLineNumber: number,\n\t) {\n\t}\n}\n\nclass View extends Disposable {\n\tpublic readonly domNode: HTMLElement;\n\tprivate readonly _content: HTMLElement;\n\tprivate readonly _scrollbar: DomScrollableElement;\n\tprivate readonly _actionBar: ActionBar;\n\n\tconstructor(\n\t\tprivate readonly _element: HTMLElement,\n\t\tprivate readonly _model: ViewModel,\n\t\tprivate readonly _width: IObservable,\n\t\tprivate readonly _height: IObservable,\n\t\tprivate readonly _models: IAccessibleDiffViewerModel,\n\t\t@ILanguageService private readonly _languageService: ILanguageService,\n\t) {\n\t\tsuper();\n\n\t\tthis.domNode = this._element;\n\t\tthis.domNode.className = 'monaco-component diff-review monaco-editor-background';\n\n\t\tconst actionBarContainer = document.createElement('div');\n\t\tactionBarContainer.className = 'diff-review-actions';\n\t\tthis._actionBar = this._register(new ActionBar(\n\t\t\tactionBarContainer\n\t\t));\n\t\tthis._register(autorun(reader => {\n\t\t\t/** @description update actions */\n\t\t\tthis._actionBar.clear();\n\t\t\tif (this._model.canClose.read(reader)) {\n\t\t\t\tthis._actionBar.push(new Action(\n\t\t\t\t\t'diffreview.close',\n\t\t\t\t\tlocalize('label.close', \"Close\"),\n\t\t\t\t\t'close-diff-review ' + ThemeIcon.asClassName(accessibleDiffViewerCloseIcon),\n\t\t\t\t\ttrue,\n\t\t\t\t\tasync () => _model.close()\n\t\t\t\t), { label: false, icon: true });\n\t\t\t}\n\t\t}));\n\n\t\tthis._content = document.createElement('div');\n\t\tthis._content.className = 'diff-review-content';\n\t\tthis._content.setAttribute('role', 'code');\n\t\tthis._scrollbar = this._register(new DomScrollableElement(this._content, {}));\n\t\treset(this.domNode, this._scrollbar.getDomNode(), actionBarContainer);\n\n\t\tthis._register(autorun(r => {\n\t\t\tthis._height.read(r);\n\t\t\tthis._width.read(r);\n\t\t\tthis._scrollbar.scanDomNode();\n\t\t}));\n\n\t\tthis._register(toDisposable(() => { reset(this.domNode); }));\n\n\t\tthis._register(applyStyle(this.domNode, { width: this._width, height: this._height }));\n\t\tthis._register(applyStyle(this._content, { width: this._width, height: this._height }));\n\n\t\tthis._register(autorunWithStore((reader, store) => {\n\t\t\t/** @description render */\n\t\t\tthis._model.currentGroup.read(reader);\n\t\t\tthis._render(store);\n\t\t}));\n\n\t\t// TODO@hediet use commands\n\t\tthis._register(addStandardDisposableListener(this.domNode, 'keydown', (e) => {\n\t\t\tif (\n\t\t\t\te.equals(KeyCode.DownArrow)\n\t\t\t\t|| e.equals(KeyMod.CtrlCmd | KeyCode.DownArrow)\n\t\t\t\t|| e.equals(KeyMod.Alt | KeyCode.DownArrow)\n\t\t\t) {\n\t\t\t\te.preventDefault();\n\t\t\t\tthis._model.goToNextLine();\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\te.equals(KeyCode.UpArrow)\n\t\t\t\t|| e.equals(KeyMod.CtrlCmd | KeyCode.UpArrow)\n\t\t\t\t|| e.equals(KeyMod.Alt | KeyCode.UpArrow)\n\t\t\t) {\n\t\t\t\te.preventDefault();\n\t\t\t\tthis._model.goToPreviousLine();\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\te.equals(KeyCode.Escape)\n\t\t\t\t|| e.equals(KeyMod.CtrlCmd | KeyCode.Escape)\n\t\t\t\t|| e.equals(KeyMod.Alt | KeyCode.Escape)\n\t\t\t\t|| e.equals(KeyMod.Shift | KeyCode.Escape)\n\t\t\t) {\n\t\t\t\te.preventDefault();\n\t\t\t\tthis._model.close();\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\te.equals(KeyCode.Space)\n\t\t\t\t|| e.equals(KeyCode.Enter)\n\t\t\t) {\n\t\t\t\te.preventDefault();\n\t\t\t\tthis._model.revealCurrentElementInEditor();\n\t\t\t}\n\t\t}));\n\t}\n\n\tprivate _render(store: DisposableStore): void {\n\t\tconst originalOptions = this._models.getOriginalOptions();\n\t\tconst modifiedOptions = this._models.getModifiedOptions();\n\n\t\tconst container = document.createElement('div');\n\t\tcontainer.className = 'diff-review-table';\n\t\tcontainer.setAttribute('role', 'list');\n\t\tcontainer.setAttribute('aria-label', localize('ariaLabel', 'Accessible Diff Viewer. Use arrow up and down to navigate.'));\n\t\tapplyFontInfo(container, modifiedOptions.get(EditorOption.fontInfo));\n\n\t\treset(this._content, container);\n\n\t\tconst originalModel = this._models.getOriginalModel();\n\t\tconst modifiedModel = this._models.getModifiedModel();\n\t\tif (!originalModel || !modifiedModel) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst originalModelOpts = originalModel.getOptions();\n\t\tconst modifiedModelOpts = modifiedModel.getOptions();\n\n\t\tconst lineHeight = modifiedOptions.get(EditorOption.lineHeight);\n\t\tconst group = this._model.currentGroup.get();\n\t\tfor (const viewItem of group?.lines || []) {\n\t\t\tif (!group) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tlet row: HTMLDivElement;\n\n\t\t\tif (viewItem.type === LineType.Header) {\n\n\t\t\t\tconst header = document.createElement('div');\n\t\t\t\theader.className = 'diff-review-row';\n\t\t\t\theader.setAttribute('role', 'listitem');\n\n\t\t\t\tconst r = group.range;\n\t\t\t\tconst diffIndex = this._model.currentGroupIndex.get();\n\t\t\t\tconst diffsLength = this._model.groups.get().length;\n\t\t\t\tconst getAriaLines = (lines: number) =>\n\t\t\t\t\tlines === 0 ? localize('no_lines_changed', \"no lines changed\")\n\t\t\t\t\t\t: lines === 1 ? localize('one_line_changed', \"1 line changed\")\n\t\t\t\t\t\t\t: localize('more_lines_changed', \"{0} lines changed\", lines);\n\n\t\t\t\tconst originalChangedLinesCntAria = getAriaLines(r.original.length);\n\t\t\t\tconst modifiedChangedLinesCntAria = getAriaLines(r.modified.length);\n\t\t\t\theader.setAttribute('aria-label', localize({\n\t\t\t\t\tkey: 'header',\n\t\t\t\t\tcomment: [\n\t\t\t\t\t\t'This is the ARIA label for a git diff header.',\n\t\t\t\t\t\t'A git diff header looks like this: @@ -154,12 +159,39 @@.',\n\t\t\t\t\t\t'That encodes that at original line 154 (which is now line 159), 12 lines were removed/changed with 39 lines.',\n\t\t\t\t\t\t'Variables 0 and 1 refer to the diff index out of total number of diffs.',\n\t\t\t\t\t\t'Variables 2 and 4 will be numbers (a line number).',\n\t\t\t\t\t\t'Variables 3 and 5 will be \"no lines changed\", \"1 line changed\" or \"X lines changed\", localized separately.'\n\t\t\t\t\t]\n\t\t\t\t}, \"Difference {0} of {1}: original line {2}, {3}, modified line {4}, {5}\",\n\t\t\t\t\t(diffIndex + 1),\n\t\t\t\t\tdiffsLength,\n\t\t\t\t\tr.original.startLineNumber,\n\t\t\t\t\toriginalChangedLinesCntAria,\n\t\t\t\t\tr.modified.startLineNumber,\n\t\t\t\t\tmodifiedChangedLinesCntAria\n\t\t\t\t));\n\n\t\t\t\tconst cell = document.createElement('div');\n\t\t\t\tcell.className = 'diff-review-cell diff-review-summary';\n\t\t\t\t// e.g.: `1/10: @@ -504,7 +517,7 @@`\n\t\t\t\tcell.appendChild(document.createTextNode(`${diffIndex + 1}/${diffsLength}: @@ -${r.original.startLineNumber},${r.original.length} +${r.modified.startLineNumber},${r.modified.length} @@`));\n\t\t\t\theader.appendChild(cell);\n\n\t\t\t\trow = header;\n\t\t\t} else {\n\t\t\t\trow = this._createRow(viewItem, lineHeight,\n\t\t\t\t\tthis._width.get(), originalOptions, originalModel, originalModelOpts, modifiedOptions, modifiedModel, modifiedModelOpts,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tcontainer.appendChild(row);\n\n\t\t\tconst isSelectedObs = derived(reader => /** @description isSelected */ this._model.currentElement.read(reader) === viewItem);\n\n\t\t\tstore.add(autorun(reader => {\n\t\t\t\t/** @description update tab index */\n\t\t\t\tconst isSelected = isSelectedObs.read(reader);\n\t\t\t\trow.tabIndex = isSelected ? 0 : -1;\n\t\t\t\tif (isSelected) {\n\t\t\t\t\trow.focus();\n\t\t\t\t}\n\t\t\t}));\n\n\t\t\tstore.add(addDisposableListener(row, 'focus', () => {\n\t\t\t\tthis._model.goToLine(viewItem);\n\t\t\t}));\n\t\t}\n\n\t\tthis._scrollbar.scanDomNode();\n\t}\n\n\tprivate _createRow(\n\t\titem: DeletedLineViewElement | AddedLineViewElement | UnchangedLineViewElement,\n\t\tlineHeight: number,\n\t\twidth: number,\n\t\toriginalOptions: IComputedEditorOptions, originalModel: ITextModel, originalModelOpts: TextModelResolvedOptions,\n\t\tmodifiedOptions: IComputedEditorOptions, modifiedModel: ITextModel, modifiedModelOpts: TextModelResolvedOptions,\n\t): HTMLDivElement {\n\t\tconst originalLayoutInfo = originalOptions.get(EditorOption.layoutInfo);\n\t\tconst originalLineNumbersWidth = originalLayoutInfo.glyphMarginWidth + originalLayoutInfo.lineNumbersWidth;\n\n\t\tconst modifiedLayoutInfo = modifiedOptions.get(EditorOption.layoutInfo);\n\t\tconst modifiedLineNumbersWidth = 10 + modifiedLayoutInfo.glyphMarginWidth + modifiedLayoutInfo.lineNumbersWidth;\n\n\t\tlet rowClassName: string = 'diff-review-row';\n\t\tlet lineNumbersExtraClassName: string = '';\n\t\tconst spacerClassName: string = 'diff-review-spacer';\n\t\tlet spacerIcon: ThemeIcon | null = null;\n\t\tswitch (item.type) {\n\t\t\tcase LineType.Added:\n\t\t\t\trowClassName = 'diff-review-row line-insert';\n\t\t\t\tlineNumbersExtraClassName = ' char-insert';\n\t\t\t\tspacerIcon = accessibleDiffViewerInsertIcon;\n\t\t\t\tbreak;\n\t\t\tcase LineType.Deleted:\n\t\t\t\trowClassName = 'diff-review-row line-delete';\n\t\t\t\tlineNumbersExtraClassName = ' char-delete';\n\t\t\t\tspacerIcon = accessibleDiffViewerRemoveIcon;\n\t\t\t\tbreak;\n\t\t}\n\n\t\tconst row = document.createElement('div');\n\t\trow.style.minWidth = width + 'px';\n\t\trow.className = rowClassName;\n\t\trow.setAttribute('role', 'listitem');\n\t\trow.ariaLevel = '';\n\n\t\tconst cell = document.createElement('div');\n\t\tcell.className = 'diff-review-cell';\n\t\tcell.style.height = `${lineHeight}px`;\n\t\trow.appendChild(cell);\n\n\t\tconst originalLineNumber = document.createElement('span');\n\t\toriginalLineNumber.style.width = (originalLineNumbersWidth + 'px');\n\t\toriginalLineNumber.style.minWidth = (originalLineNumbersWidth + 'px');\n\t\toriginalLineNumber.className = 'diff-review-line-number' + lineNumbersExtraClassName;\n\t\tif (item.originalLineNumber !== undefined) {\n\t\t\toriginalLineNumber.appendChild(document.createTextNode(String(item.originalLineNumber)));\n\t\t} else {\n\t\t\toriginalLineNumber.innerText = '\\u00a0';\n\t\t}\n\t\tcell.appendChild(originalLineNumber);\n\n\t\tconst modifiedLineNumber = document.createElement('span');\n\t\tmodifiedLineNumber.style.width = (modifiedLineNumbersWidth + 'px');\n\t\tmodifiedLineNumber.style.minWidth = (modifiedLineNumbersWidth + 'px');\n\t\tmodifiedLineNumber.style.paddingRight = '10px';\n\t\tmodifiedLineNumber.className = 'diff-review-line-number' + lineNumbersExtraClassName;\n\t\tif (item.modifiedLineNumber !== undefined) {\n\t\t\tmodifiedLineNumber.appendChild(document.createTextNode(String(item.modifiedLineNumber)));\n\t\t} else {\n\t\t\tmodifiedLineNumber.innerText = '\\u00a0';\n\t\t}\n\t\tcell.appendChild(modifiedLineNumber);\n\n\t\tconst spacer = document.createElement('span');\n\t\tspacer.className = spacerClassName;\n\n\t\tif (spacerIcon) {\n\t\t\tconst spacerCodicon = document.createElement('span');\n\t\t\tspacerCodicon.className = ThemeIcon.asClassName(spacerIcon);\n\t\t\tspacerCodicon.innerText = '\\u00a0\\u00a0';\n\t\t\tspacer.appendChild(spacerCodicon);\n\t\t} else {\n\t\t\tspacer.innerText = '\\u00a0\\u00a0';\n\t\t}\n\t\tcell.appendChild(spacer);\n\n\t\tlet lineContent: string;\n\t\tif (item.modifiedLineNumber !== undefined) {\n\t\t\tlet html: string | TrustedHTML = this._getLineHtml(modifiedModel, modifiedOptions, modifiedModelOpts.tabSize, item.modifiedLineNumber, this._languageService.languageIdCodec);\n\t\t\tif (AccessibleDiffViewer._ttPolicy) {\n\t\t\t\thtml = AccessibleDiffViewer._ttPolicy.createHTML(html as string);\n\t\t\t}\n\t\t\tcell.insertAdjacentHTML('beforeend', html as string);\n\t\t\tlineContent = modifiedModel.getLineContent(item.modifiedLineNumber);\n\t\t} else {\n\t\t\tlet html: string | TrustedHTML = this._getLineHtml(originalModel, originalOptions, originalModelOpts.tabSize, item.originalLineNumber, this._languageService.languageIdCodec);\n\t\t\tif (AccessibleDiffViewer._ttPolicy) {\n\t\t\t\thtml = AccessibleDiffViewer._ttPolicy.createHTML(html as string);\n\t\t\t}\n\t\t\tcell.insertAdjacentHTML('beforeend', html as string);\n\t\t\tlineContent = originalModel.getLineContent(item.originalLineNumber);\n\t\t}\n\n\t\tif (lineContent.length === 0) {\n\t\t\tlineContent = localize('blankLine', \"blank\");\n\t\t}\n\n\t\tlet ariaLabel: string = '';\n\t\tswitch (item.type) {\n\t\t\tcase LineType.Unchanged:\n\t\t\t\tif (item.originalLineNumber === item.modifiedLineNumber) {\n\t\t\t\t\tariaLabel = localize({ key: 'unchangedLine', comment: ['The placeholders are contents of the line and should not be translated.'] }, \"{0} unchanged line {1}\", lineContent, item.originalLineNumber);\n\t\t\t\t} else {\n\t\t\t\t\tariaLabel = localize('equalLine', \"{0} original line {1} modified line {2}\", lineContent, item.originalLineNumber, item.modifiedLineNumber);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase LineType.Added:\n\t\t\t\tariaLabel = localize('insertLine', \"+ {0} modified line {1}\", lineContent, item.modifiedLineNumber);\n\t\t\t\tbreak;\n\t\t\tcase LineType.Deleted:\n\t\t\t\tariaLabel = localize('deleteLine', \"- {0} original line {1}\", lineContent, item.originalLineNumber);\n\t\t\t\tbreak;\n\t\t}\n\t\trow.setAttribute('aria-label', ariaLabel);\n\n\t\treturn row;\n\t}\n\n\tprivate _getLineHtml(model: ITextModel, options: IComputedEditorOptions, tabSize: number, lineNumber: number, languageIdCodec: ILanguageIdCodec): string {\n\t\tconst lineContent = model.getLineContent(lineNumber);\n\t\tconst fontInfo = options.get(EditorOption.fontInfo);\n\t\tconst lineTokens = LineTokens.createEmpty(lineContent, languageIdCodec);\n\t\tconst isBasicASCII = ViewLineRenderingData.isBasicASCII(lineContent, model.mightContainNonBasicASCII());\n\t\tconst containsRTL = ViewLineRenderingData.containsRTL(lineContent, isBasicASCII, model.mightContainRTL());\n\t\tconst r = renderViewLine2(new RenderLineInput(\n\t\t\t(fontInfo.isMonospace && !options.get(EditorOption.disableMonospaceOptimizations)),\n\t\t\tfontInfo.canUseHalfwidthRightwardsArrow,\n\t\t\tlineContent,\n\t\t\tfalse,\n\t\t\tisBasicASCII,\n\t\t\tcontainsRTL,\n\t\t\t0,\n\t\t\tlineTokens,\n\t\t\t[],\n\t\t\ttabSize,\n\t\t\t0,\n\t\t\tfontInfo.spaceWidth,\n\t\t\tfontInfo.middotWidth,\n\t\t\tfontInfo.wsmiddotWidth,\n\t\t\toptions.get(EditorOption.stopRenderingLineAfter),\n\t\t\toptions.get(EditorOption.renderWhitespace),\n\t\t\toptions.get(EditorOption.renderControlCharacters),\n\t\t\toptions.get(EditorOption.fontLigatures) !== EditorFontLigatures.OFF,\n\t\t\tnull\n\t\t));\n\n\t\treturn r.html;\n\t}\n}\n\nexport class AccessibleDiffViewerModelFromEditors implements IAccessibleDiffViewerModel {\n\tconstructor(private readonly editors: DiffEditorEditors) { }\n\n\tgetOriginalModel(): ITextModel {\n\t\treturn this.editors.original.getModel()!;\n\t}\n\n\tgetOriginalOptions(): IComputedEditorOptions {\n\t\treturn this.editors.original.getOptions();\n\t}\n\n\toriginalReveal(range: Range): void {\n\t\tthis.editors.original.revealRange(range);\n\t\tthis.editors.original.setSelection(range);\n\t\tthis.editors.original.focus();\n\t}\n\n\tgetModifiedModel(): ITextModel {\n\t\treturn this.editors.modified.getModel()!;\n\t}\n\n\tgetModifiedOptions(): IComputedEditorOptions {\n\t\treturn this.editors.modified.getOptions();\n\t}\n\n\tmodifiedReveal(range?: Range | undefined): void {\n\t\tif (range) {\n\t\t\tthis.editors.modified.revealRange(range);\n\t\t\tthis.editors.modified.setSelection(range);\n\t\t}\n\t\tthis.editors.modified.focus();\n\t}\n\n\tmodifiedSetSelection(range: Range): void {\n\t\tthis.editors.modified.setSelection(range);\n\t}\n\n\tmodifiedFocus(): void {\n\t\tthis.editors.modified.focus();\n\t}\n\n\tgetModifiedPosition(): Position | undefined {\n\t\treturn this.editors.modified.getPosition() ?? undefined;\n\t}\n}\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\nimport { PixelRatio } from 'vs/base/browser/pixelRatio';\nimport * as dom from 'vs/base/browser/dom';\nimport { GlobalPointerMoveMonitor } from 'vs/base/browser/globalPointerMoveMonitor';\nimport { Widget } from 'vs/base/browser/ui/widget';\nimport { Codicon } from 'vs/base/common/codicons';\nimport { Color, HSVA, RGBA } from 'vs/base/common/color';\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport { ThemeIcon } from 'vs/base/common/themables';\nimport 'vs/css!./colorPicker';\nimport { ColorPickerModel } from 'vs/editor/contrib/colorPicker/browser/colorPickerModel';\nimport { IEditorHoverColorPickerWidget } from 'vs/editor/contrib/hover/browser/hoverTypes';\nimport { localize } from 'vs/nls';\nimport { editorHoverBackground } from 'vs/platform/theme/common/colorRegistry';\nimport { registerIcon } from 'vs/platform/theme/common/iconRegistry';\nimport { IThemeService } from 'vs/platform/theme/common/themeService';\n\nconst $ = dom.$;\n\nexport class ColorPickerHeader extends Disposable {\n\n\tprivate readonly _domNode: HTMLElement;\n\tprivate readonly _pickedColorNode: HTMLElement;\n\tprivate readonly _pickedColorPresentation: HTMLElement;\n\tprivate readonly _originalColorNode: HTMLElement;\n\tprivate readonly _closeButton: CloseButton | null = null;\n\tprivate backgroundColor: Color;\n\n\tconstructor(container: HTMLElement, private readonly model: ColorPickerModel, themeService: IThemeService, private showingStandaloneColorPicker: boolean = false) {\n\t\tsuper();\n\n\t\tthis._domNode = $('.colorpicker-header');\n\t\tdom.append(container, this._domNode);\n\n\t\tthis._pickedColorNode = dom.append(this._domNode, $('.picked-color'));\n\t\tdom.append(this._pickedColorNode, $('span.codicon.codicon-color-mode'));\n\t\tthis._pickedColorPresentation = dom.append(this._pickedColorNode, document.createElement('span'));\n\t\tthis._pickedColorPresentation.classList.add('picked-color-presentation');\n\n\t\tconst tooltip = localize('clickToToggleColorOptions', \"Click to toggle color options (rgb/hsl/hex)\");\n\t\tthis._pickedColorNode.setAttribute('title', tooltip);\n\n\t\tthis._originalColorNode = dom.append(this._domNode, $('.original-color'));\n\t\tthis._originalColorNode.style.backgroundColor = Color.Format.CSS.format(this.model.originalColor) || '';\n\n\t\tthis.backgroundColor = themeService.getColorTheme().getColor(editorHoverBackground) || Color.white;\n\t\tthis._register(themeService.onDidColorThemeChange(theme => {\n\t\t\tthis.backgroundColor = theme.getColor(editorHoverBackground) || Color.white;\n\t\t}));\n\n\t\tthis._register(dom.addDisposableListener(this._pickedColorNode, dom.EventType.CLICK, () => this.model.selectNextColorPresentation()));\n\t\tthis._register(dom.addDisposableListener(this._originalColorNode, dom.EventType.CLICK, () => {\n\t\t\tthis.model.color = this.model.originalColor;\n\t\t\tthis.model.flushColor();\n\t\t}));\n\t\tthis._register(model.onDidChangeColor(this.onDidChangeColor, this));\n\t\tthis._register(model.onDidChangePresentation(this.onDidChangePresentation, this));\n\t\tthis._pickedColorNode.style.backgroundColor = Color.Format.CSS.format(model.color) || '';\n\t\tthis._pickedColorNode.classList.toggle('light', model.color.rgba.a < 0.5 ? this.backgroundColor.isLighter() : model.color.isLighter());\n\n\t\tthis.onDidChangeColor(this.model.color);\n\n\t\t// When the color picker widget is a standalone color picker widget, then add a close button\n\t\tif (this.showingStandaloneColorPicker) {\n\t\t\tthis._domNode.classList.add('standalone-colorpicker');\n\t\t\tthis._closeButton = this._register(new CloseButton(this._domNode));\n\t\t}\n\t}\n\n\tpublic get closeButton(): CloseButton | null {\n\t\treturn this._closeButton;\n\t}\n\n\tpublic get pickedColorNode(): HTMLElement {\n\t\treturn this._pickedColorNode;\n\t}\n\n\tpublic get originalColorNode(): HTMLElement {\n\t\treturn this._originalColorNode;\n\t}\n\n\tprivate onDidChangeColor(color: Color): void {\n\t\tthis._pickedColorNode.style.backgroundColor = Color.Format.CSS.format(color) || '';\n\t\tthis._pickedColorNode.classList.toggle('light', color.rgba.a < 0.5 ? this.backgroundColor.isLighter() : color.isLighter());\n\t\tthis.onDidChangePresentation();\n\t}\n\n\tprivate onDidChangePresentation(): void {\n\t\tthis._pickedColorPresentation.textContent = this.model.presentation ? this.model.presentation.label : '';\n\t}\n}\n\nclass CloseButton extends Disposable {\n\n\tprivate _button: HTMLElement;\n\tprivate readonly _onClicked = this._register(new Emitter());\n\tpublic readonly onClicked = this._onClicked.event;\n\n\tconstructor(container: HTMLElement) {\n\t\tsuper();\n\t\tthis._button = document.createElement('div');\n\t\tthis._button.classList.add('close-button');\n\t\tdom.append(container, this._button);\n\n\t\tconst innerDiv = document.createElement('div');\n\t\tinnerDiv.classList.add('close-button-inner-div');\n\t\tdom.append(this._button, innerDiv);\n\n\t\tconst closeButton = dom.append(innerDiv, $('.button' + ThemeIcon.asCSSSelector(registerIcon('color-picker-close', Codicon.close, localize('closeIcon', 'Icon to close the color picker')))));\n\t\tcloseButton.classList.add('close-icon');\n\t\tthis._register(dom.addDisposableListener(this._button, dom.EventType.CLICK, () => {\n\t\t\tthis._onClicked.fire();\n\t\t}));\n\t}\n}\n\nexport class ColorPickerBody extends Disposable {\n\n\tprivate readonly _domNode: HTMLElement;\n\tprivate readonly _saturationBox: SaturationBox;\n\tprivate readonly _hueStrip: Strip;\n\tprivate readonly _opacityStrip: Strip;\n\tprivate readonly _insertButton: InsertButton | null = null;\n\n\tconstructor(container: HTMLElement, private readonly model: ColorPickerModel, private pixelRatio: number, isStandaloneColorPicker: boolean = false) {\n\t\tsuper();\n\n\t\tthis._domNode = $('.colorpicker-body');\n\t\tdom.append(container, this._domNode);\n\n\t\tthis._saturationBox = new SaturationBox(this._domNode, this.model, this.pixelRatio);\n\t\tthis._register(this._saturationBox);\n\t\tthis._register(this._saturationBox.onDidChange(this.onDidSaturationValueChange, this));\n\t\tthis._register(this._saturationBox.onColorFlushed(this.flushColor, this));\n\n\t\tthis._opacityStrip = new OpacityStrip(this._domNode, this.model, isStandaloneColorPicker);\n\t\tthis._register(this._opacityStrip);\n\t\tthis._register(this._opacityStrip.onDidChange(this.onDidOpacityChange, this));\n\t\tthis._register(this._opacityStrip.onColorFlushed(this.flushColor, this));\n\n\t\tthis._hueStrip = new HueStrip(this._domNode, this.model, isStandaloneColorPicker);\n\t\tthis._register(this._hueStrip);\n\t\tthis._register(this._hueStrip.onDidChange(this.onDidHueChange, this));\n\t\tthis._register(this._hueStrip.onColorFlushed(this.flushColor, this));\n\n\t\tif (isStandaloneColorPicker) {\n\t\t\tthis._insertButton = this._register(new InsertButton(this._domNode));\n\t\t\tthis._domNode.classList.add('standalone-colorpicker');\n\t\t}\n\t}\n\n\tprivate flushColor(): void {\n\t\tthis.model.flushColor();\n\t}\n\n\tprivate onDidSaturationValueChange({ s, v }: { s: number; v: number }): void {\n\t\tconst hsva = this.model.color.hsva;\n\t\tthis.model.color = new Color(new HSVA(hsva.h, s, v, hsva.a));\n\t}\n\n\tprivate onDidOpacityChange(a: number): void {\n\t\tconst hsva = this.model.color.hsva;\n\t\tthis.model.color = new Color(new HSVA(hsva.h, hsva.s, hsva.v, a));\n\t}\n\n\tprivate onDidHueChange(value: number): void {\n\t\tconst hsva = this.model.color.hsva;\n\t\tconst h = (1 - value) * 360;\n\n\t\tthis.model.color = new Color(new HSVA(h === 360 ? 0 : h, hsva.s, hsva.v, hsva.a));\n\t}\n\n\tget domNode() {\n\t\treturn this._domNode;\n\t}\n\n\tget saturationBox() {\n\t\treturn this._saturationBox;\n\t}\n\n\tget enterButton() {\n\t\treturn this._insertButton;\n\t}\n\n\tlayout(): void {\n\t\tthis._saturationBox.layout();\n\t\tthis._opacityStrip.layout();\n\t\tthis._hueStrip.layout();\n\t}\n}\n\nclass SaturationBox extends Disposable {\n\n\tprivate readonly _domNode: HTMLElement;\n\tprivate readonly selection: HTMLElement;\n\tprivate readonly _canvas: HTMLCanvasElement;\n\tprivate width!: number;\n\tprivate height!: number;\n\n\tprivate monitor: GlobalPointerMoveMonitor | null;\n\tprivate readonly _onDidChange = new Emitter<{ s: number; v: number }>();\n\treadonly onDidChange: Event<{ s: number; v: number }> = this._onDidChange.event;\n\n\tprivate readonly _onColorFlushed = new Emitter();\n\treadonly onColorFlushed: Event = this._onColorFlushed.event;\n\n\tconstructor(container: HTMLElement, private readonly model: ColorPickerModel, private pixelRatio: number) {\n\t\tsuper();\n\n\t\tthis._domNode = $('.saturation-wrap');\n\t\tdom.append(container, this._domNode);\n\n\t\t// Create canvas, draw selected color\n\t\tthis._canvas = document.createElement('canvas');\n\t\tthis._canvas.className = 'saturation-box';\n\t\tdom.append(this._domNode, this._canvas);\n\n\t\t// Add selection circle\n\t\tthis.selection = $('.saturation-selection');\n\t\tdom.append(this._domNode, this.selection);\n\n\t\tthis.layout();\n\n\t\tthis._register(dom.addDisposableListener(this._domNode, dom.EventType.POINTER_DOWN, e => this.onPointerDown(e)));\n\t\tthis._register(this.model.onDidChangeColor(this.onDidChangeColor, this));\n\t\tthis.monitor = null;\n\t}\n\n\tpublic get domNode() {\n\t\treturn this._domNode;\n\t}\n\n\tprivate onPointerDown(e: PointerEvent): void {\n\t\tif (!e.target || !(e.target instanceof Element)) {\n\t\t\treturn;\n\t\t}\n\t\tthis.monitor = this._register(new GlobalPointerMoveMonitor());\n\t\tconst origin = dom.getDomNodePagePosition(this._domNode);\n\n\t\tif (e.target !== this.selection) {\n\t\t\tthis.onDidChangePosition(e.offsetX, e.offsetY);\n\t\t}\n\n\t\tthis.monitor.startMonitoring(e.target, e.pointerId, e.buttons, event => this.onDidChangePosition(event.pageX - origin.left, event.pageY - origin.top), () => null);\n\n\t\tconst pointerUpListener = dom.addDisposableListener(e.target.ownerDocument, dom.EventType.POINTER_UP, () => {\n\t\t\tthis._onColorFlushed.fire();\n\t\t\tpointerUpListener.dispose();\n\t\t\tif (this.monitor) {\n\t\t\t\tthis.monitor.stopMonitoring(true);\n\t\t\t\tthis.monitor = null;\n\t\t\t}\n\t\t}, true);\n\t}\n\n\tprivate onDidChangePosition(left: number, top: number): void {\n\t\tconst s = Math.max(0, Math.min(1, left / this.width));\n\t\tconst v = Math.max(0, Math.min(1, 1 - (top / this.height)));\n\n\t\tthis.paintSelection(s, v);\n\t\tthis._onDidChange.fire({ s, v });\n\t}\n\n\tlayout(): void {\n\t\tthis.width = this._domNode.offsetWidth;\n\t\tthis.height = this._domNode.offsetHeight;\n\t\tthis._canvas.width = this.width * this.pixelRatio;\n\t\tthis._canvas.height = this.height * this.pixelRatio;\n\t\tthis.paint();\n\n\t\tconst hsva = this.model.color.hsva;\n\t\tthis.paintSelection(hsva.s, hsva.v);\n\t}\n\n\tprivate paint(): void {\n\t\tconst hsva = this.model.color.hsva;\n\t\tconst saturatedColor = new Color(new HSVA(hsva.h, 1, 1, 1));\n\t\tconst ctx = this._canvas.getContext('2d')!;\n\n\t\tconst whiteGradient = ctx.createLinearGradient(0, 0, this._canvas.width, 0);\n\t\twhiteGradient.addColorStop(0, 'rgba(255, 255, 255, 1)');\n\t\twhiteGradient.addColorStop(0.5, 'rgba(255, 255, 255, 0.5)');\n\t\twhiteGradient.addColorStop(1, 'rgba(255, 255, 255, 0)');\n\n\t\tconst blackGradient = ctx.createLinearGradient(0, 0, 0, this._canvas.height);\n\t\tblackGradient.addColorStop(0, 'rgba(0, 0, 0, 0)');\n\t\tblackGradient.addColorStop(1, 'rgba(0, 0, 0, 1)');\n\n\t\tctx.rect(0, 0, this._canvas.width, this._canvas.height);\n\t\tctx.fillStyle = Color.Format.CSS.format(saturatedColor)!;\n\t\tctx.fill();\n\t\tctx.fillStyle = whiteGradient;\n\t\tctx.fill();\n\t\tctx.fillStyle = blackGradient;\n\t\tctx.fill();\n\t}\n\n\tprivate paintSelection(s: number, v: number): void {\n\t\tthis.selection.style.left = `${s * this.width}px`;\n\t\tthis.selection.style.top = `${this.height - v * this.height}px`;\n\t}\n\n\tprivate onDidChangeColor(color: Color): void {\n\t\tif (this.monitor && this.monitor.isMonitoring()) {\n\t\t\treturn;\n\t\t}\n\t\tthis.paint();\n\t\tconst hsva = color.hsva;\n\t\tthis.paintSelection(hsva.s, hsva.v);\n\t}\n}\n\nabstract class Strip extends Disposable {\n\n\tprotected domNode: HTMLElement;\n\tprotected overlay: HTMLElement;\n\tprotected slider: HTMLElement;\n\tprivate height!: number;\n\n\tprivate readonly _onDidChange = new Emitter();\n\treadonly onDidChange: Event = this._onDidChange.event;\n\n\tprivate readonly _onColorFlushed = new Emitter();\n\treadonly onColorFlushed: Event = this._onColorFlushed.event;\n\n\tconstructor(container: HTMLElement, protected model: ColorPickerModel, showingStandaloneColorPicker: boolean = false) {\n\t\tsuper();\n\t\tif (showingStandaloneColorPicker) {\n\t\t\tthis.domNode = dom.append(container, $('.standalone-strip'));\n\t\t\tthis.overlay = dom.append(this.domNode, $('.standalone-overlay'));\n\t\t} else {\n\t\t\tthis.domNode = dom.append(container, $('.strip'));\n\t\t\tthis.overlay = dom.append(this.domNode, $('.overlay'));\n\t\t}\n\t\tthis.slider = dom.append(this.domNode, $('.slider'));\n\t\tthis.slider.style.top = `0px`;\n\n\t\tthis._register(dom.addDisposableListener(this.domNode, dom.EventType.POINTER_DOWN, e => this.onPointerDown(e)));\n\t\tthis._register(model.onDidChangeColor(this.onDidChangeColor, this));\n\t\tthis.layout();\n\t}\n\n\tlayout(): void {\n\t\tthis.height = this.domNode.offsetHeight - this.slider.offsetHeight;\n\n\t\tconst value = this.getValue(this.model.color);\n\t\tthis.updateSliderPosition(value);\n\t}\n\n\tprotected onDidChangeColor(color: Color) {\n\t\tconst value = this.getValue(color);\n\t\tthis.updateSliderPosition(value);\n\t}\n\n\tprivate onPointerDown(e: PointerEvent): void {\n\t\tif (!e.target || !(e.target instanceof Element)) {\n\t\t\treturn;\n\t\t}\n\t\tconst monitor = this._register(new GlobalPointerMoveMonitor());\n\t\tconst origin = dom.getDomNodePagePosition(this.domNode);\n\t\tthis.domNode.classList.add('grabbing');\n\n\t\tif (e.target !== this.slider) {\n\t\t\tthis.onDidChangeTop(e.offsetY);\n\t\t}\n\n\t\tmonitor.startMonitoring(e.target, e.pointerId, e.buttons, event => this.onDidChangeTop(event.pageY - origin.top), () => null);\n\n\t\tconst pointerUpListener = dom.addDisposableListener(e.target.ownerDocument, dom.EventType.POINTER_UP, () => {\n\t\t\tthis._onColorFlushed.fire();\n\t\t\tpointerUpListener.dispose();\n\t\t\tmonitor.stopMonitoring(true);\n\t\t\tthis.domNode.classList.remove('grabbing');\n\t\t}, true);\n\t}\n\n\tprivate onDidChangeTop(top: number): void {\n\t\tconst value = Math.max(0, Math.min(1, 1 - (top / this.height)));\n\n\t\tthis.updateSliderPosition(value);\n\t\tthis._onDidChange.fire(value);\n\t}\n\n\tprivate updateSliderPosition(value: number): void {\n\t\tthis.slider.style.top = `${(1 - value) * this.height}px`;\n\t}\n\n\tprotected abstract getValue(color: Color): number;\n}\n\nclass OpacityStrip extends Strip {\n\n\tconstructor(container: HTMLElement, model: ColorPickerModel, showingStandaloneColorPicker: boolean = false) {\n\t\tsuper(container, model, showingStandaloneColorPicker);\n\t\tthis.domNode.classList.add('opacity-strip');\n\n\t\tthis.onDidChangeColor(this.model.color);\n\t}\n\n\tprotected override onDidChangeColor(color: Color): void {\n\t\tsuper.onDidChangeColor(color);\n\t\tconst { r, g, b } = color.rgba;\n\t\tconst opaque = new Color(new RGBA(r, g, b, 1));\n\t\tconst transparent = new Color(new RGBA(r, g, b, 0));\n\n\t\tthis.overlay.style.background = `linear-gradient(to bottom, ${opaque} 0%, ${transparent} 100%)`;\n\t}\n\n\tprotected getValue(color: Color): number {\n\t\treturn color.hsva.a;\n\t}\n}\n\nclass HueStrip extends Strip {\n\n\tconstructor(container: HTMLElement, model: ColorPickerModel, showingStandaloneColorPicker: boolean = false) {\n\t\tsuper(container, model, showingStandaloneColorPicker);\n\t\tthis.domNode.classList.add('hue-strip');\n\t}\n\n\tprotected getValue(color: Color): number {\n\t\treturn 1 - (color.hsva.h / 360);\n\t}\n}\n\nexport class InsertButton extends Disposable {\n\n\tprivate _button: HTMLElement;\n\tprivate readonly _onClicked = this._register(new Emitter());\n\tpublic readonly onClicked = this._onClicked.event;\n\n\tconstructor(container: HTMLElement) {\n\t\tsuper();\n\t\tthis._button = dom.append(container, document.createElement('button'));\n\t\tthis._button.classList.add('insert-button');\n\t\tthis._button.textContent = 'Insert';\n\t\tthis._register(dom.addDisposableListener(this._button, dom.EventType.CLICK, () => {\n\t\t\tthis._onClicked.fire();\n\t\t}));\n\t}\n\n\tpublic get button(): HTMLElement {\n\t\treturn this._button;\n\t}\n}\n\nexport class ColorPickerWidget extends Widget implements IEditorHoverColorPickerWidget {\n\n\tbody: ColorPickerBody;\n\theader: ColorPickerHeader;\n\n\tconstructor(container: Node, readonly model: ColorPickerModel, private pixelRatio: number, themeService: IThemeService, standaloneColorPicker: boolean = false) {\n\t\tsuper();\n\n\t\tthis._register(PixelRatio.getInstance(dom.getWindow(container)).onDidChange(() => this.layout()));\n\n\t\tconst element = $('.colorpicker-widget');\n\t\tcontainer.appendChild(element);\n\n\t\tthis.header = this._register(new ColorPickerHeader(element, this.model, themeService, standaloneColorPicker));\n\t\tthis.body = this._register(new ColorPickerBody(element, this.model, this.pixelRatio, standaloneColorPicker));\n\t}\n\n\tlayout(): void {\n\t\tthis.body.layout();\n\t}\n}\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\nimport * as dom from 'vs/base/browser/dom';\nimport { asArray, compareBy, numberComparator } from 'vs/base/common/arrays';\nimport { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';\nimport { IMarkdownString, isEmptyMarkdownString, MarkdownString } from 'vs/base/common/htmlContent';\nimport { Disposable, DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle';\nimport { MarkdownRenderer } from 'vs/editor/browser/widget/markdownRenderer/browser/markdownRenderer';\nimport { DECREASE_HOVER_VERBOSITY_ACTION_ID, INCREASE_HOVER_VERBOSITY_ACTION_ID } from 'vs/editor/contrib/hover/browser/hoverActionIds';\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\nimport { Position } from 'vs/editor/common/core/position';\nimport { Range } from 'vs/editor/common/core/range';\nimport { IModelDecoration, ITextModel } from 'vs/editor/common/model';\nimport { ILanguageService } from 'vs/editor/common/languages/language';\nimport { HoverAnchor, HoverAnchorType, HoverRangeAnchor, IEditorHoverParticipant, IEditorHoverRenderContext, IHoverPart } from 'vs/editor/contrib/hover/browser/hoverTypes';\nimport * as nls from 'vs/nls';\nimport { IConfigurationService } from 'vs/platform/configuration/common/configuration';\nimport { IOpenerService } from 'vs/platform/opener/common/opener';\nimport { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\nimport { Hover, HoverContext, HoverProvider, HoverVerbosityAction } from 'vs/editor/common/languages';\nimport { registerIcon } from 'vs/platform/theme/common/iconRegistry';\nimport { Codicon } from 'vs/base/common/codicons';\nimport { ThemeIcon } from 'vs/base/common/themables';\nimport { onUnexpectedExternalError } from 'vs/base/common/errors';\nimport { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';\nimport { ClickAction, HoverPosition, KeyDownAction } from 'vs/base/browser/ui/hover/hoverWidget';\nimport { KeyCode } from 'vs/base/common/keyCodes';\nimport { IHoverService, WorkbenchHoverDelegate } from 'vs/platform/hover/browser/hover';\nimport { AsyncIterableObject } from 'vs/base/common/async';\nimport { LanguageFeatureRegistry } from 'vs/editor/common/languageFeatureRegistry';\nimport { getHoverProviderResultsAsAsyncIterable } from 'vs/editor/contrib/hover/browser/getHover';\n\nconst $ = dom.$;\nconst increaseHoverVerbosityIcon = registerIcon('hover-increase-verbosity', Codicon.add, nls.localize('increaseHoverVerbosity', 'Icon for increaseing hover verbosity.'));\nconst decreaseHoverVerbosityIcon = registerIcon('hover-decrease-verbosity', Codicon.remove, nls.localize('decreaseHoverVerbosity', 'Icon for decreasing hover verbosity.'));\n\nexport class MarkdownHover implements IHoverPart {\n\n\tconstructor(\n\t\tpublic readonly owner: IEditorHoverParticipant,\n\t\tpublic readonly range: Range,\n\t\tpublic readonly contents: IMarkdownString[],\n\t\tpublic readonly isBeforeContent: boolean,\n\t\tpublic readonly ordinal: number,\n\t\tpublic readonly source: HoverSource | undefined = undefined,\n\t) { }\n\n\tpublic isValidForHoverAnchor(anchor: HoverAnchor): boolean {\n\t\treturn (\n\t\t\tanchor.type === HoverAnchorType.Range\n\t\t\t&& this.range.startColumn <= anchor.range.startColumn\n\t\t\t&& this.range.endColumn >= anchor.range.endColumn\n\t\t);\n\t}\n}\n\nclass HoverSource {\n\n\tconstructor(\n\t\treadonly hover: Hover,\n\t\treadonly hoverProvider: HoverProvider,\n\t\treadonly hoverPosition: Position,\n\t) { }\n\n\tpublic supportsVerbosityAction(hoverVerbosityAction: HoverVerbosityAction): boolean {\n\t\tswitch (hoverVerbosityAction) {\n\t\t\tcase HoverVerbosityAction.Increase:\n\t\t\t\treturn this.hover.canIncreaseVerbosity ?? false;\n\t\t\tcase HoverVerbosityAction.Decrease:\n\t\t\t\treturn this.hover.canDecreaseVerbosity ?? false;\n\t\t}\n\t}\n}\n\nexport class MarkdownHoverParticipant implements IEditorHoverParticipant {\n\n\tpublic readonly hoverOrdinal: number = 3;\n\n\tprivate _renderedHoverParts: MarkdownRenderedHoverParts | undefined;\n\n\tconstructor(\n\t\tprotected readonly _editor: ICodeEditor,\n\t\t@ILanguageService private readonly _languageService: ILanguageService,\n\t\t@IOpenerService private readonly _openerService: IOpenerService,\n\t\t@IConfigurationService private readonly _configurationService: IConfigurationService,\n\t\t@ILanguageFeaturesService protected readonly _languageFeaturesService: ILanguageFeaturesService,\n\t\t@IKeybindingService private readonly _keybindingService: IKeybindingService,\n\t\t@IHoverService private readonly _hoverService: IHoverService,\n\t) { }\n\n\tpublic createLoadingMessage(anchor: HoverAnchor): MarkdownHover | null {\n\t\treturn new MarkdownHover(this, anchor.range, [new MarkdownString().appendText(nls.localize('modesContentHover.loading', \"Loading...\"))], false, 2000);\n\t}\n\n\tpublic computeSync(anchor: HoverAnchor, lineDecorations: IModelDecoration[]): MarkdownHover[] {\n\t\tif (!this._editor.hasModel() || anchor.type !== HoverAnchorType.Range) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst model = this._editor.getModel();\n\t\tconst lineNumber = anchor.range.startLineNumber;\n\t\tconst maxColumn = model.getLineMaxColumn(lineNumber);\n\t\tconst result: MarkdownHover[] = [];\n\n\t\tlet index = 1000;\n\n\t\tconst lineLength = model.getLineLength(lineNumber);\n\t\tconst languageId = model.getLanguageIdAtPosition(anchor.range.startLineNumber, anchor.range.startColumn);\n\t\tconst stopRenderingLineAfter = this._editor.getOption(EditorOption.stopRenderingLineAfter);\n\t\tconst maxTokenizationLineLength = this._configurationService.getValue('editor.maxTokenizationLineLength', {\n\t\t\toverrideIdentifier: languageId\n\t\t});\n\t\tlet stopRenderingMessage = false;\n\t\tif (stopRenderingLineAfter >= 0 && lineLength > stopRenderingLineAfter && anchor.range.startColumn >= stopRenderingLineAfter) {\n\t\t\tstopRenderingMessage = true;\n\t\t\tresult.push(new MarkdownHover(this, anchor.range, [{\n\t\t\t\tvalue: nls.localize('stopped rendering', \"Rendering paused for long line for performance reasons. This can be configured via `editor.stopRenderingLineAfter`.\")\n\t\t\t}], false, index++));\n\t\t}\n\t\tif (!stopRenderingMessage && typeof maxTokenizationLineLength === 'number' && lineLength >= maxTokenizationLineLength) {\n\t\t\tresult.push(new MarkdownHover(this, anchor.range, [{\n\t\t\t\tvalue: nls.localize('too many characters', \"Tokenization is skipped for long lines for performance reasons. This can be configured via `editor.maxTokenizationLineLength`.\")\n\t\t\t}], false, index++));\n\t\t}\n\n\t\tlet isBeforeContent = false;\n\n\t\tfor (const d of lineDecorations) {\n\t\t\tconst startColumn = (d.range.startLineNumber === lineNumber) ? d.range.startColumn : 1;\n\t\t\tconst endColumn = (d.range.endLineNumber === lineNumber) ? d.range.endColumn : maxColumn;\n\n\t\t\tconst hoverMessage = d.options.hoverMessage;\n\t\t\tif (!hoverMessage || isEmptyMarkdownString(hoverMessage)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (d.options.beforeContentClassName) {\n\t\t\t\tisBeforeContent = true;\n\t\t\t}\n\n\t\t\tconst range = new Range(anchor.range.startLineNumber, startColumn, anchor.range.startLineNumber, endColumn);\n\t\t\tresult.push(new MarkdownHover(this, range, asArray(hoverMessage), isBeforeContent, index++));\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tpublic computeAsync(anchor: HoverAnchor, lineDecorations: IModelDecoration[], token: CancellationToken): AsyncIterableObject {\n\t\tif (!this._editor.hasModel() || anchor.type !== HoverAnchorType.Range) {\n\t\t\treturn AsyncIterableObject.EMPTY;\n\t\t}\n\n\t\tconst model = this._editor.getModel();\n\n\t\tconst hoverProviderRegistry = this._languageFeaturesService.hoverProvider;\n\t\tif (!hoverProviderRegistry.has(model)) {\n\t\t\treturn AsyncIterableObject.EMPTY;\n\t\t}\n\t\tconst markdownHovers = this._getMarkdownHovers(hoverProviderRegistry, model, anchor, token);\n\t\treturn markdownHovers;\n\t}\n\n\tprivate _getMarkdownHovers(hoverProviderRegistry: LanguageFeatureRegistry, model: ITextModel, anchor: HoverRangeAnchor, token: CancellationToken): AsyncIterableObject {\n\t\tconst position = anchor.range.getStartPosition();\n\t\tconst hoverProviderResults = getHoverProviderResultsAsAsyncIterable(hoverProviderRegistry, model, position, token);\n\t\tconst markdownHovers = hoverProviderResults.filter(item => !isEmptyMarkdownString(item.hover.contents))\n\t\t\t.map(item => {\n\t\t\t\tconst range = item.hover.range ? Range.lift(item.hover.range) : anchor.range;\n\t\t\t\tconst hoverSource = new HoverSource(item.hover, item.provider, position);\n\t\t\t\treturn new MarkdownHover(this, range, item.hover.contents, false, item.ordinal, hoverSource);\n\t\t\t});\n\t\treturn markdownHovers;\n\t}\n\n\tpublic renderHoverParts(context: IEditorHoverRenderContext, hoverParts: MarkdownHover[]): IDisposable {\n\t\tthis._renderedHoverParts = new MarkdownRenderedHoverParts(\n\t\t\thoverParts,\n\t\t\tcontext.fragment,\n\t\t\tthis._editor,\n\t\t\tthis._languageService,\n\t\t\tthis._openerService,\n\t\t\tthis._keybindingService,\n\t\t\tthis._hoverService,\n\t\t\tthis._configurationService,\n\t\t\tcontext.onContentsChanged\n\t\t);\n\t\treturn this._renderedHoverParts;\n\t}\n\n\tpublic updateFocusedMarkdownHoverPartVerbosityLevel(action: HoverVerbosityAction) {\n\t\tthis._renderedHoverParts?.updateFocusedHoverPartVerbosityLevel(action);\n\t}\n}\n\ninterface RenderedHoverPart {\n\trenderedMarkdown: HTMLElement;\n\tdisposables: DisposableStore;\n\thoverSource?: HoverSource;\n}\n\ninterface FocusedHoverInfo {\n\thoverPartIndex: number;\n\t// TODO@aiday-mar is this needed?\n\tfocusRemains: boolean;\n}\n\nclass MarkdownRenderedHoverParts extends Disposable {\n\n\tprivate _renderedHoverParts: RenderedHoverPart[];\n\tprivate _hoverFocusInfo: FocusedHoverInfo = { hoverPartIndex: -1, focusRemains: false };\n\tprivate _ongoingHoverOperations: Map = new Map();\n\n\tconstructor(\n\t\thoverParts: MarkdownHover[], // we own!\n\t\thoverPartsContainer: DocumentFragment,\n\t\tprivate readonly _editor: ICodeEditor,\n\t\tprivate readonly _languageService: ILanguageService,\n\t\tprivate readonly _openerService: IOpenerService,\n\t\tprivate readonly _keybindingService: IKeybindingService,\n\t\tprivate readonly _hoverService: IHoverService,\n\t\tprivate readonly _configurationService: IConfigurationService,\n\t\tprivate readonly _onFinishedRendering: () => void,\n\t) {\n\t\tsuper();\n\t\tthis._renderedHoverParts = this._renderHoverParts(hoverParts, hoverPartsContainer, this._onFinishedRendering);\n\t\tthis._register(toDisposable(() => {\n\t\t\tthis._renderedHoverParts.forEach(renderedHoverPart => {\n\t\t\t\trenderedHoverPart.disposables.dispose();\n\t\t\t});\n\t\t}));\n\t\tthis._register(toDisposable(() => {\n\t\t\tthis._ongoingHoverOperations.forEach(operation => { operation.tokenSource.dispose(true); });\n\t\t}));\n\t}\n\n\tprivate _renderHoverParts(\n\t\thoverParts: MarkdownHover[],\n\t\thoverPartsContainer: DocumentFragment,\n\t\tonFinishedRendering: () => void,\n\t): RenderedHoverPart[] {\n\t\thoverParts.sort(compareBy(hover => hover.ordinal, numberComparator));\n\t\treturn hoverParts.map((hoverPart, hoverIndex) => {\n\t\t\tconst renderedHoverPart = this._renderHoverPart(\n\t\t\t\thoverIndex,\n\t\t\t\thoverPart.contents,\n\t\t\t\thoverPart.source,\n\t\t\t\tonFinishedRendering\n\t\t\t);\n\t\t\thoverPartsContainer.appendChild(renderedHoverPart.renderedMarkdown);\n\t\t\treturn renderedHoverPart;\n\t\t});\n\t}\n\n\tprivate _renderHoverPart(\n\t\thoverPartIndex: number,\n\t\thoverContents: IMarkdownString[],\n\t\thoverSource: HoverSource | undefined,\n\t\tonFinishedRendering: () => void\n\t): RenderedHoverPart {\n\n\t\tconst { renderedMarkdown, disposables } = this._renderMarkdownContent(hoverContents, onFinishedRendering);\n\n\t\tif (!hoverSource) {\n\t\t\treturn { renderedMarkdown, disposables };\n\t\t}\n\n\t\tconst canIncreaseVerbosity = hoverSource.supportsVerbosityAction(HoverVerbosityAction.Increase);\n\t\tconst canDecreaseVerbosity = hoverSource.supportsVerbosityAction(HoverVerbosityAction.Decrease);\n\n\t\tif (!canIncreaseVerbosity && !canDecreaseVerbosity) {\n\t\t\treturn { renderedMarkdown, disposables, hoverSource };\n\t\t}\n\n\t\tconst actionsContainer = $('div.verbosity-actions');\n\t\trenderedMarkdown.prepend(actionsContainer);\n\n\t\tdisposables.add(this._renderHoverExpansionAction(actionsContainer, HoverVerbosityAction.Increase, canIncreaseVerbosity));\n\t\tdisposables.add(this._renderHoverExpansionAction(actionsContainer, HoverVerbosityAction.Decrease, canDecreaseVerbosity));\n\n\t\tconst focusTracker = disposables.add(dom.trackFocus(renderedMarkdown));\n\t\tdisposables.add(focusTracker.onDidFocus(() => {\n\t\t\tthis._hoverFocusInfo = {\n\t\t\t\thoverPartIndex,\n\t\t\t\tfocusRemains: true\n\t\t\t};\n\t\t}));\n\t\tdisposables.add(focusTracker.onDidBlur(() => {\n\t\t\tif (this._hoverFocusInfo?.focusRemains) {\n\t\t\t\tthis._hoverFocusInfo.focusRemains = false;\n\t\t\t\treturn;\n\t\t\t}\n\t\t}));\n\t\treturn { renderedMarkdown, disposables, hoverSource };\n\t}\n\n\tprivate _renderMarkdownContent(\n\t\tmarkdownContent: IMarkdownString[],\n\t\tonFinishedRendering: () => void\n\t): RenderedHoverPart {\n\t\tconst renderedMarkdown = $('div.hover-row');\n\t\trenderedMarkdown.tabIndex = 0;\n\t\tconst renderedMarkdownContents = $('div.hover-row-contents');\n\t\trenderedMarkdown.appendChild(renderedMarkdownContents);\n\t\tconst disposables = new DisposableStore();\n\t\tdisposables.add(renderMarkdownInContainer(\n\t\t\tthis._editor,\n\t\t\trenderedMarkdownContents,\n\t\t\tmarkdownContent,\n\t\t\tthis._languageService,\n\t\t\tthis._openerService,\n\t\t\tonFinishedRendering,\n\t\t));\n\t\treturn { renderedMarkdown, disposables };\n\t}\n\n\tprivate _renderHoverExpansionAction(container: HTMLElement, action: HoverVerbosityAction, actionEnabled: boolean): DisposableStore {\n\t\tconst store = new DisposableStore();\n\t\tconst isActionIncrease = action === HoverVerbosityAction.Increase;\n\t\tconst actionElement = dom.append(container, $(ThemeIcon.asCSSSelector(isActionIncrease ? increaseHoverVerbosityIcon : decreaseHoverVerbosityIcon)));\n\t\tactionElement.tabIndex = 0;\n\t\tconst hoverDelegate = new WorkbenchHoverDelegate('mouse', false, { target: container, position: { hoverPosition: HoverPosition.LEFT } }, this._configurationService, this._hoverService);\n\t\tif (isActionIncrease) {\n\t\t\tconst kb = this._keybindingService.lookupKeybinding(INCREASE_HOVER_VERBOSITY_ACTION_ID);\n\t\t\tstore.add(this._hoverService.setupUpdatableHover(hoverDelegate, actionElement, kb ?\n\t\t\t\tnls.localize('increaseVerbosityWithKb', \"Increase Verbosity ({0})\", kb.getLabel()) :\n\t\t\t\tnls.localize('increaseVerbosity', \"Increase Verbosity\")));\n\t\t} else {\n\t\t\tconst kb = this._keybindingService.lookupKeybinding(DECREASE_HOVER_VERBOSITY_ACTION_ID);\n\t\t\tstore.add(this._hoverService.setupUpdatableHover(hoverDelegate, actionElement, kb ?\n\t\t\t\tnls.localize('decreaseVerbosityWithKb', \"Decrease Verbosity ({0})\", kb.getLabel()) :\n\t\t\t\tnls.localize('decreaseVerbosity', \"Decrease Verbosity\")));\n\t\t}\n\t\tif (!actionEnabled) {\n\t\t\tactionElement.classList.add('disabled');\n\t\t\treturn store;\n\t\t}\n\t\tactionElement.classList.add('enabled');\n\t\tconst actionFunction = () => this.updateFocusedHoverPartVerbosityLevel(action);\n\t\tstore.add(new ClickAction(actionElement, actionFunction));\n\t\tstore.add(new KeyDownAction(actionElement, actionFunction, [KeyCode.Enter, KeyCode.Space]));\n\t\treturn store;\n\t}\n\n\tpublic async updateFocusedHoverPartVerbosityLevel(action: HoverVerbosityAction): Promise {\n\t\tconst model = this._editor.getModel();\n\t\tif (!model) {\n\t\t\treturn;\n\t\t}\n\t\tconst hoverFocusedPartIndex = this._hoverFocusInfo.hoverPartIndex;\n\t\tconst hoverRenderedPart = this._getRenderedHoverPartAtIndex(hoverFocusedPartIndex);\n\t\tif (!hoverRenderedPart || !hoverRenderedPart.hoverSource?.supportsVerbosityAction(action)) {\n\t\t\treturn;\n\t\t}\n\t\tconst hoverSource = hoverRenderedPart.hoverSource;\n\t\tconst newHover = await this._fetchHover(hoverSource, model, action);\n\t\tif (!newHover) {\n\t\t\treturn;\n\t\t}\n\t\tconst newHoverSource = new HoverSource(newHover, hoverSource.hoverProvider, hoverSource.hoverPosition);\n\t\tconst newHoverRenderedPart = this._renderHoverPart(\n\t\t\thoverFocusedPartIndex,\n\t\t\tnewHover.contents,\n\t\t\tnewHoverSource,\n\t\t\tthis._onFinishedRendering\n\t\t);\n\t\tthis._replaceRenderedHoverPartAtIndex(hoverFocusedPartIndex, newHoverRenderedPart);\n\t\tthis._focusOnHoverPartWithIndex(hoverFocusedPartIndex);\n\t\tthis._onFinishedRendering();\n\t}\n\n\tprivate async _fetchHover(hoverSource: HoverSource, model: ITextModel, action: HoverVerbosityAction): Promise {\n\t\tlet verbosityDelta = action === HoverVerbosityAction.Increase ? 1 : -1;\n\t\tconst provider = hoverSource.hoverProvider;\n\t\tconst ongoingHoverOperation = this._ongoingHoverOperations.get(provider);\n\t\tif (ongoingHoverOperation) {\n\t\t\tongoingHoverOperation.tokenSource.cancel();\n\t\t\tverbosityDelta += ongoingHoverOperation.verbosityDelta;\n\t\t}\n\t\tconst tokenSource = new CancellationTokenSource();\n\t\tthis._ongoingHoverOperations.set(provider, { verbosityDelta, tokenSource });\n\t\tconst context: HoverContext = { verbosityRequest: { verbosityDelta, previousHover: hoverSource.hover } };\n\t\tlet hover: Hover | null | undefined;\n\t\ttry {\n\t\t\thover = await Promise.resolve(provider.provideHover(model, hoverSource.hoverPosition, tokenSource.token, context));\n\t\t} catch (e) {\n\t\t\tonUnexpectedExternalError(e);\n\t\t}\n\t\ttokenSource.dispose();\n\t\tthis._ongoingHoverOperations.delete(provider);\n\t\treturn hover;\n\t}\n\n\tprivate _replaceRenderedHoverPartAtIndex(index: number, renderedHoverPart: RenderedHoverPart): void {\n\t\tif (index >= this._renderHoverParts.length || index < 0) {\n\t\t\treturn;\n\t\t}\n\t\tconst currentRenderedHoverPart = this._renderedHoverParts[index];\n\t\tconst currentRenderedMarkdown = currentRenderedHoverPart.renderedMarkdown;\n\t\tcurrentRenderedMarkdown.replaceWith(renderedHoverPart.renderedMarkdown);\n\t\tcurrentRenderedHoverPart.disposables.dispose();\n\t\tthis._renderedHoverParts[index] = renderedHoverPart;\n\t}\n\n\tprivate _focusOnHoverPartWithIndex(index: number): void {\n\t\tthis._renderedHoverParts[index].renderedMarkdown.focus();\n\t\tthis._hoverFocusInfo.focusRemains = true;\n\t}\n\n\tprivate _getRenderedHoverPartAtIndex(index: number): RenderedHoverPart | undefined {\n\t\treturn this._renderedHoverParts[index];\n\t}\n}\n\nexport function renderMarkdownHovers(\n\tcontext: IEditorHoverRenderContext,\n\thoverParts: MarkdownHover[],\n\teditor: ICodeEditor,\n\tlanguageService: ILanguageService,\n\topenerService: IOpenerService,\n): IDisposable {\n\n\t// Sort hover parts to keep them stable since they might come in async, out-of-order\n\thoverParts.sort(compareBy(hover => hover.ordinal, numberComparator));\n\n\tconst disposables = new DisposableStore();\n\tfor (const hoverPart of hoverParts) {\n\t\tdisposables.add(renderMarkdownInContainer(\n\t\t\teditor,\n\t\t\tcontext.fragment,\n\t\t\thoverPart.contents,\n\t\t\tlanguageService,\n\t\t\topenerService,\n\t\t\tcontext.onContentsChanged,\n\t\t));\n\t}\n\treturn disposables;\n}\n\nfunction renderMarkdownInContainer(\n\teditor: ICodeEditor,\n\tcontainer: DocumentFragment | HTMLElement,\n\tmarkdownStrings: IMarkdownString[],\n\tlanguageService: ILanguageService,\n\topenerService: IOpenerService,\n\tonFinishedRendering: () => void,\n): IDisposable {\n\tconst store = new DisposableStore();\n\tfor (const contents of markdownStrings) {\n\t\tif (isEmptyMarkdownString(contents)) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst markdownHoverElement = $('div.markdown-hover');\n\t\tconst hoverContentsElement = dom.append(markdownHoverElement, $('div.hover-contents'));\n\t\tconst renderer = store.add(new MarkdownRenderer({ editor }, languageService, openerService));\n\t\tstore.add(renderer.onDidRenderAsync(() => {\n\t\t\thoverContentsElement.className = 'hover-contents code-hover-contents';\n\t\t\tonFinishedRendering();\n\t\t}));\n\t\tconst renderedContents = store.add(renderer.render(contents));\n\t\thoverContentsElement.appendChild(renderedContents.element);\n\t\tcontainer.appendChild(markdownHoverElement);\n\t}\n\treturn store;\n}\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\nimport * as dom from 'vs/base/browser/dom';\nimport * as aria from 'vs/base/browser/ui/aria/aria';\nimport { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';\nimport { Codicon } from 'vs/base/common/codicons';\nimport { Event } from 'vs/base/common/event';\nimport { IMarkdownString } from 'vs/base/common/htmlContent';\nimport { Disposable, DisposableStore } from 'vs/base/common/lifecycle';\nimport { escapeRegExpCharacters } from 'vs/base/common/strings';\nimport { assertIsDefined } from 'vs/base/common/types';\nimport 'vs/css!./parameterHints';\nimport { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser';\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\nimport * as languages from 'vs/editor/common/languages';\nimport { ILanguageService } from 'vs/editor/common/languages/language';\nimport { IMarkdownRenderResult, MarkdownRenderer } from 'vs/editor/browser/widget/markdownRenderer/browser/markdownRenderer';\nimport { ParameterHintsModel } from 'vs/editor/contrib/parameterHints/browser/parameterHintsModel';\nimport { Context } from 'vs/editor/contrib/parameterHints/browser/provideSignatureHelp';\nimport * as nls from 'vs/nls';\nimport { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';\nimport { IOpenerService } from 'vs/platform/opener/common/opener';\nimport { listHighlightForeground, registerColor } from 'vs/platform/theme/common/colorRegistry';\nimport { registerIcon } from 'vs/platform/theme/common/iconRegistry';\nimport { ThemeIcon } from 'vs/base/common/themables';\nimport { StopWatch } from 'vs/base/common/stopwatch';\nimport { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';\n\nconst $ = dom.$;\n\nconst parameterHintsNextIcon = registerIcon('parameter-hints-next', Codicon.chevronDown, nls.localize('parameterHintsNextIcon', 'Icon for show next parameter hint.'));\nconst parameterHintsPreviousIcon = registerIcon('parameter-hints-previous', Codicon.chevronUp, nls.localize('parameterHintsPreviousIcon', 'Icon for show previous parameter hint.'));\n\nexport class ParameterHintsWidget extends Disposable implements IContentWidget {\n\n\tprivate static readonly ID = 'editor.widget.parameterHintsWidget';\n\n\tprivate readonly markdownRenderer: MarkdownRenderer;\n\tprivate readonly renderDisposeables = this._register(new DisposableStore());\n\tprivate readonly keyVisible: IContextKey;\n\tprivate readonly keyMultipleSignatures: IContextKey;\n\n\tprivate domNodes?: {\n\t\treadonly element: HTMLElement;\n\t\treadonly signature: HTMLElement;\n\t\treadonly docs: HTMLElement;\n\t\treadonly overloads: HTMLElement;\n\t\treadonly scrollbar: DomScrollableElement;\n\t};\n\n\tprivate visible: boolean = false;\n\tprivate announcedLabel: string | null = null;\n\n\t// Editor.IContentWidget.allowEditorOverflow\n\tallowEditorOverflow = true;\n\n\tconstructor(\n\t\tprivate readonly editor: ICodeEditor,\n\t\tprivate readonly model: ParameterHintsModel,\n\t\t@IContextKeyService contextKeyService: IContextKeyService,\n\t\t@IOpenerService openerService: IOpenerService,\n\t\t@ILanguageService languageService: ILanguageService,\n\t\t@ITelemetryService private readonly telemetryService: ITelemetryService,\n\t) {\n\t\tsuper();\n\n\t\tthis.markdownRenderer = this._register(new MarkdownRenderer({ editor }, languageService, openerService));\n\n\t\tthis.keyVisible = Context.Visible.bindTo(contextKeyService);\n\t\tthis.keyMultipleSignatures = Context.MultipleSignatures.bindTo(contextKeyService);\n\t}\n\n\tprivate createParameterHintDOMNodes() {\n\t\tconst element = $('.editor-widget.parameter-hints-widget');\n\t\tconst wrapper = dom.append(element, $('.phwrapper'));\n\t\twrapper.tabIndex = -1;\n\n\t\tconst controls = dom.append(wrapper, $('.controls'));\n\t\tconst previous = dom.append(controls, $('.button' + ThemeIcon.asCSSSelector(parameterHintsPreviousIcon)));\n\t\tconst overloads = dom.append(controls, $('.overloads'));\n\t\tconst next = dom.append(controls, $('.button' + ThemeIcon.asCSSSelector(parameterHintsNextIcon)));\n\n\t\tthis._register(dom.addDisposableListener(previous, 'click', e => {\n\t\t\tdom.EventHelper.stop(e);\n\t\t\tthis.previous();\n\t\t}));\n\n\t\tthis._register(dom.addDisposableListener(next, 'click', e => {\n\t\t\tdom.EventHelper.stop(e);\n\t\t\tthis.next();\n\t\t}));\n\n\t\tconst body = $('.body');\n\t\tconst scrollbar = new DomScrollableElement(body, {\n\t\t\talwaysConsumeMouseWheel: true,\n\t\t});\n\t\tthis._register(scrollbar);\n\t\twrapper.appendChild(scrollbar.getDomNode());\n\n\t\tconst signature = dom.append(body, $('.signature'));\n\t\tconst docs = dom.append(body, $('.docs'));\n\n\t\telement.style.userSelect = 'text';\n\n\t\tthis.domNodes = {\n\t\t\telement,\n\t\t\tsignature,\n\t\t\toverloads,\n\t\t\tdocs,\n\t\t\tscrollbar,\n\t\t};\n\n\t\tthis.editor.addContentWidget(this);\n\t\tthis.hide();\n\n\t\tthis._register(this.editor.onDidChangeCursorSelection(e => {\n\t\t\tif (this.visible) {\n\t\t\t\tthis.editor.layoutContentWidget(this);\n\t\t\t}\n\t\t}));\n\n\t\tconst updateFont = () => {\n\t\t\tif (!this.domNodes) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst fontInfo = this.editor.getOption(EditorOption.fontInfo);\n\t\t\tthis.domNodes.element.style.fontSize = `${fontInfo.fontSize}px`;\n\t\t\tthis.domNodes.element.style.lineHeight = `${fontInfo.lineHeight / fontInfo.fontSize}`;\n\t\t};\n\n\t\tupdateFont();\n\n\t\tthis._register(Event.chain(\n\t\t\tthis.editor.onDidChangeConfiguration.bind(this.editor),\n\t\t\t$ => $.filter(e => e.hasChanged(EditorOption.fontInfo))\n\t\t)(updateFont));\n\n\t\tthis._register(this.editor.onDidLayoutChange(e => this.updateMaxHeight()));\n\t\tthis.updateMaxHeight();\n\t}\n\n\tpublic show(): void {\n\t\tif (this.visible) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (!this.domNodes) {\n\t\t\tthis.createParameterHintDOMNodes();\n\t\t}\n\n\t\tthis.keyVisible.set(true);\n\t\tthis.visible = true;\n\t\tsetTimeout(() => {\n\t\t\tthis.domNodes?.element.classList.add('visible');\n\t\t}, 100);\n\t\tthis.editor.layoutContentWidget(this);\n\t}\n\n\tpublic hide(): void {\n\t\tthis.renderDisposeables.clear();\n\n\t\tif (!this.visible) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.keyVisible.reset();\n\t\tthis.visible = false;\n\t\tthis.announcedLabel = null;\n\t\tthis.domNodes?.element.classList.remove('visible');\n\t\tthis.editor.layoutContentWidget(this);\n\t}\n\n\tgetPosition(): IContentWidgetPosition | null {\n\t\tif (this.visible) {\n\t\t\treturn {\n\t\t\t\tposition: this.editor.getPosition(),\n\t\t\t\tpreference: [ContentWidgetPositionPreference.ABOVE, ContentWidgetPositionPreference.BELOW]\n\t\t\t};\n\t\t}\n\t\treturn null;\n\t}\n\n\tpublic render(hints: languages.SignatureHelp): void {\n\t\tthis.renderDisposeables.clear();\n\n\t\tif (!this.domNodes) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst multiple = hints.signatures.length > 1;\n\t\tthis.domNodes.element.classList.toggle('multiple', multiple);\n\t\tthis.keyMultipleSignatures.set(multiple);\n\n\t\tthis.domNodes.signature.innerText = '';\n\t\tthis.domNodes.docs.innerText = '';\n\n\t\tconst signature = hints.signatures[hints.activeSignature];\n\t\tif (!signature) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst code = dom.append(this.domNodes.signature, $('.code'));\n\t\tconst fontInfo = this.editor.getOption(EditorOption.fontInfo);\n\t\tcode.style.fontSize = `${fontInfo.fontSize}px`;\n\t\tcode.style.fontFamily = fontInfo.fontFamily;\n\n\t\tconst hasParameters = signature.parameters.length > 0;\n\t\tconst activeParameterIndex = signature.activeParameter ?? hints.activeParameter;\n\n\t\tif (!hasParameters) {\n\t\t\tconst label = dom.append(code, $('span'));\n\t\t\tlabel.textContent = signature.label;\n\t\t} else {\n\t\t\tthis.renderParameters(code, signature, activeParameterIndex);\n\t\t}\n\n\t\tconst activeParameter: languages.ParameterInformation | undefined = signature.parameters[activeParameterIndex];\n\t\tif (activeParameter?.documentation) {\n\t\t\tconst documentation = $('span.documentation');\n\t\t\tif (typeof activeParameter.documentation === 'string') {\n\t\t\t\tdocumentation.textContent = activeParameter.documentation;\n\t\t\t} else {\n\t\t\t\tconst renderedContents = this.renderMarkdownDocs(activeParameter.documentation);\n\t\t\t\tdocumentation.appendChild(renderedContents.element);\n\t\t\t}\n\t\t\tdom.append(this.domNodes.docs, $('p', {}, documentation));\n\t\t}\n\n\t\tif (signature.documentation === undefined) {\n\t\t\t/** no op */\n\t\t} else if (typeof signature.documentation === 'string') {\n\t\t\tdom.append(this.domNodes.docs, $('p', {}, signature.documentation));\n\t\t} else {\n\t\t\tconst renderedContents = this.renderMarkdownDocs(signature.documentation);\n\t\t\tdom.append(this.domNodes.docs, renderedContents.element);\n\t\t}\n\n\t\tconst hasDocs = this.hasDocs(signature, activeParameter);\n\n\t\tthis.domNodes.signature.classList.toggle('has-docs', hasDocs);\n\t\tthis.domNodes.docs.classList.toggle('empty', !hasDocs);\n\n\t\tthis.domNodes.overloads.textContent =\n\t\t\tString(hints.activeSignature + 1).padStart(hints.signatures.length.toString().length, '0') + '/' + hints.signatures.length;\n\n\t\tif (activeParameter) {\n\t\t\tlet labelToAnnounce = '';\n\t\t\tconst param = signature.parameters[activeParameterIndex];\n\t\t\tif (Array.isArray(param.label)) {\n\t\t\t\tlabelToAnnounce = signature.label.substring(param.label[0], param.label[1]);\n\t\t\t} else {\n\t\t\t\tlabelToAnnounce = param.label;\n\t\t\t}\n\t\t\tif (param.documentation) {\n\t\t\t\tlabelToAnnounce += typeof param.documentation === 'string' ? `, ${param.documentation}` : `, ${param.documentation.value}`;\n\t\t\t}\n\t\t\tif (signature.documentation) {\n\t\t\t\tlabelToAnnounce += typeof signature.documentation === 'string' ? `, ${signature.documentation}` : `, ${signature.documentation.value}`;\n\t\t\t}\n\n\t\t\t// Select method gets called on every user type while parameter hints are visible.\n\t\t\t// We do not want to spam the user with same announcements, so we only announce if the current parameter changed.\n\n\t\t\tif (this.announcedLabel !== labelToAnnounce) {\n\t\t\t\taria.alert(nls.localize('hint', \"{0}, hint\", labelToAnnounce));\n\t\t\t\tthis.announcedLabel = labelToAnnounce;\n\t\t\t}\n\t\t}\n\n\t\tthis.editor.layoutContentWidget(this);\n\t\tthis.domNodes.scrollbar.scanDomNode();\n\t}\n\n\tprivate renderMarkdownDocs(markdown: IMarkdownString | undefined): IMarkdownRenderResult {\n\t\tconst stopWatch = new StopWatch();\n\t\tconst renderedContents = this.renderDisposeables.add(this.markdownRenderer.render(markdown, {\n\t\t\tasyncRenderCallback: () => {\n\t\t\t\tthis.domNodes?.scrollbar.scanDomNode();\n\t\t\t}\n\t\t}));\n\t\trenderedContents.element.classList.add('markdown-docs');\n\n\t\ttype RenderMarkdownPerformanceClassification = {\n\t\t\towner: 'donjayamanne';\n\t\t\tcomment: 'Measure the time taken to render markdown for parameter hints';\n\t\t\trenderDuration: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Time in ms to render the markdown' };\n\t\t};\n\n\t\ttype RenderMarkdownPerformanceEvent = {\n\t\t\trenderDuration: number;\n\t\t};\n\t\tconst renderDuration = stopWatch.elapsed();\n\t\tif (renderDuration > 300) {\n\t\t\tthis.telemetryService.publicLog2('parameterHints.parseMarkdown', {\n\t\t\t\trenderDuration\n\t\t\t});\n\t\t}\n\n\t\treturn renderedContents;\n\t}\n\n\tprivate hasDocs(signature: languages.SignatureInformation, activeParameter: languages.ParameterInformation | undefined): boolean {\n\t\tif (activeParameter && typeof activeParameter.documentation === 'string' && assertIsDefined(activeParameter.documentation).length > 0) {\n\t\t\treturn true;\n\t\t}\n\t\tif (activeParameter && typeof activeParameter.documentation === 'object' && assertIsDefined(activeParameter.documentation).value.length > 0) {\n\t\t\treturn true;\n\t\t}\n\t\tif (signature.documentation && typeof signature.documentation === 'string' && assertIsDefined(signature.documentation).length > 0) {\n\t\t\treturn true;\n\t\t}\n\t\tif (signature.documentation && typeof signature.documentation === 'object' && assertIsDefined(signature.documentation.value).length > 0) {\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tprivate renderParameters(parent: HTMLElement, signature: languages.SignatureInformation, activeParameterIndex: number): void {\n\t\tconst [start, end] = this.getParameterLabelOffsets(signature, activeParameterIndex);\n\n\t\tconst beforeSpan = document.createElement('span');\n\t\tbeforeSpan.textContent = signature.label.substring(0, start);\n\n\t\tconst paramSpan = document.createElement('span');\n\t\tparamSpan.textContent = signature.label.substring(start, end);\n\t\tparamSpan.className = 'parameter active';\n\n\t\tconst afterSpan = document.createElement('span');\n\t\tafterSpan.textContent = signature.label.substring(end);\n\n\t\tdom.append(parent, beforeSpan, paramSpan, afterSpan);\n\t}\n\n\tprivate getParameterLabelOffsets(signature: languages.SignatureInformation, paramIdx: number): [number, number] {\n\t\tconst param = signature.parameters[paramIdx];\n\t\tif (!param) {\n\t\t\treturn [0, 0];\n\t\t} else if (Array.isArray(param.label)) {\n\t\t\treturn param.label;\n\t\t} else if (!param.label.length) {\n\t\t\treturn [0, 0];\n\t\t} else {\n\t\t\tconst regex = new RegExp(`(\\\\W|^)${escapeRegExpCharacters(param.label)}(?=\\\\W|$)`, 'g');\n\t\t\tregex.test(signature.label);\n\t\t\tconst idx = regex.lastIndex - param.label.length;\n\t\t\treturn idx >= 0\n\t\t\t\t? [idx, regex.lastIndex]\n\t\t\t\t: [0, 0];\n\t\t}\n\t}\n\n\tnext(): void {\n\t\tthis.editor.focus();\n\t\tthis.model.next();\n\t}\n\n\tprevious(): void {\n\t\tthis.editor.focus();\n\t\tthis.model.previous();\n\t}\n\n\tgetDomNode(): HTMLElement {\n\t\tif (!this.domNodes) {\n\t\t\tthis.createParameterHintDOMNodes();\n\t\t}\n\t\treturn this.domNodes!.element;\n\t}\n\n\tgetId(): string {\n\t\treturn ParameterHintsWidget.ID;\n\t}\n\n\tprivate updateMaxHeight(): void {\n\t\tif (!this.domNodes) {\n\t\t\treturn;\n\t\t}\n\t\tconst height = Math.max(this.editor.getLayoutInfo().height / 4, 250);\n\t\tconst maxHeight = `${height}px`;\n\t\tthis.domNodes.element.style.maxHeight = maxHeight;\n\t\tconst wrapper = this.domNodes.element.getElementsByClassName('phwrapper') as HTMLCollectionOf;\n\t\tif (wrapper.length) {\n\t\t\twrapper[0].style.maxHeight = maxHeight;\n\t\t}\n\t}\n}\n\nregisterColor('editorHoverWidget.highlightForeground', { dark: listHighlightForeground, light: listHighlightForeground, hcDark: listHighlightForeground, hcLight: listHighlightForeground }, nls.localize('editorHoverWidgetHighlightForeground', 'Foreground color of the active item in the parameter hint.'));\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\nimport { KeyCode, KeyMod } from 'vs/base/common/keyCodes';\nimport { Lazy } from 'vs/base/common/lazy';\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\nimport { EditorAction, EditorCommand, EditorContributionInstantiation, registerEditorAction, registerEditorCommand, registerEditorContribution, ServicesAccessor } from 'vs/editor/browser/editorExtensions';\nimport { IEditorContribution } from 'vs/editor/common/editorCommon';\nimport { EditorContextKeys } from 'vs/editor/common/editorContextKeys';\nimport * as languages from 'vs/editor/common/languages';\nimport { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';\nimport { ParameterHintsModel, TriggerContext } from 'vs/editor/contrib/parameterHints/browser/parameterHintsModel';\nimport { Context } from 'vs/editor/contrib/parameterHints/browser/provideSignatureHelp';\nimport * as nls from 'vs/nls';\nimport { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';\nimport { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';\nimport { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';\nimport { ParameterHintsWidget } from './parameterHintsWidget';\n\nexport class ParameterHintsController extends Disposable implements IEditorContribution {\n\n\tpublic static readonly ID = 'editor.controller.parameterHints';\n\n\tpublic static get(editor: ICodeEditor): ParameterHintsController | null {\n\t\treturn editor.getContribution(ParameterHintsController.ID);\n\t}\n\n\tprivate readonly editor: ICodeEditor;\n\tprivate readonly model: ParameterHintsModel;\n\tprivate readonly widget: Lazy;\n\n\tconstructor(\n\t\teditor: ICodeEditor,\n\t\t@IInstantiationService instantiationService: IInstantiationService,\n\t\t@ILanguageFeaturesService languageFeaturesService: ILanguageFeaturesService,\n\t) {\n\t\tsuper();\n\n\t\tthis.editor = editor;\n\n\t\tthis.model = this._register(new ParameterHintsModel(editor, languageFeaturesService.signatureHelpProvider));\n\n\t\tthis._register(this.model.onChangedHints(newParameterHints => {\n\t\t\tif (newParameterHints) {\n\t\t\t\tthis.widget.value.show();\n\t\t\t\tthis.widget.value.render(newParameterHints);\n\t\t\t} else {\n\t\t\t\tthis.widget.rawValue?.hide();\n\t\t\t}\n\t\t}));\n\n\t\tthis.widget = new Lazy(() => this._register(instantiationService.createInstance(ParameterHintsWidget, this.editor, this.model)));\n\t}\n\n\tcancel(): void {\n\t\tthis.model.cancel();\n\t}\n\n\tprevious(): void {\n\t\tthis.widget.rawValue?.previous();\n\t}\n\n\tnext(): void {\n\t\tthis.widget.rawValue?.next();\n\t}\n\n\ttrigger(context: TriggerContext): void {\n\t\tthis.model.trigger(context, 0);\n\t}\n}\n\nexport class TriggerParameterHintsAction extends EditorAction {\n\n\tconstructor() {\n\t\tsuper({\n\t\t\tid: 'editor.action.triggerParameterHints',\n\t\t\tlabel: nls.localize('parameterHints.trigger.label', \"Trigger Parameter Hints\"),\n\t\t\talias: 'Trigger Parameter Hints',\n\t\t\tprecondition: EditorContextKeys.hasSignatureHelpProvider,\n\t\t\tkbOpts: {\n\t\t\t\tkbExpr: EditorContextKeys.editorTextFocus,\n\t\t\t\tprimary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.Space,\n\t\t\t\tweight: KeybindingWeight.EditorContrib\n\t\t\t}\n\t\t});\n\t}\n\n\tpublic run(accessor: ServicesAccessor, editor: ICodeEditor): void {\n\t\tconst controller = ParameterHintsController.get(editor);\n\t\tcontroller?.trigger({\n\t\t\ttriggerKind: languages.SignatureHelpTriggerKind.Invoke\n\t\t});\n\t}\n}\n\nregisterEditorContribution(ParameterHintsController.ID, ParameterHintsController, EditorContributionInstantiation.BeforeFirstInteraction);\nregisterEditorAction(TriggerParameterHintsAction);\n\nconst weight = KeybindingWeight.EditorContrib + 75;\n\nconst ParameterHintsCommand = EditorCommand.bindToContribution(ParameterHintsController.get);\n\nregisterEditorCommand(new ParameterHintsCommand({\n\tid: 'closeParameterHints',\n\tprecondition: Context.Visible,\n\thandler: x => x.cancel(),\n\tkbOpts: {\n\t\tweight: weight,\n\t\tkbExpr: EditorContextKeys.focus,\n\t\tprimary: KeyCode.Escape,\n\t\tsecondary: [KeyMod.Shift | KeyCode.Escape]\n\t}\n}));\n\nregisterEditorCommand(new ParameterHintsCommand({\n\tid: 'showPrevParameterHint',\n\tprecondition: ContextKeyExpr.and(Context.Visible, Context.MultipleSignatures),\n\thandler: x => x.previous(),\n\tkbOpts: {\n\t\tweight: weight,\n\t\tkbExpr: EditorContextKeys.focus,\n\t\tprimary: KeyCode.UpArrow,\n\t\tsecondary: [KeyMod.Alt | KeyCode.UpArrow],\n\t\tmac: { primary: KeyCode.UpArrow, secondary: [KeyMod.Alt | KeyCode.UpArrow, KeyMod.WinCtrl | KeyCode.KeyP] }\n\t}\n}));\n\nregisterEditorCommand(new ParameterHintsCommand({\n\tid: 'showNextParameterHint',\n\tprecondition: ContextKeyExpr.and(Context.Visible, Context.MultipleSignatures),\n\thandler: x => x.next(),\n\tkbOpts: {\n\t\tweight: weight,\n\t\tkbExpr: EditorContextKeys.focus,\n\t\tprimary: KeyCode.DownArrow,\n\t\tsecondary: [KeyMod.Alt | KeyCode.DownArrow],\n\t\tmac: { primary: KeyCode.DownArrow, secondary: [KeyMod.Alt | KeyCode.DownArrow, KeyMod.WinCtrl | KeyCode.KeyN] }\n\t}\n}));\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 *--------------------------------------------------------------------------------------------*/\nimport 'vs/css!./bannerController';\nimport { $, append, clearNode } from 'vs/base/browser/dom';\nimport { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';\nimport { Action } from 'vs/base/common/actions';\nimport { MarkdownString } from 'vs/base/common/htmlContent';\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport { MarkdownRenderer } from 'vs/editor/browser/widget/markdownRenderer/browser/markdownRenderer';\nimport { ICodeEditor } from 'vs/editor/browser/editorBrowser';\nimport { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';\nimport { ILinkDescriptor, Link } from 'vs/platform/opener/browser/link';\nimport { widgetClose } from 'vs/platform/theme/common/iconRegistry';\nimport { ThemeIcon } from 'vs/base/common/themables';\n\nconst BANNER_ELEMENT_HEIGHT = 26;\n\nexport class BannerController extends Disposable {\n\tprivate readonly banner: Banner;\n\n\tconstructor(\n\t\tprivate readonly _editor: ICodeEditor,\n\t\t@IInstantiationService private readonly instantiationService: IInstantiationService,\n\t) {\n\t\tsuper();\n\n\t\tthis.banner = this._register(this.instantiationService.createInstance(Banner));\n\t}\n\n\tpublic hide() {\n\t\tthis._editor.setBanner(null, 0);\n\t\tthis.banner.clear();\n\t}\n\n\tpublic show(item: IBannerItem) {\n\t\tthis.banner.show({\n\t\t\t...item,\n\t\t\tonClose: () => {\n\t\t\t\tthis.hide();\n\t\t\t\titem.onClose?.();\n\t\t\t}\n\t\t});\n\t\tthis._editor.setBanner(this.banner.element, BANNER_ELEMENT_HEIGHT);\n\t}\n}\n\n// TODO@hediet: Investigate if this can be reused by the workspace banner (bannerPart.ts).\nclass Banner extends Disposable {\n\tpublic element: HTMLElement;\n\n\tprivate readonly markdownRenderer: MarkdownRenderer;\n\n\tprivate messageActionsContainer: HTMLElement | undefined;\n\n\tprivate actionBar: ActionBar | undefined;\n\n\tconstructor(\n\t\t@IInstantiationService private readonly instantiationService: IInstantiationService,\n\t) {\n\t\tsuper();\n\n\t\tthis.markdownRenderer = this.instantiationService.createInstance(MarkdownRenderer, {});\n\n\t\tthis.element = $('div.editor-banner');\n\t\tthis.element.tabIndex = 0;\n\t}\n\n\tprivate getAriaLabel(item: IBannerItem): string | undefined {\n\t\tif (item.ariaLabel) {\n\t\t\treturn item.ariaLabel;\n\t\t}\n\t\tif (typeof item.message === 'string') {\n\t\t\treturn item.message;\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\tprivate getBannerMessage(message: MarkdownString | string): HTMLElement {\n\t\tif (typeof message === 'string') {\n\t\t\tconst element = $('span');\n\t\t\telement.innerText = message;\n\t\t\treturn element;\n\t\t}\n\n\t\treturn this.markdownRenderer.render(message).element;\n\t}\n\n\tpublic clear() {\n\t\tclearNode(this.element);\n\t}\n\n\tpublic show(item: IBannerItem) {\n\t\t// Clear previous item\n\t\tclearNode(this.element);\n\n\t\t// Banner aria label\n\t\tconst ariaLabel = this.getAriaLabel(item);\n\t\tif (ariaLabel) {\n\t\t\tthis.element.setAttribute('aria-label', ariaLabel);\n\t\t}\n\n\t\t// Icon\n\t\tconst iconContainer = append(this.element, $('div.icon-container'));\n\t\ticonContainer.setAttribute('aria-hidden', 'true');\n\n\t\tif (item.icon) {\n\t\t\ticonContainer.appendChild($(`div${ThemeIcon.asCSSSelector(item.icon)}`));\n\t\t}\n\n\t\t// Message\n\t\tconst messageContainer = append(this.element, $('div.message-container'));\n\t\tmessageContainer.setAttribute('aria-hidden', 'true');\n\t\tmessageContainer.appendChild(this.getBannerMessage(item.message));\n\n\t\t// Message Actions\n\t\tthis.messageActionsContainer = append(this.element, $('div.message-actions-container'));\n\t\tif (item.actions) {\n\t\t\tfor (const action of item.actions) {\n\t\t\t\tthis._register(this.instantiationService.createInstance(Link, this.messageActionsContainer, { ...action, tabIndex: -1 }, {}));\n\t\t\t}\n\t\t}\n\n\t\t// Action\n\t\tconst actionBarContainer = append(this.element, $('div.action-container'));\n\t\tthis.actionBar = this._register(new ActionBar(actionBarContainer));\n\t\tthis.actionBar.push(this._register(\n\t\t\tnew Action(\n\t\t\t\t'banner.close',\n\t\t\t\t'Close Banner',\n\t\t\t\tThemeIcon.asClassName(widgetClose),\n\t\t\t\ttrue,\n\t\t\t\t() => {\n\t\t\t\t\tif (typeof item.onClose === 'function') {\n\t\t\t\t\t\titem.onClose();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t)\n\t\t), { icon: true, label: false });\n\t\tthis.actionBar.setFocusable(false);\n\t}\n}\n\nexport interface IBannerItem {\n\treadonly id: string;\n\treadonly icon: ThemeIcon | undefined;\n\treadonly message: string | MarkdownString;\n\treadonly actions?: ILinkDescriptor[];\n\treadonly ariaLabel?: string;\n\treadonly onClose?: () => void;\n}\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\nimport { asCSSPropertyValue, asCSSUrl } from 'vs/base/browser/dom';\nimport { Emitter, Event } from 'vs/base/common/event';\nimport { DisposableStore, IDisposable } from 'vs/base/common/lifecycle';\nimport { ThemeIcon } from 'vs/base/common/themables';\nimport { getIconRegistry, IconContribution, IconFontDefinition } from 'vs/platform/theme/common/iconRegistry';\nimport { IProductIconTheme, IThemeService } from 'vs/platform/theme/common/themeService';\n\nexport interface IIconsStyleSheet extends IDisposable {\n\tgetCSS(): string;\n\treadonly onDidChange: Event;\n}\n\nexport function getIconsStyleSheet(themeService: IThemeService | undefined): IIconsStyleSheet {\n\tconst disposable = new DisposableStore();\n\n\tconst onDidChangeEmmiter = disposable.add(new Emitter());\n\tconst iconRegistry = getIconRegistry();\n\tdisposable.add(iconRegistry.onDidChange(() => onDidChangeEmmiter.fire()));\n\tif (themeService) {\n\t\tdisposable.add(themeService.onDidProductIconThemeChange(() => onDidChangeEmmiter.fire()));\n\t}\n\n\treturn {\n\t\tdispose: () => disposable.dispose(),\n\t\tonDidChange: onDidChangeEmmiter.event,\n\t\tgetCSS() {\n\t\t\tconst productIconTheme = themeService ? themeService.getProductIconTheme() : new UnthemedProductIconTheme();\n\t\t\tconst usedFontIds: { [id: string]: IconFontDefinition } = {};\n\n\t\t\tconst rules: string[] = [];\n\t\t\tconst rootAttribs: string[] = [];\n\t\t\tfor (const contribution of iconRegistry.getIcons()) {\n\t\t\t\tconst definition = productIconTheme.getIcon(contribution);\n\t\t\t\tif (!definition) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst fontContribution = definition.font;\n\t\t\t\tconst fontFamilyVar = `--vscode-icon-${contribution.id}-font-family`;\n\t\t\t\tconst contentVar = `--vscode-icon-${contribution.id}-content`;\n\t\t\t\tif (fontContribution) {\n\t\t\t\t\tusedFontIds[fontContribution.id] = fontContribution.definition;\n\t\t\t\t\trootAttribs.push(\n\t\t\t\t\t\t`${fontFamilyVar}: ${asCSSPropertyValue(fontContribution.id)};`,\n\t\t\t\t\t\t`${contentVar}: '${definition.fontCharacter}';`,\n\t\t\t\t\t);\n\t\t\t\t\trules.push(`.codicon-${contribution.id}:before { content: '${definition.fontCharacter}'; font-family: ${asCSSPropertyValue(fontContribution.id)}; }`);\n\t\t\t\t} else {\n\t\t\t\t\trootAttribs.push(`${contentVar}: '${definition.fontCharacter}'; ${fontFamilyVar}: 'codicon';`);\n\t\t\t\t\trules.push(`.codicon-${contribution.id}:before { content: '${definition.fontCharacter}'; }`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (const id in usedFontIds) {\n\t\t\t\tconst definition = usedFontIds[id];\n\t\t\t\tconst fontWeight = definition.weight ? `font-weight: ${definition.weight};` : '';\n\t\t\t\tconst fontStyle = definition.style ? `font-style: ${definition.style};` : '';\n\t\t\t\tconst src = definition.src.map(l => `${asCSSUrl(l.location)} format('${l.format}')`).join(', ');\n\t\t\t\trules.push(`@font-face { src: ${src}; font-family: ${asCSSPropertyValue(id)};${fontWeight}${fontStyle} font-display: block; }`);\n\t\t\t}\n\n\t\t\trules.push(`:root { ${rootAttribs.join(' ')} }`);\n\n\t\t\treturn rules.join('\\n');\n\t\t}\n\t};\n}\n\nexport class UnthemedProductIconTheme implements IProductIconTheme {\n\tgetIcon(contribution: IconContribution) {\n\t\tconst iconRegistry = getIconRegistry();\n\t\tlet definition = contribution.defaults;\n\t\twhile (ThemeIcon.isThemeIcon(definition)) {\n\t\t\tconst c = iconRegistry.getIcon(definition.id);\n\t\t\tif (!c) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tdefinition = c.defaults;\n\t\t}\n\t\treturn definition;\n\t}\n}\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 * Color scheme used by the OS and by color themes.\n */\nexport enum ColorScheme {\n\tDARK = 'dark',\n\tLIGHT = 'light',\n\tHIGH_CONTRAST_DARK = 'hcDark',\n\tHIGH_CONTRAST_LIGHT = 'hcLight'\n}\n\nexport function isHighContrast(scheme: ColorScheme): boolean {\n\treturn scheme === ColorScheme.HIGH_CONTRAST_DARK || scheme === ColorScheme.HIGH_CONTRAST_LIGHT;\n}\n\nexport function isDark(scheme: ColorScheme): boolean {\n\treturn scheme === ColorScheme.DARK || scheme === ColorScheme.HIGH_CONTRAST_DARK;\n}\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\nimport * as browser from 'vs/base/browser/browser';\nimport { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode';\nimport * as platform from 'vs/base/common/platform';\nimport { IVisibleLine } from 'vs/editor/browser/view/viewLayer';\nimport { RangeUtil } from 'vs/editor/browser/viewParts/lines/rangeUtil';\nimport { StringBuilder } from 'vs/editor/common/core/stringBuilder';\nimport { IEditorConfiguration } from 'vs/editor/common/config/editorConfiguration';\nimport { FloatHorizontalRange, VisibleRanges } from 'vs/editor/browser/view/renderingContext';\nimport { LineDecoration } from 'vs/editor/common/viewLayout/lineDecorations';\nimport { CharacterMapping, ForeignElementType, RenderLineInput, renderViewLine, LineRange, DomPosition } from 'vs/editor/common/viewLayout/viewLineRenderer';\nimport { ViewportData } from 'vs/editor/common/viewLayout/viewLinesViewportData';\nimport { InlineDecorationType } from 'vs/editor/common/viewModel';\nimport { ColorScheme, isHighContrast } from 'vs/platform/theme/common/theme';\nimport { EditorOption, EditorFontLigatures } from 'vs/editor/common/config/editorOptions';\nimport { DomReadingContext } from 'vs/editor/browser/viewParts/lines/domReadingContext';\n\nconst canUseFastRenderedViewLine = (function () {\n\tif (platform.isNative) {\n\t\t// In VSCode we know very well when the zoom level changes\n\t\treturn true;\n\t}\n\n\tif (platform.isLinux || browser.isFirefox || browser.isSafari) {\n\t\t// On Linux, it appears that zooming affects char widths (in pixels), which is unexpected.\n\t\t// --\n\t\t// Even though we read character widths correctly, having read them at a specific zoom level\n\t\t// does not mean they are the same at the current zoom level.\n\t\t// --\n\t\t// This could be improved if we ever figure out how to get an event when browsers zoom,\n\t\t// but until then we have to stick with reading client rects.\n\t\t// --\n\t\t// The same has been observed with Firefox on Windows7\n\t\t// --\n\t\t// The same has been oversved with Safari\n\t\treturn false;\n\t}\n\n\treturn true;\n})();\n\nlet monospaceAssumptionsAreValid = true;\n\nexport class ViewLineOptions {\n\tpublic readonly themeType: ColorScheme;\n\tpublic readonly renderWhitespace: 'none' | 'boundary' | 'selection' | 'trailing' | 'all';\n\tpublic readonly renderControlCharacters: boolean;\n\tpublic readonly spaceWidth: number;\n\tpublic readonly middotWidth: number;\n\tpublic readonly wsmiddotWidth: number;\n\tpublic readonly useMonospaceOptimizations: boolean;\n\tpublic readonly canUseHalfwidthRightwardsArrow: boolean;\n\tpublic readonly lineHeight: number;\n\tpublic readonly stopRenderingLineAfter: number;\n\tpublic readonly fontLigatures: string;\n\n\tconstructor(config: IEditorConfiguration, themeType: ColorScheme) {\n\t\tthis.themeType = themeType;\n\t\tconst options = config.options;\n\t\tconst fontInfo = options.get(EditorOption.fontInfo);\n\t\tconst experimentalWhitespaceRendering = options.get(EditorOption.experimentalWhitespaceRendering);\n\t\tif (experimentalWhitespaceRendering === 'off') {\n\t\t\tthis.renderWhitespace = options.get(EditorOption.renderWhitespace);\n\t\t} else {\n\t\t\t// whitespace is rendered in a different layer\n\t\t\tthis.renderWhitespace = 'none';\n\t\t}\n\t\tthis.renderControlCharacters = options.get(EditorOption.renderControlCharacters);\n\t\tthis.spaceWidth = fontInfo.spaceWidth;\n\t\tthis.middotWidth = fontInfo.middotWidth;\n\t\tthis.wsmiddotWidth = fontInfo.wsmiddotWidth;\n\t\tthis.useMonospaceOptimizations = (\n\t\t\tfontInfo.isMonospace\n\t\t\t&& !options.get(EditorOption.disableMonospaceOptimizations)\n\t\t);\n\t\tthis.canUseHalfwidthRightwardsArrow = fontInfo.canUseHalfwidthRightwardsArrow;\n\t\tthis.lineHeight = options.get(EditorOption.lineHeight);\n\t\tthis.stopRenderingLineAfter = options.get(EditorOption.stopRenderingLineAfter);\n\t\tthis.fontLigatures = options.get(EditorOption.fontLigatures);\n\t}\n\n\tpublic equals(other: ViewLineOptions): boolean {\n\t\treturn (\n\t\t\tthis.themeType === other.themeType\n\t\t\t&& this.renderWhitespace === other.renderWhitespace\n\t\t\t&& this.renderControlCharacters === other.renderControlCharacters\n\t\t\t&& this.spaceWidth === other.spaceWidth\n\t\t\t&& this.middotWidth === other.middotWidth\n\t\t\t&& this.wsmiddotWidth === other.wsmiddotWidth\n\t\t\t&& this.useMonospaceOptimizations === other.useMonospaceOptimizations\n\t\t\t&& this.canUseHalfwidthRightwardsArrow === other.canUseHalfwidthRightwardsArrow\n\t\t\t&& this.lineHeight === other.lineHeight\n\t\t\t&& this.stopRenderingLineAfter === other.stopRenderingLineAfter\n\t\t\t&& this.fontLigatures === other.fontLigatures\n\t\t);\n\t}\n}\n\nexport class ViewLine implements IVisibleLine {\n\n\tpublic static readonly CLASS_NAME = 'view-line';\n\n\tprivate _options: ViewLineOptions;\n\tprivate _isMaybeInvalid: boolean;\n\tprivate _renderedViewLine: IRenderedViewLine | null;\n\n\tconstructor(options: ViewLineOptions) {\n\t\tthis._options = options;\n\t\tthis._isMaybeInvalid = true;\n\t\tthis._renderedViewLine = null;\n\t}\n\n\t// --- begin IVisibleLineData\n\n\tpublic getDomNode(): HTMLElement | null {\n\t\tif (this._renderedViewLine && this._renderedViewLine.domNode) {\n\t\t\treturn this._renderedViewLine.domNode.domNode;\n\t\t}\n\t\treturn null;\n\t}\n\tpublic setDomNode(domNode: HTMLElement): void {\n\t\tif (this._renderedViewLine) {\n\t\t\tthis._renderedViewLine.domNode = createFastDomNode(domNode);\n\t\t} else {\n\t\t\tthrow new Error('I have no rendered view line to set the dom node to...');\n\t\t}\n\t}\n\n\tpublic onContentChanged(): void {\n\t\tthis._isMaybeInvalid = true;\n\t}\n\tpublic onTokensChanged(): void {\n\t\tthis._isMaybeInvalid = true;\n\t}\n\tpublic onDecorationsChanged(): void {\n\t\tthis._isMaybeInvalid = true;\n\t}\n\tpublic onOptionsChanged(newOptions: ViewLineOptions): void {\n\t\tthis._isMaybeInvalid = true;\n\t\tthis._options = newOptions;\n\t}\n\tpublic onSelectionChanged(): boolean {\n\t\tif (isHighContrast(this._options.themeType) || this._options.renderWhitespace === 'selection') {\n\t\t\tthis._isMaybeInvalid = true;\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\tpublic renderLine(lineNumber: number, deltaTop: number, lineHeight: number, viewportData: ViewportData, sb: StringBuilder): boolean {\n\t\tif (this._isMaybeInvalid === false) {\n\t\t\t// it appears that nothing relevant has changed\n\t\t\treturn false;\n\t\t}\n\n\t\tthis._isMaybeInvalid = false;\n\n\t\tconst lineData = viewportData.getViewLineRenderingData(lineNumber);\n\t\tconst options = this._options;\n\t\tconst actualInlineDecorations = LineDecoration.filter(lineData.inlineDecorations, lineNumber, lineData.minColumn, lineData.maxColumn);\n\n\t\t// Only send selection information when needed for rendering whitespace\n\t\tlet selectionsOnLine: LineRange[] | null = null;\n\t\tif (isHighContrast(options.themeType) || this._options.renderWhitespace === 'selection') {\n\t\t\tconst selections = viewportData.selections;\n\t\t\tfor (const selection of selections) {\n\n\t\t\t\tif (selection.endLineNumber < lineNumber || selection.startLineNumber > lineNumber) {\n\t\t\t\t\t// Selection does not intersect line\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst startColumn = (selection.startLineNumber === lineNumber ? selection.startColumn : lineData.minColumn);\n\t\t\t\tconst endColumn = (selection.endLineNumber === lineNumber ? selection.endColumn : lineData.maxColumn);\n\n\t\t\t\tif (startColumn < endColumn) {\n\t\t\t\t\tif (isHighContrast(options.themeType)) {\n\t\t\t\t\t\tactualInlineDecorations.push(new LineDecoration(startColumn, endColumn, 'inline-selected-text', InlineDecorationType.Regular));\n\t\t\t\t\t}\n\t\t\t\t\tif (this._options.renderWhitespace === 'selection') {\n\t\t\t\t\t\tif (!selectionsOnLine) {\n\t\t\t\t\t\t\tselectionsOnLine = [];\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tselectionsOnLine.push(new LineRange(startColumn - 1, endColumn - 1));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst renderLineInput = new RenderLineInput(\n\t\t\toptions.useMonospaceOptimizations,\n\t\t\toptions.canUseHalfwidthRightwardsArrow,\n\t\t\tlineData.content,\n\t\t\tlineData.continuesWithWrappedLine,\n\t\t\tlineData.isBasicASCII,\n\t\t\tlineData.containsRTL,\n\t\t\tlineData.minColumn - 1,\n\t\t\tlineData.tokens,\n\t\t\tactualInlineDecorations,\n\t\t\tlineData.tabSize,\n\t\t\tlineData.startVisibleColumn,\n\t\t\toptions.spaceWidth,\n\t\t\toptions.middotWidth,\n\t\t\toptions.wsmiddotWidth,\n\t\t\toptions.stopRenderingLineAfter,\n\t\t\toptions.renderWhitespace,\n\t\t\toptions.renderControlCharacters,\n\t\t\toptions.fontLigatures !== EditorFontLigatures.OFF,\n\t\t\tselectionsOnLine\n\t\t);\n\n\t\tif (this._renderedViewLine && this._renderedViewLine.input.equals(renderLineInput)) {\n\t\t\t// no need to do anything, we have the same render input\n\t\t\treturn false;\n\t\t}\n\n\t\tsb.appendString('
    ');\n\n\t\tconst output = renderViewLine(renderLineInput, sb);\n\n\t\tsb.appendString('
    ');\n\n\t\tlet renderedViewLine: IRenderedViewLine | null = null;\n\t\tif (monospaceAssumptionsAreValid && canUseFastRenderedViewLine && lineData.isBasicASCII && options.useMonospaceOptimizations && output.containsForeignElements === ForeignElementType.None) {\n\t\t\trenderedViewLine = new FastRenderedViewLine(\n\t\t\t\tthis._renderedViewLine ? this._renderedViewLine.domNode : null,\n\t\t\t\trenderLineInput,\n\t\t\t\toutput.characterMapping\n\t\t\t);\n\t\t}\n\n\t\tif (!renderedViewLine) {\n\t\t\trenderedViewLine = createRenderedLine(\n\t\t\t\tthis._renderedViewLine ? this._renderedViewLine.domNode : null,\n\t\t\t\trenderLineInput,\n\t\t\t\toutput.characterMapping,\n\t\t\t\toutput.containsRTL,\n\t\t\t\toutput.containsForeignElements\n\t\t\t);\n\t\t}\n\n\t\tthis._renderedViewLine = renderedViewLine;\n\n\t\treturn true;\n\t}\n\n\tpublic layoutLine(lineNumber: number, deltaTop: number, lineHeight: number): void {\n\t\tif (this._renderedViewLine && this._renderedViewLine.domNode) {\n\t\t\tthis._renderedViewLine.domNode.setTop(deltaTop);\n\t\t\tthis._renderedViewLine.domNode.setHeight(lineHeight);\n\t\t}\n\t}\n\n\t// --- end IVisibleLineData\n\n\tpublic getWidth(context: DomReadingContext | null): number {\n\t\tif (!this._renderedViewLine) {\n\t\t\treturn 0;\n\t\t}\n\t\treturn this._renderedViewLine.getWidth(context);\n\t}\n\n\tpublic getWidthIsFast(): boolean {\n\t\tif (!this._renderedViewLine) {\n\t\t\treturn true;\n\t\t}\n\t\treturn this._renderedViewLine.getWidthIsFast();\n\t}\n\n\tpublic needsMonospaceFontCheck(): boolean {\n\t\tif (!this._renderedViewLine) {\n\t\t\treturn false;\n\t\t}\n\t\treturn (this._renderedViewLine instanceof FastRenderedViewLine);\n\t}\n\n\tpublic monospaceAssumptionsAreValid(): boolean {\n\t\tif (!this._renderedViewLine) {\n\t\t\treturn monospaceAssumptionsAreValid;\n\t\t}\n\t\tif (this._renderedViewLine instanceof FastRenderedViewLine) {\n\t\t\treturn this._renderedViewLine.monospaceAssumptionsAreValid();\n\t\t}\n\t\treturn monospaceAssumptionsAreValid;\n\t}\n\n\tpublic onMonospaceAssumptionsInvalidated(): void {\n\t\tif (this._renderedViewLine && this._renderedViewLine instanceof FastRenderedViewLine) {\n\t\t\tthis._renderedViewLine = this._renderedViewLine.toSlowRenderedLine();\n\t\t}\n\t}\n\n\tpublic getVisibleRangesForRange(lineNumber: number, startColumn: number, endColumn: number, context: DomReadingContext): VisibleRanges | null {\n\t\tif (!this._renderedViewLine) {\n\t\t\treturn null;\n\t\t}\n\n\t\tstartColumn = Math.min(this._renderedViewLine.input.lineContent.length + 1, Math.max(1, startColumn));\n\t\tendColumn = Math.min(this._renderedViewLine.input.lineContent.length + 1, Math.max(1, endColumn));\n\n\t\tconst stopRenderingLineAfter = this._renderedViewLine.input.stopRenderingLineAfter;\n\n\t\tif (stopRenderingLineAfter !== -1 && startColumn > stopRenderingLineAfter + 1 && endColumn > stopRenderingLineAfter + 1) {\n\t\t\t// This range is obviously not visible\n\t\t\treturn new VisibleRanges(true, [new FloatHorizontalRange(this.getWidth(context), 0)]);\n\t\t}\n\n\t\tif (stopRenderingLineAfter !== -1 && startColumn > stopRenderingLineAfter + 1) {\n\t\t\tstartColumn = stopRenderingLineAfter + 1;\n\t\t}\n\n\t\tif (stopRenderingLineAfter !== -1 && endColumn > stopRenderingLineAfter + 1) {\n\t\t\tendColumn = stopRenderingLineAfter + 1;\n\t\t}\n\n\t\tconst horizontalRanges = this._renderedViewLine.getVisibleRangesForRange(lineNumber, startColumn, endColumn, context);\n\t\tif (horizontalRanges && horizontalRanges.length > 0) {\n\t\t\treturn new VisibleRanges(false, horizontalRanges);\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tpublic getColumnOfNodeOffset(spanNode: HTMLElement, offset: number): number {\n\t\tif (!this._renderedViewLine) {\n\t\t\treturn 1;\n\t\t}\n\t\treturn this._renderedViewLine.getColumnOfNodeOffset(spanNode, offset);\n\t}\n}\n\ninterface IRenderedViewLine {\n\tdomNode: FastDomNode | null;\n\treadonly input: RenderLineInput;\n\tgetWidth(context: DomReadingContext | null): number;\n\tgetWidthIsFast(): boolean;\n\tgetVisibleRangesForRange(lineNumber: number, startColumn: number, endColumn: number, context: DomReadingContext): FloatHorizontalRange[] | null;\n\tgetColumnOfNodeOffset(spanNode: HTMLElement, offset: number): number;\n}\n\nconst enum Constants {\n\t/**\n\t * It seems that rounding errors occur with long lines, so the purely multiplication based\n\t * method is only viable for short lines. For longer lines, we look up the real position of\n\t * every 300th character and use multiplication based on that.\n\t *\n\t * See https://github.com/microsoft/vscode/issues/33178\n\t */\n\tMaxMonospaceDistance = 300\n}\n\n/**\n * A rendered line which is guaranteed to contain only regular ASCII and is rendered with a monospace font.\n */\nclass FastRenderedViewLine implements IRenderedViewLine {\n\n\tpublic domNode: FastDomNode | null;\n\tpublic readonly input: RenderLineInput;\n\n\tprivate readonly _characterMapping: CharacterMapping;\n\tprivate readonly _charWidth: number;\n\tprivate readonly _keyColumnPixelOffsetCache: Float32Array | null;\n\tprivate _cachedWidth: number = -1;\n\n\tconstructor(domNode: FastDomNode | null, renderLineInput: RenderLineInput, characterMapping: CharacterMapping) {\n\t\tthis.domNode = domNode;\n\t\tthis.input = renderLineInput;\n\t\tconst keyColumnCount = Math.floor(renderLineInput.lineContent.length / Constants.MaxMonospaceDistance);\n\t\tif (keyColumnCount > 0) {\n\t\t\tthis._keyColumnPixelOffsetCache = new Float32Array(keyColumnCount);\n\t\t\tfor (let i = 0; i < keyColumnCount; i++) {\n\t\t\t\tthis._keyColumnPixelOffsetCache[i] = -1;\n\t\t\t}\n\t\t} else {\n\t\t\tthis._keyColumnPixelOffsetCache = null;\n\t\t}\n\n\t\tthis._characterMapping = characterMapping;\n\t\tthis._charWidth = renderLineInput.spaceWidth;\n\t}\n\n\tpublic getWidth(context: DomReadingContext | null): number {\n\t\tif (!this.domNode || this.input.lineContent.length < Constants.MaxMonospaceDistance) {\n\t\t\tconst horizontalOffset = this._characterMapping.getHorizontalOffset(this._characterMapping.length);\n\t\t\treturn Math.round(this._charWidth * horizontalOffset);\n\t\t}\n\t\tif (this._cachedWidth === -1) {\n\t\t\tthis._cachedWidth = this._getReadingTarget(this.domNode).offsetWidth;\n\t\t\tcontext?.markDidDomLayout();\n\t\t}\n\t\treturn this._cachedWidth;\n\t}\n\n\tpublic getWidthIsFast(): boolean {\n\t\treturn (this.input.lineContent.length < Constants.MaxMonospaceDistance) || this._cachedWidth !== -1;\n\t}\n\n\tpublic monospaceAssumptionsAreValid(): boolean {\n\t\tif (!this.domNode) {\n\t\t\treturn monospaceAssumptionsAreValid;\n\t\t}\n\t\tif (this.input.lineContent.length < Constants.MaxMonospaceDistance) {\n\t\t\tconst expectedWidth = this.getWidth(null);\n\t\t\tconst actualWidth = (this.domNode.domNode.firstChild).offsetWidth;\n\t\t\tif (Math.abs(expectedWidth - actualWidth) >= 2) {\n\t\t\t\t// more than 2px off\n\t\t\t\tconsole.warn(`monospace assumptions have been violated, therefore disabling monospace optimizations!`);\n\t\t\t\tmonospaceAssumptionsAreValid = false;\n\t\t\t}\n\t\t}\n\t\treturn monospaceAssumptionsAreValid;\n\t}\n\n\tpublic toSlowRenderedLine(): RenderedViewLine {\n\t\treturn createRenderedLine(this.domNode, this.input, this._characterMapping, false, ForeignElementType.None);\n\t}\n\n\tpublic getVisibleRangesForRange(lineNumber: number, startColumn: number, endColumn: number, context: DomReadingContext): FloatHorizontalRange[] | null {\n\t\tconst startPosition = this._getColumnPixelOffset(lineNumber, startColumn, context);\n\t\tconst endPosition = this._getColumnPixelOffset(lineNumber, endColumn, context);\n\t\treturn [new FloatHorizontalRange(startPosition, endPosition - startPosition)];\n\t}\n\n\tprivate _getColumnPixelOffset(lineNumber: number, column: number, context: DomReadingContext): number {\n\t\tif (column <= Constants.MaxMonospaceDistance) {\n\t\t\tconst horizontalOffset = this._characterMapping.getHorizontalOffset(column);\n\t\t\treturn this._charWidth * horizontalOffset;\n\t\t}\n\n\t\tconst keyColumnOrdinal = Math.floor((column - 1) / Constants.MaxMonospaceDistance) - 1;\n\t\tconst keyColumn = (keyColumnOrdinal + 1) * Constants.MaxMonospaceDistance + 1;\n\t\tlet keyColumnPixelOffset = -1;\n\t\tif (this._keyColumnPixelOffsetCache) {\n\t\t\tkeyColumnPixelOffset = this._keyColumnPixelOffsetCache[keyColumnOrdinal];\n\t\t\tif (keyColumnPixelOffset === -1) {\n\t\t\t\tkeyColumnPixelOffset = this._actualReadPixelOffset(lineNumber, keyColumn, context);\n\t\t\t\tthis._keyColumnPixelOffsetCache[keyColumnOrdinal] = keyColumnPixelOffset;\n\t\t\t}\n\t\t}\n\n\t\tif (keyColumnPixelOffset === -1) {\n\t\t\t// Could not read actual key column pixel offset\n\t\t\tconst horizontalOffset = this._characterMapping.getHorizontalOffset(column);\n\t\t\treturn this._charWidth * horizontalOffset;\n\t\t}\n\n\t\tconst keyColumnHorizontalOffset = this._characterMapping.getHorizontalOffset(keyColumn);\n\t\tconst horizontalOffset = this._characterMapping.getHorizontalOffset(column);\n\t\treturn keyColumnPixelOffset + this._charWidth * (horizontalOffset - keyColumnHorizontalOffset);\n\t}\n\n\tprivate _getReadingTarget(myDomNode: FastDomNode): HTMLElement {\n\t\treturn myDomNode.domNode.firstChild;\n\t}\n\n\tprivate _actualReadPixelOffset(lineNumber: number, column: number, context: DomReadingContext): number {\n\t\tif (!this.domNode) {\n\t\t\treturn -1;\n\t\t}\n\t\tconst domPosition = this._characterMapping.getDomPosition(column);\n\t\tconst r = RangeUtil.readHorizontalRanges(this._getReadingTarget(this.domNode), domPosition.partIndex, domPosition.charIndex, domPosition.partIndex, domPosition.charIndex, context);\n\t\tif (!r || r.length === 0) {\n\t\t\treturn -1;\n\t\t}\n\t\treturn r[0].left;\n\t}\n\n\tpublic getColumnOfNodeOffset(spanNode: HTMLElement, offset: number): number {\n\t\treturn getColumnOfNodeOffset(this._characterMapping, spanNode, offset);\n\t}\n}\n\n/**\n * Every time we render a line, we save what we have rendered in an instance of this class.\n */\nclass RenderedViewLine implements IRenderedViewLine {\n\n\tpublic domNode: FastDomNode | null;\n\tpublic readonly input: RenderLineInput;\n\n\tprotected readonly _characterMapping: CharacterMapping;\n\tprivate readonly _isWhitespaceOnly: boolean;\n\tprivate readonly _containsForeignElements: ForeignElementType;\n\tprivate _cachedWidth: number;\n\n\t/**\n\t * This is a map that is used only when the line is guaranteed to have no RTL text.\n\t */\n\tprivate readonly _pixelOffsetCache: Float32Array | null;\n\n\tconstructor(domNode: FastDomNode | null, renderLineInput: RenderLineInput, characterMapping: CharacterMapping, containsRTL: boolean, containsForeignElements: ForeignElementType) {\n\t\tthis.domNode = domNode;\n\t\tthis.input = renderLineInput;\n\t\tthis._characterMapping = characterMapping;\n\t\tthis._isWhitespaceOnly = /^\\s*$/.test(renderLineInput.lineContent);\n\t\tthis._containsForeignElements = containsForeignElements;\n\t\tthis._cachedWidth = -1;\n\n\t\tthis._pixelOffsetCache = null;\n\t\tif (!containsRTL || this._characterMapping.length === 0 /* the line is empty */) {\n\t\t\tthis._pixelOffsetCache = new Float32Array(Math.max(2, this._characterMapping.length + 1));\n\t\t\tfor (let column = 0, len = this._characterMapping.length; column <= len; column++) {\n\t\t\t\tthis._pixelOffsetCache[column] = -1;\n\t\t\t}\n\t\t}\n\t}\n\n\t// --- Reading from the DOM methods\n\n\tprotected _getReadingTarget(myDomNode: FastDomNode): HTMLElement {\n\t\treturn myDomNode.domNode.firstChild;\n\t}\n\n\t/**\n\t * Width of the line in pixels\n\t */\n\tpublic getWidth(context: DomReadingContext | null): number {\n\t\tif (!this.domNode) {\n\t\t\treturn 0;\n\t\t}\n\t\tif (this._cachedWidth === -1) {\n\t\t\tthis._cachedWidth = this._getReadingTarget(this.domNode).offsetWidth;\n\t\t\tcontext?.markDidDomLayout();\n\t\t}\n\t\treturn this._cachedWidth;\n\t}\n\n\tpublic getWidthIsFast(): boolean {\n\t\tif (this._cachedWidth === -1) {\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\t/**\n\t * Visible ranges for a model range\n\t */\n\tpublic getVisibleRangesForRange(lineNumber: number, startColumn: number, endColumn: number, context: DomReadingContext): FloatHorizontalRange[] | null {\n\t\tif (!this.domNode) {\n\t\t\treturn null;\n\t\t}\n\t\tif (this._pixelOffsetCache !== null) {\n\t\t\t// the text is LTR\n\t\t\tconst startOffset = this._readPixelOffset(this.domNode, lineNumber, startColumn, context);\n\t\t\tif (startOffset === -1) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst endOffset = this._readPixelOffset(this.domNode, lineNumber, endColumn, context);\n\t\t\tif (endOffset === -1) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\treturn [new FloatHorizontalRange(startOffset, endOffset - startOffset)];\n\t\t}\n\n\t\treturn this._readVisibleRangesForRange(this.domNode, lineNumber, startColumn, endColumn, context);\n\t}\n\n\tprotected _readVisibleRangesForRange(domNode: FastDomNode, lineNumber: number, startColumn: number, endColumn: number, context: DomReadingContext): FloatHorizontalRange[] | null {\n\t\tif (startColumn === endColumn) {\n\t\t\tconst pixelOffset = this._readPixelOffset(domNode, lineNumber, startColumn, context);\n\t\t\tif (pixelOffset === -1) {\n\t\t\t\treturn null;\n\t\t\t} else {\n\t\t\t\treturn [new FloatHorizontalRange(pixelOffset, 0)];\n\t\t\t}\n\t\t} else {\n\t\t\treturn this._readRawVisibleRangesForRange(domNode, startColumn, endColumn, context);\n\t\t}\n\t}\n\n\tprotected _readPixelOffset(domNode: FastDomNode, lineNumber: number, column: number, context: DomReadingContext): number {\n\t\tif (this._characterMapping.length === 0) {\n\t\t\t// This line has no content\n\t\t\tif (this._containsForeignElements === ForeignElementType.None) {\n\t\t\t\t// We can assume the line is really empty\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tif (this._containsForeignElements === ForeignElementType.After) {\n\t\t\t\t// We have foreign elements after the (empty) line\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tif (this._containsForeignElements === ForeignElementType.Before) {\n\t\t\t\t// We have foreign elements before the (empty) line\n\t\t\t\treturn this.getWidth(context);\n\t\t\t}\n\t\t\t// We have foreign elements before & after the (empty) line\n\t\t\tconst readingTarget = this._getReadingTarget(domNode);\n\t\t\tif (readingTarget.firstChild) {\n\t\t\t\tcontext.markDidDomLayout();\n\t\t\t\treturn (readingTarget.firstChild).offsetWidth;\n\t\t\t} else {\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t}\n\n\t\tif (this._pixelOffsetCache !== null) {\n\t\t\t// the text is LTR\n\n\t\t\tconst cachedPixelOffset = this._pixelOffsetCache[column];\n\t\t\tif (cachedPixelOffset !== -1) {\n\t\t\t\treturn cachedPixelOffset;\n\t\t\t}\n\n\t\t\tconst result = this._actualReadPixelOffset(domNode, lineNumber, column, context);\n\t\t\tthis._pixelOffsetCache[column] = result;\n\t\t\treturn result;\n\t\t}\n\n\t\treturn this._actualReadPixelOffset(domNode, lineNumber, column, context);\n\t}\n\n\tprivate _actualReadPixelOffset(domNode: FastDomNode, lineNumber: number, column: number, context: DomReadingContext): number {\n\t\tif (this._characterMapping.length === 0) {\n\t\t\t// This line has no content\n\t\t\tconst r = RangeUtil.readHorizontalRanges(this._getReadingTarget(domNode), 0, 0, 0, 0, context);\n\t\t\tif (!r || r.length === 0) {\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t\treturn r[0].left;\n\t\t}\n\n\t\tif (column === this._characterMapping.length && this._isWhitespaceOnly && this._containsForeignElements === ForeignElementType.None) {\n\t\t\t// This branch helps in the case of whitespace only lines which have a width set\n\t\t\treturn this.getWidth(context);\n\t\t}\n\n\t\tconst domPosition = this._characterMapping.getDomPosition(column);\n\n\t\tconst r = RangeUtil.readHorizontalRanges(this._getReadingTarget(domNode), domPosition.partIndex, domPosition.charIndex, domPosition.partIndex, domPosition.charIndex, context);\n\t\tif (!r || r.length === 0) {\n\t\t\treturn -1;\n\t\t}\n\t\tconst result = r[0].left;\n\t\tif (this.input.isBasicASCII) {\n\t\t\tconst horizontalOffset = this._characterMapping.getHorizontalOffset(column);\n\t\t\tconst expectedResult = Math.round(this.input.spaceWidth * horizontalOffset);\n\t\t\tif (Math.abs(expectedResult - result) <= 1) {\n\t\t\t\treturn expectedResult;\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tprivate _readRawVisibleRangesForRange(domNode: FastDomNode, startColumn: number, endColumn: number, context: DomReadingContext): FloatHorizontalRange[] | null {\n\n\t\tif (startColumn === 1 && endColumn === this._characterMapping.length) {\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\n\n\t\t\treturn [new FloatHorizontalRange(0, this.getWidth(context))];\n\t\t}\n\n\t\tconst startDomPosition = this._characterMapping.getDomPosition(startColumn);\n\t\tconst endDomPosition = this._characterMapping.getDomPosition(endColumn);\n\n\t\treturn RangeUtil.readHorizontalRanges(this._getReadingTarget(domNode), startDomPosition.partIndex, startDomPosition.charIndex, endDomPosition.partIndex, endDomPosition.charIndex, context);\n\t}\n\n\t/**\n\t * Returns the column for the text found at a specific offset inside a rendered dom node\n\t */\n\tpublic getColumnOfNodeOffset(spanNode: HTMLElement, offset: number): number {\n\t\treturn getColumnOfNodeOffset(this._characterMapping, spanNode, offset);\n\t}\n}\n\nclass WebKitRenderedViewLine extends RenderedViewLine {\n\tprotected override _readVisibleRangesForRange(domNode: FastDomNode, lineNumber: number, startColumn: number, endColumn: number, context: DomReadingContext): FloatHorizontalRange[] | null {\n\t\tconst output = super._readVisibleRangesForRange(domNode, lineNumber, startColumn, endColumn, context);\n\n\t\tif (!output || output.length === 0 || startColumn === endColumn || (startColumn === 1 && endColumn === this._characterMapping.length)) {\n\t\t\treturn output;\n\t\t}\n\n\t\t// WebKit is buggy and returns an expanded range (to contain words in some cases)\n\t\t// The last client rect is enlarged (I think)\n\t\tif (!this.input.containsRTL) {\n\t\t\t// This is an attempt to patch things up\n\t\t\t// Find position of last column\n\t\t\tconst endPixelOffset = this._readPixelOffset(domNode, lineNumber, endColumn, context);\n\t\t\tif (endPixelOffset !== -1) {\n\t\t\t\tconst lastRange = output[output.length - 1];\n\t\t\t\tif (lastRange.left < endPixelOffset) {\n\t\t\t\t\t// Trim down the width of the last visible range to not go after the last column's position\n\t\t\t\t\tlastRange.width = endPixelOffset - lastRange.left;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn output;\n\t}\n}\n\nconst createRenderedLine: (domNode: FastDomNode | null, renderLineInput: RenderLineInput, characterMapping: CharacterMapping, containsRTL: boolean, containsForeignElements: ForeignElementType) => RenderedViewLine = (function () {\n\tif (browser.isWebKit) {\n\t\treturn createWebKitRenderedLine;\n\t}\n\treturn createNormalRenderedLine;\n})();\n\nfunction createWebKitRenderedLine(domNode: FastDomNode | null, renderLineInput: RenderLineInput, characterMapping: CharacterMapping, containsRTL: boolean, containsForeignElements: ForeignElementType): RenderedViewLine {\n\treturn new WebKitRenderedViewLine(domNode, renderLineInput, characterMapping, containsRTL, containsForeignElements);\n}\n\nfunction createNormalRenderedLine(domNode: FastDomNode | null, renderLineInput: RenderLineInput, characterMapping: CharacterMapping, containsRTL: boolean, containsForeignElements: ForeignElementType): RenderedViewLine {\n\treturn new RenderedViewLine(domNode, renderLineInput, characterMapping, containsRTL, containsForeignElements);\n}\n\nexport function getColumnOfNodeOffset(characterMapping: CharacterMapping, spanNode: HTMLElement, offset: number): number {\n\tconst spanNodeTextContentLength = spanNode.textContent!.length;\n\n\tlet spanIndex = -1;\n\twhile (spanNode) {\n\t\tspanNode = spanNode.previousSibling;\n\t\tspanIndex++;\n\t}\n\n\treturn characterMapping.getColumn(new DomPosition(spanIndex, offset), spanNodeTextContentLength);\n}\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\nimport { IPointerHandlerHelper } from 'vs/editor/browser/controller/mouseHandler';\nimport { IMouseTargetContentEmptyData, IMouseTargetMarginData, IMouseTarget, IMouseTargetContentEmpty, IMouseTargetContentText, IMouseTargetContentWidget, IMouseTargetMargin, IMouseTargetOutsideEditor, IMouseTargetOverlayWidget, IMouseTargetScrollbar, IMouseTargetTextarea, IMouseTargetUnknown, IMouseTargetViewZone, IMouseTargetContentTextData, IMouseTargetViewZoneData, MouseTargetType } from 'vs/editor/browser/editorBrowser';\nimport { ClientCoordinates, EditorMouseEvent, EditorPagePosition, PageCoordinates, CoordinatesRelativeToEditor } from 'vs/editor/browser/editorDom';\nimport { PartFingerprint, PartFingerprints } from 'vs/editor/browser/view/viewPart';\nimport { ViewLine } from 'vs/editor/browser/viewParts/lines/viewLine';\nimport { IViewCursorRenderData } from 'vs/editor/browser/viewParts/viewCursors/viewCursor';\nimport { EditorLayoutInfo, EditorOption } from 'vs/editor/common/config/editorOptions';\nimport { Position } from 'vs/editor/common/core/position';\nimport { Range as EditorRange } from 'vs/editor/common/core/range';\nimport { HorizontalPosition } from 'vs/editor/browser/view/renderingContext';\nimport { ViewContext } from 'vs/editor/common/viewModel/viewContext';\nimport { IViewModel } from 'vs/editor/common/viewModel';\nimport { CursorColumns } from 'vs/editor/common/core/cursorColumns';\nimport * as dom from 'vs/base/browser/dom';\nimport { AtomicTabMoveOperations, Direction } from 'vs/editor/common/cursor/cursorAtomicMoveOperations';\nimport { PositionAffinity } from 'vs/editor/common/model';\nimport { InjectedText } from 'vs/editor/common/modelLineProjectionData';\nimport { Mutable } from 'vs/base/common/types';\nimport { Lazy } from 'vs/base/common/lazy';\n\nconst enum HitTestResultType {\n\tUnknown,\n\tContent,\n}\n\nclass UnknownHitTestResult {\n\treadonly type = HitTestResultType.Unknown;\n\tconstructor(\n\t\treadonly hitTarget: HTMLElement | null = null\n\t) { }\n}\n\nclass ContentHitTestResult {\n\treadonly type = HitTestResultType.Content;\n\n\tget hitTarget(): HTMLElement { return this.spanNode; }\n\n\tconstructor(\n\t\treadonly position: Position,\n\t\treadonly spanNode: HTMLElement,\n\t\treadonly injectedText: InjectedText | null,\n\t) { }\n}\n\ntype HitTestResult = UnknownHitTestResult | ContentHitTestResult;\n\nnamespace HitTestResult {\n\texport function createFromDOMInfo(ctx: HitTestContext, spanNode: HTMLElement, offset: number): HitTestResult {\n\t\tconst position = ctx.getPositionFromDOMInfo(spanNode, offset);\n\t\tif (position) {\n\t\t\treturn new ContentHitTestResult(position, spanNode, null);\n\t\t}\n\t\treturn new UnknownHitTestResult(spanNode);\n\t}\n}\n\nexport class PointerHandlerLastRenderData {\n\tconstructor(\n\t\tpublic readonly lastViewCursorsRenderData: IViewCursorRenderData[],\n\t\tpublic readonly lastTextareaPosition: Position | null\n\t) { }\n}\n\nexport class MouseTarget {\n\n\tprivate static _deduceRage(position: Position): EditorRange;\n\tprivate static _deduceRage(position: Position, range: EditorRange | null): EditorRange;\n\tprivate static _deduceRage(position: Position | null): EditorRange | null;\n\tprivate static _deduceRage(position: Position | null, range: EditorRange | null = null): EditorRange | null {\n\t\tif (!range && position) {\n\t\t\treturn new EditorRange(position.lineNumber, position.column, position.lineNumber, position.column);\n\t\t}\n\t\treturn range ?? null;\n\t}\n\tpublic static createUnknown(element: HTMLElement | null, mouseColumn: number, position: Position | null): IMouseTargetUnknown {\n\t\treturn { type: MouseTargetType.UNKNOWN, element, mouseColumn, position, range: this._deduceRage(position) };\n\t}\n\tpublic static createTextarea(element: HTMLElement | null, mouseColumn: number): IMouseTargetTextarea {\n\t\treturn { type: MouseTargetType.TEXTAREA, element, mouseColumn, position: null, range: null };\n\t}\n\tpublic static createMargin(type: MouseTargetType.GUTTER_GLYPH_MARGIN | MouseTargetType.GUTTER_LINE_NUMBERS | MouseTargetType.GUTTER_LINE_DECORATIONS, element: HTMLElement | null, mouseColumn: number, position: Position, range: EditorRange, detail: IMouseTargetMarginData): IMouseTargetMargin {\n\t\treturn { type, element, mouseColumn, position, range, detail };\n\t}\n\tpublic static createViewZone(type: MouseTargetType.GUTTER_VIEW_ZONE | MouseTargetType.CONTENT_VIEW_ZONE, element: HTMLElement | null, mouseColumn: number, position: Position, detail: IMouseTargetViewZoneData): IMouseTargetViewZone {\n\t\treturn { type, element, mouseColumn, position, range: this._deduceRage(position), detail };\n\t}\n\tpublic static createContentText(element: HTMLElement | null, mouseColumn: number, position: Position, range: EditorRange | null, detail: IMouseTargetContentTextData): IMouseTargetContentText {\n\t\treturn { type: MouseTargetType.CONTENT_TEXT, element, mouseColumn, position, range: this._deduceRage(position, range), detail };\n\t}\n\tpublic static createContentEmpty(element: HTMLElement | null, mouseColumn: number, position: Position, detail: IMouseTargetContentEmptyData): IMouseTargetContentEmpty {\n\t\treturn { type: MouseTargetType.CONTENT_EMPTY, element, mouseColumn, position, range: this._deduceRage(position), detail };\n\t}\n\tpublic static createContentWidget(element: HTMLElement | null, mouseColumn: number, detail: string): IMouseTargetContentWidget {\n\t\treturn { type: MouseTargetType.CONTENT_WIDGET, element, mouseColumn, position: null, range: null, detail };\n\t}\n\tpublic static createScrollbar(element: HTMLElement | null, mouseColumn: number, position: Position): IMouseTargetScrollbar {\n\t\treturn { type: MouseTargetType.SCROLLBAR, element, mouseColumn, position, range: this._deduceRage(position) };\n\t}\n\tpublic static createOverlayWidget(element: HTMLElement | null, mouseColumn: number, detail: string): IMouseTargetOverlayWidget {\n\t\treturn { type: MouseTargetType.OVERLAY_WIDGET, element, mouseColumn, position: null, range: null, detail };\n\t}\n\tpublic static createOutsideEditor(mouseColumn: number, position: Position, outsidePosition: 'above' | 'below' | 'left' | 'right', outsideDistance: number): IMouseTargetOutsideEditor {\n\t\treturn { type: MouseTargetType.OUTSIDE_EDITOR, element: null, mouseColumn, position, range: this._deduceRage(position), outsidePosition, outsideDistance };\n\t}\n\n\tprivate static _typeToString(type: MouseTargetType): string {\n\t\tif (type === MouseTargetType.TEXTAREA) {\n\t\t\treturn 'TEXTAREA';\n\t\t}\n\t\tif (type === MouseTargetType.GUTTER_GLYPH_MARGIN) {\n\t\t\treturn 'GUTTER_GLYPH_MARGIN';\n\t\t}\n\t\tif (type === MouseTargetType.GUTTER_LINE_NUMBERS) {\n\t\t\treturn 'GUTTER_LINE_NUMBERS';\n\t\t}\n\t\tif (type === MouseTargetType.GUTTER_LINE_DECORATIONS) {\n\t\t\treturn 'GUTTER_LINE_DECORATIONS';\n\t\t}\n\t\tif (type === MouseTargetType.GUTTER_VIEW_ZONE) {\n\t\t\treturn 'GUTTER_VIEW_ZONE';\n\t\t}\n\t\tif (type === MouseTargetType.CONTENT_TEXT) {\n\t\t\treturn 'CONTENT_TEXT';\n\t\t}\n\t\tif (type === MouseTargetType.CONTENT_EMPTY) {\n\t\t\treturn 'CONTENT_EMPTY';\n\t\t}\n\t\tif (type === MouseTargetType.CONTENT_VIEW_ZONE) {\n\t\t\treturn 'CONTENT_VIEW_ZONE';\n\t\t}\n\t\tif (type === MouseTargetType.CONTENT_WIDGET) {\n\t\t\treturn 'CONTENT_WIDGET';\n\t\t}\n\t\tif (type === MouseTargetType.OVERVIEW_RULER) {\n\t\t\treturn 'OVERVIEW_RULER';\n\t\t}\n\t\tif (type === MouseTargetType.SCROLLBAR) {\n\t\t\treturn 'SCROLLBAR';\n\t\t}\n\t\tif (type === MouseTargetType.OVERLAY_WIDGET) {\n\t\t\treturn 'OVERLAY_WIDGET';\n\t\t}\n\t\treturn 'UNKNOWN';\n\t}\n\n\tpublic static toString(target: IMouseTarget): string {\n\t\treturn this._typeToString(target.type) + ': ' + target.position + ' - ' + target.range + ' - ' + JSON.stringify((target).detail);\n\t}\n}\n\nclass ElementPath {\n\n\tpublic static isTextArea(path: Uint8Array): boolean {\n\t\treturn (\n\t\t\tpath.length === 2\n\t\t\t&& path[0] === PartFingerprint.OverflowGuard\n\t\t\t&& path[1] === PartFingerprint.TextArea\n\t\t);\n\t}\n\n\tpublic static isChildOfViewLines(path: Uint8Array): boolean {\n\t\treturn (\n\t\t\tpath.length >= 4\n\t\t\t&& path[0] === PartFingerprint.OverflowGuard\n\t\t\t&& path[3] === PartFingerprint.ViewLines\n\t\t);\n\t}\n\n\tpublic static isStrictChildOfViewLines(path: Uint8Array): boolean {\n\t\treturn (\n\t\t\tpath.length > 4\n\t\t\t&& path[0] === PartFingerprint.OverflowGuard\n\t\t\t&& path[3] === PartFingerprint.ViewLines\n\t\t);\n\t}\n\n\tpublic static isChildOfScrollableElement(path: Uint8Array): boolean {\n\t\treturn (\n\t\t\tpath.length >= 2\n\t\t\t&& path[0] === PartFingerprint.OverflowGuard\n\t\t\t&& path[1] === PartFingerprint.ScrollableElement\n\t\t);\n\t}\n\n\tpublic static isChildOfMinimap(path: Uint8Array): boolean {\n\t\treturn (\n\t\t\tpath.length >= 2\n\t\t\t&& path[0] === PartFingerprint.OverflowGuard\n\t\t\t&& path[1] === PartFingerprint.Minimap\n\t\t);\n\t}\n\n\tpublic static isChildOfContentWidgets(path: Uint8Array): boolean {\n\t\treturn (\n\t\t\tpath.length >= 4\n\t\t\t&& path[0] === PartFingerprint.OverflowGuard\n\t\t\t&& path[3] === PartFingerprint.ContentWidgets\n\t\t);\n\t}\n\n\tpublic static isChildOfOverflowGuard(path: Uint8Array): boolean {\n\t\treturn (\n\t\t\tpath.length >= 1\n\t\t\t&& path[0] === PartFingerprint.OverflowGuard\n\t\t);\n\t}\n\n\tpublic static isChildOfOverflowingContentWidgets(path: Uint8Array): boolean {\n\t\treturn (\n\t\t\tpath.length >= 1\n\t\t\t&& path[0] === PartFingerprint.OverflowingContentWidgets\n\t\t);\n\t}\n\n\tpublic static isChildOfOverlayWidgets(path: Uint8Array): boolean {\n\t\treturn (\n\t\t\tpath.length >= 2\n\t\t\t&& path[0] === PartFingerprint.OverflowGuard\n\t\t\t&& path[1] === PartFingerprint.OverlayWidgets\n\t\t);\n\t}\n\n\tpublic static isChildOfOverflowingOverlayWidgets(path: Uint8Array): boolean {\n\t\treturn (\n\t\t\tpath.length >= 1\n\t\t\t&& path[0] === PartFingerprint.OverflowingOverlayWidgets\n\t\t);\n\t}\n}\n\nexport class HitTestContext {\n\n\tpublic readonly viewModel: IViewModel;\n\tpublic readonly layoutInfo: EditorLayoutInfo;\n\tpublic readonly viewDomNode: HTMLElement;\n\tpublic readonly lineHeight: number;\n\tpublic readonly stickyTabStops: boolean;\n\tpublic readonly typicalHalfwidthCharacterWidth: number;\n\tpublic readonly lastRenderData: PointerHandlerLastRenderData;\n\n\tprivate readonly _context: ViewContext;\n\tprivate readonly _viewHelper: IPointerHandlerHelper;\n\n\tconstructor(context: ViewContext, viewHelper: IPointerHandlerHelper, lastRenderData: PointerHandlerLastRenderData) {\n\t\tthis.viewModel = context.viewModel;\n\t\tconst options = context.configuration.options;\n\t\tthis.layoutInfo = options.get(EditorOption.layoutInfo);\n\t\tthis.viewDomNode = viewHelper.viewDomNode;\n\t\tthis.lineHeight = options.get(EditorOption.lineHeight);\n\t\tthis.stickyTabStops = options.get(EditorOption.stickyTabStops);\n\t\tthis.typicalHalfwidthCharacterWidth = options.get(EditorOption.fontInfo).typicalHalfwidthCharacterWidth;\n\t\tthis.lastRenderData = lastRenderData;\n\t\tthis._context = context;\n\t\tthis._viewHelper = viewHelper;\n\t}\n\n\tpublic getZoneAtCoord(mouseVerticalOffset: number): IMouseTargetViewZoneData | null {\n\t\treturn HitTestContext.getZoneAtCoord(this._context, mouseVerticalOffset);\n\t}\n\n\tpublic static getZoneAtCoord(context: ViewContext, mouseVerticalOffset: number): IMouseTargetViewZoneData | null {\n\t\t// The target is either a view zone or the empty space after the last view-line\n\t\tconst viewZoneWhitespace = context.viewLayout.getWhitespaceAtVerticalOffset(mouseVerticalOffset);\n\n\t\tif (viewZoneWhitespace) {\n\t\t\tconst viewZoneMiddle = viewZoneWhitespace.verticalOffset + viewZoneWhitespace.height / 2;\n\t\t\tconst lineCount = context.viewModel.getLineCount();\n\t\t\tlet positionBefore: Position | null = null;\n\t\t\tlet position: Position | null;\n\t\t\tlet positionAfter: Position | null = null;\n\n\t\t\tif (viewZoneWhitespace.afterLineNumber !== lineCount) {\n\t\t\t\t// There are more lines after this view zone\n\t\t\t\tpositionAfter = new Position(viewZoneWhitespace.afterLineNumber + 1, 1);\n\t\t\t}\n\t\t\tif (viewZoneWhitespace.afterLineNumber > 0) {\n\t\t\t\t// There are more lines above this view zone\n\t\t\t\tpositionBefore = new Position(viewZoneWhitespace.afterLineNumber, context.viewModel.getLineMaxColumn(viewZoneWhitespace.afterLineNumber));\n\t\t\t}\n\n\t\t\tif (positionAfter === null) {\n\t\t\t\tposition = positionBefore;\n\t\t\t} else if (positionBefore === null) {\n\t\t\t\tposition = positionAfter;\n\t\t\t} else if (mouseVerticalOffset < viewZoneMiddle) {\n\t\t\t\tposition = positionBefore;\n\t\t\t} else {\n\t\t\t\tposition = positionAfter;\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tviewZoneId: viewZoneWhitespace.id,\n\t\t\t\tafterLineNumber: viewZoneWhitespace.afterLineNumber,\n\t\t\t\tpositionBefore: positionBefore,\n\t\t\t\tpositionAfter: positionAfter,\n\t\t\t\tposition: position!\n\t\t\t};\n\t\t}\n\t\treturn null;\n\t}\n\n\tpublic getFullLineRangeAtCoord(mouseVerticalOffset: number): { range: EditorRange; isAfterLines: boolean } {\n\t\tif (this._context.viewLayout.isAfterLines(mouseVerticalOffset)) {\n\t\t\t// Below the last line\n\t\t\tconst lineNumber = this._context.viewModel.getLineCount();\n\t\t\tconst maxLineColumn = this._context.viewModel.getLineMaxColumn(lineNumber);\n\t\t\treturn {\n\t\t\t\trange: new EditorRange(lineNumber, maxLineColumn, lineNumber, maxLineColumn),\n\t\t\t\tisAfterLines: true\n\t\t\t};\n\t\t}\n\n\t\tconst lineNumber = this._context.viewLayout.getLineNumberAtVerticalOffset(mouseVerticalOffset);\n\t\tconst maxLineColumn = this._context.viewModel.getLineMaxColumn(lineNumber);\n\t\treturn {\n\t\t\trange: new EditorRange(lineNumber, 1, lineNumber, maxLineColumn),\n\t\t\tisAfterLines: false\n\t\t};\n\t}\n\n\tpublic getLineNumberAtVerticalOffset(mouseVerticalOffset: number): number {\n\t\treturn this._context.viewLayout.getLineNumberAtVerticalOffset(mouseVerticalOffset);\n\t}\n\n\tpublic isAfterLines(mouseVerticalOffset: number): boolean {\n\t\treturn this._context.viewLayout.isAfterLines(mouseVerticalOffset);\n\t}\n\n\tpublic isInTopPadding(mouseVerticalOffset: number): boolean {\n\t\treturn this._context.viewLayout.isInTopPadding(mouseVerticalOffset);\n\t}\n\n\tpublic isInBottomPadding(mouseVerticalOffset: number): boolean {\n\t\treturn this._context.viewLayout.isInBottomPadding(mouseVerticalOffset);\n\t}\n\n\tpublic getVerticalOffsetForLineNumber(lineNumber: number): number {\n\t\treturn this._context.viewLayout.getVerticalOffsetForLineNumber(lineNumber);\n\t}\n\n\tpublic findAttribute(element: Element, attr: string): string | null {\n\t\treturn HitTestContext._findAttribute(element, attr, this._viewHelper.viewDomNode);\n\t}\n\n\tprivate static _findAttribute(element: Element, attr: string, stopAt: Element): string | null {\n\t\twhile (element && element !== element.ownerDocument.body) {\n\t\t\tif (element.hasAttribute && element.hasAttribute(attr)) {\n\t\t\t\treturn element.getAttribute(attr);\n\t\t\t}\n\t\t\tif (element === stopAt) {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\telement = element.parentNode;\n\t\t}\n\t\treturn null;\n\t}\n\n\tpublic getLineWidth(lineNumber: number): number {\n\t\treturn this._viewHelper.getLineWidth(lineNumber);\n\t}\n\n\tpublic visibleRangeForPosition(lineNumber: number, column: number): HorizontalPosition | null {\n\t\treturn this._viewHelper.visibleRangeForPosition(lineNumber, column);\n\t}\n\n\tpublic getPositionFromDOMInfo(spanNode: HTMLElement, offset: number): Position | null {\n\t\treturn this._viewHelper.getPositionFromDOMInfo(spanNode, offset);\n\t}\n\n\tpublic getCurrentScrollTop(): number {\n\t\treturn this._context.viewLayout.getCurrentScrollTop();\n\t}\n\n\tpublic getCurrentScrollLeft(): number {\n\t\treturn this._context.viewLayout.getCurrentScrollLeft();\n\t}\n}\n\nabstract class BareHitTestRequest {\n\n\tpublic readonly editorPos: EditorPagePosition;\n\tpublic readonly pos: PageCoordinates;\n\tpublic readonly relativePos: CoordinatesRelativeToEditor;\n\tpublic readonly mouseVerticalOffset: number;\n\tpublic readonly isInMarginArea: boolean;\n\tpublic readonly isInContentArea: boolean;\n\tpublic readonly mouseContentHorizontalOffset: number;\n\n\tprotected readonly mouseColumn: number;\n\n\tconstructor(ctx: HitTestContext, editorPos: EditorPagePosition, pos: PageCoordinates, relativePos: CoordinatesRelativeToEditor) {\n\t\tthis.editorPos = editorPos;\n\t\tthis.pos = pos;\n\t\tthis.relativePos = relativePos;\n\n\t\tthis.mouseVerticalOffset = Math.max(0, ctx.getCurrentScrollTop() + this.relativePos.y);\n\t\tthis.mouseContentHorizontalOffset = ctx.getCurrentScrollLeft() + this.relativePos.x - ctx.layoutInfo.contentLeft;\n\t\tthis.isInMarginArea = (this.relativePos.x < ctx.layoutInfo.contentLeft && this.relativePos.x >= ctx.layoutInfo.glyphMarginLeft);\n\t\tthis.isInContentArea = !this.isInMarginArea;\n\t\tthis.mouseColumn = Math.max(0, MouseTargetFactory._getMouseColumn(this.mouseContentHorizontalOffset, ctx.typicalHalfwidthCharacterWidth));\n\t}\n}\n\nclass HitTestRequest extends BareHitTestRequest {\n\tprivate readonly _ctx: HitTestContext;\n\tprivate readonly _eventTarget: HTMLElement | null;\n\tpublic readonly hitTestResult = new Lazy(() => MouseTargetFactory.doHitTest(this._ctx, this));\n\tprivate _useHitTestTarget: boolean;\n\tprivate _targetPathCacheElement: HTMLElement | null = null;\n\tprivate _targetPathCacheValue: Uint8Array = new Uint8Array(0);\n\n\tpublic get target(): HTMLElement | null {\n\t\tif (this._useHitTestTarget) {\n\t\t\treturn this.hitTestResult.value.hitTarget;\n\t\t}\n\t\treturn this._eventTarget;\n\t}\n\n\tpublic get targetPath(): Uint8Array {\n\t\tif (this._targetPathCacheElement !== this.target) {\n\t\t\tthis._targetPathCacheElement = this.target;\n\t\t\tthis._targetPathCacheValue = PartFingerprints.collect(this.target, this._ctx.viewDomNode);\n\t\t}\n\t\treturn this._targetPathCacheValue;\n\t}\n\n\tconstructor(ctx: HitTestContext, editorPos: EditorPagePosition, pos: PageCoordinates, relativePos: CoordinatesRelativeToEditor, eventTarget: HTMLElement | null) {\n\t\tsuper(ctx, editorPos, pos, relativePos);\n\t\tthis._ctx = ctx;\n\t\tthis._eventTarget = eventTarget;\n\n\t\t// If no event target is passed in, we will use the hit test target\n\t\tconst hasEventTarget = Boolean(this._eventTarget);\n\t\tthis._useHitTestTarget = !hasEventTarget;\n\t}\n\n\tpublic override toString(): string {\n\t\treturn `pos(${this.pos.x},${this.pos.y}), editorPos(${this.editorPos.x},${this.editorPos.y}), relativePos(${this.relativePos.x},${this.relativePos.y}), mouseVerticalOffset: ${this.mouseVerticalOffset}, mouseContentHorizontalOffset: ${this.mouseContentHorizontalOffset}\\n\\ttarget: ${this.target ? (this.target).outerHTML : null}`;\n\t}\n\n\tpublic get wouldBenefitFromHitTestTargetSwitch(): boolean {\n\t\treturn (\n\t\t\t!this._useHitTestTarget\n\t\t\t&& this.hitTestResult.value.hitTarget !== null\n\t\t\t&& this.target !== this.hitTestResult.value.hitTarget\n\t\t);\n\t}\n\n\tpublic switchToHitTestTarget(): void {\n\t\tthis._useHitTestTarget = true;\n\t}\n\n\tprivate _getMouseColumn(position: Position | null = null): number {\n\t\tif (position && position.column < this._ctx.viewModel.getLineMaxColumn(position.lineNumber)) {\n\t\t\t// Most likely, the line contains foreign decorations...\n\t\t\treturn CursorColumns.visibleColumnFromColumn(this._ctx.viewModel.getLineContent(position.lineNumber), position.column, this._ctx.viewModel.model.getOptions().tabSize) + 1;\n\t\t}\n\t\treturn this.mouseColumn;\n\t}\n\n\tpublic fulfillUnknown(position: Position | null = null): IMouseTargetUnknown {\n\t\treturn MouseTarget.createUnknown(this.target, this._getMouseColumn(position), position);\n\t}\n\tpublic fulfillTextarea(): IMouseTargetTextarea {\n\t\treturn MouseTarget.createTextarea(this.target, this._getMouseColumn());\n\t}\n\tpublic fulfillMargin(type: MouseTargetType.GUTTER_GLYPH_MARGIN | MouseTargetType.GUTTER_LINE_NUMBERS | MouseTargetType.GUTTER_LINE_DECORATIONS, position: Position, range: EditorRange, detail: IMouseTargetMarginData): IMouseTargetMargin {\n\t\treturn MouseTarget.createMargin(type, this.target, this._getMouseColumn(position), position, range, detail);\n\t}\n\tpublic fulfillViewZone(type: MouseTargetType.GUTTER_VIEW_ZONE | MouseTargetType.CONTENT_VIEW_ZONE, position: Position, detail: IMouseTargetViewZoneData): IMouseTargetViewZone {\n\t\treturn MouseTarget.createViewZone(type, this.target, this._getMouseColumn(position), position, detail);\n\t}\n\tpublic fulfillContentText(position: Position, range: EditorRange | null, detail: IMouseTargetContentTextData): IMouseTargetContentText {\n\t\treturn MouseTarget.createContentText(this.target, this._getMouseColumn(position), position, range, detail);\n\t}\n\tpublic fulfillContentEmpty(position: Position, detail: IMouseTargetContentEmptyData): IMouseTargetContentEmpty {\n\t\treturn MouseTarget.createContentEmpty(this.target, this._getMouseColumn(position), position, detail);\n\t}\n\tpublic fulfillContentWidget(detail: string): IMouseTargetContentWidget {\n\t\treturn MouseTarget.createContentWidget(this.target, this._getMouseColumn(), detail);\n\t}\n\tpublic fulfillScrollbar(position: Position): IMouseTargetScrollbar {\n\t\treturn MouseTarget.createScrollbar(this.target, this._getMouseColumn(position), position);\n\t}\n\tpublic fulfillOverlayWidget(detail: string): IMouseTargetOverlayWidget {\n\t\treturn MouseTarget.createOverlayWidget(this.target, this._getMouseColumn(), detail);\n\t}\n}\n\ninterface ResolvedHitTestRequest extends HitTestRequest {\n\treadonly target: HTMLElement;\n}\n\nconst EMPTY_CONTENT_AFTER_LINES: IMouseTargetContentEmptyData = { isAfterLines: true };\n\nfunction createEmptyContentDataInLines(horizontalDistanceToText: number): IMouseTargetContentEmptyData {\n\treturn {\n\t\tisAfterLines: false,\n\t\thorizontalDistanceToText: horizontalDistanceToText\n\t};\n}\n\nexport class MouseTargetFactory {\n\n\tprivate readonly _context: ViewContext;\n\tprivate readonly _viewHelper: IPointerHandlerHelper;\n\n\tconstructor(context: ViewContext, viewHelper: IPointerHandlerHelper) {\n\t\tthis._context = context;\n\t\tthis._viewHelper = viewHelper;\n\t}\n\n\tpublic mouseTargetIsWidget(e: EditorMouseEvent): boolean {\n\t\tconst t = e.target;\n\t\tconst path = PartFingerprints.collect(t, this._viewHelper.viewDomNode);\n\n\t\t// Is it a content widget?\n\t\tif (ElementPath.isChildOfContentWidgets(path) || ElementPath.isChildOfOverflowingContentWidgets(path)) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Is it an overlay widget?\n\t\tif (ElementPath.isChildOfOverlayWidgets(path) || ElementPath.isChildOfOverflowingOverlayWidgets(path)) {\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tpublic createMouseTarget(lastRenderData: PointerHandlerLastRenderData, editorPos: EditorPagePosition, pos: PageCoordinates, relativePos: CoordinatesRelativeToEditor, target: HTMLElement | null): IMouseTarget {\n\t\tconst ctx = new HitTestContext(this._context, this._viewHelper, lastRenderData);\n\t\tconst request = new HitTestRequest(ctx, editorPos, pos, relativePos, target);\n\t\ttry {\n\t\t\tconst r = MouseTargetFactory._createMouseTarget(ctx, request);\n\n\t\t\tif (r.type === MouseTargetType.CONTENT_TEXT) {\n\t\t\t\t// Snap to the nearest soft tab boundary if atomic soft tabs are enabled.\n\t\t\t\tif (ctx.stickyTabStops && r.position !== null) {\n\t\t\t\t\tconst position = MouseTargetFactory._snapToSoftTabBoundary(r.position, ctx.viewModel);\n\t\t\t\t\tconst range = EditorRange.fromPositions(position, position).plusRange(r.range);\n\t\t\t\t\treturn request.fulfillContentText(position, range, r.detail);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// console.log(MouseTarget.toString(r));\n\t\t\treturn r;\n\t\t} catch (err) {\n\t\t\t// console.log(err);\n\t\t\treturn request.fulfillUnknown();\n\t\t}\n\t}\n\n\tprivate static _createMouseTarget(ctx: HitTestContext, request: HitTestRequest): IMouseTarget {\n\n\t\t// console.log(`${domHitTestExecuted ? '=>' : ''}CAME IN REQUEST: ${request}`);\n\n\t\tif (request.target === null) {\n\t\t\t// No target\n\t\t\treturn request.fulfillUnknown();\n\t\t}\n\n\t\t// we know for a fact that request.target is not null\n\t\tconst resolvedRequest = request;\n\n\t\tlet result: IMouseTarget | null = null;\n\n\t\tif (!ElementPath.isChildOfOverflowGuard(request.targetPath) && !ElementPath.isChildOfOverflowingContentWidgets(request.targetPath) && !ElementPath.isChildOfOverflowingOverlayWidgets(request.targetPath)) {\n\t\t\t// We only render dom nodes inside the overflow guard or in the overflowing content widgets\n\t\t\tresult = result || request.fulfillUnknown();\n\t\t}\n\n\t\tresult = result || MouseTargetFactory._hitTestContentWidget(ctx, resolvedRequest);\n\t\tresult = result || MouseTargetFactory._hitTestOverlayWidget(ctx, resolvedRequest);\n\t\tresult = result || MouseTargetFactory._hitTestMinimap(ctx, resolvedRequest);\n\t\tresult = result || MouseTargetFactory._hitTestScrollbarSlider(ctx, resolvedRequest);\n\t\tresult = result || MouseTargetFactory._hitTestViewZone(ctx, resolvedRequest);\n\t\tresult = result || MouseTargetFactory._hitTestMargin(ctx, resolvedRequest);\n\t\tresult = result || MouseTargetFactory._hitTestViewCursor(ctx, resolvedRequest);\n\t\tresult = result || MouseTargetFactory._hitTestTextArea(ctx, resolvedRequest);\n\t\tresult = result || MouseTargetFactory._hitTestViewLines(ctx, resolvedRequest);\n\t\tresult = result || MouseTargetFactory._hitTestScrollbar(ctx, resolvedRequest);\n\n\t\treturn (result || request.fulfillUnknown());\n\t}\n\n\tprivate static _hitTestContentWidget(ctx: HitTestContext, request: ResolvedHitTestRequest): IMouseTarget | null {\n\t\t// Is it a content widget?\n\t\tif (ElementPath.isChildOfContentWidgets(request.targetPath) || ElementPath.isChildOfOverflowingContentWidgets(request.targetPath)) {\n\t\t\tconst widgetId = ctx.findAttribute(request.target, 'widgetId');\n\t\t\tif (widgetId) {\n\t\t\t\treturn request.fulfillContentWidget(widgetId);\n\t\t\t} else {\n\t\t\t\treturn request.fulfillUnknown();\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate static _hitTestOverlayWidget(ctx: HitTestContext, request: ResolvedHitTestRequest): IMouseTarget | null {\n\t\t// Is it an overlay widget?\n\t\tif (ElementPath.isChildOfOverlayWidgets(request.targetPath) || ElementPath.isChildOfOverflowingOverlayWidgets(request.targetPath)) {\n\t\t\tconst widgetId = ctx.findAttribute(request.target, 'widgetId');\n\t\t\tif (widgetId) {\n\t\t\t\treturn request.fulfillOverlayWidget(widgetId);\n\t\t\t} else {\n\t\t\t\treturn request.fulfillUnknown();\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate static _hitTestViewCursor(ctx: HitTestContext, request: ResolvedHitTestRequest): IMouseTarget | null {\n\n\t\tif (request.target) {\n\t\t\t// Check if we've hit a painted cursor\n\t\t\tconst lastViewCursorsRenderData = ctx.lastRenderData.lastViewCursorsRenderData;\n\n\t\t\tfor (const d of lastViewCursorsRenderData) {\n\n\t\t\t\tif (request.target === d.domNode) {\n\t\t\t\t\treturn request.fulfillContentText(d.position, null, { mightBeForeignElement: false, injectedText: null });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (request.isInContentArea) {\n\t\t\t// Edge has a bug when hit-testing the exact position of a cursor,\n\t\t\t// instead of returning the correct dom node, it returns the\n\t\t\t// first or last rendered view line dom node, therefore help it out\n\t\t\t// and first check if we are on top of a cursor\n\n\t\t\tconst lastViewCursorsRenderData = ctx.lastRenderData.lastViewCursorsRenderData;\n\t\t\tconst mouseContentHorizontalOffset = request.mouseContentHorizontalOffset;\n\t\t\tconst mouseVerticalOffset = request.mouseVerticalOffset;\n\n\t\t\tfor (const d of lastViewCursorsRenderData) {\n\n\t\t\t\tif (mouseContentHorizontalOffset < d.contentLeft) {\n\t\t\t\t\t// mouse position is to the left of the cursor\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (mouseContentHorizontalOffset > d.contentLeft + d.width) {\n\t\t\t\t\t// mouse position is to the right of the cursor\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst cursorVerticalOffset = ctx.getVerticalOffsetForLineNumber(d.position.lineNumber);\n\n\t\t\t\tif (\n\t\t\t\t\tcursorVerticalOffset <= mouseVerticalOffset\n\t\t\t\t\t&& mouseVerticalOffset <= cursorVerticalOffset + d.height\n\t\t\t\t) {\n\t\t\t\t\treturn request.fulfillContentText(d.position, null, { mightBeForeignElement: false, injectedText: null });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tprivate static _hitTestViewZone(ctx: HitTestContext, request: ResolvedHitTestRequest): IMouseTarget | null {\n\t\tconst viewZoneData = ctx.getZoneAtCoord(request.mouseVerticalOffset);\n\t\tif (viewZoneData) {\n\t\t\tconst mouseTargetType = (request.isInContentArea ? MouseTargetType.CONTENT_VIEW_ZONE : MouseTargetType.GUTTER_VIEW_ZONE);\n\t\t\treturn request.fulfillViewZone(mouseTargetType, viewZoneData.position, viewZoneData);\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tprivate static _hitTestTextArea(ctx: HitTestContext, request: ResolvedHitTestRequest): IMouseTarget | null {\n\t\t// Is it the textarea?\n\t\tif (ElementPath.isTextArea(request.targetPath)) {\n\t\t\tif (ctx.lastRenderData.lastTextareaPosition) {\n\t\t\t\treturn request.fulfillContentText(ctx.lastRenderData.lastTextareaPosition, null, { mightBeForeignElement: false, injectedText: null });\n\t\t\t}\n\t\t\treturn request.fulfillTextarea();\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate static _hitTestMargin(ctx: HitTestContext, request: ResolvedHitTestRequest): IMouseTarget | null {\n\t\tif (request.isInMarginArea) {\n\t\t\tconst res = ctx.getFullLineRangeAtCoord(request.mouseVerticalOffset);\n\t\t\tconst pos = res.range.getStartPosition();\n\t\t\tlet offset = Math.abs(request.relativePos.x);\n\t\t\tconst detail: Mutable = {\n\t\t\t\tisAfterLines: res.isAfterLines,\n\t\t\t\tglyphMarginLeft: ctx.layoutInfo.glyphMarginLeft,\n\t\t\t\tglyphMarginWidth: ctx.layoutInfo.glyphMarginWidth,\n\t\t\t\tlineNumbersWidth: ctx.layoutInfo.lineNumbersWidth,\n\t\t\t\toffsetX: offset\n\t\t\t};\n\n\t\t\toffset -= ctx.layoutInfo.glyphMarginLeft;\n\n\t\t\tif (offset <= ctx.layoutInfo.glyphMarginWidth) {\n\t\t\t\t// On the glyph margin\n\t\t\t\tconst modelCoordinate = ctx.viewModel.coordinatesConverter.convertViewPositionToModelPosition(res.range.getStartPosition());\n\t\t\t\tconst lanes = ctx.viewModel.glyphLanes.getLanesAtLine(modelCoordinate.lineNumber);\n\t\t\t\tdetail.glyphMarginLane = lanes[Math.floor(offset / ctx.lineHeight)];\n\t\t\t\treturn request.fulfillMargin(MouseTargetType.GUTTER_GLYPH_MARGIN, pos, res.range, detail);\n\t\t\t}\n\t\t\toffset -= ctx.layoutInfo.glyphMarginWidth;\n\n\t\t\tif (offset <= ctx.layoutInfo.lineNumbersWidth) {\n\t\t\t\t// On the line numbers\n\t\t\t\treturn request.fulfillMargin(MouseTargetType.GUTTER_LINE_NUMBERS, pos, res.range, detail);\n\t\t\t}\n\t\t\toffset -= ctx.layoutInfo.lineNumbersWidth;\n\n\t\t\t// On the line decorations\n\t\t\treturn request.fulfillMargin(MouseTargetType.GUTTER_LINE_DECORATIONS, pos, res.range, detail);\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate static _hitTestViewLines(ctx: HitTestContext, request: ResolvedHitTestRequest): IMouseTarget | null {\n\t\tif (!ElementPath.isChildOfViewLines(request.targetPath)) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif (ctx.isInTopPadding(request.mouseVerticalOffset)) {\n\t\t\treturn request.fulfillContentEmpty(new Position(1, 1), EMPTY_CONTENT_AFTER_LINES);\n\t\t}\n\n\t\t// Check if it is below any lines and any view zones\n\t\tif (ctx.isAfterLines(request.mouseVerticalOffset) || ctx.isInBottomPadding(request.mouseVerticalOffset)) {\n\t\t\t// This most likely indicates it happened after the last view-line\n\t\t\tconst lineCount = ctx.viewModel.getLineCount();\n\t\t\tconst maxLineColumn = ctx.viewModel.getLineMaxColumn(lineCount);\n\t\t\treturn request.fulfillContentEmpty(new Position(lineCount, maxLineColumn), EMPTY_CONTENT_AFTER_LINES);\n\t\t}\n\n\t\t// Check if we are hitting a view-line (can happen in the case of inline decorations on empty lines)\n\t\t// See https://github.com/microsoft/vscode/issues/46942\n\t\tif (ElementPath.isStrictChildOfViewLines(request.targetPath)) {\n\t\t\tconst lineNumber = ctx.getLineNumberAtVerticalOffset(request.mouseVerticalOffset);\n\t\t\tif (ctx.viewModel.getLineLength(lineNumber) === 0) {\n\t\t\t\tconst lineWidth = ctx.getLineWidth(lineNumber);\n\t\t\t\tconst detail = createEmptyContentDataInLines(request.mouseContentHorizontalOffset - lineWidth);\n\t\t\t\treturn request.fulfillContentEmpty(new Position(lineNumber, 1), detail);\n\t\t\t}\n\n\t\t\tconst lineWidth = ctx.getLineWidth(lineNumber);\n\t\t\tif (request.mouseContentHorizontalOffset >= lineWidth) {\n\t\t\t\t// TODO: This is wrong for RTL\n\t\t\t\tconst detail = createEmptyContentDataInLines(request.mouseContentHorizontalOffset - lineWidth);\n\t\t\t\tconst pos = new Position(lineNumber, ctx.viewModel.getLineMaxColumn(lineNumber));\n\t\t\t\treturn request.fulfillContentEmpty(pos, detail);\n\t\t\t}\n\t\t}\n\n\t\t// Do the hit test (if not already done)\n\t\tconst hitTestResult = request.hitTestResult.value;\n\n\t\tif (hitTestResult.type === HitTestResultType.Content) {\n\t\t\treturn MouseTargetFactory.createMouseTargetFromHitTestPosition(ctx, request, hitTestResult.spanNode, hitTestResult.position, hitTestResult.injectedText);\n\t\t}\n\n\t\t// We didn't hit content...\n\t\tif (request.wouldBenefitFromHitTestTargetSwitch) {\n\t\t\t// We actually hit something different... Give it one last change by trying again with this new target\n\t\t\trequest.switchToHitTestTarget();\n\t\t\treturn this._createMouseTarget(ctx, request);\n\t\t}\n\n\t\t// We have tried everything...\n\t\treturn request.fulfillUnknown();\n\t}\n\n\tprivate static _hitTestMinimap(ctx: HitTestContext, request: ResolvedHitTestRequest): IMouseTarget | null {\n\t\tif (ElementPath.isChildOfMinimap(request.targetPath)) {\n\t\t\tconst possibleLineNumber = ctx.getLineNumberAtVerticalOffset(request.mouseVerticalOffset);\n\t\t\tconst maxColumn = ctx.viewModel.getLineMaxColumn(possibleLineNumber);\n\t\t\treturn request.fulfillScrollbar(new Position(possibleLineNumber, maxColumn));\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate static _hitTestScrollbarSlider(ctx: HitTestContext, request: ResolvedHitTestRequest): IMouseTarget | null {\n\t\tif (ElementPath.isChildOfScrollableElement(request.targetPath)) {\n\t\t\tif (request.target && request.target.nodeType === 1) {\n\t\t\t\tconst className = request.target.className;\n\t\t\t\tif (className && /\\b(slider|scrollbar)\\b/.test(className)) {\n\t\t\t\t\tconst possibleLineNumber = ctx.getLineNumberAtVerticalOffset(request.mouseVerticalOffset);\n\t\t\t\t\tconst maxColumn = ctx.viewModel.getLineMaxColumn(possibleLineNumber);\n\t\t\t\t\treturn request.fulfillScrollbar(new Position(possibleLineNumber, maxColumn));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate static _hitTestScrollbar(ctx: HitTestContext, request: ResolvedHitTestRequest): IMouseTarget | null {\n\t\t// Is it the overview ruler?\n\t\t// Is it a child of the scrollable element?\n\t\tif (ElementPath.isChildOfScrollableElement(request.targetPath)) {\n\t\t\tconst possibleLineNumber = ctx.getLineNumberAtVerticalOffset(request.mouseVerticalOffset);\n\t\t\tconst maxColumn = ctx.viewModel.getLineMaxColumn(possibleLineNumber);\n\t\t\treturn request.fulfillScrollbar(new Position(possibleLineNumber, maxColumn));\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tpublic getMouseColumn(relativePos: CoordinatesRelativeToEditor): number {\n\t\tconst options = this._context.configuration.options;\n\t\tconst layoutInfo = options.get(EditorOption.layoutInfo);\n\t\tconst mouseContentHorizontalOffset = this._context.viewLayout.getCurrentScrollLeft() + relativePos.x - layoutInfo.contentLeft;\n\t\treturn MouseTargetFactory._getMouseColumn(mouseContentHorizontalOffset, options.get(EditorOption.fontInfo).typicalHalfwidthCharacterWidth);\n\t}\n\n\tpublic static _getMouseColumn(mouseContentHorizontalOffset: number, typicalHalfwidthCharacterWidth: number): number {\n\t\tif (mouseContentHorizontalOffset < 0) {\n\t\t\treturn 1;\n\t\t}\n\t\tconst chars = Math.round(mouseContentHorizontalOffset / typicalHalfwidthCharacterWidth);\n\t\treturn (chars + 1);\n\t}\n\n\tprivate static createMouseTargetFromHitTestPosition(ctx: HitTestContext, request: HitTestRequest, spanNode: HTMLElement, pos: Position, injectedText: InjectedText | null): IMouseTarget {\n\t\tconst lineNumber = pos.lineNumber;\n\t\tconst column = pos.column;\n\n\t\tconst lineWidth = ctx.getLineWidth(lineNumber);\n\n\t\tif (request.mouseContentHorizontalOffset > lineWidth) {\n\t\t\tconst detail = createEmptyContentDataInLines(request.mouseContentHorizontalOffset - lineWidth);\n\t\t\treturn request.fulfillContentEmpty(pos, detail);\n\t\t}\n\n\t\tconst visibleRange = ctx.visibleRangeForPosition(lineNumber, column);\n\n\t\tif (!visibleRange) {\n\t\t\treturn request.fulfillUnknown(pos);\n\t\t}\n\n\t\tconst columnHorizontalOffset = visibleRange.left;\n\n\t\tif (Math.abs(request.mouseContentHorizontalOffset - columnHorizontalOffset) < 1) {\n\t\t\treturn request.fulfillContentText(pos, null, { mightBeForeignElement: !!injectedText, injectedText });\n\t\t}\n\n\t\t// Let's define a, b, c and check if the offset is in between them...\n\t\tinterface OffsetColumn { offset: number; column: number }\n\n\t\tconst points: OffsetColumn[] = [];\n\t\tpoints.push({ offset: visibleRange.left, column: column });\n\t\tif (column > 1) {\n\t\t\tconst visibleRange = ctx.visibleRangeForPosition(lineNumber, column - 1);\n\t\t\tif (visibleRange) {\n\t\t\t\tpoints.push({ offset: visibleRange.left, column: column - 1 });\n\t\t\t}\n\t\t}\n\t\tconst lineMaxColumn = ctx.viewModel.getLineMaxColumn(lineNumber);\n\t\tif (column < lineMaxColumn) {\n\t\t\tconst visibleRange = ctx.visibleRangeForPosition(lineNumber, column + 1);\n\t\t\tif (visibleRange) {\n\t\t\t\tpoints.push({ offset: visibleRange.left, column: column + 1 });\n\t\t\t}\n\t\t}\n\n\t\tpoints.sort((a, b) => a.offset - b.offset);\n\n\t\tconst mouseCoordinates = request.pos.toClientCoordinates(dom.getWindow(ctx.viewDomNode));\n\t\tconst spanNodeClientRect = spanNode.getBoundingClientRect();\n\t\tconst mouseIsOverSpanNode = (spanNodeClientRect.left <= mouseCoordinates.clientX && mouseCoordinates.clientX <= spanNodeClientRect.right);\n\n\t\tlet rng: EditorRange | null = null;\n\n\t\tfor (let i = 1; i < points.length; i++) {\n\t\t\tconst prev = points[i - 1];\n\t\t\tconst curr = points[i];\n\t\t\tif (prev.offset <= request.mouseContentHorizontalOffset && request.mouseContentHorizontalOffset <= curr.offset) {\n\t\t\t\trng = new EditorRange(lineNumber, prev.column, lineNumber, curr.column);\n\n\t\t\t\t// See https://github.com/microsoft/vscode/issues/152819\n\t\t\t\t// Due to the use of zwj, the browser's hit test result is skewed towards the left\n\t\t\t\t// Here we try to correct that if the mouse horizontal offset is closer to the right than the left\n\n\t\t\t\tconst prevDelta = Math.abs(prev.offset - request.mouseContentHorizontalOffset);\n\t\t\t\tconst nextDelta = Math.abs(curr.offset - request.mouseContentHorizontalOffset);\n\n\t\t\t\tpos = (\n\t\t\t\t\tprevDelta < nextDelta\n\t\t\t\t\t\t? new Position(lineNumber, prev.column)\n\t\t\t\t\t\t: new Position(lineNumber, curr.column)\n\t\t\t\t);\n\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn request.fulfillContentText(pos, rng, { mightBeForeignElement: !mouseIsOverSpanNode || !!injectedText, injectedText });\n\t}\n\n\t/**\n\t * Most probably WebKit browsers and Edge\n\t */\n\tprivate static _doHitTestWithCaretRangeFromPoint(ctx: HitTestContext, request: BareHitTestRequest): HitTestResult {\n\n\t\t// In Chrome, especially on Linux it is possible to click between lines,\n\t\t// so try to adjust the `hity` below so that it lands in the center of a line\n\t\tconst lineNumber = ctx.getLineNumberAtVerticalOffset(request.mouseVerticalOffset);\n\t\tconst lineStartVerticalOffset = ctx.getVerticalOffsetForLineNumber(lineNumber);\n\t\tconst lineEndVerticalOffset = lineStartVerticalOffset + ctx.lineHeight;\n\n\t\tconst isBelowLastLine = (\n\t\t\tlineNumber === ctx.viewModel.getLineCount()\n\t\t\t&& request.mouseVerticalOffset > lineEndVerticalOffset\n\t\t);\n\n\t\tif (!isBelowLastLine) {\n\t\t\tconst lineCenteredVerticalOffset = Math.floor((lineStartVerticalOffset + lineEndVerticalOffset) / 2);\n\t\t\tlet adjustedPageY = request.pos.y + (lineCenteredVerticalOffset - request.mouseVerticalOffset);\n\n\t\t\tif (adjustedPageY <= request.editorPos.y) {\n\t\t\t\tadjustedPageY = request.editorPos.y + 1;\n\t\t\t}\n\t\t\tif (adjustedPageY >= request.editorPos.y + request.editorPos.height) {\n\t\t\t\tadjustedPageY = request.editorPos.y + request.editorPos.height - 1;\n\t\t\t}\n\n\t\t\tconst adjustedPage = new PageCoordinates(request.pos.x, adjustedPageY);\n\n\t\t\tconst r = this._actualDoHitTestWithCaretRangeFromPoint(ctx, adjustedPage.toClientCoordinates(dom.getWindow(ctx.viewDomNode)));\n\t\t\tif (r.type === HitTestResultType.Content) {\n\t\t\t\treturn r;\n\t\t\t}\n\t\t}\n\n\t\t// Also try to hit test without the adjustment (for the edge cases that we are near the top or bottom)\n\t\treturn this._actualDoHitTestWithCaretRangeFromPoint(ctx, request.pos.toClientCoordinates(dom.getWindow(ctx.viewDomNode)));\n\t}\n\n\tprivate static _actualDoHitTestWithCaretRangeFromPoint(ctx: HitTestContext, coords: ClientCoordinates): HitTestResult {\n\t\tconst shadowRoot = dom.getShadowRoot(ctx.viewDomNode);\n\t\tlet range: Range;\n\t\tif (shadowRoot) {\n\t\t\tif (typeof (shadowRoot).caretRangeFromPoint === 'undefined') {\n\t\t\t\trange = shadowCaretRangeFromPoint(shadowRoot, coords.clientX, coords.clientY);\n\t\t\t} else {\n\t\t\t\trange = (shadowRoot).caretRangeFromPoint(coords.clientX, coords.clientY);\n\t\t\t}\n\t\t} else {\n\t\t\trange = (ctx.viewDomNode.ownerDocument).caretRangeFromPoint(coords.clientX, coords.clientY);\n\t\t}\n\n\t\tif (!range || !range.startContainer) {\n\t\t\treturn new UnknownHitTestResult();\n\t\t}\n\n\t\t// Chrome always hits a TEXT_NODE, while Edge sometimes hits a token span\n\t\tconst startContainer = range.startContainer;\n\n\t\tif (startContainer.nodeType === startContainer.TEXT_NODE) {\n\t\t\t// startContainer is expected to be the token text\n\t\t\tconst parent1 = startContainer.parentNode; // expected to be the token span\n\t\t\tconst parent2 = parent1 ? parent1.parentNode : null; // expected to be the view line container span\n\t\t\tconst parent3 = parent2 ? parent2.parentNode : null; // expected to be the view line div\n\t\t\tconst parent3ClassName = parent3 && parent3.nodeType === parent3.ELEMENT_NODE ? (parent3).className : null;\n\n\t\t\tif (parent3ClassName === ViewLine.CLASS_NAME) {\n\t\t\t\treturn HitTestResult.createFromDOMInfo(ctx, parent1, range.startOffset);\n\t\t\t} else {\n\t\t\t\treturn new UnknownHitTestResult(startContainer.parentNode);\n\t\t\t}\n\t\t} else if (startContainer.nodeType === startContainer.ELEMENT_NODE) {\n\t\t\t// startContainer is expected to be the token span\n\t\t\tconst parent1 = startContainer.parentNode; // expected to be the view line container span\n\t\t\tconst parent2 = parent1 ? parent1.parentNode : null; // expected to be the view line div\n\t\t\tconst parent2ClassName = parent2 && parent2.nodeType === parent2.ELEMENT_NODE ? (parent2).className : null;\n\n\t\t\tif (parent2ClassName === ViewLine.CLASS_NAME) {\n\t\t\t\treturn HitTestResult.createFromDOMInfo(ctx, startContainer, (startContainer).textContent!.length);\n\t\t\t} else {\n\t\t\t\treturn new UnknownHitTestResult(startContainer);\n\t\t\t}\n\t\t}\n\n\t\treturn new UnknownHitTestResult();\n\t}\n\n\t/**\n\t * Most probably Gecko\n\t */\n\tprivate static _doHitTestWithCaretPositionFromPoint(ctx: HitTestContext, coords: ClientCoordinates): HitTestResult {\n\t\tconst hitResult: { offsetNode: Node; offset: number } = (ctx.viewDomNode.ownerDocument).caretPositionFromPoint(coords.clientX, coords.clientY);\n\n\t\tif (hitResult.offsetNode.nodeType === hitResult.offsetNode.TEXT_NODE) {\n\t\t\t// offsetNode is expected to be the token text\n\t\t\tconst parent1 = hitResult.offsetNode.parentNode; // expected to be the token span\n\t\t\tconst parent2 = parent1 ? parent1.parentNode : null; // expected to be the view line container span\n\t\t\tconst parent3 = parent2 ? parent2.parentNode : null; // expected to be the view line div\n\t\t\tconst parent3ClassName = parent3 && parent3.nodeType === parent3.ELEMENT_NODE ? (parent3).className : null;\n\n\t\t\tif (parent3ClassName === ViewLine.CLASS_NAME) {\n\t\t\t\treturn HitTestResult.createFromDOMInfo(ctx, hitResult.offsetNode.parentNode, hitResult.offset);\n\t\t\t} else {\n\t\t\t\treturn new UnknownHitTestResult(hitResult.offsetNode.parentNode);\n\t\t\t}\n\t\t}\n\n\t\t// For inline decorations, Gecko sometimes returns the `` of the line and the offset is the `` with the inline decoration\n\t\t// Some other times, it returns the `` with the inline decoration\n\t\tif (hitResult.offsetNode.nodeType === hitResult.offsetNode.ELEMENT_NODE) {\n\t\t\tconst parent1 = hitResult.offsetNode.parentNode;\n\t\t\tconst parent1ClassName = parent1 && parent1.nodeType === parent1.ELEMENT_NODE ? (parent1).className : null;\n\t\t\tconst parent2 = parent1 ? parent1.parentNode : null;\n\t\t\tconst parent2ClassName = parent2 && parent2.nodeType === parent2.ELEMENT_NODE ? (parent2).className : null;\n\n\t\t\tif (parent1ClassName === ViewLine.CLASS_NAME) {\n\t\t\t\t// it returned the `` of the line and the offset is the `` with the inline decoration\n\t\t\t\tconst tokenSpan = hitResult.offsetNode.childNodes[Math.min(hitResult.offset, hitResult.offsetNode.childNodes.length - 1)];\n\t\t\t\tif (tokenSpan) {\n\t\t\t\t\treturn HitTestResult.createFromDOMInfo(ctx, tokenSpan, 0);\n\t\t\t\t}\n\t\t\t} else if (parent2ClassName === ViewLine.CLASS_NAME) {\n\t\t\t\t// it returned the `` with the inline decoration\n\t\t\t\treturn HitTestResult.createFromDOMInfo(ctx, hitResult.offsetNode, 0);\n\t\t\t}\n\t\t}\n\n\t\treturn new UnknownHitTestResult(hitResult.offsetNode);\n\t}\n\n\tprivate static _snapToSoftTabBoundary(position: Position, viewModel: IViewModel): Position {\n\t\tconst lineContent = viewModel.getLineContent(position.lineNumber);\n\t\tconst { tabSize } = viewModel.model.getOptions();\n\t\tconst newPosition = AtomicTabMoveOperations.atomicPosition(lineContent, position.column - 1, tabSize, Direction.Nearest);\n\t\tif (newPosition !== -1) {\n\t\t\treturn new Position(position.lineNumber, newPosition + 1);\n\t\t}\n\t\treturn position;\n\t}\n\n\tpublic static doHitTest(ctx: HitTestContext, request: BareHitTestRequest): HitTestResult {\n\n\t\tlet result: HitTestResult = new UnknownHitTestResult();\n\t\tif (typeof (ctx.viewDomNode.ownerDocument).caretRangeFromPoint === 'function') {\n\t\t\tresult = this._doHitTestWithCaretRangeFromPoint(ctx, request);\n\t\t} else if ((ctx.viewDomNode.ownerDocument).caretPositionFromPoint) {\n\t\t\tresult = this._doHitTestWithCaretPositionFromPoint(ctx, request.pos.toClientCoordinates(dom.getWindow(ctx.viewDomNode)));\n\t\t}\n\t\tif (result.type === HitTestResultType.Content) {\n\t\t\tconst injectedText = ctx.viewModel.getInjectedTextAt(result.position);\n\n\t\t\tconst normalizedPosition = ctx.viewModel.normalizePosition(result.position, PositionAffinity.None);\n\t\t\tif (injectedText || !normalizedPosition.equals(result.position)) {\n\t\t\t\tresult = new ContentHitTestResult(normalizedPosition, result.spanNode, injectedText);\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n}\n\nfunction shadowCaretRangeFromPoint(shadowRoot: ShadowRoot, x: number, y: number): Range {\n\tconst range = document.createRange();\n\n\t// Get the element under the point\n\tlet el: Element | null = (shadowRoot).elementFromPoint(x, y);\n\n\tif (el !== null) {\n\t\t// Get the last child of the element until its firstChild is a text node\n\t\t// This assumes that the pointer is on the right of the line, out of the tokens\n\t\t// and that we want to get the offset of the last token of the line\n\t\twhile (el && el.firstChild && el.firstChild.nodeType !== el.firstChild.TEXT_NODE && el.lastChild && el.lastChild.firstChild) {\n\t\t\tel = el.lastChild;\n\t\t}\n\n\t\t// Grab its rect\n\t\tconst rect = el.getBoundingClientRect();\n\n\t\t// And its font (the computed shorthand font property might be empty, see #3217)\n\t\tconst elWindow = dom.getWindow(el);\n\t\tconst fontStyle = elWindow.getComputedStyle(el, null).getPropertyValue('font-style');\n\t\tconst fontVariant = elWindow.getComputedStyle(el, null).getPropertyValue('font-variant');\n\t\tconst fontWeight = elWindow.getComputedStyle(el, null).getPropertyValue('font-weight');\n\t\tconst fontSize = elWindow.getComputedStyle(el, null).getPropertyValue('font-size');\n\t\tconst lineHeight = elWindow.getComputedStyle(el, null).getPropertyValue('line-height');\n\t\tconst fontFamily = elWindow.getComputedStyle(el, null).getPropertyValue('font-family');\n\t\tconst font = `${fontStyle} ${fontVariant} ${fontWeight} ${fontSize}/${lineHeight} ${fontFamily}`;\n\n\t\t// And also its txt content\n\t\tconst text = (el as any).innerText;\n\n\t\t// Position the pixel cursor at the left of the element\n\t\tlet pixelCursor = rect.left;\n\t\tlet offset = 0;\n\t\tlet step: number;\n\n\t\t// If the point is on the right of the box put the cursor after the last character\n\t\tif (x > rect.left + rect.width) {\n\t\t\toffset = text.length;\n\t\t} else {\n\t\t\tconst charWidthReader = CharWidthReader.getInstance();\n\t\t\t// Goes through all the characters of the innerText, and checks if the x of the point\n\t\t\t// belongs to the character.\n\t\t\tfor (let i = 0; i < text.length + 1; i++) {\n\t\t\t\t// The step is half the width of the character\n\t\t\t\tstep = charWidthReader.getCharWidth(text.charAt(i), font) / 2;\n\t\t\t\t// Move to the center of the character\n\t\t\t\tpixelCursor += step;\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\n\t\t\t\tif (x < pixelCursor) {\n\t\t\t\t\toffset = i;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t// Move between the current character and the next\n\t\t\t\tpixelCursor += step;\n\t\t\t}\n\t\t}\n\n\t\t// Creates a range with the text node of the element and set the offset found\n\t\trange.setStart(el.firstChild!, offset);\n\t\trange.setEnd(el.firstChild!, offset);\n\t}\n\n\treturn range;\n}\n\nclass CharWidthReader {\n\tprivate static _INSTANCE: CharWidthReader | null = null;\n\n\tpublic static getInstance(): CharWidthReader {\n\t\tif (!CharWidthReader._INSTANCE) {\n\t\t\tCharWidthReader._INSTANCE = new CharWidthReader();\n\t\t}\n\t\treturn CharWidthReader._INSTANCE;\n\t}\n\n\tprivate readonly _cache: { [cacheKey: string]: number };\n\tprivate readonly _canvas: HTMLCanvasElement;\n\n\tprivate constructor() {\n\t\tthis._cache = {};\n\t\tthis._canvas = document.createElement('canvas');\n\t}\n\n\tpublic getCharWidth(char: string, font: string): number {\n\t\tconst cacheKey = char + font;\n\t\tif (this._cache[cacheKey]) {\n\t\t\treturn this._cache[cacheKey];\n\t\t}\n\n\t\tconst context = this._canvas.getContext('2d')!;\n\t\tcontext.font = font;\n\t\tconst metrics = context.measureText(char);\n\t\tconst width = metrics.width;\n\t\tthis._cache[cacheKey] = width;\n\t\treturn width;\n\t}\n}\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\nimport * as dom from 'vs/base/browser/dom';\nimport { StandardWheelEvent, IMouseWheelEvent } from 'vs/base/browser/mouseEvent';\nimport { Disposable, IDisposable } from 'vs/base/common/lifecycle';\nimport * as platform from 'vs/base/common/platform';\nimport { HitTestContext, MouseTarget, MouseTargetFactory, PointerHandlerLastRenderData } from 'vs/editor/browser/controller/mouseTarget';\nimport { IMouseTarget, IMouseTargetOutsideEditor, IMouseTargetViewZoneData, MouseTargetType } from 'vs/editor/browser/editorBrowser';\nimport { ClientCoordinates, EditorMouseEvent, EditorMouseEventFactory, GlobalEditorPointerMoveMonitor, createEditorPagePosition, createCoordinatesRelativeToEditor, PageCoordinates } from 'vs/editor/browser/editorDom';\nimport { ViewController } from 'vs/editor/browser/view/viewController';\nimport { EditorZoom } from 'vs/editor/common/config/editorZoom';\nimport { Position } from 'vs/editor/common/core/position';\nimport { Selection } from 'vs/editor/common/core/selection';\nimport { HorizontalPosition } from 'vs/editor/browser/view/renderingContext';\nimport { ViewContext } from 'vs/editor/common/viewModel/viewContext';\nimport * as viewEvents from 'vs/editor/common/viewEvents';\nimport { ViewEventHandler } from 'vs/editor/common/viewEventHandler';\nimport { EditorOption } from 'vs/editor/common/config/editorOptions';\nimport { NavigationCommandRevealType } from 'vs/editor/browser/coreCommands';\nimport { MouseWheelClassifier } from 'vs/base/browser/ui/scrollbar/scrollableElement';\n\nexport interface IPointerHandlerHelper {\n\tviewDomNode: HTMLElement;\n\tlinesContentDomNode: HTMLElement;\n\tviewLinesDomNode: HTMLElement;\n\n\tfocusTextArea(): void;\n\tdispatchTextAreaEvent(event: CustomEvent): void;\n\n\t/**\n\t * Get the last rendered information for cursors & textarea.\n\t */\n\tgetLastRenderData(): PointerHandlerLastRenderData;\n\n\t/**\n\t * Render right now\n\t */\n\trenderNow(): void;\n\n\tshouldSuppressMouseDownOnViewZone(viewZoneId: string): boolean;\n\tshouldSuppressMouseDownOnWidget(widgetId: string): boolean;\n\n\t/**\n\t * Decode a position from a rendered dom node\n\t */\n\tgetPositionFromDOMInfo(spanNode: HTMLElement, offset: number): Position | null;\n\n\tvisibleRangeForPosition(lineNumber: number, column: number): HorizontalPosition | null;\n\tgetLineWidth(lineNumber: number): number;\n}\n\nexport class MouseHandler extends ViewEventHandler {\n\n\tprotected _context: ViewContext;\n\tprotected viewController: ViewController;\n\tprotected viewHelper: IPointerHandlerHelper;\n\tprotected mouseTargetFactory: MouseTargetFactory;\n\tprotected readonly _mouseDownOperation: MouseDownOperation;\n\tprivate lastMouseLeaveTime: number;\n\tprivate _height: number;\n\tprivate _mouseLeaveMonitor: IDisposable | null = null;\n\n\tconstructor(context: ViewContext, viewController: ViewController, viewHelper: IPointerHandlerHelper) {\n\t\tsuper();\n\n\t\tthis._context = context;\n\t\tthis.viewController = viewController;\n\t\tthis.viewHelper = viewHelper;\n\t\tthis.mouseTargetFactory = new MouseTargetFactory(this._context, viewHelper);\n\n\t\tthis._mouseDownOperation = this._register(new MouseDownOperation(\n\t\t\tthis._context,\n\t\t\tthis.viewController,\n\t\t\tthis.viewHelper,\n\t\t\tthis.mouseTargetFactory,\n\t\t\t(e, testEventTarget) => this._createMouseTarget(e, testEventTarget),\n\t\t\t(e) => this._getMouseColumn(e)\n\t\t));\n\n\t\tthis.lastMouseLeaveTime = -1;\n\t\tthis._height = this._context.configuration.options.get(EditorOption.layoutInfo).height;\n\n\t\tconst mouseEvents = new EditorMouseEventFactory(this.viewHelper.viewDomNode);\n\n\t\tthis._register(mouseEvents.onContextMenu(this.viewHelper.viewDomNode, (e) => this._onContextMenu(e, true)));\n\n\t\tthis._register(mouseEvents.onMouseMove(this.viewHelper.viewDomNode, (e) => {\n\t\t\tthis._onMouseMove(e);\n\n\t\t\t// See https://github.com/microsoft/vscode/issues/138789\n\t\t\t// When moving the mouse really quickly, the browser sometimes forgets to\n\t\t\t// send us a `mouseleave` or `mouseout` event. We therefore install here\n\t\t\t// a global `mousemove` listener to manually recover if the mouse goes outside\n\t\t\t// the editor. As soon as the mouse leaves outside of the editor, we\n\t\t\t// remove this listener\n\n\t\t\tif (!this._mouseLeaveMonitor) {\n\t\t\t\tthis._mouseLeaveMonitor = dom.addDisposableListener(this.viewHelper.viewDomNode.ownerDocument, 'mousemove', (e) => {\n\t\t\t\t\tif (!this.viewHelper.viewDomNode.contains(e.target as Node | null)) {\n\t\t\t\t\t\t// went outside the editor!\n\t\t\t\t\t\tthis._onMouseLeave(new EditorMouseEvent(e, false, this.viewHelper.viewDomNode));\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t}));\n\n\t\tthis._register(mouseEvents.onMouseUp(this.viewHelper.viewDomNode, (e) => this._onMouseUp(e)));\n\n\t\tthis._register(mouseEvents.onMouseLeave(this.viewHelper.viewDomNode, (e) => this._onMouseLeave(e)));\n\n\t\t// `pointerdown` events can't be used to determine if there's a double click, or triple click\n\t\t// because their `e.detail` is always 0.\n\t\t// We will therefore save the pointer id for the mouse and then reuse it in the `mousedown` event\n\t\t// for `element.setPointerCapture`.\n\t\tlet capturePointerId: number = 0;\n\t\tthis._register(mouseEvents.onPointerDown(this.viewHelper.viewDomNode, (e, pointerId) => {\n\t\t\tcapturePointerId = pointerId;\n\t\t}));\n\t\t// The `pointerup` listener registered by `GlobalEditorPointerMoveMonitor` does not get invoked 100% of the times.\n\t\t// I speculate that this is because the `pointerup` listener is only registered during the `mousedown` event, and perhaps\n\t\t// the `pointerup` event is already queued for dispatching, which makes it that the new listener doesn't get fired.\n\t\t// See https://github.com/microsoft/vscode/issues/146486 for repro steps.\n\t\t// To compensate for that, we simply register here a `pointerup` listener and just communicate it.\n\t\tthis._register(dom.addDisposableListener(this.viewHelper.viewDomNode, dom.EventType.POINTER_UP, (e: PointerEvent) => {\n\t\t\tthis._mouseDownOperation.onPointerUp();\n\t\t}));\n\t\tthis._register(mouseEvents.onMouseDown(this.viewHelper.viewDomNode, (e) => this._onMouseDown(e, capturePointerId)));\n\t\tthis._setupMouseWheelZoomListener();\n\n\t\tthis._context.addEventHandler(this);\n\t}\n\n\tprivate _setupMouseWheelZoomListener(): void {\n\n\t\tconst classifier = MouseWheelClassifier.INSTANCE;\n\n\t\tlet prevMouseWheelTime = 0;\n\t\tlet gestureStartZoomLevel = EditorZoom.getZoomLevel();\n\t\tlet gestureHasZoomModifiers = false;\n\t\tlet gestureAccumulatedDelta = 0;\n\n\t\tconst onMouseWheel = (browserEvent: IMouseWheelEvent) => {\n\t\t\tthis.viewController.emitMouseWheel(browserEvent);\n\n\t\t\tif (!this._context.configuration.options.get(EditorOption.mouseWheelZoom)) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst e = new StandardWheelEvent(browserEvent);\n\t\t\tclassifier.acceptStandardWheelEvent(e);\n\n\t\t\tif (classifier.isPhysicalMouseWheel()) {\n\t\t\t\tif (hasMouseWheelZoomModifiers(browserEvent)) {\n\t\t\t\t\tconst zoomLevel: number = EditorZoom.getZoomLevel();\n\t\t\t\t\tconst delta = e.deltaY > 0 ? 1 : -1;\n\t\t\t\t\tEditorZoom.setZoomLevel(zoomLevel + delta);\n\t\t\t\t\te.preventDefault();\n\t\t\t\t\te.stopPropagation();\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// we consider mousewheel events that occur within 50ms of each other to be part of the same gesture\n\t\t\t\t// we don't want to consider mouse wheel events where ctrl/cmd is pressed during the inertia phase\n\t\t\t\t// we also want to accumulate deltaY values from the same gesture and use that to set the zoom level\n\t\t\t\tif (Date.now() - prevMouseWheelTime > 50) {\n\t\t\t\t\t// reset if more than 50ms have passed\n\t\t\t\t\tgestureStartZoomLevel = EditorZoom.getZoomLevel();\n\t\t\t\t\tgestureHasZoomModifiers = hasMouseWheelZoomModifiers(browserEvent);\n\t\t\t\t\tgestureAccumulatedDelta = 0;\n\t\t\t\t}\n\n\t\t\t\tprevMouseWheelTime = Date.now();\n\t\t\t\tgestureAccumulatedDelta += e.deltaY;\n\n\t\t\t\tif (gestureHasZoomModifiers) {\n\t\t\t\t\tEditorZoom.setZoomLevel(gestureStartZoomLevel + gestureAccumulatedDelta / 5);\n\t\t\t\t\te.preventDefault();\n\t\t\t\t\te.stopPropagation();\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\tthis._register(dom.addDisposableListener(this.viewHelper.viewDomNode, dom.EventType.MOUSE_WHEEL, onMouseWheel, { capture: true, passive: false }));\n\n\t\tfunction hasMouseWheelZoomModifiers(browserEvent: IMouseWheelEvent): boolean {\n\t\t\treturn (\n\t\t\t\tplatform.isMacintosh\n\t\t\t\t\t// on macOS we support cmd + two fingers scroll (`metaKey` set)\n\t\t\t\t\t// and also the two fingers pinch gesture (`ctrKey` set)\n\t\t\t\t\t? ((browserEvent.metaKey || browserEvent.ctrlKey) && !browserEvent.shiftKey && !browserEvent.altKey)\n\t\t\t\t\t: (browserEvent.ctrlKey && !browserEvent.metaKey && !browserEvent.shiftKey && !browserEvent.altKey)\n\t\t\t);\n\t\t}\n\t}\n\n\tpublic override dispose(): void {\n\t\tthis._context.removeEventHandler(this);\n\t\tif (this._mouseLeaveMonitor) {\n\t\t\tthis._mouseLeaveMonitor.dispose();\n\t\t\tthis._mouseLeaveMonitor = null;\n\t\t}\n\t\tsuper.dispose();\n\t}\n\n\t// --- begin event handlers\n\tpublic override onConfigurationChanged(e: viewEvents.ViewConfigurationChangedEvent): boolean {\n\t\tif (e.hasChanged(EditorOption.layoutInfo)) {\n\t\t\t// layout change\n\t\t\tconst height = this._context.configuration.options.get(EditorOption.layoutInfo).height;\n\t\t\tif (this._height !== height) {\n\t\t\t\tthis._height = height;\n\t\t\t\tthis._mouseDownOperation.onHeightChanged();\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\tpublic override onCursorStateChanged(e: viewEvents.ViewCursorStateChangedEvent): boolean {\n\t\tthis._mouseDownOperation.onCursorStateChanged(e);\n\t\treturn false;\n\t}\n\tpublic override onFocusChanged(e: viewEvents.ViewFocusChangedEvent): boolean {\n\t\treturn false;\n\t}\n\t// --- end event handlers\n\n\tpublic getTargetAtClientPoint(clientX: number, clientY: number): IMouseTarget | null {\n\t\tconst clientPos = new ClientCoordinates(clientX, clientY);\n\t\tconst pos = clientPos.toPageCoordinates(dom.getWindow(this.viewHelper.viewDomNode));\n\t\tconst editorPos = createEditorPagePosition(this.viewHelper.viewDomNode);\n\n\t\tif (pos.y < editorPos.y || pos.y > editorPos.y + editorPos.height || pos.x < editorPos.x || pos.x > editorPos.x + editorPos.width) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst relativePos = createCoordinatesRelativeToEditor(this.viewHelper.viewDomNode, editorPos, pos);\n\t\treturn this.mouseTargetFactory.createMouseTarget(this.viewHelper.getLastRenderData(), editorPos, pos, relativePos, null);\n\t}\n\n\tprotected _createMouseTarget(e: EditorMouseEvent, testEventTarget: boolean): IMouseTarget {\n\t\tlet target = e.target;\n\t\tif (!this.viewHelper.viewDomNode.contains(target)) {\n\t\t\tconst shadowRoot = dom.getShadowRoot(this.viewHelper.viewDomNode);\n\t\t\tif (shadowRoot) {\n\t\t\t\ttarget = (shadowRoot).elementsFromPoint(e.posx, e.posy).find(\n\t\t\t\t\t(el: Element) => this.viewHelper.viewDomNode.contains(el)\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\treturn this.mouseTargetFactory.createMouseTarget(this.viewHelper.getLastRenderData(), e.editorPos, e.pos, e.relativePos, testEventTarget ? target : null);\n\t}\n\n\tprivate _getMouseColumn(e: EditorMouseEvent): number {\n\t\treturn this.mouseTargetFactory.getMouseColumn(e.relativePos);\n\t}\n\n\tprotected _onContextMenu(e: EditorMouseEvent, testEventTarget: boolean): void {\n\t\tthis.viewController.emitContextMenu({\n\t\t\tevent: e,\n\t\t\ttarget: this._createMouseTarget(e, testEventTarget)\n\t\t});\n\t}\n\n\tprotected _onMouseMove(e: EditorMouseEvent): void {\n\t\tconst targetIsWidget = this.mouseTargetFactory.mouseTargetIsWidget(e);\n\t\tif (!targetIsWidget) {\n\t\t\te.preventDefault();\n\t\t}\n\n\t\tif (this._mouseDownOperation.isActive()) {\n\t\t\t// In selection/drag operation\n\t\t\treturn;\n\t\t}\n\t\tconst actualMouseMoveTime = e.timestamp;\n\t\tif (actualMouseMoveTime < this.lastMouseLeaveTime) {\n\t\t\t// Due to throttling, this event occurred before the mouse left the editor, therefore ignore it.\n\t\t\treturn;\n\t\t}\n\n\t\tthis.viewController.emitMouseMove({\n\t\t\tevent: e,\n\t\t\ttarget: this._createMouseTarget(e, true)\n\t\t});\n\t}\n\n\tprotected _onMouseLeave(e: EditorMouseEvent): void {\n\t\tif (this._mouseLeaveMonitor) {\n\t\t\tthis._mouseLeaveMonitor.dispose();\n\t\t\tthis._mouseLeaveMonitor = null;\n\t\t}\n\t\tthis.lastMouseLeaveTime = (new Date()).getTime();\n\t\tthis.viewController.emitMouseLeave({\n\t\t\tevent: e,\n\t\t\ttarget: null\n\t\t});\n\t}\n\n\tprotected _onMouseUp(e: EditorMouseEvent): void {\n\t\tthis.viewController.emitMouseUp({\n\t\t\tevent: e,\n\t\t\ttarget: this._createMouseTarget(e, true)\n\t\t});\n\t}\n\n\tprotected _onMouseDown(e: EditorMouseEvent, pointerId: number): void {\n\t\tconst t = this._createMouseTarget(e, true);\n\n\t\tconst targetIsContent = (t.type === MouseTargetType.CONTENT_TEXT || t.type === MouseTargetType.CONTENT_EMPTY);\n\t\tconst targetIsGutter = (t.type === MouseTargetType.GUTTER_GLYPH_MARGIN || t.type === MouseTargetType.GUTTER_LINE_NUMBERS || t.type === MouseTargetType.GUTTER_LINE_DECORATIONS);\n\t\tconst targetIsLineNumbers = (t.type === MouseTargetType.GUTTER_LINE_NUMBERS);\n\t\tconst selectOnLineNumbers = this._context.configuration.options.get(EditorOption.selectOnLineNumbers);\n\t\tconst targetIsViewZone = (t.type === MouseTargetType.CONTENT_VIEW_ZONE || t.type === MouseTargetType.GUTTER_VIEW_ZONE);\n\t\tconst targetIsWidget = (t.type === MouseTargetType.CONTENT_WIDGET);\n\n\t\tlet shouldHandle = e.leftButton || e.middleButton;\n\t\tif (platform.isMacintosh && e.leftButton && e.ctrlKey) {\n\t\t\tshouldHandle = false;\n\t\t}\n\n\t\tconst focus = () => {\n\t\t\te.preventDefault();\n\t\t\tthis.viewHelper.focusTextArea();\n\t\t};\n\n\t\tif (shouldHandle && (targetIsContent || (targetIsLineNumbers && selectOnLineNumbers))) {\n\t\t\tfocus();\n\t\t\tthis._mouseDownOperation.start(t.type, e, pointerId);\n\n\t\t} else if (targetIsGutter) {\n\t\t\t// Do not steal focus\n\t\t\te.preventDefault();\n\t\t} else if (targetIsViewZone) {\n\t\t\tconst viewZoneData = t.detail;\n\t\t\tif (shouldHandle && this.viewHelper.shouldSuppressMouseDownOnViewZone(viewZoneData.viewZoneId)) {\n\t\t\t\tfocus();\n\t\t\t\tthis._mouseDownOperation.start(t.type, e, pointerId);\n\t\t\t\te.preventDefault();\n\t\t\t}\n\t\t} else if (targetIsWidget && this.viewHelper.shouldSuppressMouseDownOnWidget(t.detail)) {\n\t\t\tfocus();\n\t\t\te.preventDefault();\n\t\t}\n\n\t\tthis.viewController.emitMouseDown({\n\t\t\tevent: e,\n\t\t\ttarget: t\n\t\t});\n\t}\n}\n\nclass MouseDownOperation extends Disposable {\n\n\tprivate readonly _createMouseTarget: (e: EditorMouseEvent, testEventTarget: boolean) => IMouseTarget;\n\tprivate readonly _getMouseColumn: (e: EditorMouseEvent) => number;\n\n\tprivate readonly _mouseMoveMonitor: GlobalEditorPointerMoveMonitor;\n\tprivate readonly _topBottomDragScrolling: TopBottomDragScrolling;\n\tprivate readonly _mouseState: MouseDownState;\n\n\tprivate _currentSelection: Selection;\n\tprivate _isActive: boolean;\n\tprivate _lastMouseEvent: EditorMouseEvent | null;\n\n\tconstructor(\n\t\tprivate readonly _context: ViewContext,\n\t\tprivate readonly _viewController: ViewController,\n\t\tprivate readonly _viewHelper: IPointerHandlerHelper,\n\t\tprivate readonly _mouseTargetFactory: MouseTargetFactory,\n\t\tcreateMouseTarget: (e: EditorMouseEvent, testEventTarget: boolean) => IMouseTarget,\n\t\tgetMouseColumn: (e: EditorMouseEvent) => number\n\t) {\n\t\tsuper();\n\t\tthis._createMouseTarget = createMouseTarget;\n\t\tthis._getMouseColumn = getMouseColumn;\n\n\t\tthis._mouseMoveMonitor = this._register(new GlobalEditorPointerMoveMonitor(this._viewHelper.viewDomNode));\n\t\tthis._topBottomDragScrolling = this._register(new TopBottomDragScrolling(\n\t\t\tthis._context,\n\t\t\tthis._viewHelper,\n\t\t\tthis._mouseTargetFactory,\n\t\t\t(position, inSelectionMode, revealType) => this._dispatchMouse(position, inSelectionMode, revealType)\n\t\t));\n\t\tthis._mouseState = new MouseDownState();\n\n\t\tthis._currentSelection = new Selection(1, 1, 1, 1);\n\t\tthis._isActive = false;\n\t\tthis._lastMouseEvent = null;\n\t}\n\n\tpublic override dispose(): void {\n\t\tsuper.dispose();\n\t}\n\n\tpublic isActive(): boolean {\n\t\treturn this._isActive;\n\t}\n\n\tprivate _onMouseDownThenMove(e: EditorMouseEvent): void {\n\t\tthis._lastMouseEvent = e;\n\t\tthis._mouseState.setModifiers(e);\n\n\t\tconst position = this._findMousePosition(e, false);\n\t\tif (!position) {\n\t\t\t// Ignoring because position is unknown\n\t\t\treturn;\n\t\t}\n\n\t\tif (this._mouseState.isDragAndDrop) {\n\t\t\tthis._viewController.emitMouseDrag({\n\t\t\t\tevent: e,\n\t\t\t\ttarget: position\n\t\t\t});\n\t\t} else {\n\t\t\tif (position.type === MouseTargetType.OUTSIDE_EDITOR && (position.outsidePosition === 'above' || position.outsidePosition === 'below')) {\n\t\t\t\tthis._topBottomDragScrolling.start(position, e);\n\t\t\t} else {\n\t\t\t\tthis._topBottomDragScrolling.stop();\n\t\t\t\tthis._dispatchMouse(position, true, NavigationCommandRevealType.Minimal);\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic start(targetType: MouseTargetType, e: EditorMouseEvent, pointerId: number): void {\n\t\tthis._lastMouseEvent = e;\n\n\t\tthis._mouseState.setStartedOnLineNumbers(targetType === MouseTargetType.GUTTER_LINE_NUMBERS);\n\t\tthis._mouseState.setStartButtons(e);\n\t\tthis._mouseState.setModifiers(e);\n\t\tconst position = this._findMousePosition(e, true);\n\t\tif (!position || !position.position) {\n\t\t\t// Ignoring because position is unknown\n\t\t\treturn;\n\t\t}\n\n\t\tthis._mouseState.trySetCount(e.detail, position.position);\n\n\t\t// Overwrite the detail of the MouseEvent, as it will be sent out in an event and contributions might rely on it.\n\t\te.detail = this._mouseState.count;\n\n\t\tconst options = this._context.configuration.options;\n\n\t\tif (!options.get(EditorOption.readOnly)\n\t\t\t&& options.get(EditorOption.dragAndDrop)\n\t\t\t&& !options.get(EditorOption.columnSelection)\n\t\t\t&& !this._mouseState.altKey // we don't support multiple mouse\n\t\t\t&& e.detail < 2 // only single click on a selection can work\n\t\t\t&& !this._isActive // the mouse is not down yet\n\t\t\t&& !this._currentSelection.isEmpty() // we don't drag single cursor\n\t\t\t&& (position.type === MouseTargetType.CONTENT_TEXT) // single click on text\n\t\t\t&& position.position && this._currentSelection.containsPosition(position.position) // single click on a selection\n\t\t) {\n\t\t\tthis._mouseState.isDragAndDrop = true;\n\t\t\tthis._isActive = true;\n\n\t\t\tthis._mouseMoveMonitor.startMonitoring(\n\t\t\t\tthis._viewHelper.viewLinesDomNode,\n\t\t\t\tpointerId,\n\t\t\t\te.buttons,\n\t\t\t\t(e) => this._onMouseDownThenMove(e),\n\t\t\t\t(browserEvent?: MouseEvent | KeyboardEvent) => {\n\t\t\t\t\tconst position = this._findMousePosition(this._lastMouseEvent!, false);\n\n\t\t\t\t\tif (dom.isKeyboardEvent(browserEvent)) {\n\t\t\t\t\t\t// cancel\n\t\t\t\t\t\tthis._viewController.emitMouseDropCanceled();\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis._viewController.emitMouseDrop({\n\t\t\t\t\t\t\tevent: this._lastMouseEvent!,\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\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\tthis._stop();\n\t\t\t\t}\n\t\t\t);\n\n\t\t\treturn;\n\t\t}\n\n\t\tthis._mouseState.isDragAndDrop = false;\n\t\tthis._dispatchMouse(position, e.shiftKey, NavigationCommandRevealType.Minimal);\n\n\t\tif (!this._isActive) {\n\t\t\tthis._isActive = true;\n\t\t\tthis._mouseMoveMonitor.startMonitoring(\n\t\t\t\tthis._viewHelper.viewLinesDomNode,\n\t\t\t\tpointerId,\n\t\t\t\te.buttons,\n\t\t\t\t(e) => this._onMouseDownThenMove(e),\n\t\t\t\t() => this._stop()\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate _stop(): void {\n\t\tthis._isActive = false;\n\t\tthis._topBottomDragScrolling.stop();\n\t}\n\n\tpublic onHeightChanged(): void {\n\t\tthis._mouseMoveMonitor.stopMonitoring();\n\t}\n\n\tpublic onPointerUp(): void {\n\t\tthis._mouseMoveMonitor.stopMonitoring();\n\t}\n\n\tpublic onCursorStateChanged(e: viewEvents.ViewCursorStateChangedEvent): void {\n\t\tthis._currentSelection = e.selections[0];\n\t}\n\n\tprivate _getPositionOutsideEditor(e: EditorMouseEvent): IMouseTarget | null {\n\t\tconst editorContent = e.editorPos;\n\t\tconst model = this._context.viewModel;\n\t\tconst viewLayout = this._context.viewLayout;\n\n\t\tconst mouseColumn = this._getMouseColumn(e);\n\n\t\tif (e.posy < editorContent.y) {\n\t\t\tconst outsideDistance = editorContent.y - e.posy;\n\t\t\tconst verticalOffset = Math.max(viewLayout.getCurrentScrollTop() - outsideDistance, 0);\n\t\t\tconst viewZoneData = HitTestContext.getZoneAtCoord(this._context, verticalOffset);\n\t\t\tif (viewZoneData) {\n\t\t\t\tconst newPosition = this._helpPositionJumpOverViewZone(viewZoneData);\n\t\t\t\tif (newPosition) {\n\t\t\t\t\treturn MouseTarget.createOutsideEditor(mouseColumn, newPosition, 'above', outsideDistance);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst aboveLineNumber = viewLayout.getLineNumberAtVerticalOffset(verticalOffset);\n\t\t\treturn MouseTarget.createOutsideEditor(mouseColumn, new Position(aboveLineNumber, 1), 'above', outsideDistance);\n\t\t}\n\n\t\tif (e.posy > editorContent.y + editorContent.height) {\n\t\t\tconst outsideDistance = e.posy - editorContent.y - editorContent.height;\n\t\t\tconst verticalOffset = viewLayout.getCurrentScrollTop() + e.relativePos.y;\n\t\t\tconst viewZoneData = HitTestContext.getZoneAtCoord(this._context, verticalOffset);\n\t\t\tif (viewZoneData) {\n\t\t\t\tconst newPosition = this._helpPositionJumpOverViewZone(viewZoneData);\n\t\t\t\tif (newPosition) {\n\t\t\t\t\treturn MouseTarget.createOutsideEditor(mouseColumn, newPosition, 'below', outsideDistance);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst belowLineNumber = viewLayout.getLineNumberAtVerticalOffset(verticalOffset);\n\t\t\treturn MouseTarget.createOutsideEditor(mouseColumn, new Position(belowLineNumber, model.getLineMaxColumn(belowLineNumber)), 'below', outsideDistance);\n\t\t}\n\n\t\tconst possibleLineNumber = viewLayout.getLineNumberAtVerticalOffset(viewLayout.getCurrentScrollTop() + e.relativePos.y);\n\n\t\tif (e.posx < editorContent.x) {\n\t\t\tconst outsideDistance = editorContent.x - e.posx;\n\t\t\treturn MouseTarget.createOutsideEditor(mouseColumn, new Position(possibleLineNumber, 1), 'left', outsideDistance);\n\t\t}\n\n\t\tif (e.posx > editorContent.x + editorContent.width) {\n\t\t\tconst outsideDistance = e.posx - editorContent.x - editorContent.width;\n\t\t\treturn MouseTarget.createOutsideEditor(mouseColumn, new Position(possibleLineNumber, model.getLineMaxColumn(possibleLineNumber)), 'right', outsideDistance);\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tprivate _findMousePosition(e: EditorMouseEvent, testEventTarget: boolean): IMouseTarget | null {\n\t\tconst positionOutsideEditor = this._getPositionOutsideEditor(e);\n\t\tif (positionOutsideEditor) {\n\t\t\treturn positionOutsideEditor;\n\t\t}\n\n\t\tconst t = this._createMouseTarget(e, testEventTarget);\n\t\tconst hintedPosition = t.position;\n\t\tif (!hintedPosition) {\n\t\t\treturn null;\n\t\t}\n\n\t\tif (t.type === MouseTargetType.CONTENT_VIEW_ZONE || t.type === MouseTargetType.GUTTER_VIEW_ZONE) {\n\t\t\tconst newPosition = this._helpPositionJumpOverViewZone(t.detail);\n\t\t\tif (newPosition) {\n\t\t\t\treturn MouseTarget.createViewZone(t.type, t.element, t.mouseColumn, newPosition, t.detail);\n\t\t\t}\n\t\t}\n\n\t\treturn t;\n\t}\n\n\tprivate _helpPositionJumpOverViewZone(viewZoneData: IMouseTargetViewZoneData): Position | null {\n\t\t// Force position on view zones to go above or below depending on where selection started from\n\t\tconst selectionStart = new Position(this._currentSelection.selectionStartLineNumber, this._currentSelection.selectionStartColumn);\n\t\tconst positionBefore = viewZoneData.positionBefore;\n\t\tconst positionAfter = viewZoneData.positionAfter;\n\n\t\tif (positionBefore && positionAfter) {\n\t\t\tif (positionBefore.isBefore(selectionStart)) {\n\t\t\t\treturn positionBefore;\n\t\t\t} else {\n\t\t\t\treturn positionAfter;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t}\n\n\tprivate _dispatchMouse(position: IMouseTarget, inSelectionMode: boolean, revealType: NavigationCommandRevealType): void {\n\t\tif (!position.position) {\n\t\t\treturn;\n\t\t}\n\t\tthis._viewController.dispatchMouse({\n\t\t\tposition: position.position,\n\t\t\tmouseColumn: position.mouseColumn,\n\t\t\tstartedOnLineNumbers: this._mouseState.startedOnLineNumbers,\n\t\t\trevealType,\n\n\t\t\tinSelectionMode: inSelectionMode,\n\t\t\tmouseDownCount: this._mouseState.count,\n\t\t\taltKey: this._mouseState.altKey,\n\t\t\tctrlKey: this._mouseState.ctrlKey,\n\t\t\tmetaKey: this._mouseState.metaKey,\n\t\t\tshiftKey: this._mouseState.shiftKey,\n\n\t\t\tleftButton: this._mouseState.leftButton,\n\t\t\tmiddleButton: this._mouseState.middleButton,\n\n\t\t\tonInjectedText: position.type === MouseTargetType.CONTENT_TEXT && position.detail.injectedText !== null\n\t\t});\n\t}\n}\n\nclass TopBottomDragScrolling extends Disposable {\n\n\tprivate _operation: TopBottomDragScrollingOperation | null;\n\n\tconstructor(\n\t\tprivate readonly _context: ViewContext,\n\t\tprivate readonly _viewHelper: IPointerHandlerHelper,\n\t\tprivate readonly _mouseTargetFactory: MouseTargetFactory,\n\t\tprivate readonly _dispatchMouse: (position: IMouseTarget, inSelectionMode: boolean, revealType: NavigationCommandRevealType) => void,\n\t) {\n\t\tsuper();\n\t\tthis._operation = null;\n\t}\n\n\tpublic override dispose(): void {\n\t\tsuper.dispose();\n\t\tthis.stop();\n\t}\n\n\tpublic start(position: IMouseTargetOutsideEditor, mouseEvent: EditorMouseEvent): void {\n\t\tif (this._operation) {\n\t\t\tthis._operation.setPosition(position, mouseEvent);\n\t\t} else {\n\t\t\tthis._operation = new TopBottomDragScrollingOperation(this._context, this._viewHelper, this._mouseTargetFactory, this._dispatchMouse, position, mouseEvent);\n\t\t}\n\t}\n\n\tpublic stop(): void {\n\t\tif (this._operation) {\n\t\t\tthis._operation.dispose();\n\t\t\tthis._operation = null;\n\t\t}\n\t}\n}\n\nclass TopBottomDragScrollingOperation extends Disposable {\n\n\tprivate _position: IMouseTargetOutsideEditor;\n\tprivate _mouseEvent: EditorMouseEvent;\n\tprivate _lastTime: number;\n\tprivate _animationFrameDisposable: IDisposable;\n\n\tconstructor(\n\t\tprivate readonly _context: ViewContext,\n\t\tprivate readonly _viewHelper: IPointerHandlerHelper,\n\t\tprivate readonly _mouseTargetFactory: MouseTargetFactory,\n\t\tprivate readonly _dispatchMouse: (position: IMouseTarget, inSelectionMode: boolean, revealType: NavigationCommandRevealType) => void,\n\t\tposition: IMouseTargetOutsideEditor,\n\t\tmouseEvent: EditorMouseEvent\n\t) {\n\t\tsuper();\n\t\tthis._position = position;\n\t\tthis._mouseEvent = mouseEvent;\n\t\tthis._lastTime = Date.now();\n\t\tthis._animationFrameDisposable = dom.scheduleAtNextAnimationFrame(dom.getWindow(mouseEvent.browserEvent), () => this._execute());\n\t}\n\n\tpublic override dispose(): void {\n\t\tthis._animationFrameDisposable.dispose();\n\t\tsuper.dispose();\n\t}\n\n\tpublic setPosition(position: IMouseTargetOutsideEditor, mouseEvent: EditorMouseEvent): void {\n\t\tthis._position = position;\n\t\tthis._mouseEvent = mouseEvent;\n\t}\n\n\t/**\n\t * update internal state and return elapsed ms since last time\n\t */\n\tprivate _tick(): number {\n\t\tconst now = Date.now();\n\t\tconst elapsed = now - this._lastTime;\n\t\tthis._lastTime = now;\n\t\treturn elapsed;\n\t}\n\n\t/**\n\t * get the number of lines per second to auto-scroll\n\t */\n\tprivate _getScrollSpeed(): number {\n\t\tconst lineHeight = this._context.configuration.options.get(EditorOption.lineHeight);\n\t\tconst viewportInLines = this._context.configuration.options.get(EditorOption.layoutInfo).height / lineHeight;\n\t\tconst outsideDistanceInLines = this._position.outsideDistance / lineHeight;\n\n\t\tif (outsideDistanceInLines <= 1.5) {\n\t\t\treturn Math.max(30, viewportInLines * (1 + outsideDistanceInLines));\n\t\t}\n\t\tif (outsideDistanceInLines <= 3) {\n\t\t\treturn Math.max(60, viewportInLines * (2 + outsideDistanceInLines));\n\t\t}\n\t\treturn Math.max(200, viewportInLines * (7 + outsideDistanceInLines));\n\t}\n\n\tprivate _execute(): void {\n\t\tconst lineHeight = this._context.configuration.options.get(EditorOption.lineHeight);\n\t\tconst scrollSpeedInLines = this._getScrollSpeed();\n\t\tconst elapsed = this._tick();\n\t\tconst scrollInPixels = scrollSpeedInLines * (elapsed / 1000) * lineHeight;\n\t\tconst scrollValue = (this._position.outsidePosition === 'above' ? -scrollInPixels : scrollInPixels);\n\n\t\tthis._context.viewModel.viewLayout.deltaScrollNow(0, scrollValue);\n\t\tthis._viewHelper.renderNow();\n\n\t\tconst viewportData = this._context.viewLayout.getLinesViewportData();\n\t\tconst edgeLineNumber = (this._position.outsidePosition === 'above' ? viewportData.startLineNumber : viewportData.endLineNumber);\n\n\t\t// First, try to find a position that matches the horizontal position of the mouse\n\t\tlet mouseTarget: IMouseTarget;\n\t\t{\n\t\t\tconst editorPos = createEditorPagePosition(this._viewHelper.viewDomNode);\n\t\t\tconst horizontalScrollbarHeight = this._context.configuration.options.get(EditorOption.layoutInfo).horizontalScrollbarHeight;\n\t\t\tconst pos = new PageCoordinates(this._mouseEvent.pos.x, editorPos.y + editorPos.height - horizontalScrollbarHeight - 0.1);\n\t\t\tconst relativePos = createCoordinatesRelativeToEditor(this._viewHelper.viewDomNode, editorPos, pos);\n\t\t\tmouseTarget = this._mouseTargetFactory.createMouseTarget(this._viewHelper.getLastRenderData(), editorPos, pos, relativePos, null);\n\t\t}\n\t\tif (!mouseTarget.position || mouseTarget.position.lineNumber !== edgeLineNumber) {\n\t\t\tif (this._position.outsidePosition === 'above') {\n\t\t\t\tmouseTarget = MouseTarget.createOutsideEditor(this._position.mouseColumn, new Position(edgeLineNumber, 1), 'above', this._position.outsideDistance);\n\t\t\t} else {\n\t\t\t\tmouseTarget = MouseTarget.createOutsideEditor(this._position.mouseColumn, new Position(edgeLineNumber, this._context.viewModel.getLineMaxColumn(edgeLineNumber)), 'below', this._position.outsideDistance);\n\t\t\t}\n\t\t}\n\n\t\tthis._dispatchMouse(mouseTarget, true, NavigationCommandRevealType.None);\n\t\tthis._animationFrameDisposable = dom.scheduleAtNextAnimationFrame(dom.getWindow(mouseTarget.element), () => this._execute());\n\t}\n}\n\nclass MouseDownState {\n\n\tprivate static readonly CLEAR_MOUSE_DOWN_COUNT_TIME = 400; // ms\n\n\tprivate _altKey: boolean;\n\tpublic get altKey(): boolean { return this._altKey; }\n\n\tprivate _ctrlKey: boolean;\n\tpublic get ctrlKey(): boolean { return this._ctrlKey; }\n\n\tprivate _metaKey: boolean;\n\tpublic get metaKey(): boolean { return this._metaKey; }\n\n\tprivate _shiftKey: boolean;\n\tpublic get shiftKey(): boolean { return this._shiftKey; }\n\n\tprivate _leftButton: boolean;\n\tpublic get leftButton(): boolean { return this._leftButton; }\n\n\tprivate _middleButton: boolean;\n\tpublic get middleButton(): boolean { return this._middleButton; }\n\n\tprivate _startedOnLineNumbers: boolean;\n\tpublic get startedOnLineNumbers(): boolean { return this._startedOnLineNumbers; }\n\n\tprivate _lastMouseDownPosition: Position | null;\n\tprivate _lastMouseDownPositionEqualCount: number;\n\tprivate _lastMouseDownCount: number;\n\tprivate _lastSetMouseDownCountTime: number;\n\tpublic isDragAndDrop: boolean;\n\n\tconstructor() {\n\t\tthis._altKey = false;\n\t\tthis._ctrlKey = false;\n\t\tthis._metaKey = false;\n\t\tthis._shiftKey = false;\n\t\tthis._leftButton = false;\n\t\tthis._middleButton = false;\n\t\tthis._startedOnLineNumbers = false;\n\t\tthis._lastMouseDownPosition = null;\n\t\tthis._lastMouseDownPositionEqualCount = 0;\n\t\tthis._lastMouseDownCount = 0;\n\t\tthis._lastSetMouseDownCountTime = 0;\n\t\tthis.isDragAndDrop = false;\n\t}\n\n\tpublic get count(): number {\n\t\treturn this._lastMouseDownCount;\n\t}\n\n\tpublic setModifiers(source: EditorMouseEvent) {\n\t\tthis._altKey = source.altKey;\n\t\tthis._ctrlKey = source.ctrlKey;\n\t\tthis._metaKey = source.metaKey;\n\t\tthis._shiftKey = source.shiftKey;\n\t}\n\n\tpublic setStartButtons(source: EditorMouseEvent) {\n\t\tthis._leftButton = source.leftButton;\n\t\tthis._middleButton = source.middleButton;\n\t}\n\n\tpublic setStartedOnLineNumbers(startedOnLineNumbers: boolean): void {\n\t\tthis._startedOnLineNumbers = startedOnLineNumbers;\n\t}\n\n\tpublic trySetCount(setMouseDownCount: number, newMouseDownPosition: Position): void {\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)\n\t\tconst currentTime = (new Date()).getTime();\n\t\tif (currentTime - this._lastSetMouseDownCountTime > MouseDownState.CLEAR_MOUSE_DOWN_COUNT_TIME) {\n\t\t\tsetMouseDownCount = 1;\n\t\t}\n\t\tthis._lastSetMouseDownCountTime = currentTime;\n\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)\n\t\tif (setMouseDownCount > this._lastMouseDownCount + 1) {\n\t\t\tsetMouseDownCount = this._lastMouseDownCount + 1;\n\t\t}\n\n\t\t// c. Invalidate multiple clicking if the logical position is different\n\t\tif (this._lastMouseDownPosition && this._lastMouseDownPosition.equals(newMouseDownPosition)) {\n\t\t\tthis._lastMouseDownPositionEqualCount++;\n\t\t} else {\n\t\t\tthis._lastMouseDownPositionEqualCount = 1;\n\t\t}\n\t\tthis._lastMouseDownPosition = newMouseDownPosition;\n\n\t\t// Finally set the lastMouseDownCount\n\t\tthis._lastMouseDownCount = Math.min(setMouseDownCount, this._lastMouseDownPositionEqualCount);\n\t}\n\n}\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\nimport { BrowserFeatures } from 'vs/base/browser/canIUse';\nimport * as dom from 'vs/base/browser/dom';\nimport { EventType, Gesture, GestureEvent } from 'vs/base/browser/touch';\nimport { mainWindow } from 'vs/base/browser/window';\nimport { Disposable } from 'vs/base/common/lifecycle';\nimport * as platform from 'vs/base/common/platform';\nimport { IPointerHandlerHelper, MouseHandler } from 'vs/editor/browser/controller/mouseHandler';\nimport { TextAreaSyntethicEvents } from 'vs/editor/browser/controller/textAreaInput';\nimport { NavigationCommandRevealType } from 'vs/editor/browser/coreCommands';\nimport { IMouseTarget, MouseTargetType } from 'vs/editor/browser/editorBrowser';\nimport { EditorMouseEvent, EditorPointerEventFactory } from 'vs/editor/browser/editorDom';\nimport { ViewController } from 'vs/editor/browser/view/viewController';\nimport { ViewContext } from 'vs/editor/common/viewModel/viewContext';\n\n/**\n * Currently only tested on iOS 13/ iPadOS.\n */\nexport class PointerEventHandler extends MouseHandler {\n\tprivate _lastPointerType: string;\n\tconstructor(context: ViewContext, viewController: ViewController, viewHelper: IPointerHandlerHelper) {\n\t\tsuper(context, viewController, viewHelper);\n\n\t\tthis._register(Gesture.addTarget(this.viewHelper.linesContentDomNode));\n\t\tthis._register(dom.addDisposableListener(this.viewHelper.linesContentDomNode, EventType.Tap, (e) => this.onTap(e)));\n\t\tthis._register(dom.addDisposableListener(this.viewHelper.linesContentDomNode, EventType.Change, (e) => this.onChange(e)));\n\t\tthis._register(dom.addDisposableListener(this.viewHelper.linesContentDomNode, EventType.Contextmenu, (e: MouseEvent) => this._onContextMenu(new EditorMouseEvent(e, false, this.viewHelper.viewDomNode), false)));\n\n\t\tthis._lastPointerType = 'mouse';\n\n\t\tthis._register(dom.addDisposableListener(this.viewHelper.linesContentDomNode, 'pointerdown', (e: any) => {\n\t\t\tconst pointerType = e.pointerType;\n\t\t\tif (pointerType === 'mouse') {\n\t\t\t\tthis._lastPointerType = 'mouse';\n\t\t\t\treturn;\n\t\t\t} else if (pointerType === 'touch') {\n\t\t\t\tthis._lastPointerType = 'touch';\n\t\t\t} else {\n\t\t\t\tthis._lastPointerType = 'pen';\n\t\t\t}\n\t\t}));\n\n\t\t// PonterEvents\n\t\tconst pointerEvents = new EditorPointerEventFactory(this.viewHelper.viewDomNode);\n\n\t\tthis._register(pointerEvents.onPointerMove(this.viewHelper.viewDomNode, (e) => this._onMouseMove(e)));\n\t\tthis._register(pointerEvents.onPointerUp(this.viewHelper.viewDomNode, (e) => this._onMouseUp(e)));\n\t\tthis._register(pointerEvents.onPointerLeave(this.viewHelper.viewDomNode, (e) => this._onMouseLeave(e)));\n\t\tthis._register(pointerEvents.onPointerDown(this.viewHelper.viewDomNode, (e, pointerId) => this._onMouseDown(e, pointerId)));\n\t}\n\n\tprivate onTap(event: GestureEvent): void {\n\t\tif (!event.initialTarget || !this.viewHelper.linesContentDomNode.contains(event.initialTarget)) {\n\t\t\treturn;\n\t\t}\n\n\t\tevent.preventDefault();\n\t\tthis.viewHelper.focusTextArea();\n\t\tthis._dispatchGesture(event, /*inSelectionMode*/false);\n\t}\n\n\tprivate onChange(event: GestureEvent): void {\n\t\tif (this._lastPointerType === 'touch') {\n\t\t\tthis._context.viewModel.viewLayout.deltaScrollNow(-event.translationX, -event.translationY);\n\t\t}\n\t\tif (this._lastPointerType === 'pen') {\n\t\t\tthis._dispatchGesture(event, /*inSelectionMode*/true);\n\t\t}\n\t}\n\n\tprivate _dispatchGesture(event: GestureEvent, inSelectionMode: boolean): void {\n\t\tconst target = this._createMouseTarget(new EditorMouseEvent(event, false, this.viewHelper.viewDomNode), false);\n\t\tif (target.position) {\n\t\t\tthis.viewController.dispatchMouse({\n\t\t\t\tposition: target.position,\n\t\t\t\tmouseColumn: target.position.column,\n\t\t\t\tstartedOnLineNumbers: false,\n\t\t\t\trevealType: NavigationCommandRevealType.Minimal,\n\t\t\t\tmouseDownCount: event.tapCount,\n\t\t\t\tinSelectionMode,\n\t\t\t\taltKey: false,\n\t\t\t\tctrlKey: false,\n\t\t\t\tmetaKey: false,\n\t\t\t\tshiftKey: false,\n\t\t\t\tleftButton: false,\n\t\t\t\tmiddleButton: false,\n\t\t\t\tonInjectedText: target.type === MouseTargetType.CONTENT_TEXT && target.detail.injectedText !== null\n\t\t\t});\n\t\t}\n\t}\n\n\tprotected override _onMouseDown(e: EditorMouseEvent, pointerId: number): void {\n\t\tif ((e.browserEvent as any).pointerType === 'touch') {\n\t\t\treturn;\n\t\t}\n\n\t\tsuper._onMouseDown(e, pointerId);\n\t}\n}\n\nclass TouchHandler extends MouseHandler {\n\n\tconstructor(context: ViewContext, viewController: ViewController, viewHelper: IPointerHandlerHelper) {\n\t\tsuper(context, viewController, viewHelper);\n\n\t\tthis._register(Gesture.addTarget(this.viewHelper.linesContentDomNode));\n\n\t\tthis._register(dom.addDisposableListener(this.viewHelper.linesContentDomNode, EventType.Tap, (e) => this.onTap(e)));\n\t\tthis._register(dom.addDisposableListener(this.viewHelper.linesContentDomNode, EventType.Change, (e) => this.onChange(e)));\n\t\tthis._register(dom.addDisposableListener(this.viewHelper.linesContentDomNode, EventType.Contextmenu, (e: MouseEvent) => this._onContextMenu(new EditorMouseEvent(e, false, this.viewHelper.viewDomNode), false)));\n\t}\n\n\tprivate onTap(event: GestureEvent): void {\n\t\tevent.preventDefault();\n\n\t\tthis.viewHelper.focusTextArea();\n\n\t\tconst target = this._createMouseTarget(new EditorMouseEvent(event, false, this.viewHelper.viewDomNode), false);\n\n\t\tif (target.position) {\n\t\t\t// Send the tap event also to the